COMRAD404 / HOWTO

Как сделать чат-бота по своим документам

Практическое руководство по сборке чат-бота, который отвечает по вашим PDF, DOCX и базе знаний: от очистки документов и поиска до проверки качества.

Сделать чат-бота по своим документам обычно значит не дообучать модель, а собрать RAG-схему: очистить документы, разбить их на фрагменты, проиндексировать фрагменты, искать релевантный контекст по вопросу и передавать его модели с жёсткой инструкцией отвечать только по найденным данным. Это подходит для регламентов, базы знаний, инструкций, договорных шаблонов и внутренней документации. Метод не подходит там, где данные меняются каждую минуту, где нужен строго детерминированный результат без вероятностной генерации, или где ответ имеет юридические последствия без обязательной проверки человеком.

Короткий ответ

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

  • Не начинайте с fine-tuning. Для документов почти всегда нужен поиск по актуальному контенту, а не изменение весов модели.
  • Сразу закладывайте ссылки на источник. Пользователь должен видеть, из какого документа и раздела взят ответ.
  • Храните метаданные. Минимум: название документа, раздел, версия, дата, права доступа.
  • Планируйте режим «нет ответа». Галлюцинации начинаются там, где модель заставляют отвечать любой ценой.

Если у вас десяток коротких документов и пользователям нужна в первую очередь навигация, а не развернутые ответы, обычный полнотекстовый поиск может быть дешевле и надёжнее. Если же документы содержат таблицы, идентификаторы, статусы и числовые поля, лучше отвечать через SQL, API или бизнес-логику, а не через языковую модель.

Что понадобится

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

Сценарий Когда выбирать Стек Ограничения
Быстрый прототип Нужно проверить идею за день-два OpenAI API с управляемым поиском по файлам Меньше контроля над пайплайном, сложнее тонко настраивать retrieval
Рабочий RAG с контролем Нужны свои правила чанкинга, фильтры, метаданные и журналирование OpenAI API + pgvector или Qdrant Нужно поддерживать индексацию, хранилище и обновления
Если у вас уже PostgreSQL Хотите минимизировать число сервисов PostgreSQL + pgvector Может быть тесно при большом объёме и сложных search-сценариях
Отдельный search layer Большой корпус, отдельная команда, нужны гибкие фильтры и масштабирование Qdrant + собственный ingestion Больше инфраструктуры и операционной нагрузки
  • Документы. PDF, DOCX, HTML, Markdown, выгрузки из wiki. Если файл не машиночитаем, сначала OCR.
  • Среда разработки. Чаще всего Python для скриптов загрузки и индексации.
  • Модель для ответов и эмбеддингов. Удобно стартовать с OpenAI API.
  • Оркестрация. Можно писать всё вручную, но для загрузчиков и пайплайнов часто используют LangChain.
  • Хранилище. Для простоты — pgvector, для отдельного векторного сервиса — Qdrant.
  • Тестовый набор вопросов. Без него невозможно понять, улучшает ли что-то качество.

Минимальный состав метаданных для каждого фрагмента: document_id, title, section, version, updated_at, access_scope, source_url или путь к файлу. Без этого вы быстро потеряете управляемость.

Пошаговый план

1. Определите задачу и политику ответа

Сначала зафиксируйте, что именно бот должен делать: пересказывать инструкции, находить разделы, отвечать по регламентам, подсказывать шаблоны или цитировать политику. Отдельно пропишите, на какие вопросы он не должен отвечать. Например: не интерпретировать право, не придумывать сроки, не отвечать без найденного источника. Это важнее, чем выбор модели.

2. Подготовьте документы

Соберите документы в единый список источников и удалите мусор: сканы без OCR, дубликаты, черновики, старые версии, файлы без владельца. Если в PDF много колонтитулов, повторяющихся номеров страниц и таблиц содержания, уберите их до индексации. Иначе поиск начнёт вытаскивать шум вместо смысла.

Хорошая практика — хранить не просто текст, а нормализованную структуру: документ, раздел, подраздел, абзац. Для FAQ и инструкций это сильно улучшает поиск.

