Перейти к содержимому
01 янв. 2026 г.·7 мин чтения

Ссылки на источники в ответах LLM без выдуманных цитат

Разбираем, как настроить ссылки на источники в ответах LLM: поиск фрагментов, формат цитат, проверка совпадений, ошибки и чек-лист перед запуском.

Ссылки на источники в ответах LLM без выдуманных цитат

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

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

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

Разница между ответом с цитатой и без нее видна сразу. Ответ без цитаты звучит так: "Возврат возможен в течение 30 дней". Проверить тут нечего. Ответ с цитатой выглядит иначе: "Регламент возвратов, версия 2.3, п. 4.2: 'Возврат возможен в течение 14 календарных дней'". Такой ответ уже можно открыть, сверить и оспорить, если модель ошиблась в трактовке.

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

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

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

Как выглядит проверяемая цитата

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

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

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

Рабочий шаблон простой:

  • тезис модели
  • источник: документ, раздел, страница
  • дословная цитата в кавычках
  • вывод модели отдельно от цитаты

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

Например, слабый вариант такой: "Компания хранит логи в РФ, источник: политика безопасности". Нормальный вариант короче и точнее: "Логи хранятся на серверах в РФ" [Политика обработки ПДн v3.2, раздел 4.3, стр. 12]. Цитата: "Логи и резервные копии размещаются на серверах, расположенных на территории РФ". Вывод модели: это правило относится к операционным логам и бэкапам.

Дословный фрагмент не должен быть длинным. Обычно хватает 1-3 предложений или 300-500 символов. Длинная вставка только мешает читать и часто выдает проблему: модель не нашла прямого подтверждения и пытается закрыть дыру большим куском текста.

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

Для внутренней базы знаний в RAG-сценарии удобнее хранить эти поля в метаданных каждого чанка. Тогда и в ответах через RU LLM можно требовать не список "источников вообще", а точную опору под каждый спорный тезис.

Из чего собирается такой ответ

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

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

Поиск должен идти первым. Система не должна сначала просить модель "вспомнить" документ, а потом искать подтверждение. Сначала она поднимает 3-10 фрагментов, которые ближе всего к вопросу, и только потом строит ответ. Так меньше риск, что модель подменит факт правдоподобной фразой.

У каждого куска текста нужны метаданные. Минимум - идентификатор документа, версия, дата обновления и место в документе: раздел, пункт, страница или номер абзаца. Полезно хранить и служебные поля: кто владелец документа, можно ли его показывать этому пользователю, когда фрагмент попал в индекс. Без этого ссылка выглядит аккуратно, но проверить ее трудно.

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

Последний слой - логирование. Сохраняйте не только вопрос и готовый ответ, но и список выбранных фрагментов, их версии, ранги поиска и итоговый промпт. Тогда спорный ответ можно разобрать по шагам: поиск ошибся, метаданные устарели или модель сослалась не на тот кусок.

Если команда работает через RU LLM, такой аудит удобно держать рядом с вызовами модели. Запросы идут через единый OpenAI-совместимый эндпоинт, а маршрутизация, логи и внутренняя проверка остаются в одном контуре.

Как настроить процесс по шагам

Если вам нужны ссылки на источники в ответах LLM, начинать надо не с промпта, а с корпуса документов. Модель не умеет честно цитировать хаос. Она либо путает версии, либо красиво достраивает пропущенное.

Обычно рабочая схема выглядит так:

  1. Сначала чистят документы: убирают дубли, черновики и устаревшие версии.
  2. Потом режут текст на куски, которые держат один смысловой блок.
  3. К каждому куску добавляют метаданные: title, page, section, version, document_id.
  4. После этого настраивают гибридный поиск: по смыслу и по точным словам.
  5. В конце задают жесткое правило для генерации и проверку ответа по схеме.

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

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

Метаданные нужны не для красоты. Они делают ответ проверяемым и для человека, и для кода. Когда модель возвращает не просто "в документе сказано", а название, номер страницы, раздел и версию, спорить уже проще. Для внутренних баз по 152-ФЗ это особенно полезно: юрист, инженер и аудитор должны открыть один и тот же фрагмент, а не гадать, где он был.

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

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

Последний слой - валидация. Задайте схему ответа с полями для текста, списка цитат и метаданных источника. Если page, section или document_id пустые, такой ответ лучше отбросить и пересобрать. Иначе система выглядит аккуратно, а аудит разваливается на первом же спорном случае.

Как задать формат ответа модели

Сравните модели на цитатах
Проверьте, какая модель лучше держит JSON, ссылки и точные фрагменты.

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

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

Для каждого такого утверждения просите не пересказ, а дословный фрагмент из найденного документа. Поле можно назвать exact_quote или quote_text. Название не так важно. Важно, чтобы там лежал текст без перефразирования.

