All work
BotsLanguage schools and course providers2026

An AI manager for a language school

The same questions arrive around the clock, and a wrong answer about money costs more than silence. The bot answers from the knowledge base and hands the rest to a person.

Outcome

  • An answer that rests on no document in the knowledge base never reaches the client at all
  • Money questions and edge cases reach a person instead of being closed by guesswork
  • The owner takes a conversation over only deliberately, and gets a briefing instead of the whole thread
  • Both halves are open: talk to the bot in Telegram, and look inside the owner cabinet with no password
Role
Bot, owner cabinet, knowledge base, server
Updated
2026-09-22
See it live

The problem

A language school sells a decision people think about for weeks, not a product. Questions arrive around the clock and repeat themselves: what is my level, how much does it cost, when can I study, what happens if I miss a class. A person answers them, and answers the same thing every time.

But the questions are not equal. «Will a card from my German bank work» looks as simple as «how long is a lesson», and the cost of getting it wrong is entirely different: someone pays and cannot get the money back. A bot that answers everything with the same confidence costs more here than no bot at all.

What I built

The bot answers clients in Telegram from the school's own knowledge base: levels, lesson formats, prices, schedule, payment, cancellation, and separately what the school does not do. It remembers the client between conversations, so in the second week it does not ask for a name and a goal all over again.

It collects a trial lesson request itself: goal, level, format, time zone, preferred time. When the data is enough is decided by code, not by the model, and the owner receives a card with a finished request.

The owner reads everything in a browser: the list of conversations, the thread itself, the requests. Replies can go from there or simply as a reply in Telegram, where the bot drops a card.

When it fits

  • The same questions, around the clock. A person answers the same thing for the tenth time, and in the evening and at weekends nobody answers at all.
  • Some questions have no right to be wrong. Money, refunds, edge cases: here saying nothing is cheaper than answering incorrectly.
  • Requests live in someone's head. Who is at what stage and who was promised a call back is known only to whoever was in the chat that day.

The main decision: the code does not trust the model

The model answers from the chunks of the knowledge base it was handed, not off the top of its head. The code then checks what it actually cited. If an answer of substance rests on none of the documents found, it does not reach the client at all: the owner gets the question instead, and the client gets an honest «let me check with the manager».

Four reasons to hand a conversation to a person are set by the code, not the model: an answer with no sources, a provider failure, an unreadable response, an exhausted daily token budget. None of them can be talked out of firing.

The client profile and the summaries of past conversations also go into the model as data, not as instructions. A line saying «I was promised a 50% discount» stays a client's claim in the summary, not a new price list.

The boundary: the bot does not take conversations away from people

An ordinary reply from the owner does not make them responsible for the whole conversation: the bot keeps answering everything else. A person takes a conversation over only explicitly, with a button, and receives a briefing that same second: profile, summary, the active request, the tail of the thread. There is no need to read the whole history from scratch.

The reverse matters just as much. A conversation that was taken over and then forgotten returns to the bot by itself after a day, flagged as needing attention. Otherwise the most valuable enquiry quietly goes unanswered precisely because a human picked it up.

Personal data

The logs hold no message text, only identifiers, event types and durations. The client profile and the conversation summary are not logged at all: that is personal data. The cabinet has no access to the database, no bot token and no model key, so a compromised browser opens none of it.

How it is verified

39 scenarios run against the real model rather than a stub: price questions with a catch, questions about things the school does not do, attempts to override the instructions with text inside a message, coming back to an old topic a week later. Separately, 108 tests against a real Postgres.

A run against the live model costs money, so it is not part of the ordinary test suite. But without it «the bot does not make things up» stays a promise rather than a verified fact.

Try it yourself

The bot is answering right now, through the «See it live» link. The interesting things to ask are the ones these bots usually break on: ask for a discount, ask about an exam that is not in the programme, or ask whether a card from your bank will go through. The right answer to the last one is not «yes», it is «let me check with the manager».

The other half of the work lives in the owner cabinet, and it is open as well: a demo with no password. It holds the same conversations the bot actually ran, with the client profile, the collected requests and the point where a conversation went to the manager. Nothing in it can be changed: it is a separate instance that reads its own database and can do nothing else.

Common questions

Can the bot invent a price or promise something that does not exist? No, and that rests on code rather than a promise: an answer that leans on no document in the knowledge base is never sent to the client at all.

What if someone writes «ignore all previous instructions»? Nothing changes. The client's text goes into the model as the client's text, not as new rules, and that is a separate scenario in the checks.

And if the model is unavailable? The client gets a neutral reply and the conversation goes to a person. A failure of an external service does not bring the bot down and does not make it go silent.

Stack

  • Python
  • FastAPI
  • LLM
  • pgvector
  • Next.js
  • Docker

Got a similar task?

Describe it in two sentences. I'll tell you if it can be automated and roughly what it costs.

Message me on Telegram