3. Разбейте текст на фрагменты

Чанк должен быть достаточно маленьким для точного поиска и достаточно большим, чтобы не терялся смысл. Для обычной прозы обычно начинают с диапазона 500-1000 токенов и небольшого overlap, но для таблиц, списков шагов и коротких регламентов куски лучше делать меньше. Не режьте текст посередине таблицы или инструкции: если шаги 1-5 попали в разные фрагменты, бот начнёт собирать ответ из обрывков.

Добавляйте к каждому чанку заголовок раздела и путь вида Политика безопасности → Доступ → Сброс пароля. Такой контекст полезен и для retrieval, и для финального ответа.

4. Проиндексируйте фрагменты

Дальше каждому фрагменту нужен вектор и запись в хранилище. Если вы делаете прототип, можно использовать управляемые средства поиска у провайдера модели. Если нужен контроль, создавайте эмбеддинги сами и записывайте их в pgvector или Qdrant. Ключевой момент: индексируйте не только текст, но и метаданные для фильтрации по отделу, продукту, версии и правам доступа.

Если у одного пользователя есть доступ только к части базы знаний, фильтровать надо до генерации ответа, а не после. Иначе модель может увидеть лишний контекст даже если вы его потом не покажете в интерфейсе.

5. Настройте retrieval

На входе есть вопрос пользователя. Перед ответом система должна найти несколько наиболее релевантных фрагментов, при необходимости отфильтровать их по правам и версии, а затем передать модели только этот набор. На практике стоит проверять не только векторный поиск, но и гибридный режим: семантика плюс полнотекстовый поиск по ключевым словам. Это особенно важно для артикулов, кодов ошибок, названий полей и внутренних идентификаторов.

Если видите, что в топ результатов часто попадают почти релевантные куски, добавьте reranking. Ещё одна полезная мера — отдельный шаг на переписывание вопроса в поисковый запрос, но только если вы контролируете, как это влияет на смысл.

6. Сформируйте prompt и ответ

Главная инструкция модели должна быть короткой и жёсткой: Отвечай только по предоставленному контексту. Если ответа нет или он неоднозначен, скажи об этом. Приводи ссылки на источник и не скрывай неопределённость. Не просите «быть полезным любой ценой». Это прямой путь к выдуманным деталям.

Возвращайте не только текст ответа, но и список использованных фрагментов: название документа, раздел, версия, ссылка или путь к исходнику. Для внутренних систем полезно показывать цитаты рядом с ответом, чтобы пользователь мог сразу проверить формулировку.

7. Добавьте обновление, версии и контроль доступа

После первого демо обычно забывают о самом важном: документы меняются. Вам нужен ingestion-процесс, который умеет переиндексировать обновлённые файлы, помечать старые версии, удалять отозванные документы и не плодить дубликаты. Иначе через месяц бот начнёт отвечать по устаревшему регламенту.

Отдельно продумайте аудит: кто загрузил документ, когда он был обновлён, по какому набору фрагментов построен ответ. Для чувствительных сценариев это обязательное требование.

8. Проведите оценку до запуска

Соберите набор реальных вопросов от будущих пользователей. Включите в него не только простые вопросы, но и коварные: похожие документы разных версий, вопросы без ответа, вопросы с кодами ошибок, многошаговые инструкции и кейсы с ограничением доступа. По каждому вопросу заранее зафиксируйте ожидаемый источник или допустимый тип ответа, например «нет данных».

Пока бот не умеет стабильно находить правильные фрагменты, менять модель генерации почти бессмысленно. В большинстве провалов виноват retrieval, а не сам текстовый ответ.

