Чат-бот для вопросов о госполитике, который ссылается на источники, а не гадает
Как RAG-чат-бот на LangChain, pgvector и Express отвечает на вопросы граждан по официальным документам, со ссылками на источники и порогом уверенности.
Чат-бот, отвечающий на вопросы о государственной политике, легко построить и трудно ему доверять. Цель здесь не гладкий текст. Цель — ответ, который гражданин может сверить с официальным документом. Вокруг этой единственной идеи и построен проект policy-qa-system, RAG-чат-бот с открытым исходным кодом.
Публично, но нечитаемо
Государства публикуют огромные объёмы материалов: размеры пособий, требования к заявлениям, правила права на выплаты. Формально всё это есть в интернете. Фактически обычному человеку пригодно очень немногое. Тот, кто просто хочет узнать, что ему положено или какие документы принести, упирается в 30-страничный текст, написанный для сотрудников ведомства.
Дальше всё предсказуемо. Люди звонят на горячую линию и спрашивают то, что уже опубликовано, или сдаются и действуют наугад. В крупных государственных службах, где много документов, этот разрыв встречается постоянно. Информация существует. Не хватает способа задать ей вопрос.
Система закрывает этот разрыв с помощью генерации с дополнением через поиск (RAG). Люди задают бытовые вопросы простым языком и получают ответ, опирающийся на настоящий исходный документ, с приложенной ссылкой. Это не универсальный чат-бот, импровизирующий на тему политики. Он говорит только на основе документов, которые ему дали.
Найти, прочитать, ответить, сослаться
Каждый вопрос проходит четыре шага:
- Поиск по проиндексированным документам фрагментов, наиболее подходящих к вопросу.
- Чтение этих фрагментов вместе с вопросом.
- Ответ обычным языком, а не канцеляритом.
- Указание точного источника, чтобы ответ можно было проверить, а не просто поверить.
Большинство проектов чат-ботов пропускают последний шаг, а здесь он важнее всего. Ответ о положенных выплатах полезен, только если кто-то может его подтвердить. Поэтому каждый ответ несёт ссылку, а если ничего подходящего не нашлось, система говорит, что не уверена, вместо того чтобы гадать.
Пример простым языком
Возьмём вопрос «Сколько составляет еженедельная выплата на двоих детей?» Ответ выглядит так:
For 2 children: first child gets the standard rate, second child
gets the additional-child rate (combined weekly and yearly totals
shown together). An income-based charge may apply above a set
household income threshold.
Source: Official rates document, section on child payments
Цифры зависят от того, документы какой страны проиндексированы, поскольку система не привязана к одному набору правил. Это шаблон для вопросов и ответов граждан, а не фиксированный набор данных.
Технологический стек
- Фронтенд: React 18, TypeScript и Tailwind CSS
- Бэкенд: Node.js с Express
- ИИ и RAG: LangChain и LangGraph
- Векторное хранилище: PostgreSQL с pgvector
- Развёртывание: Docker
Ничего экзотического. Команда, которая станет использовать это всерьёз, заменит примерные документы собственным официальным набором, а поиск, ссылки и генерация простым языком останутся как есть.
Архитектура
Запрос идёт от вопроса пользователя через интерфейс на React к Express API, который передаёт его в цепочку поиска. Вот схема:
User question
│
▼
React UI ──► Express API
│
▼
LangChain retrieval ──► PostgreSQL + pgvector (indexed policy docs)
│
▼
LLM answer generation (grounded in retrieved sections)
│
▼
Answer + citation + confidence score
Оценка уверенности заслуживает не меньше внимания, чем сам ответ. Когда поиск не находит ничего достаточно близкого к вопросу, система так и сообщает, и у модели не появляется шанса заполнить пробел чем-то правдоподобным.
Код, который имеет значение
Во-первых, цепочка не выдаёт свободный текст сама по себе. Вместе с ответом она обязана вернуть источник:
const response = await chain.invoke({
question,
context: retrievedChunks,
});
return {
answer: response.answer,
sources: retrievedChunks.map(c => ({
document: c.metadata.document,
section: c.metadata.section,
})),
confidence: response.confidence,
};
Во-вторых, порог уверенности решает, отвечать или признать, что ничего не найдено:
if (topMatchScore < CONFIDENCE_THRESHOLD) {
return {
answer: "I couldn't find a reliable answer to that in the indexed documents.",
sources: [],
};
}
Проверка крошечная, но именно она отделяет чат-бот, на который люди могут положиться, от того, который лишь звучит уверенно.
Что сработало
- Обязательные ссылки с самого начала улучшили поиск. Расплывчатое совпадение сразу бросается в глаза, когда нужно показать, откуда оно взялось.
- Даже грубый порог уверенности резко сократил число неверных ответов, выданных уверенным тоном. Это выглядело мелкой функцией, а оказалось одним из самых сильных факторов доверия.
- Заменяемый набор документов означает, что та же система может обслуживать совсем разные области политики, достаточно переиндексировать.
Что далось тяжело
- Упрощать, не искажая. Формулировки в нормативных текстах точны не просто так, и сделать их дружелюбнее, не потеряв условие вроде лимита дохода или правила права на выплату, требует настоящей аккуратности. Полностью это не решено.
- Понимать, когда сказать «не знаю». Слишком низкий порог позволяет системе отвечать на то, на что не стоит, а слишком высокий заставляет отказываться от вопросов, с которыми она бы хорошо справилась. Практическим решением стала ручная настройка на небольшом наборе реальных вопросов.
- Зрелость. Это основа для дальнейшей работы, а не готовый к развёртыванию продукт. Прежде чем его увидят реальные пользователи, нужен нормальный конвейер загрузки документов, постоянная проверка примеров ответов и тестирование на пограничных случаях.
Место среди других проектов
Он входит в небольшое семейство ИИ-проектов с открытым кодом, построенных на оркестрации LLM через LangChain и LangGraph: система вопросов и ответов по документам, агент для код-ревью и инструмент, превращающий голосовые заметки в пользовательские истории для Agile. Общий уклон у них один — к ответам, которые можно проверить, а не к ответам, которые просто звучат правильно.
Попробуйте
Репозиторий быстро запускается локально:
git clone https://github.com/Srameshgitnow/policy-qa-system.git
cd policy-qa-system
npm install
npm run dev
В README описаны настройка, переменные окружения и индексация собственных документов. Пробелы в логике ссылок и идеи насчёт порога уверенности приветствуются в виде issues или pull request.