Мой блог
Как мы научили ИИ читать корпоративные регламенты: от наивного RAG до измеримого pipeline
В крупных компаниях с обширной нормативной базой — сотнями инструкций, положений о закупках, регламентов командировок и матриц ответственности — специалисты регулярно тратят время на консультацию коллег. Вопросы звучат одинаково: «Как оформить постоплату?», «Кто утверждает риски по договору?», «В какой срок нужно подать заявку?». Опытные сотрудники знают решения не потому, что помнят сотни страниц текста наизусть, а потому что неоднократно открывали нужные файлы и помнят структуру документов. Однако экспертов мало, нормативная база огромна, а запросы поступают непрерывно.
Идея создать «Помощника сотрудника», способного отвечать на вопросы понятным языком со строгой ссылкой на пункт документа, кажется очевидной. В теории задача выглядит стандартно: загрузить файлы, разрезать их на фрагменты, построить векторы, найти через semantic search несколько релевантных кусков и передать их в LLM с инструкцией отвечать строго по источнику. Мы в команде тоже рассчитывали обойтись базовым пайплайном. Практика показала, что реальный корпоративный RAG устроить гораздо сложнее.
Попытка №1: RAG «по учебнику»
Первый прототип я собрал за несколько дней. Стек был прозрачным: оркестрация на n8n, векторная база Qdrant, эмбеддинги, гибридный поиск и генеративная языковая модель. База быстро проиндексировалась, векторы построились, а нейросеть выдавала внешне убедительные ответы. Проблемы начались при тестировании на реальных сценариях.
Цифровой ассистент путал заявку на расчёт с заявкой на тендер, искажал зоны ответственности и «терял» важные пороговые условия вроде «при сумме сделки от 500 тысяч рублей». Главный вывод первых тестов: красивый, гладкий текст от LLM и юридически верный ответ по регламенту — абсолютно разные вещи. Когда мы проанализировали фрагменты (chunks), попадавшие в контекст модели, причина ошибок стала очевидной.
Регламент — это не статья из интернета
Корпоративная документация имеет специфическую внутреннюю топологию: вложенные пункты (например, 5.3.1.2), таблицы на десятки колонок, объединённые ячейки, матрицы полномочий, примечания и перекрёстные ссылки. Смысл нормы существует только в неразрывной связи со структурой.
Если взять строку из таблицы регламента, то без названия колонки и заголовка раздела она превращается в набор бессмысленных цифр. Стандартный чанкер, нарезающий текст строго по 1000 символов, уничтожает эту семантику. В итоге условие попадает в один фрагмент, действие — во второй, а исключение из правила — в третий. Каждый из этих кусков формально похож на запрос пользователя, но ни один не содержит нормативного правила целиком.
Как четыре дня превратились в некорректный ответ
Характерный пример: на вопрос о сроке подготовки коммерческого предложения система уверенно ответила «четыре рабочих дня». Данное число действительно фигурировало в документе, но относилось к совершенно другому этапу согласований. Шапка таблицы оказалась в одном фрагменте, а строки со сроками — в другом. Модель не придумала число, но полностью потеряла его связь с нужным столбцом. Увеличение параметра top-k, изменение температуры или кручение параметров векторного поиска не решали проблему — документ нужно правильно считывать ещё на этапе индексации.
Инфраструктура и стек: одной нейросети недостаточно
Параллельно мы проектировали целевую инфраструктуру. Корпоративный сервис должен был выдерживать высокую нагрузку, поддерживать большое контекстное окно и функционировать в изолированном контуре. Основной генеративный слой мы решили строить на gpt-oss-120b, опираясь на успешный опыт наших партнёров.
Для размещения 120B-модели мы развернули выделенный сервер в Selectel на базе NVIDIA RTX PRO 6000 Blackwell с 96 GB VRAM. Это позволило запустить собственное OpenAI-совместимое API и измерять реальные инженерные метрики: задержку (latency), загрузку VRAM, количество параллельных сессий, время до первого токена (TTFT) и скорость генерации.
Тесты показали, что одна модель не закрывает весь спектр задач. В результате мы сформировали узкоспециализированный стек:
- Генерация ответов: gpt-oss-120b;
- Векторный поиск (semantic retrieval): GigaEmbeddings-instruct от Cloud.ru, показавшая отличные результаты на русскоязычных регламентах;
- Переранжирование (reranking): bge-reranker-v2-m3;
- Обработка визуального контента и схем: мультимодальная модель Qwen3.6-35B-A3B, выбранная по балансу скорости и качества.
Главный архитектурный поворот: работа с данными до поиска
Переломный момент наступил во время проектирования системы с архитектором проекта и руководителем Центра компетенций ИИ. Главная концепция заключалась в следующем: нельзя компенсировать плохую подготовку документов наращиванием мощности LLM или усложнением промптов.
Мы полностью перестроили пайплайн, разделив его на два изолированных контура: индексацию и обработку запроса.
Как устроен итоговый pipeline системы
На этапе индексации документы (DOCX, PDF, страницы Confluence, вложенные файлы) поступают на извлечение контента. Текстовый слой передаётся напрямую, а визуальные схемы и таблицы обрабатываются через Qwen3.6-35B-A3B. Весь материал приводится к структурированному Markdown. Далее выполняется структура-ориентированное разбиение на chunks с сохранением заголовков и списков. Фрагменты поступают в две ветки: лексическую (нормализация через Natasha / Razdel и индексация в FTS5/BM25) и векторную (построение эмбеддингов в GigaEmbeddings-instruct).
На этапе обработки запроса вопрос пользователя проходит нормализацию (раскрытие аббревиатур через глоссарий, отброс стоп-лемм). Затем параллельно запускаются BM25 и векторный поиск. Результаты объединяются алгоритмом Reciprocal Rank Fusion (RRF) и передаются в bge-reranker-v2-m3. Модель gpt-oss-120b получает TOP-5 самых релевантных фрагментов и формирует ответ с точной ссылкой на пункт документа. Весь процесс логируется и оценивается в Arize Phoenix.
Markdown как единый стандарт документов
Приведение всех файлов к Markdown необходимо для сохранения иерархии. Заголовки разных уровней (#, ##, ###) и табличная разметка позволяют модели видоизменять плоский текст в структуру с четким контекстом. Для LLM разница между полосой текста без разделителей и структурированной Markdown-таблицей является критической.
Почему мы отказались от жесткого chunk size
Фиксированная нарезка (например, ровно 1000 символов) разрушает нормативный смысл. В нашей архитектуре размер фрагмента в 1000–2000 символов — это ориентир, а не жесткая граница. Если таблица или логический абзац продолжаются, система формирует chunk размером 1400 символов, сохраняя целостность правила.
Каждый фрагмент автоматически наследует метаданные своего логического пути:
Документ > Раздел > Подраздел > Текст фрагмента
При семантическом поиске передача такого контекста существенно повышает точность попадания.
Почему перекрытие (overlap) вредит регламентам
В классических туториалах рекомендуют использовать overlap (например, 200 символов) для предотвращения потери мыслей на стыках. В нормативных документах это приводит к объединению разных правил. Если в пункте 5.3 описаны условия для сделок категории A, а в 5.4 — для категории B, то при overlap конец одного правила попадает в фрагмент другого.
Кроме того, перекрытие формирует почти идентичные дубликаты, которые забивают итоговый top-k. Мы приняли решение использовать строго структурные границы блоков без применения overlap.
Гибридный поиск: объединение лексики и семантики
Векторный поиск отличный выбор, когда пользователь ищет «оформление поездки», а в базе написано «порядок направления в служебную командировку». Но регламенты насыщены точными идентификаторами: номерами пунктов (5.3.2), временными интервалами (15:00), суммами и внутренними аббревиатурами. Для работы с ними необходим гибридный подход.
Лексическая ветка (BM25)
Для точного поиска используется SQLite FTS5 с алгоритмом BM25. Предварительно текст лемматизируется библиотеками Natasha и Razdel, благодаря чему формы «согласовать», «согласование» и «согласованный» приводятся к единой норме. Также отсекается канцелярский шум вроде слова «осуществляется», не несущий поисковой нагрузки.
Dense-ветка (векторный поиск)
Параллельно выполняется семантический поиск через GigaEmbeddings-instruct. В результате система получает два независимых списка ранжирования от BM25 и Dense-модели.
Слияние рангов через Reciprocal Rank Fusion (RRF)
Сравнивать оценки BM25 score и косинусное сходство векторного поиска напрямую нельзя — у них разные шкалы. Для объединения результатов мы применяем алгоритм RRF:
score(d) = Σ 1 / (k + rank(d))
RRF оценивает позицию документа в каждом из списков, формируя объективный сбалансированный топ кандидатов для передаче реранкеру.
Реранкинг: точечная переоценка кандидатов
Векторный и лексический поиск быстро отсекают заведомо нерелевантный массив данных. Переранжировщик bge-reranker-v2-m3 выполняет более глубокую оценку: он попарно сравнивает исходный запрос с каждым кандидатом из топа. Так как реранкинг ресурсоёмок, он запускается только на отобранных кандидатах, формируя финальные TOP-5 фрагментов для LLM.
Словари и нормализация корпоративного сленга
Сотрудники редко формулируют вопросы канцеляризмами. Вместо «просроченная дебиторская задолженность» в запрос летит «ПДЗ». Мы интегрировали в систему специализированный глоссарий, который работает на двух уровнях:
- При поиске: запрос автоматически обогащается полной терминологией.
- При генерации: в промпт модели передаётся точечное определение найденной аббревиатуры.
Если запрос слишком абстрактный (например, «Какой срок?»), система настроена не искать случайные совпадения, а задавать уточняющий вопрос: «Срок какого именно процесса вас интересует?».
Создание Gold Dataset и отказ от субъективных оценок
Оценка «кажется, ответы стали лучше» непригодна для продакшена. Мы создали контрольный размеченный датасет (Gold Dataset), включающий:
- Эталонные вопросы и ответы;
- Список обязательных фактов;
- Точные ссылки на документы и пункты;
- Размеченные релевантные chunks;
- Маркеры вопросов, на которые в базе нет ответа (системный отказ).
Умение корректно отказаться от ответа при отсутствии данных — ключевой показатель безопасности корпоративной AI-системы.
Трехуровневое измерение качества
Процесс проверки был разделен на три изолированных этапа: Retrieval, Context и Answer Generation. Это позволяет точно локализовать проблему: если ответ неполный, мы сразу видим, пропустил ли факт векторный поиск (проблема Context Recall) или языковая модель проигнорировала переданный ей фрагмент (проблема генерации).
Эксперимент: оценка эффекта от включения reranker
Для подтверждения эффективности реранкера мы провели эксперимент на 20 контрольных вопросах (17 с эталонными ответами и 3 на корректный отказ). Каждый прогон повторялся трижды (всего 60 итераций) в двух конфигурациях: без реранкера и с подключенным bge-reranker-v2-m3.
| Метрика | Без reranker | С reranker | Изменение |
|---|---|---|---|
| Recall@5 | 0,285 | 0,464 | +63% |
| MRR@5 | 0,531 | 0,814 | +53% |
| Precision@5 | 0,220 | 0,378 | +72% |
| Context Precision@5 | 0,451 | 0,759 | +68% |
| Context Recall | 0,501 | 0,768 | +53% |
| Faithfulness | 0,973 | 0,984 | +1% |
| Correctness | 0,377 | 0,586 | +55% |
| Completeness | 0,542 | 0,696 | +28% |
| No-answer Correctness | 0,983 | 0,950 | −3% |
Детальная интерпретация результатов эксперимента
Recall@5: с 0,29 до 0,46
Метрика показывает долю эталонных фрагментов, попавших в TOP-5 контекста. Рост на 63% подтверждает, что реранкер эффективно отбирает нужные данные. Максимальное значение 0,464 обусловлено тем, что для ряда вопросов эксперты разметили более 5 подтверждающих кусков текста, тогда как модель строго ограничена пятью фрагментами.
MRR@5: с 0,53 до 0,81
Показатель Mean Reciprocal Rank определяет, насколько высоко в списке оказывается первый релевантный chunk. Значение 0,814 говорит о том, что ключевые данные практически всегда поднимаются на 1–2 позицию.
Context Precision и Context Recall
Context Precision вырос с 0,45 до 0,76 — шума в контексте стало значительно меньше. Context Recall увеличился с 0,50 до 0,77. Это означает, что LLM теперь получает около 75% всех необходимых для ответа фактов против 50% ранее.
Correctness: рост до 0,59
Итоговая точность ответов увеличилась с 0,38 до 0,59. В нашей методологии при наличии противоречий регламенту оценка обнуляется. В нормативной базе разница между «не более 10 дней» и «не менее 10 дней» критична, и включение реранкера напрямую повлияло на бизнес-достоверность ответов.
Особенность Faithfulness и работы отказа от ответа
Метрика Faithfulness (отсутствие галлюцинаций) изначально была высокой (0,973) и поднялась до 0,984. Это показало, что модель не выдумывает факты, а проблема качества лежала именно в полноте поиска.
Незначительное снижение No-answer Correctness с 0,983 до 0,950 было связано с дефектом поиска по одному конкретному вопросу: реранкер отфильтровал посторонние фрагменты, и модель предпочла честно отказаться от ответа. После точечной настройки поиска дефект был устранен.
Автоматический контроль через LLM-as-a-judge
Для автоматизированной проверки ответов мы применили подход LLM-as-a-judge. После калибровки на роль судьи была выбрана DeepSeek-V4-Pro. Она анализирует связку «вопрос + найденный контекст + ответ ассистента» и классифицирует ошибки по трем категориям:
- Critical: прямое противоречие источнику или неверное утверждение;
- Missing: факт присутствовал в контексте, но не попал в ответ;
- Extra: генерация избыточной информации, о которой не просили.
Сквозная отладка и трассировка в Arize Phoenix
В качестве системы observability мы выбрали Arize Phoenix. Каждый запрос фиксируется в виде детализированного трейса: от нормализации текста и оценок BM25/Dense до итогового промпта и вердикта LLM-judge. Это позволяет моментально определять источник проблемы — был ли нужный документ пропущен поиском или модель проигнорировала его на этапе генерации.
A/B-тестирование изменений в пайплайне
Любые правки в архитектуре мы тестируем по A/B-схеме. Запускаются две параллельные конфигурации (Baseline и Experiment), через которые прогоняется один и тот же Gold Dataset. Архитектурное решение принимается только на основе сухих цифр по всем 9 метрикам.
Как метрики выявили «векторный коллапс» в данных
В процессе отладки один из вопросов стабильно отправлялся моделью в отказ. Изучение трейсов в Phoenix показало, что векторный поиск уходил в кластер реестра рисков — длинного однотипного документа, ячейки которого забивали весь top-k. Нужный регламент находился в базе, но не пробивался сквозь плотный векторный кластер. Это доказало: оптимизировать нужно не только алгоритмы, но и сам состав индексируемого корпуса.
Главные выводы для разработки корпоративного RAG
- Структура первична: сохраняйте иерархию и таблицы при конвертации документов. Восстанавливать смысл силами LLM значительно дороже.
- Начинайте с архитектуры, а не с дорогой модели: качественный chunking, словарные нормы и гибридный поиск дают больший прирост, чем замена генеративной нейросети.
- Гибридный поиск обязателен: точные цифры и аббревиатуры требуют лексики (BM25), смысловые формулировки — семантики.
- Калибруйте LLM-судью: автоматические метрики полезны только при регулярной валидации на реальных кейсах.
- Опирайтесь на измерения: отказ от субъективных оценок в пользу сквозных метрик — единственный путь превращения RAG из прототипа в надежный инженерный продукт.
Источник: habr.com
