Task
Companies want a consultant that answers customers on the site and in Telegram from their own price list and FAQ. It must not make up prices or terms, must show where an answer comes from, and must honestly call a manager when the question is outside the base. Customer data has to stay with the company, and the demo has to open without sign-up and cost nothing.
Solution
One embedding model, multilingual-e5-small in int8, runs both on the server through onnxruntime and in the browser through transformers.js, so both modes find the same fragments. The answer is the fragment itself or a model's text written only from it. When the best fragment fails the meaning or the word threshold, the consultant refuses and offers a manager. A lead is saved to the database first and then sent to Telegram, so a Telegram failure does not lose it.
What was done
- Built hybrid search: a local e5 model in PostgreSQL with pgvector plus word overlap weighted by rarity
- Tuned the “don't know” thresholds on 21 questions: from the FAQ, off-topic and borderline
- Connected GigaChat and OpenAI-compatible models behind one interface, answers use only the fragments
- Built the hand-off to a manager: name, phone, the question and the whole dialog arrive in Telegram
- Let visitors upload their own text or PDF and ask about it, the file lives only for the session
- Limited the demo: 10 questions a day per visitor, a daily token budget and a queue for model calls
- Built a widget that goes on a site in one line, and a Telegram bot on the same engine
- Added a browser mode on transformers.js with the same model: the search can run on the visitor's device
- Added a demo mode: the manager form runs to the end, but the lead is only shown, names and phones are not kept
Result
The acceptance smoke on the real model: 10 of 10 FAQ questions find their fragment, 3 of 3 off-topic questions get “don't know”. The project starts with docker compose up, and the demo on this site is the same container in demo mode: it answers at once and shows the lead instead of sending it.
Developer's note
What was hard
The hardest part was teaching it to refuse. e5 similarity alone did not separate off-topic questions: “how much is the honey cake?” scored 0.802 and “how much is an iPhone 15 repair?” 0.812. A second score on words weighted by rarity solved it: “how much” is in many price fragments and weighs almost nothing.
What came easy
The hand-off to a manager came easy: a short form with a phone check and a Telegram message with the whole dialog.
Technologies
PythonFastAPIPostgreSQLpgvectorONNX Runtimemultilingual-e5transformers.jsaiogramGigaChatDocker