Главная / Статьи / Чат-бот для вопросов о госполитике, который ссылается на источники, а не гадает

Чат-бот для вопросов о госполитике, который ссылается на источники, а не гадает

Как RAG-чат-бот на LangChain, pgvector и Express отвечает на вопросы граждан по официальным документам, со ссылками на источники и порогом уверенности.

1144 слов

Чат-бот, отвечающий на вопросы о государственной политике, легко построить и трудно ему доверять. Цель здесь не гладкий текст. Цель — ответ, который гражданин может сверить с официальным документом. Вокруг этой единственной идеи и построен проект policy-qa-system, RAG-чат-бот с открытым исходным кодом.

Публично, но нечитаемо

Государства публикуют огромные объёмы материалов: размеры пособий, требования к заявлениям, правила права на выплаты. Формально всё это есть в интернете. Фактически обычному человеку пригодно очень немногое. Тот, кто просто хочет узнать, что ему положено или какие документы принести, упирается в 30-страничный текст, написанный для сотрудников ведомства.

Дальше всё предсказуемо. Люди звонят на горячую линию и спрашивают то, что уже опубликовано, или сдаются и действуют наугад. В крупных государственных службах, где много документов, этот разрыв встречается постоянно. Информация существует. Не хватает способа задать ей вопрос.

Система закрывает этот разрыв с помощью генерации с дополнением через поиск (RAG). Люди задают бытовые вопросы простым языком и получают ответ, опирающийся на настоящий исходный документ, с приложенной ссылкой. Это не универсальный чат-бот, импровизирующий на тему политики. Он говорит только на основе документов, которые ему дали.

Найти, прочитать, ответить, сослаться

Каждый вопрос проходит четыре шага:

  1. Поиск по проиндексированным документам фрагментов, наиболее подходящих к вопросу.
  2. Чтение этих фрагментов вместе с вопросом.
  3. Ответ обычным языком, а не канцеляритом.
  4. Указание точного источника, чтобы ответ можно было проверить, а не просто поверить.

Большинство проектов чат-ботов пропускают последний шаг, а здесь он важнее всего. Ответ о положенных выплатах полезен, только если кто-то может его подтвердить. Поэтому каждый ответ несёт ссылку, а если ничего подходящего не нашлось, система говорит, что не уверена, вместо того чтобы гадать.

Пример простым языком

Возьмём вопрос «Сколько составляет еженедельная выплата на двоих детей?» Ответ выглядит так:

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.