Задача
Компании хотят консультанта, который отвечает клиентам на сайте и в Telegram по их прайсу и частым вопросам. Он не должен выдумывать цены и условия, должен показывать, откуда взят ответ, а на вопрос вне базы честно звать менеджера. Данные клиентов должны оставаться у компании, а демо — открываться без регистрации и ничего не стоить.
Решение
Одна модель эмбеддингов, multilingual-e5-small в int8, работает и на сервере через onnxruntime, и в браузере через transformers.js, поэтому оба режима находят одни и те же фрагменты. Ответ — сам фрагмент или текст модели, написанный только по нему. Если лучший фрагмент не проходит порог по смыслу и по словам, консультант отказывается и предлагает менеджера. Заявка сначала сохраняется в базе, потом уходит в Telegram, поэтому сбой Telegram её не теряет.
Решённые задачи
- Собрал гибридный поиск: локальная модель e5 в PostgreSQL с pgvector и совпадение слов с весом по редкости
- Подобрал пороги «не знаю» на 21 вопросе: из FAQ, вне базы и пограничных
- Подключил GigaChat и OpenAI-совместимые модели за одним интерфейсом, ответ пишется только по фрагментам
- Сделал заявку менеджеру: имя, телефон, вопрос и вся переписка приходят в Telegram
- Дал посетителю загрузить свой текст или PDF и спросить по нему, файл живёт только в сессии
- Ограничил демо: 10 вопросов в сутки с посетителя, дневной бюджет токенов и очередь вызовов модели
- Сделал виджет, который ставится на сайт одной строкой, и Telegram-бот на том же движке
- Сделал режим браузера на transformers.js с той же моделью: поиск может идти прямо на устройстве посетителя
- Сделал демо-режим: анкета менеджера проходит до конца, но заявка только показывается, имена и телефоны не хранятся
Результат
Приёмочный смоук на настоящей модели: 10 из 10 вопросов из FAQ находят свой фрагмент, 3 из 3 вопросов не по теме получают «не знаю». Проект поднимается командой docker compose up, а демо на этом сайте — тот же контейнер в демо-режиме: отвечает сразу, а заявку показывает вместо отправки.
Комментарий разработчика
Что было трудно
Сложнее всего было научить его отказываться. Одно сходство e5 не отделяло вопросы вне базы: «Почём медовик?» набирал 0.802, а «Сколько стоит ремонт iPhone 15?» — 0.812. Помогла вторая оценка, по словам с весом по редкости: «стоит» есть во многих фрагментах прайса и почти ничего не весит.
Что далось легко
Легко далась заявка менеджеру: короткая анкета с проверкой телефона и сообщение в Telegram со всей перепиской.
Технологии
PythonFastAPIPostgreSQLpgvectorONNX Runtimemultilingual-e5transformers.jsaiogramGigaChatDocker