Головна / Статті / Чат-бот для запитань про державну політику, який посилається на джерела, а не вгадує

Чат-бот для запитань про державну політику, який посилається на джерела, а не вгадує

Як 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.