Grounding, citations, and hallucination control
Require evidence-backed answers, verify citations mechanically, and measure faithfulness instead of trusting confident prose.
Lesson content is currently available in Russian.
What you will learn
- →Писать grounded-промпты: правила опоры на контекст, формат цитат и условия отказа.
- →Строить механическую верификацию цитат: каждая ссылка указывает на реально переданный фрагмент.
- →Разворачивать NLI/LLM-judge проверку faithfulness на потоке ответов и выбирать действие при провале.
Откуда берутся галлюцинации в RAG
RAG уменьшает галлюцинации, но не устраняет их — меняется их природа. Четыре продакшен-источника. Конфликт контекста и параметрической памяти: в документах «лимит 100 запросов/мин», модель помнит из претрейна «60» — и без жёсткой инструкции может выбрать память; это задокументированный эффект (knowledge conflicts), усиливающийся, когда контекст противоречит «общеизвестному». Слабый retrieval: нерелевантные чанки в промпте — модель «дотягивает» ответ до вопроса из головы. Сшивание фрагментов: два верных факта из разных чанков склеиваются в неверный вывод — даты из одного документа приписываются событию из другого. Давление формата: инструкция «дай развёрнутый ответ» вынуждает заполнять пробелы, когда фактов на развёрнутый ответ нет.
Важное следствие: контроль галлюцинаций — не один приём, а слоёная защита. Слой 1 — retrieval (уроки 1–4): в контекст попадает нужное и не попадает мусор. Слой 2 — промпт: правила опоры на контекст и право на отказ. Слой 3 — формат ответа: обязательные цитаты, делающие проверяемым каждое утверждение. Слой 4 — автоматическая верификация: механическая проверка цитат и семантическая проверка faithfulness. Ни один слой в одиночку не даёт продакшен-надёжности; в этом уроке — слои 2–4.
База для калибровки ожиданий: даже у лучших моделей faithfulness на сложных доменах не абсолютен, поэтому вопрос ставится не «как исключить галлюцинации», а «какой остаточный уровень приемлем для продукта и как его непрерывно измерять» — мостик к следующему уроку.
Grounded-промптинг и право на отказ
Рабочий скелет grounded-промпта — четыре блока правил:
Отвечай ТОЛЬКО по фрагментам в <context>. Правила:
1. Каждое фактическое утверждение снабжай ссылкой [N] на фрагмент-источник.
2. Если фрагменты не содержат ответа — скажи об этом прямо и не отвечай
по общим знаниям. Не смешивай знания модели с фактами из контекста.
3. Если фрагменты противоречат друг другу — покажи оба варианта с датами
и источниками, не выбирай молча один.
4. Отвечай ровно настолько подробно, насколько позволяют фрагменты.
<context>
<doc id="1" source="pricing.md" updated="2026-05-10">…</doc>
<doc id="2" source="release-notes/v3.2.md" updated="2026-06-01">…</doc>
</context>
Детали, которые решают. Нумерованные doc-теги с метаданными дают модели адреса для цитат и материал для разрешения конфликтов (свежая дата побеждает). Правило 3 против молчаливого выбора — конфликтующие версии документации это норма жизни, а не исключение. Правило 4 снимает давление формата: лучше три подтверждённых предложения, чем десять «гладких».
Отказ от ответа настраивается как продуктовое решение с явным порогом. Полезная шкала: отвечать уверенно (факты покрывают вопрос) / отвечать с оговоркой («в документации указано X, но раздел не обновлялся с версии 2.0») / отказаться с маршрутом («не нашёл в базе; передаю оператору»). Формулировку отказа пишите заранее и тестируйте — дефолтное «я не могу помочь» без маршрута раздражает пользователей и хоронит доверие к продукту быстрее редких галлюцинаций.
Цитаты: механическая верификация и extraction-first
Цитата ценна тем, что её можно проверить машиной. Минимальный контур: ответ парсится на утверждения с метками [N], и для каждой проверяется, что (а) фрагмент N существовал в переданном контексте и (б) утверждение реально им подкреплено. Проверка (а) — тривиальный код; для (б) есть быстрый лексический прокси и точная семантическая проверка:
def check_citations(answer: str, ctx: dict[int, str]) -> list[Claim]:
claims = split_into_claims(answer) # предложения с [N]
for c in claims:
if c.doc_id not in ctx:
c.status = 'fabricated_ref' # ссылка в никуда
elif token_overlap(c.text, ctx[c.doc_id]) < 0.35:
c.status = 'suspect' # на дообследование NLI
else:
c.status = 'ok'
return claims
Ссылки «в никуда» — реальный и частый класс дефектов: модель пишет [7], когда фрагментов было пять. Ловится строкой кода, а без проверки выглядит как убедительно оформленный ответ.
Более сильная схема — extraction-first (quote-then-answer): первым шагом модель дословно выписывает релевантные цитаты из контекста, вторым — собирает ответ только из выписанного. Дословность шага 1 проверяется посимвольным поиском по контексту — это уже не оценка, а факт. Схема снижает галлюцинации сшивания и почти закрывает конфликт с параметрической памятью, ценой роста токенов на ~30–50% и чуть более «сухих» ответов. Для доменов с ценой ошибки (юридические, медицинские, финансовые ответы) этот размен почти всегда правильный. Anthropic поддерживает этот паттерн нативно через Citations API — модель возвращает структурированные ссылки на переданные документы вместо текстовых [N].
Faithfulness на потоке: NLI и LLM-judge
Лексический overlap не отличит перефразированную правду от тонкого искажения («лимит можно увеличить» → «лимит увеличивается автоматически»). Семантическая проверка faithfulness работает так: ответ разбивается на атомарные утверждения, и для каждого проверяется, следует ли оно из контекста (entailment). Два инструмента: специализированные NLI-модели (дёшево, быстро, слабее на длинных многосоставных фрагментах) и LLM-judge с бинарной рубрикой «подкреплено/не подкреплено» на каждое утверждение (точнее, дороже). Метрика faithfulness в Ragas — доля подкреплённых утверждений — устроена ровно так, и её можно гонять как оффлайн на eval-наборе, так и сэмплированно на живом трафике.
Продакшен-контур: на каждый (или сэмплированный — например, 10% плюс все ответы с низкой уверенностью) ответ считается faithfulness-скор; при провале порога выбирается действие по цене ошибки домена. Варианты действий по возрастанию строгости: залогировать для разбора; показать ответ с плашкой «не удалось проверить по источникам»; перегенерировать с ужесточённым промптом; заменить отказом с маршрутом на человека. Blocking-проверка добавляет латентность (сотни миллисекунд на judge), поэтому её ставят только там, где цена ошибки выше цены задержки.
Закрывающая мысль слоёной защиты: логи верификации — не только предохранитель, но и датасет. Утверждения с провальным faithfulness — это готовые кейсы для error analysis: они показывают, где ломается retrieval (мусор в контексте), где промпт (модель игнорирует правила), а где формат (давление на развёрнутость). Этот поток кейсов питает eval-набор следующего урока — контроль галлюцинаций и измерение качества образуют один цикл.
Practice
Контур grounding и верификации
Перепишите промпт своего RAG по четырёхблочному скелету (цитаты [N], отказ, конфликты, длина по фактам). Реализуйте механическую проверку цитат (fabricated_ref + overlap-прокси) и прогоните 20 вопросов: 12 с ответом в базе, 4 без ответа, 4 с конфликтующими документами. Для 12 первых посчитайте faithfulness через Ragas или LLM-judge по бинарной рубрике.
Deliverable
Промпт, код верификации и отчёт: доля ответов с корректными цитатами, поведение на 4 вопросах без ответа (ожидание: отказ с маршрутом), поведение на конфликтах (ожидание: показаны оба варианта), faithfulness-скор с разбором каждого провального утверждения.
Checkpoint
Продакт спрашивает: «можем ли мы гарантировать, что бот не выдумывает?» Дайте честный инженерный ответ: какие слои защиты есть, что каждый ловит и что остаётся.
- ✓ Названы источники галлюцинаций в RAG: конфликт с параметрической памятью, слабый retrieval, сшивание фрагментов, давление формата.
- ✓ Описана слоёная защита: grounded-промпт с правом на отказ, обязательные цитаты с механической проверкой, faithfulness-контур (NLI/judge) на потоке.
- ✓ Сформулировано, что гарантия невозможна — есть измеримый остаточный уровень, порог приемлемости и действия при провале (плашка, перегенерация, эскалация).
Check yourself
Sources