{
  "answer": "Лимит хранения логов составляет 30 дней.",
  "citations": [
    {
      "claim": "Лимит хранения логов составляет 30 дней.",
      "document_id": "policy-logs-01",
      "exact_quote": "Срок хранения логов составляет 30 календарных дней.",
      "page": 12,
      "section": "4.3"
    }
  ]
}

Но тут есть жесткое правило: модель не должна выдумывать page, section и document_id. Если ретривер не передал эти поля в контексте, пусть модель ставит null или вообще не возвращает их. Иначе вы получите красивую ложь, которую трудно заметить на глаз.

Если поиск ничего не нашел, это тоже нормальный результат. Лучше разрешить пустой массив citations, чем заставлять модель "спасти" ответ фантазией. В таком случае answer может прямо сказать, что подтверждение в доступном контексте не найдено.

Для промпта обычно хватает четырех правил:

  • Верни JSON с полями answer и citations.
  • Добавляй цитату только там, где утверждение можно проверить по документу.
  • Используй только поля источника, которые пришли во входном контексте.
  • Если подтверждения нет, верни citations: [].

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

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

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

Где система чаще всего ломается

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

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

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

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

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

Тревожные признаки

Есть несколько признаков, что система уже дает слабые цитаты:

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

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

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

Пример на внутренней базе знаний

Подберите строгий маршрут
Для ответов с цитатами выберите модели и провайдеров через один шлюз.

Представьте внутреннюю базу знаний службы поддержки. В ней лежат три документа: "Регламент обработки запросов клиентов", "Инструкция для первой линии" и "Порядок эскалации спорных случаев". Сотрудник задает вопрос: "Можно ли отправить клиенту договор на личную почту, если он сам попросил об этом в чате?"

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

Поиск не должен вытаскивать весь документ целиком. Лучше, когда система находит 2-3 коротких фрагмента рядом с нужным местом. В этом примере поиск поднимает кусок из регламента про "подтвержденные каналы связи", фрагмент из инструкции с прямым запретом на личную почту и абзац из порядка эскалации про исключения по согласованию.

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

Ответ: Нет, оператор не должен отправлять договор на личную почту клиента по просьбе в чате.
Основание: "Личная электронная почта клиента не относится к подтвержденным каналам передачи документов" (Инструкция для первой линии, п. 2.7).
Дополнение: "Исключение допускается только после согласования с руководителем смены" (Порядок эскалации спорных случаев, п. 3.2).

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

Иногда система должна честно остановиться. Допустим, сотрудник спрашивает: "Можно ли отправить скан паспорта клиента в корпоративный мессенджер для ускорения проверки?" Поиск находит фрагменты про почту и архив, но не находит прямого правила про мессенджер. Тогда нормальный ответ выглядит так:

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

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

Проверка перед запуском

Не меняйте рабочий код
Переведите вызовы на единый API и не переписывайте текущую интеграцию.

Запускать такую систему по демо-вопросам опасно. Нужны хотя бы 20 живых запросов, которые люди правда задают поддержке, аналитикам или внутреннему чат-боту. Если взять только удобные примеры, модель покажет аккуратные ответы, а проблемы всплывут уже в рабочем контуре.

Лучше собрать небольшой тестовый набор вручную. Пусть в нем будут короткие вопросы, расплывчатые формулировки, запросы с датами, сокращениями и конфликтующими версиями документов. Такой набор быстро показывает, где модель отвечает по памяти, а где реально опирается на текст.

Для каждого вопроса удобно вести простую таблицу:

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

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

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

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

Отдельно проверьте OCR, таблицы и PDF-сканы. Именно там ломаются номера строк, ячейки, сноски и переносы, а вместе с ними ломается и цитирование. Если вы строите аудит ответов через RU LLM внутри российского контура, имеет смысл сохранять audit trail по каждому запросу. Потом проще понять, какой кусок документа попал в ответ и где цепочка дала сбой.

Если после такого прогона 3-4 вопроса из 20 все еще дают красивые, но пустые ответы, систему рано выпускать. Сначала чините поиск, разметку документов и правила, по которым модель обязана молчать, когда не нашла опору.

Что делать дальше в продакшене

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

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

Полезно хранить в логе не только текст ответа. Минимальный набор такой:

  • исходный запрос пользователя
  • найденные фрагменты с ID документа и версией
  • итоговые citations, которые модель отдала пользователю
  • выбранную модель и маршрут запроса

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

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

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

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

Для продакшена в РФ здесь полезен и инфраструктурный слой. Например, RU LLM дает единый API-шлюз для вызова разных моделей, а логи, биллинг и хранение данных остаются внутри российского контура. Это удобно, когда команда хочет сохранить текущие SDK и промпты, но не терять прозрачность маршрута и след для аудита.

Хороший рабочий признак простой: по любому спорному ответу команда за пару минут поднимает запрос, видит найденные куски текста, сравнивает их с citations и понимает, где именно произошла ошибка.