Перейти к содержанию
Публикация AiManual

Как поймать AI-бота на ошибке до скриншота клиента: логирование RAG и guardrails на практике

Бот пообещал клиенту бесплатный ремонт, смешав гарантию с расширенным планом, которого у клиента не было, и компания выполнила обещание. Разбираем два слоя защи

Коротко

Что будет в материале

  1. 01

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

  2. 02

    Почему это дороже, чем кажется: прецедент Air Canada и цена обещания

  3. 03

    Слой 1: логирование retrieved-чанков рядом с каждым ответом

  4. 04

    Слой 2: live-проверка ответа перед отправкой

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

Без первого слоя вы не поймёте, откуда взялась ошибка. Без второго ошибка дойдёт до клиента, и дальше начнётся разговор со скриншотом. В публичном разборе на r/LocalLLaMA инженер описал именно такой случай: бот пообещал бесплатный ремонт, ответ был связным и по теме, а в логах ничего не выглядело подозрительно.

Дальше по делу: что именно логировать, как устроена проверка на выходе, чем отличаются Orq AI и Nemo Guardrails и почему guardrail не отменяет утреннего чтения транскриптов.

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

Компания перевела поддержку на собственную self-hosted модель, чтобы данные клиентов оставались внутри, и бот отвечал по help-документам через RAG. Один клиент получил ответ: случайное повреждение покрыто гарантией, ремонт будет бесплатным. Ни то, ни другое не соответствовало действительности.

Причина в retrieval. Бот вытащил документ о расширенном плане, которого у клиента не было, и склеил два условия: гарантию и правила расширенного покрытия. Ответ получился гладким и тематически уместным, поэтому в логах не выглядел подозрительным. Клиент прислал скриншот, и компания выполнила обещание: спорить со скриншотом собственного бота бессмысленно, позиция проигрышная по определению (разбор кейса от первого лица).

Почему «ответ по теме» - плохой критерий качества

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

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

Проверка faithfulness устроена иначе: она сопоставляет утверждения ответа с контекстом, который реально был извлечён. На кейсе Similarweb видно, как LLM-as-judge и трейсинг в LangSmith ловят расхождение между ответом и источниками, а заодно как ошибка калибровки судьи едва не замаскировала реальные улучшения агента (разбор оценки длинных отчётов).

Чем это отличается от галлюцинации «из воздуха»

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

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

Почему это дороже, чем кажется: прецедент Air Canada и цена обещания

В 2024 году Air Canada проиграла разбирательство в трибунале: её чатбот дал вводящую в заблуждение информацию о тарифах для bereavement fares. Детали решения для инженерной задачи вторичны, важен факт: спор дошёл до трибунала и компания его проиграла (публичный разбор со ссылкой на прецедент).

Что именно показал кейс Air Canada

Чатбот выдал информацию о тарифах, которая не соответствовала реальным условиям, и клиент на неё опирался. Трибунал встал на сторону клиента. Для команд, которые строят поддержку на LLM, вывод звучит так: ответ бота воспринимают как позицию компании, а не как черновик.

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

Почему скриншот сильнее внутренних логов

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

В кейсе компания выбрала дешёвый путь и выполнила обещание. Дальше арифметика: стоимость одного неверного ответа о покрытии выше стоимости логирования и guardrail, потому что обещание превращается в обязательство, которое нельзя отозвать. Защита должна стоять на границе отправки, как детерминированный gateway в истории агента, который без прав всё равно выполнил PATCH в HubSpot и изменил не ту запись (разбор runtime-контроля).

Слой 1: логирование retrieved-чанков рядом с каждым ответом

Первый слой отвечает на вопрос «почему бот это сказал». Без него разбор инцидента превращается в археологию по остаткам чата и воспоминаниям оператора.

Что именно писать в лог, чтобы разбор был возможен

Минимальный набор полей на каждый ответ:

  • id диалога и id сообщения, чтобы связать запрос с ответом и с последующей эскалацией;
  • текст запроса после нормализации;
  • top-k извлечённых чанков: id чанка, document_id, раздел, версия документа, score ретривера;
  • метаданные клиента, которые влияют на ответ: наличие расширенного плана, регион, тип устройства;
  • версия индекса и версия модели;
  • финальный промпт и финальный ответ;
  • latency и признак срабатывания guardrail.
{
  "trace_id": "c7f1...",
  "message_id": "m-88412",
  "query": "разбил телефон, почините бесплатно?",
  "retrieved": [
    {"chunk_id": "warranty-3", "doc": "warranty.md", "score": 0.81},
    {"chunk_id": "ext-plan-7", "doc": "extended_plan.md", "score": 0.79}
  ],
  "customer": {"plan": "none", "region": "ru"},
  "index_version": "2026-09-30",
  "model": "",
  "answer": "Да, ремонт бесплатный",
  "guardrail": "not_checked"
}

Отдельный пункт про приватность. Логи содержат клиентские данные, и в self-hosted схеме они должны оставаться в той же инфраструктуре. Иначе требование «данные не покидают компанию» ломается на этапе наблюдаемости, самом скучном и самом незаметном.

Хранить нужно чанки и версию индекса на момент ответа. После переиндексации чанк с тем же id может содержать другой текст, и инцидент перестанет воспроизводиться.