Типичные ошибки

  • Индексировать сырой PDF как есть. Симптом: в ответах мусор из колонтитулов и номеров страниц. Лечение: очистка, OCR, структурирование по разделам.
  • Слишком крупные чанки. Симптом: бот отвечает общими словами и путает соседние разделы. Лечение: уменьшить размер и разбивать по смысловым границам.
  • Слишком мелкие чанки. Симптом: теряется контекст и инструкция распадается на обрывки. Лечение: объединять связанные абзацы, добавлять заголовок раздела.
  • Нет режима «не знаю». Симптом: уверенные, но неверные ответы. Лечение: жёсткий prompt, порог на retrieval, отказ от ответа без источника.
  • Игнорирование прав доступа. Симптом: бот отвечает по закрытым документам. Лечение: фильтрация по access_scope на этапе поиска.
  • Нет версионности. Симптом: смешиваются старые и новые правила. Лечение: хранить version, updated_at и политику деактивации старых индексов.
  • Проверять только на красивых демо-вопросах. Симптом: на пилоте всё хорошо, в реальной работе провал. Лечение: набор сложных тестов и ручная разметка ожиданий.
  • Пытаться решать таблицы и расчёты чистой генерацией. Симптом: неправильные числа и статусы. Лечение: отдельные инструменты, SQL, API, правила.

Как проверить результат

Проверять нужно не «нравится ли ответ», а три вещи отдельно: нашёл ли бот правильный контекст, правильно ли он интерпретировал найденное и не нарушил ли права доступа. Для этого удобно вести таблицу вопросов с ожидаемыми источниками и статусом проверки.

Проверка Что смотреть Признак проблемы
Retrieval Попали ли в топ релевантные фрагменты Правильный ответ есть в базе, но не найден
Faithfulness Нет ли в ответе фактов, которых нет в контексте Ответ звучит убедительно, но источник этого не подтверждает
Цитирование Есть ли ссылка на документ, раздел и версию Пользователь не может проверить источник
Нет ответа Умеет ли бот отказываться от выдумки На пустой вопрос появляется якобы точный ответ
Доступ Не видит ли пользователь чужие документы В выдаче есть закрытые фрагменты
  1. Соберите 30-100 реальных вопросов от пользователей разных ролей.
  2. Для каждого вопроса отметьте ожидаемый документ или допустимый отказ от ответа.
  3. Прогоните систему и отдельно сохраните найденные фрагменты, итоговый ответ и метаданные.
  4. Разберите ошибки по типам: плохой OCR, неверный чанк, слабый retrieval, конфликт версий, галлюцинация модели.
  5. Меняйте по одному параметру за раз: сначала документы и поиск, потом prompt, потом модель.

Если после правок растёт только «красота» формулировок, а не точность источников, вы улучшаете не то звено. Для чат-бота по документам качество поиска почти всегда важнее литературности ответа.

FAQ

Нужно ли дообучать модель на своих документах?

Обычно нет. Дообучение меняет стиль и поведение, но плохо решает задачу актуальных знаний. Если документы обновляются, RAG почти всегда практичнее.

Можно ли обойтись без векторной базы?

Да, для очень маленького корпуса можно начать с управляемого поиска по файлам у провайдера модели или даже с полнотекстового поиска. Но как только появляются метаданные, права доступа и требования к качеству retrieval, отдельное хранилище становится удобнее.

Что делать с PDF-сканами?

Сначала OCR, затем ручочная проверка качества извлечения. Плохой OCR портит весь пайплайн: индекс становится шумным, а бот начинает уверенно цитировать бессмысленные строки.

Какой размер чанка выбрать?

Единого числа нет. Для длинных описательных текстов можно стартовать с умеренно крупных фрагментов, для инструкций и таблиц — с более мелких. Проверяйте результат на своём наборе вопросов, а не на абстрактных советах.

Как не допустить утечки закрытых документов?

Храните права доступа в метаданных и фильтруйте кандидаты до передачи контекста модели. Не полагайтесь на то, что интерфейс потом скроет лишние ссылки: это уже поздно.

Когда такой бот лучше не делать?

Когда пользователю нужен не текстовый ответ, а точный транзакционный результат: статус заявки, остаток на складе, расчёт тарифа, юридически значимое решение. В таких случаях правильнее сначала получить данные из систем-источников, а модель использовать только для объяснения.

Читайте также

LINKS