Почему нам пришлось превратить нормативные документы в граф, а не просто загрузить их в векторную базу. llm.. llm. rag.. llm. rag. semantic search.. llm. rag. semantic search. базы данных.. llm. rag. semantic search. базы данных. гост.. llm. rag. semantic search. базы данных. гост. ИИ.. llm. rag. semantic search. базы данных. гост. ИИ. искусственный интеллект.. llm. rag. semantic search. базы данных. гост. ИИ. искусственный интеллект. Машинное обучение.. llm. rag. semantic search. базы данных. гост. ИИ. искусственный интеллект. Машинное обучение. нейросети.. llm. rag. semantic search. базы данных. гост. ИИ. искусственный интеллект. Машинное обучение. нейросети. нормативные документы.. llm. rag. semantic search. базы данных. гост. ИИ. искусственный интеллект. Машинное обучение. нейросети. нормативные документы. Поисковая оптимизация.. llm. rag. semantic search. базы данных. гост. ИИ. искусственный интеллект. Машинное обучение. нейросети. нормативные документы. Поисковая оптимизация. СП СНИП.. llm. rag. semantic search. базы данных. гост. ИИ. искусственный интеллект. Машинное обучение. нейросети. нормативные документы. Поисковая оптимизация. СП СНИП. строительство.

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

Мы увидели это на практике, когда строили систему для работы с нормативкой. Сначала задача выглядела стандартно: есть документы, есть вопросы пользователей, есть поиск по смыслу. Значит, нужен обычный RAG. Но довольно быстро стало ясно, что главная проблема здесь не генерация. Главная проблема в том, как представить документ так, чтобы retrieval не разрушал его структуру и смысл.

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

TL;DR

  • Нормативные документы плохо ложатся в модель «плоский набор чанков».

  • Слишком маленькие фрагменты теряют контекст, слишком большие дают шумный retrieval.

  • Одного семантического поиска недостаточно: нужны точечный поиск по пунктам, работа с таблицами, терминами и кросс-ссылками.

  • Для одного пользовательского вопроса система может запускать несколько разных поисков и потом объединять результаты.

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

  • Поэтому документ пришлось моделировать не как текст, а как иерархический граф узлов и связей.

Где ломается обычный RAG

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

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

Проблема выглядела так:

  • пользователь задаёт вопрос по конкретному требованию;

  • semantic search находит похожий по формулировке пункт;

  • но рядом есть подпункт, примечание или ссылка на другой документ, без которых ответ уже не совсем корректен;

  • модель видит только один «подходящий» кусок текста и строит ответ так, будто этого достаточно.

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

Именно в этот момент стало ясно: проблема не в том, что модель «недоумна». Проблема в том, что документ представлен слишком плоско.

Первый поворот: документ перестал быть просто текстом

Вместо «документ = длинная строка» мы начали строить структурную модель. Базовая идея была такой: документ состоит не из абзацев, а из адресуемых элементов.

В нашей модели появились:

  • документ как корневая сущность;

  • узлы документа: разделы, пункты, подпункты;

  • таблицы как отдельные элементы;

  • формулы как отдельные элементы;

  • связи между узлами;

  • термины и их определения.

То есть сначала документ превращается в иерархию, и только потом эта иерархия индексируется.

Внутри проекта это выглядит примерно так:

Почему нам пришлось превратить нормативные документы в граф, а не просто загрузить их в векторную базу - 1

Это был первый важный поворот. Мы перестали индексировать «что получилось после парсинга» и начали индексировать нормализованную модель документа.

Почему одного узла оказалось недостаточно

Следующая проблема была чуть менее очевидной. Даже если у вас уже есть иерархия, это ещё не означает, что retrieval автоматически станет хорошим.

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

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

  • увидеть соседний подпункт того же раздела;

  • подтянуть примечание;

  • учесть таблицу;

  • проверить, нет ли обязательной ссылки на другой документ или на другой пункт.

То есть retrieval должен приносить не просто близкий фрагмент, а минимально достаточный контекст.

Но не как попало. Важный момент был в том, что мы не делали generic chunking по пред��ожениям или просто по токенам. Мы группировали соседние элементы, у которых общий родитель и общий уровень вложенности. Проще говоря, система понимала, что это не просто несколько строк подряд, а логически родственные пункты внутри одного раздела.

Мы экспериментировали с размером фрагментов и довольно быстро поняли, что одного «идеального» числа нет. Слишком маленькие группы теряют смысл, слишком большие ухудшают точность retrieval. Поэтому вместо жёсткой универсальной нарезки полезнее иметь структурную группировку с ограничением по размеру, которое можно подстраивать под домен и качество документов.

Практический эффект был заметный. Меньше стало ответов, где модель цеплялась за один «почти правильный» пункт и не видела его окружение. А в индекс начали попадать не только атомарные узлы, но и более устойчивые смысловые блоки.

Почему семантического поиска оказалось недостаточно

Если пользователь задаёт вопрос в свободной форме, векторный поиск действительно помогает. Но в нормативке пользователь часто спрашивает не «смысл в общем», а что-то очень конкретное:

  • покажи пункт 6.2.2;

  • найди таблицу 7.1;

  • что означает такой-то термин;

  • где в документе описан конкретный параметр;

  • какие связанные нормы нужно учитывать вместе с этим пунктом.