Langfuse и Arize Phoenix: где они реально помогают

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

  • разбор инцидента без реконструкции по памяти;
  • фильтрация по времени и по кластеру похожих запросов;
  • проверка гипотезы «модель виновата» против гипотезы «retrieval принёс не тот документ».

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

Слой 2: live-проверка ответа перед отправкой

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

Логика правила формулируется так: проверяем не «похоже ли на правду», а «подтверждается ли конкретное утверждение конкретным чанком для этого клиента».

если ответ содержит утверждение о покрытии ремонта
   и ни один retrieved-чанк не содержит условие покрытия
       для профиля клиента (plan = "extended")
   то заблокировать и эскалировать человеку

Условие с профилем обязательно. Фрагмент о расширенном плане существует и действительно подтверждает бесплатный ремонт, но только для владельцев плана. Без проверки профиля guardrail пропустит ровно тот ответ, который сломал поддержку в кейсе.

Какие утверждения проверять в первую очередь

Короткий список высокого риска:

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

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

Блокировать или переписывать

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

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

Orq AI или Nemo Guardrails: как выбрать под свой стек

Качество ответов часто упирается в обвязку и данные, а не в дообучение модели: в сравнении «1С Напарник» с агентом на Deep Agents и pgvector open-source обвязка обошлась без дообучения там, где хватало нормального RAG (разбор сравнения). С guardrails та же история: сначала обвязка, потом модель.

КритерийOrq AINemo Guardrails
Как работает проверкаevaluators запускаются как guardrails и блокируют ответ при провале проверкипроверки пишет и поддерживает команда
Размещениеесть on-prem установка, данные не покидают инфраструктуру компаниив исходном разборе деталей нет, смотреть документацию
Объём ручной работыниже: механизм блокировки уже естьвыше: больше проверок писать самим

Когда on-prem решающий фактор

В кейсе выбор self-hosted модели был условием, а не бонусом: данные клиентов остаются внутри компании. Если это требование не обсуждается, облачный guardrail, который читает текст обращения, ломает всю схему целиком. Из двух вариантов on-prem установка в исходном разборе названа у Orq AI.

Для Nemo Guardrails автор разбора деталей по размещению не приводит, поэтому утверждать, что он не подходит под self-hosted сценарий, мы не будем. Этот пункт надо проверять по документации фреймворка и по своей инфраструктуре.

Сколько ручной работы вы готовы поддерживать

Nemo Guardrails требует писать больше проверок самим. Это даёт контроль и прозрачность, а вместе с ними поддержку, тесты и обновления при каждой правке политик возврата или гарантии. Orq AI в исходном разборе описан как механизм, где evaluators сразу работают блокирующим guardrail.

Критерий выбора простой: готова ли команда владеть набором правил как кодом. Если да, ручной путь предсказуем и не добавляет ещё один слой с собственными ограничениями. Если нужен более готовый блокирующий механизм, смотреть в сторону Orq AI. Цены и лицензии в исходном разборе не приводятся, их проверяют у поставщика.

Ловит ли guardrail больше, чем ручное чтение транскриптов

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

Сильные стороны выходного guardrail

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

Ограничение: правило ловит только то, что в нём описано. Смешение двух реальных политик проскочит, если проверка не содержит сценарий «у клиента нет второго плана».

Что даёт ручное чтение транскриптов

  • находит новые паттерны ошибок, которые ещё не стали правилом;
  • показывает странные формулировки и пробелы в документации;
  • выявляет случаи, где сам guardrail сработал неверно и заблокировал корректный ответ.

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

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

Минимальный чек-лист: от логов до блокирующего guardrail

Последовательность, которая работает без переписывания архитектуры:

  1. Включить логирование retrieved-чанков с id, источником, score и версией индекса (Langfuse или Arize Phoenix).
  2. Выписать короткий список утверждений высокого риска: покрытие, возвраты, сроки, цены.
  3. Сделать проверку подтверждения: каждое утверждение из списка опирается на чанк, подходящий профилю клиента.
  4. Выбрать механизм: Orq AI с on-prem установкой или Nemo Guardrails с собственными проверками.
  5. Настроить эскалацию к человеку при блоке и понятный статус для клиента вместо тишины.
  6. Раз в неделю разбирать заблокированные и пропущенные случаи и обновлять правила.

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

Порядок действий и типичные ошибки

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

Как измерять эффект

Метрики, которые снимаются со своей системы без внешних бенчмарков:

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

Первые две важнее остальных: они показывают, ловит ли guardrail ошибки или просто мешает работать.

Что запомнить

  • Связный ответ не равен корректному: смешение двух реальных политик выглядит в логах абсолютно нормально.
  • Без логов retrieved-чанков инцидент не разобрать: нужны чанки, score, источник и версия индекса.
  • Выходной guardrail блокирует опасные обещания, но требует поддержки правил и не отменяет выборочное чтение транскриптов.

Прецедент Air Canada 2024 года показывает цену ошибки: разбирательство дошло до трибунала, и компания его проиграла.

Кому это точно нужно

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

Первый шаг на этой неделе: включить запись retrieved-чанков и версии индекса. Правила имеет смысл писать, когда перед глазами есть 20-30 реальных диалогов и видно, какие утверждения действительно опасны.

Подписаться на канал