Чат-бот, который не выдумывает: как заземлить ответы
Бот не врёт, потому что злой. Он врёт, потому что вы не дали ему права сказать «не знаю».
Запустили мы как-то FAQ-бота для службы поддержки. На демо он отвечал блестяще. Через два дня клиент переслал диалог, где бот уверенно объяснял пользователю условия возврата, которых в компании никогда не было. Сочинил с нуля. Вежливо, складно, с точностью до процентов. И полностью неправда.
Языковая модель не знает, что она не знает. Спросите её про вашу политику возвратов — и она выдаст самый правдоподобный текст, а не правду. Это разные вещи. Лечится это не «более умной моделью», а тем, что вы заставляете её отвечать только по вашим документам. Это и есть RAG.
Как это работает по шагам
Сначала документы режутся на куски — чанки. Не по тысяче слов и не по предложению. Я обычно беру 300–500 токенов с небольшим перехлёстом, чтобы мысль не обрывалась ровно на границе. Каждый чанк прогоняется через модель эмбеддингов и превращается в вектор — координаты смысла. Всё это лежит в векторной базе.
Когда приходит вопрос, он тоже превращается в вектор, и база возвращает несколько ближайших чанков. Эти куски — и только они — попадают в промпт как контекст. Модель отвечает, опираясь на них, а не на то, что она «помнит» из интернета. Дальше — самое важное.
Право сказать «не знаю»
Большинство ботов галлюцинируют не из-за плохого поиска, а из-за плохого промпта. Если вы просто даёте модели контекст и вопрос, она будет отвечать всегда — даже когда в контексте пусто. Ей нужно явно разрешить сдаваться. Вот тот системный промпт, который я ставлю по умолчанию.
You answer ONLY from the provided context.
If the answer is not in the context, reply exactly:
"I don't have that in our docs — let me connect you to a human."
Never use outside knowledge. Never guess.
After each answer, cite the source: [source: <doc>, <section>].
---
Context:
{{ retrieved_chunks }}
Question: {{ user_question }}Если retrieval вернул ноль чанков выше порога схожести — не зовите модель вообще. Сразу отдавайте «не знаю» и передавайте оператору. Пустой контекст плюс языковая модель — это рецепт уверенной выдумки.
И обязательно показывайте источники. Не для красоты — это ваш детектор лжи. Когда под ответом стоит «раздел 4.2 регламента возвратов», пользователь может проверить, а вы при отладке сразу видите, на какой чанк бот опёрся. Если ответ есть, а ссылки нет — значит, модель снова сочиняет, и это видно невооружённым глазом.
«Не знаю, но я позову человека» — это не провал бота. Это единственный честный ответ, когда ответа в документах нет.
Бот, который в 30% случаев честно говорит «не знаю», полезнее бота, который отвечает на всё и в одном случае из десяти врёт. Первому доверяешь. Второго приходится перепроверять, а тогда зачем он нужен. Заземление — это не про то, чтобы модель знала больше. Это про то, чтобы она молчала, когда не знает.
Хотите так же — но в своём проекте?
Разберём ваш процесс и где его безопасно автоматизировать.