Для таких вопросов одного vector search недостаточно. Нужны разные режимы retrieval:

  • точечный поиск по пункту;

  • поиск по таблице;

  • лексический поиск;

  • гибридный поиск;

  • терминологический поиск;

  • поиск связанных элементов по ссылкам.

Иными словами, retrieval здесь перестаёт быть одной функцией и превращается в набор специализированных инструментов.

Почему один вопрос может запускать несколько поисков

Когда пользователь задаёт вопрос, система не обязана выбирать ровно один способ поиска. Наоборот, в реальном сценарии она может решить, что один и тот же запрос лучше проверить несколькими стратегиями одновременно.

Например, в одном вопросе могут смешиваться сразу несколько намерений:

  • пользователь упоминает конкретный пункт;

  • одновременно ссылается на таблицу;

  • формулирует часть запроса как свободный текст;

  • использует термин, который полезно проверить через отдельный терминологический слой.

В этом случае хороший retrieval не должен искусственно сужать задачу до одного запроса. Он может:

  • сначала попробовать точечный поиск по пункту;

  • параллельно проверить таблицу;

  • отдельно сходить в keyword search;

  • а затем объединить результаты и передать их в context builder.

Схематично это выглядит так:

Почему нам пришлось превратить нормативные документы в граф, а не просто загрузить их в векторную базу - 2

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

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

Зачем понадобился слой терминов

Параллельно выяснилось, что пользователь и документ часто говорят об одном и том же по-разному.

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

Поэтому мы добавили отдельную обработку терминов:

  • из документа извлекаются термины;

  • к каждому термину привязывается определение;

  • термины индексируются отдельно;

  • retrieval может использовать терминологический слой как дополнительный сигнал.

Это особенно полезно в случаях, когда пользователь спрашивает не номер пункта, а понятие из предметной области.

Момент, когда стало ясно, что без графа не обойтись

Но даже иерархии и терминов оказалось недостаточно.

Проблема была в том, что некоторые ответы зависят не от одного найденного пункта, а от жёсткой цепочки связей. Например:

  • найденный пункт требует учитывать ещё один пункт;

  • пункт ссылается на другой документ;

  • таблица релевантна только вместе с описывающим её разделом;

  • ограничение находится не там, где основной тезис.

Семантический поиск может найти основной фрагмент. Но он не гарантирует, что подтянется обязательный связанный контекст. Иногда этот контекст находится слишком далеко по смыслу, чтобы попасть в top-k. Иногда он формально не очень похож на запрос пользователя, но без него ответ будет неполным или даже ошибочным.

Именно поэтому нам понадобился граф связей.

В нём у узлов есть не только положение в иерархии, но и отношения типа:

  • mandatory — этот узел нужно обязательно учитывать вместе с другим;

  • cross — кросс-ссылка на другой фрагмент или документ;

  • связи документ → узел;

  • связи узел → таблица;

  • связи между документами.

А дальше эти связи уже участвуют в retrieval. Если найден релевантный узел, система не просто радуется попаданию. Она проверяет, не нужно ли принудительно подтянуть ещё связанные элементы.

Почему нам пришлось превратить нормативные документы в граф, а не просто загрузить их в векторную базу - 3

Вот здесь система и перестаёт быть «чатом поверх документов». Она начинает становиться инженерным инструментом.

Что это изменило на практике

Самое важное изменение было не в том, что ответы стали «более умными». Они стали более устойчивыми.

Система стала лучше справляться с вопросами, где нужно:

  • сослаться на конкретный пункт;

  • не потерять соседний уточняющий контекст;

  • подтянуть обязательную связанную норму;

  • корректно работать с таблицами;

  • не путать термин и просто похожую фразу;

  • строить ответ не по одному куску текста, а по минимально достаточной цепочке.

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

Что мы из этого вынесли

Если коротко, то главный урок такой: в сложном документном домене качество определяется не моделью и не промптом, а представлением данных.

В нашем случае это означало несколько вещей.

Во-первых, документ нельзя рассматривать как плоский текст. Нужна адресуемая структура.

Во-вторых, chunking должен учитывать смысловую иерархию документа, а не только ограничение по длине.

В-третьих, retrieval должен быть многослойным. Vector search полезен, но он не заменяет точечный поиск, lexical-сигналы, термины, связи и композицию нескольких поисковых стратегий на один вопрос.

В-четвёртых, если для правильного ответа нужны обязательные связанные нормы, они должны быть выражены в данных явно. Надеяться, что модель «сама догадается», в таких сценариях нельзя.

Вывод

Мы начинали как многие: с идеи «построим RAG по документам». Но по мере работы стало ясно, что для нормативки этого недостаточно.

Чтобы система действительно работала, пришлось пройти несколько этапов:

  • от плоских кусков текста к иерархическим узлам;

  • от одиночных фрагментов к структурным группам;

  • от одного поиска по эмбеддингам к гибридному retrieval;

  • от просто индекса документов к терминологическому слою;

  • от «похожего текста» к графу обязательных и кросс-ссылок.

В какой-то момент это перестаёт быть «LLM поверх базы» и становится полноценной инженерной системой, где retrieval — уже не вспомогательная деталь, а ядро качества.

Именно это, как нам кажется, и отделяет демонстрационный RAG от рабочего инструмента по нормативным документам.

Автор: Gofoloman

Источник

Rambler's Top100