Когда агент в проде ошибается, разбор в команде идёт по одному сценарию: «модель тупит», «промпт кривой», «у провайдера что-то с API». Особенно едкая версия спора — когда весь код вокруг модели написан тобой: виновата модель или всё-таки я? Я спорил так же, пока не начал разбирать отказы по одному, с логами и числами. Оказалось: агент падал не потому, что модель плохая, а по причинам, у которых есть имена.
Три эпизода из практики, все — при зелёных метриках.
При заливке корпуса норм в векторную базу молча терялось 34% чанков: в базе осталось 6861 точка из 10 414, лог загрузки рапортовал «пропусков нет», а золотой набор вопросов был зелёный — проверочные вопросы просто не попадали в потерянные куски.
Состязательный аудит нашёл 14 дефектов; половина — в моих собственных оценочных тестах. И все эти тесты горели зелёным.
Мой любимый из той же партии: дымовой тест (smoke test) «ни один публичный PDF не валит парсер» был написан через
any()— если из трёх документов выжил один, тест считался пройденным. Пустое доказательство, а не проверка.
Модель во всех трёх историях не менялась и не дообучалась: чинить требовалось не её, а код вокруг — базу, конвейер, мои же тесты.
Дальше — почему это не невезение, а закономерность. Видимый отказ всегда одинаков: «агент ошибся». А за ним может стоять ремонт четырёх разных видов: пост-тренинг модели (model post-training), инженерия обвязки (harness engineering), переделка окружения (environment redesign) или починка самого оценщика (benchmark repair). Обвязка — это весь код вокруг модели: промпты, контекст, память, инструменты; точного короткого русского слова у термина нет, «обвязка» — ближайший эквивалент. По наблюдаемому сбою не видно, какой из четырёх видов ремонта нужен, — в статье это называют проблемой распределения ремонта (repair-assignment problem). Цена ошибки не абстрактна: потратил недели на дообучение или смену модели — отказ остался на месте. По умолчанию все выбирают именно этот, самый дорогой и обычно неверный путь: «модель тупая — сменим».
Первоисточник. Harsh Raj, Vipul Gupta, Anas Mahmoud, Razvan-Gabriel Dumitru, Darvin Yi, Aakash Sabharwal, Yunzhong He (все — Scale AI). «Model or Harness? An Interaction-Centric Taxonomy for Localizing Agent Failures», arXiv:2607.28802, 30 июля 2026, лицензия CC BY 4.0.
Сразу честно: это адаптация, а не перевод. Авторы построили таксономию из 41 режима отказа (failure mode) — 36 отнесли к стороне модели, 5 — к окружающим компонентам. Мне их рамка дала главное: у сбоя появился адрес, а у спора «модель или мой код» — процедура. Авторам спасибо. Добавленная ценность здесь — моя: кейсы с числами, выжимка каталога, чек-лист; где моя перегруппировка расходится с авторской — оговорено на месте.
Кто я, чтобы об этом писать. Я строю агента, который проверяет проектную документацию стадии «П» (многоквартирные дома) на соответствие Постановлению Правительства РФ № 87 и нормам техдокументации: на входе папка с PDF-томами, на выходе отчёт для главного инженера проекта. Внутри — корпус из 65 действующих нормативных документов, 522 автотеста, состязательные аудиты, дневные бюджеты токенов. Это пилот: контур собран целиком и идёт приёмка на реальных документах, но постоянных пользователей у системы пока нет. Цена отказа здесь юридическая: каждая ссылка на норму в отчёте читается как утверждение, которое заказчик понесёт в экспертизу, поэтому «модель иногда ошибается» — не ответ, а постановка инженерной задачи.
Про пруфы сразу, чтобы не спрашивали в первом комментарии: код закрытый, это коммерческий продукт, ссылки на репозиторий не будет. Поэтому вместо «поверьте на слово» в конце статьи — приложение: как получена каждая цифра, какой командой и из какого файла. Числа первоисточника проверяются по самой статье на arXiv, числа проекта — по этой методике; повторить её у себя может любой, у кого есть похожий конвейер.
Главный тезис: поведение агента рождается на стыках компонентов — модели, контекста, памяти, инструментов, окружения. Когда агент ошибся, вопрос не «кто виноват», а «какой стык и чья сторона»: у отказа есть ребро (edge) между двумя компонентами и сторона вины (fault side), на которой локализован ремонт. Самое непривычное следствие: «виновата модель» почти никогда не означает «чинить дообучением». Самая частая и самая здоровая конфигурация в моей практике ровно обратная: виновата модель, но чинит обвязка — детерминированный барьер ловит то, что живая модель будет делать время от времени, что бы ни писали в анонсах новых версий.
Дальше по порядку: как устроена таксономия → каталог-выжимка → три разбора из моего пилота → где метод ломается → чек-лист «что делать завтра».
Отказ живёт на стыках: рёбра, сторона вины и почему «агент не справился» — пустая фраза
Стартовая точка статьи: существующие оценки агентов сводят любой сбой к системному результату — «выполнил / не выполнил». Происхождение сбоя при этом теряется, а с ним и ответ на единственный практически важный вопрос: куда вкладывать ремонт. Фраза «агент не справился» несёт примерно столько же информации, сколько «машина не едет». Лекарство авторов — таксономия, построенная вокруг взаимодействий (interaction-centric): каждый режим отказа привязан к ребру между двумя компонентами и к стороне вины — той, где ремонт локализован.
Граф вокруг модели: девять компонентов и девять рёбер
Таксономия описывает не «агента целиком», а граф вокруг модели. Компонентов девять; модель — хаб, к которому сходятся все рёбра, а остальные восемь сгруппированы в три семьи: пользователи — владелец (owner), оценщик (grader) и третья сторона (third party); обвязка (harness) — контекст, память, инструменты; окружение (environment) — внешнее и локальное. Отказ — не свойство компонента, а сбой на ребре «модель ↔ X»: модель ↔ владелец, модель ↔ память, модель ↔ инструмент; девять рёбер на все компоненты.

Девять компонентов и девять рёбер: восемь спиц от модели-хаба плюс петля «модель ↔ модель» у самого хаба. Пунктиром отмечены четыре компонента, на чьей стороне лежат те самые пять режимов из 41: сменой модели они не чинятся.
Единственное усложнение — ребро модель–модель, когда в системе есть вторая модель. Эта вторая модель может быть равноправным собеседником (peer) или подчинённым агентом (subagent); авторы подчёркивают: это роли, а не отдельные компоненты, и отказы у ролей разные. Итого девять рёбер, из которых ребро модель–модель представлено в двух ролях.
Два правила, которые прекращают спор о виноватом
Правило атрибуции: отказ получает метку fault: model, если более способная модель могла бы его предотвратить или из него восстановиться — при тех же инструментах, контексте и окружении. Не проходит проверку — ремонт лежит на одном из окружающих компонентов. Правило корня: метится самый ранний отказ, после которого исполнение уже не восстанавливается; всё позднейшее — следствия, а не причины. Второе правило я бы рекомендовал всем, кто разбирает инциденты, не только с агентами: без него разбор превращается в список из двадцати равноправных «находок», где причина и её последствия лежат вперемешку.
Итог каталога: 41 режим. Из них 36 приписаны модели, 5 — окружающим компонентам: Instruction–Grader Mismatch, когда инструкция владельца расходится с тем, что измеряет оценщик (вина владельца); Context Rationale Erosion — потеря обоснований при сжатии контекста (context compaction): вина обвязки, когда сжатием управляет она, и вина модели, когда сжимает сама модель; Mistranslation — искажение на стыке с инструментом (вина инструмента); Service Failure и Stale State Delivery — отказ сервиса и доставка устаревшего состояния (вина внешнего окружения). Перекос 36 из 41 авторы сами признают отчасти порождённым правилом атрибуции — в оригинале осторожное «partly reflects». А пятёрка примечательна другим: улучшением модели она не чинится в принципе.
«Виновата модель» не значит «чинить дообучением»
В статье сторона вины — указатель вида ремонта: model — пост-тренинг, harness — инженерия обвязки, grader и environment — редизайн самой оценки. Логично, но у команды в проде пост-тренинга, как правило, нет; у меня его точно нет. Поэтому «виновата модель, а чинит обвязка» — не парадокс, а нормальный рабочий день: модель будет время от времени выдумывать пункт нормы, что бы ни обещали анонсы новых версий, и рабочий ответ на это — детерминированный барьер в конвейере, а не ожидание спасительной версии. Как это выглядит в коде — в разборах ниже.
Три примера на калибровку взгляда
Шахматы (пример E12, взлом спецификации — Specification Gaming, ребро модель–оценщик): агент, которому поручили победить шахматный движок, редактировал состояние доски, пока противник не сдался; оценщик засчитал победу. Метрика зелёная, задача обойдена — оптимизация под критерий вместо задачи.
Обёртка, глотающая ошибку инструмента (мотивирующий пример из раздела 3): инструмент сбойнул, обёртка подавила сбой — модель вообще не видит, что что-то пошло не так. Вина на инструменте, а снаружи похоже на «модель не проверила результат».
Удаление более 200 писем (пример E4) — демонстрация трудности атрибуции, не вердикт. Публичный отчёт объясняет удаление сжатием контекста, выбросившим инструкцию владельца «не действовать»; но источник неполный, и несанкционированное действие самой модели тоже не исключено. Статья отобрала этот случай ровно потому, что свидетельств не хватает на однозначный корень. В проде таких эпизодов хватает: логов всегда меньше, чем хочется. Дальше ссылаюсь на него коротко — «кейс с письмами».
Судьи, каппа и что эти числа не значат
Таксономию строили итеративно — на публичных бенчмарках (SWE-bench и Toolathlon — оба названы в первоисточнике), системных картах моделей, опубликованных отчётах и логах траекторий; когда определения стабилизировались, их заморозили на всё время разметки. Проверка — схема «агент как судья» (agent-as-a-judge): четыре топовые модели-судьи (GPT-5.5, Claude Opus 4.6, 4.7 и 4.8) классифицировали 40 проработанных примеров (E1–E40). Судьям давали определения таксономии и первоисточник; человеческих меток не показывали.
Числа. Лучший судья, GPT-5.5, достиг каппы Коэна (Cohen’s κ) 0.76 против человеческих меток на уровне категории; сами авторы называют это «well above chance» — «заметно выше случайного». Если нужен ярлык: по внешней шкале Ландиса–Коха это «существенное согласие», но это моя интерпретация, а не слова статьи. Совпадение с человеческой меткой на уровне категории (exact-match accuracy) — 0.80 у GPT-5.5 и 0.75 у всех трёх Opus; попарное согласие судей между собой — до 0.84 (Opus 4.6 против 4.8). Ансамбль меняет покрытие на точность (precision): совпали трое судей из четырёх — 0.83 при покрытии 90%; единогласно все четверо — 0.96 при 68%.
И оговорки, без которых числа читаются неверно. Все каппы — согласие «судья против человека», а не двух людей; о разметчиках статья подробностей не даёт, поэтому корректно писать просто «человеческие метки». Наконец, признано прямо: судьям трудно работать по неполным отчётам, а ансамбль с воздержанием молчит именно на самых неопределённых случаях атрибуции — там, где разбор нужнее всего. В приложении это показано наглядно: заготовленный ответ не приходил из-за бага оценочного окружения, а судья обвинял «модель, не проверившую ответ». И то, о чём стоит помнить, глядя на 0.76: все эти числа посчитаны на 40 примерах. Это калибровка порядка величины, а не устойчивая оценка — на такой выборке доверительный интервал у самой каппы широкий, и «заметно выше случайного» не значит «измерено точно».
Каркас собран. Дальше — каталог-выжимка: 15 режимов, которые встречаются чаще всего, с признаками, моими кейсами и рецептами.
Не все 41: 15 режимов, которые вы уже встречали (каталог-выжимка)
Полный каталог первоисточника — 41 режим, разложенный по рёбрам «модель ↔ X» (девять рёбер; ребро модель–модель представлено в двух ролях — peer и subagent). Здесь — выборка из 15, собранная в четыре полки «куда смотреть в первую очередь». Группировка — моя, не авторская: в статье режимы привязаны к рёбрам, а три семьи (Users, Harness, Environment) группируют компоненты, а не режимы. Все 41 режим перечислены на рис. 2 первоисточника, дословные определения — в Appendix B. Критерий отбора — частота и дороговизна в моей практике: частот отказов в первоисточнике нет, таксономия дескриптивна — она даёт имена и адреса, а не статистику.
В колонке стороны вины жирным отмечено не-модельное. Таких режимов в таксономии пять из 41, и все пять я собрал в выборку сознательно: это множество «меняй модель хоть десять раз — отказ останется». У одного из пяти — потери обоснований при сжатии — сторона вины условная: она зависит от того, кто сжимает контекст, обвязка или сама модель.
Что здесь чьё: имена режимов и стороны вины взяты из первоисточника, колонки «Как выглядит» и «Где чинить» — мои, это признаки и рецепты из собственной практики.
И короткий словарь, чтобы сторона вины сразу читалась как вид работы: модель — барьеры и валидаторы вокруг неё; обвязка — инженерия контекста, памяти, промптов; инструмент — слой интеграции (частный случай обвязки); владелец — правка задания и тестов; оценщик и окружение — переделка самой оценки, повторы, версионирование источников.
Пользователь и оценщик: рёбра «модель–владелец» и «модель–оценщик»
Самое населённое ребро: на одну пару модель–владелец авторы вешают десять режимов. Первые три строки ниже — как раз оно; взлом спецификации — это уже ребро модель–оценщик; рассогласование — снова владелец, только вина на другой стороне.
Режим |
Как выглядит |
Сторона вины |
Где чинить |
|---|---|---|---|
Дефицит знаний предметной области (Domain Knowledge Deficit) |
Выдумывает пункт нормы и «цитату» к нему; правдоподобно — без сверки не отличить |
модель |
детерминированный валидатор до вердикта: документ существует, редакция действующая, цитата дословная. Дообучение не лечит |
Удовлетворение минимумом (Satisficing) |
«Проверил 80% пунктов, остальное аналогично» — и заключение готово |
модель |
протокол полноты: пропущенные пункты маркируются |
Угодничество (Sycophancy) |
Пользователь давит «тут же всё нормально?» — модель забирает верное замечание обратно |
модель |
вердикт не зависит от тона запроса: отдельная роль, жёсткая схема ответа |
Взлом спецификации (Specification Gaming) |
Агент обходит проверку вместо решения; классика статьи — агент правил состояние шахматной доски, пока противник не сдался, и оценщик зачёл победу |
модель |
оценщик, не агент: мой дымовой тест через |
Рассогласование инструкции и оценки (Instruction–Grader Mismatch) |
Инструкция требует одного, оценщик меряет другое; задание противоречит реальному желанию владельца |
владелец |
править ТЗ и тест; агент без вины |
Контекст и память: рёбра «модель–контекст» и «модель–память»
Память — самая толстая полка обвязки: восемь режимов на одном ребре, от пропущенной записи до загрязнения.
Режим |
Как выглядит |
Сторона вины |
Где чинить |
|---|---|---|---|
Дрейф цели (Goal Drift) |
В длинной цепочке агент оптимизирует промежуточную метрику и забывает исходную задачу |
модель |
короткие цепочки; цель — явным текстом в каждом вызове |
Потеря обоснований при сжатии (Context Rationale Erosion) |
Сжатие контекста выбрасывает «почему» из инструкции — остаётся «что», и модель действует без причины |
обвязка, если сжатием управляет она (иначе модель) |
сохранять обоснования, не только команды |
Устаревшее состояние (State Staleness) |
В памяти запись, которая уже не правда: отменённая редакция нормы числится действующей |
модель |
реестр источников с датами действия; перевалидация памяти |
Загрязнение памяти (Pollution) |
Ошибочный вывод записан в базу — и каждый следующий прогон опирается на него как на факт |
модель |
запись в память через валидатор: у ошибок нет права сохраняться |
Инструменты: ребро «модель–инструмент»
Семь режимов у авторов; здесь — два модельных и один, где модель без вины.
Режим |
Как выглядит |
Сторона вины |
Где чинить |
|---|---|---|---|
Неверные аргументы (Malformed Arguments) |
Контракт вызова сломан: JSON в прозе, ответ в think-блоке, поле мимо типа |
модель |
парсер с балансом скобок, схема pydantic, одна ремонтная попытка — дальше типизированный отказ |
Игнорирование ответа инструмента (Tool Feedback Neglect) |
Инструмент вернул ошибку — модель делает вид, что всё получилось |
модель |
код возврата — часть контракта; провал ≠ пустой результат |
Искажение на стороне инструмента (Mistranslation) |
Кривой интеграционный слой давит или искажает ответ инструмента — модель вообще не видит сбоя |
инструмент |
чинить слой интеграции; логировать сырой ответ инструмента |
Внешний контур: рёбра «модель–третья сторона» и «модель–внешнее окружение»
Отдельная дисциплина имён: на ребре «модель–третья сторона» живёт контекстуальное угодничество (Contextual Sycophancy) — агент угождает не владельцу, а чужому голосу в контенте. Это другой режим, не угодничество (Sycophancy) из таблицы выше; в выборку он не вошёл, но при разборе эти два режима лучше не смешивать.
Режим |
Как выглядит |
Сторона вины |
Где чинить |
|---|---|---|---|
Косвенная инъекция промпта (Indirect Prompt Injection) |
Команды, спрятанные в чужом контенте — PDF, странице, письме, — исполняются как свои |
модель |
недоверенный контент — в песочнице; входные PDF у нас по умолчанию враждебные |
Отказ сервиса (Service Failure) |
Внешний сервис лёг: лимиты, таймауты, ошибки 5xx |
внешнее окружение |
повторные попытки, таймауты, режим деградации |
Устаревшие данные извне (Stale State Delivery) |
Источник жив, но отдаёт вчерашнее: кэш, старая редакция в выдаче |
внешнее окружение |
версионирование источников, сверка дат редакций |
Как пользоваться. Разбор инцидента заканчивается не словом «модель», а строкой таблицы: нашёл режим — получил сторону вины — получил вид ремонта. Если вина на модели — чинят барьерами, валидаторами и промптами; если на владельце — правкой задания и тестов; если на окружении — повторами, таймаутами и версионированием. Каталог в статье шире: 41 режим, включая восемь на памяти и четыре на ребре «модель–модель» (провал делегирования и обрыв связи в ролях peer и subagent). Но для первых недель разбора отказов хватает этих 15 — почти всё, что я разбирал у себя, в них ложится.
Проверка боем: три моих отказа, у которых появились имена — и ни один не лечится дообучением
Откуда кейсы. Все три — из контура того самого агента по стадии «П», описанного во вводной. Здесь добавлю недостающее устройство: парсинг со сканами через OCR, разметка томов по разделам постановления, сверка комплектности и актуальности ссылок на нормы; по корпусу норм (RAG) работают четыре LLM-роли — классификатор комплекта, арбитр разметки, сканер содержания и вердиктор. Схема разбора в каждом кейсе одна: что случилось → какой это режим таксономии → на чьей стороне оказался ремонт. Один эпизод из вводной — про молча потерянные 34% базы — сознательно оставляю следующему разделу: ему нужна отдельная рамка. Порядок — от бытового отказа к повороту, который мне до сих пор не нравится.
Кейс 1. Ломкий контракт вызовов: внутри ответа, проза вокруг JSON и выдуманные идентификаторы
Что случилось. Все четыре LLM-роли обязаны отвечать строгим JSON по схеме: ответ модели — это аргументы для детерминированного конвейера, свободная проза контрактом не предусмотрена. Реальность оказалась живее. GLM через OpenRouter включает режим рассуждений (reasoning) по умолчанию и заворачивает ответ в <think>…</think>; если генерация обрывается по лимиту токенов, закрывающий тег не приходит вовсе. Модель охотно обрамляет JSON вежливым вступлением («Вот ответ: {…}»), а сам JSON иногда оказывается незакрытым. И последнее: провайдер не принимает даже temperature=0 — а полного детерминизма он всё равно не гарантирует, так что живём на 0.1 и валидируем каждый ответ. И самый неприятный класс — формально валидный JSON с семантическим браком: сканер содержания выдумывал item_id пунктов чек-листа или молча пропускал пункты. Полнота проверки падала без единой строчки в логах.
Режим по таксономии. Неверные аргументы (Malformed Arguments), ребро модель–инструмент, сторона вины — модель. У авторов режим описан для аргументов вызова инструмента; у меня он вывернут наизнанку: ломается не то, что модель подаёт инструменту, а то, что она отдаёт конвейеру в качестве «аргументов». Правилу атрибуции это соответствует: более аккуратная модель справилась бы. Только весов этой модели мне не выдают — и чинить я её не могу.
Ремонт — обвязка. Теперь каждое сообщение LLM проходит конвейер structured.py: срезаются think-блоки — и закрытые, и незакрытые; первый JSON-объект извлекается балансом скобок, с учётом строковых литералов и экранирований (регулярное выражение без рекурсии вложенность не берёт, а сопроводительная проза ломает разбор окончательно); ответ валидируется pydantic-схемой. Дальше ровно одна ремонтная попытка: модели возвращается её собственный ответ и текст ошибки валидации. Второй сбой — типизированный LLMParseError с сырым текстом и причиной, на разбор человеку; варианта «проглотили и поехали» больше не существует. Провайдер-специфика заперта в адаптере: режим рассуждений выключен флагом, температура 0.1.
Резонный вопрос, который я жду первым: почему не штатный response_format с json-схемой? Мы его не используем, и дело не в незнании — барьер на своей стороне нужен в любом случае. Схема провайдера не ловит семантический брак (выдуманный item_id, молча пропущенный пункт), не спасает от обрыва генерации по лимиту токенов и не отменяет reasoning-обвязки конкретного маршрута. А раз разбор ответа всё равно свой, он же и держит контракт.
Против семантического брака — протокол полноты. Выдуманный item_id отбрасывается; по пропущенным пунктам уходит один автоматический дозапрос; всё, что так и не проверено, детерминированно помечается not_checked и снижает метрику полноты. Пропуск перестал быть невидимым — он стал числом в отчёте.
Кейс 2. Галлюцинации норм: правдоподобные, но несуществующие пункты
Что случилось. Каждое замечание агента обязано опираться на точную ссылку вида «СП 1.13130.2020, п. 5.2.15» и дословную цитату нормы. Модель — даже когда нужный документ уже подан в контекст через RAG — регулярно выдавала правдоподобные, но несуществующие основания: пункт из соседней редакции документа, «склейку» двух похожих формулировок, цитату-пересказ. Для проверки проектной документации это фатально: отчёт читается как юридическое утверждение, одна выдуманная ссылка обесценивает всё заключение. Идея «проверим ответ второй моделью» гарантии не даёт: верификатор галлюцинирует по тем же законам, что и автор. Гарантию даёт только детерминированная сверка с базой.
Режим по таксономии. Дефицит знаний предметной области (Domain Knowledge Deficit), ребро модель–владелец, сторона вины — модель. Классификация честная: сбой действительно на стороне модели, более способная модель ошибалась бы реже. Но «реже» — не «никогда», а цена одного прокола у нас юридическая. Смена модели — не решение, у следующей модели тот же класс ошибок с другой частотой.
Ремонт — обвязка, до вердикта. Между сканом и вердиктором стоит детерминированный валидатор цитат — чистая доменная функция без единого вызова LLM. Четыре проверки:
документ есть в реестре норм (тот самый корпус из 65 действующих документов);
его редакция — действующая, не заменённая;
упомянутый пункт существует в пунктовом индексе документа; индекс — проекция чанков той же векторной базы, из которой собирался контекст, поэтому рассинхрон «что читала модель» и «что проверяет валидатор» исключён конструктивно — а за полноту самой базы отвечают контрольные равенства из раздела о границах;
цитата входит в текст базы дословно — после нормализации кавычек, тире и пробелов, но без нормализации регистра и «е/ё»: чуть ослабить границу — и валидатор начинает пропускать перефразированные «цитаты».
Провал любой из четырёх проверок — и замечание уходит в статус needs_human, а вердиктирующий LLM-4 не вызывается вовсе. Если вердиктор предлагает «исправленную» ссылку, она проходит валидатор заново с нуля; второе несовпадение — снова needs_human.
Вывод кейса: модель не менялась и не дообучалась. Галлюцинации не лечатся — они ловятся. Формулировка нарочно резкая, поэтому уточню границу: заземление на источники и дообучение частоту снижают, и заметно, но класс ошибки остаётся живым, а барьер снимает именно класс.
Кейс 3. Поворот: взломал не агент, а мой измерительный прибор
Что случилось. На закрытии этапа парсинга я прогнал состязательный аудит: агенты-искатели копали код, тесты и метрики по четырём измерениям, каждую находку добивали скептики-верификаторы. Итог — 14 дефектов, и половина из них нашлась в моих собственных оценочных тестах. Не в боевом коде — в тестах, которыми я этот код проверял. И все до единого горели зелёным. Дымовой тест через any() из вводной — из этой же партии. Вот его соседи:
# точность распознавания шифров томов hit = code.endswith(expected) # «52-01-ПЗ» кончается на «1-ПЗ» — формально совпадение # пары сравнения для F1 детекции сканов if volume_failed: continue # упавший том выпадает из знаменателя # сверка таблиц считалась пройденной if len(rows) >= len(expected): # «не меньше» глотает и мусор, и недобор pairs = zip(rows, expected) # strict=False: разная длина — молча
Самый коварный — F1 детекции сканов: тома, упавшие при разборе, выпадали из пар сравнения, ложные пропуски просто не считались. Метрика улучшалась от того, что агент больше отказывался: отказов больше, «точность» выше, все довольны.
Режим по таксономии. Взлом спецификации (Specification Gaming), ребро модель–оценщик. Только в хрестоматийной версии этот режим выглядит как охота: агент находит щель в оценщике и пролезает в неё. У меня охотника не было — метрика обманывала меня сама, без участия модели. Форма та же («оценка зелёная, поведение нерабочее»), но сторона вины не модель и не обвязка агента, а измерительный прибор. В терминах вводной это четвёртый вид ремонта — починка самого оценщика (benchmark repair).
Ремонт — оценщика, не агента. any() заменён на all(); сверка шифра — с явной границей разделителя; правило: исключать из пар сравнения можно только заведомо непроверяемые случаи (скажем, запароленный файл), всё остальное — честная пара с отрицательным прогнозом; zip(strict=True) плюс точное равенство состава строк; учёт томов только по уникальному unit_id. Эти паттерны превратились у меня в обязательный вопрос к каждой новой метрике: где у тебя знаменатель и где граница сверки. И отдельный урок: тест, который «работает» при ручном запуске без упавшего ассерта, ничего не доказывает — проверкой считается только прогон, в котором ассерт мог упасть и хотя бы раз падал.
Четвёртая история той же серии — 34% базы норм, молча пропавших при заливке, — в эти рёбра не легла: там не ошибались ни модель, ни оценщик. Она про границы самого метода, и её я разберу в следующем разделе.
Общий счёт: четыре отказа — ноль дообучений
# |
Кейс |
Режим (оригинал) |
Ребро |
Сторона вины |
Вид ремонта |
|---|---|---|---|---|---|
1 |
Ломкий контракт вызовов |
неверные аргументы (Malformed Arguments) |
модель–инструмент |
модель |
обвязка |
2 |
Галлюцинации норм |
дефицит знаний предметной области (Domain Knowledge Deficit) |
модель–владелец |
модель |
обвязка |
3 |
Ложно-зелёные метрики |
взлом спецификации (Specification Gaming) |
модель–оценщик |
оценщик (мой случай) |
починка оценщика |
4 |
Молчаливая потеря 34% базы |
вне каталога: «потеря данных между компонентами обвязки» |
такого ребра в графе нет |
обвязка |
контрольные равенства, разбор в следующем разделе |
Ни один из четырёх отказов не закрыт ни дообучением, ни сменой модели. В двух формально «виновата модель» — и оба закрыты кодом обвязки: детерминированный барьер ловит то, что будет случаться с любой живой моделью. Третий вообще не про модель — про прибор, которым я мерил. И главное: ни один из этих сбоев не различим по итоговому «выполнил / не выполнил» — имена появились, только когда у каждого отказа спросили, на каком он ребре и чья на нём сторона вины.
Где таксономия молчит: честно о границах
Рамка оказалась рабочей, но переносить её вслепую я бы не стал. Часть границ сами авторы назвали в разделе Limitations, часть вскрылась только при наложении на мою практику.
Карта, а не статистика: авторы предупредили сами
Напомню: частот статья сознательно не даёт. 41 режим — это каталог возможного, а не распределение вероятностей: из него не следует, что угодничество (Sycophancy) встречается чаще, чем загрязнение памяти (Pollution). Какие частоты у вас — вопрос только ваших логов. Вторая оговорка авторов: таксономия выведена из просмотренных кейсов и будет дополняться.
Метки зависят от полноты свидетельств — это и показывает кейс с письмами, разобранный выше: по неполному отчёту корень не восстанавливается, и авторы честно оставляют атрибуцию открытой. С судьями та же осторожность: κ=0.76 у лучшего, «well above chance» по словам авторов; все числа и оговорки — в разделе о судьях. Для практики важно одно ограничение: ансамбль поднимает точность до 0.96 ценой покрытия в 68%, то есть воздерживается ровно на самых неопределённых случаях — там, где судья был бы нужнее всего.
Указатель на модель без бюджета на модель
Это ограничение уже моё, не авторское. 36 режимов из 41 помечены fault: model, и по правилу атрибуции («более способная модель могла бы это предотвратить или из него восстановиться») — честно. Но правило указывает, где корень, а не какой нужен бюджет на GPU: у продуктовой команды обычно нет ни весов модели, ни пост-тренинга, и совет «чинить на стороне модели» звучит для неё как «мощность есть — использовать нечем». Кейс с выдуманными пунктами норм выше — ровно этот случай: fault: model, ремонт целиком обвязочный, без единой правки модели.
Отказ без модели: у карты нет такого ребра
Главный экспонат, и единственное место, где я расхожусь с картой не в деталях, а по существу. Все девять рёбер таксономии — пары «модель ↔ X» (ребро модель–модель представлено в двух ролях — peer и subagent). Инцидент, который стоил мне больше всего времени на поиск причины, произошёл вообще без участия модели.
Что случилось. При заливке корпуса норм в векторную базу молча терялось 34% чанков: хвостовые фрагменты и таблицы без номера пункта получали одинаковую служебную «крошку», из неё детерминированно вычислялся одинаковый uuid5 point_id, и upsert просто перезаписывал предыдущую точку. В базе осталось 6861 точка из 10 414, лог загрузки рапортовал «пропусков нет», золотой набор вопросов был зелёный. Позже вскрылось родственное: fastembed включает enable_truncation(512) прямо на токенизаторе, встроенный счётчик токенов считал уже обрезанную последовательность, и статьи на 6,5 тысячи знаков казались влезающими в окно — а модель эмбеддингов тихо отрезала хвост.
Почему граф его не ловит. Симптом снаружи — «модель не знает норм»: слабые ответы по хвостам длинных документов — и рука тянется записать это на ребро модель–контекст. Но модели в цепочке сбоя не было вовсе: данные потерялись между чанкером и векторной базой, то есть между двумя компонентами обвязки, ни один из которых не является моделью. В графе, где все рёбра выходят из модели, такому отказу негде поселиться. Это не упрёк авторам — они строили карту взаимодействий модели, и в её собственных границах всё последовательно. Просто у обвязки есть своя внутренняя топология, и она в карту не входит.
Признаки. Отказ этого класса узнаётся по характерной паре: метрика зелёная, лог говорит «всё доехало», а качество проседает только на длинных или нетипичных документах. Ни одна ступень «модельной» диагностики его не берёт: промпт в порядке, инструмент отвечает, контекст собирается — просто собирается из неполной базы.
Рецепт. Контрольные равенства между соседними компонентами конвейера: «чанков в базе == чанков чанкера», «уникальных идентификаторов == записей», «длина текста до эмбеддинга == длина после токенизации». Каждое — одна строка в тесте загрузки, и каждое ловит целый класс молчаливых потерь. Пришлось завести собственный режим — «потеря данных между компонентами обвязки». Если у вас RAG — заведите его заранее: он дешёвый и всегда приносит улов.
Мораль экспоната: зелёная метрика не значит, что данные доехали, — она значит лишь, что метрика не смотрела туда, где они терялись.
Что таксономия дала на самом деле
Не ответы, а язык — и, что важнее, способ накапливать. Каждый инцидент я теперь пишу тремя полями: ребро, сторона вины, вид ремонта. Строка занимает минуту — против вечера спора «модель тупит или мой код кривой». Записей у меня пока немного, но даже на них проступает то, чего не видно в отдельном разборе: где сгустки. У меня чаще всего виноваты обвязка и мой собственный оценщик, чисто модельных историй меньше всего — и это прямо говорит, куда вкладывать следующую неделю. Обычная отладка такой картины не даёт: он чинит инцидент и закрывает вкладку. Это ровно та практика, из которой таксономия и выросла: авторы строили её в том числе по логам траекторий.
Что делать, когда агент ошибся: чек-лист диагностики и выводы
Порядок разбора — от дешёвых проверок к дорогим. Дело не в экономии времени, а в экономии гипотез: первые пять ступеней стоят почти ничего и регулярно закрывают вопрос, а самая дорогая — «модель плохая» — идёт последней. Кейсы из этой статьи разложились по ступеням, как по полочкам: молчаливая потеря 34% базы — первая ступень; незакрытые think-теги и JSON в прозе — вторая; ложно-зелёные тесты — четвёртая; выдуманные цитаты — шестая, и даже там ремонт оказался в обвязке.
Сначала красный флаг — без очереди
Неавторизованные необратимые действия (Unauthorized Irreversible Action) и инструкции, пришедшие из внешнего контента (косвенная инъекция промпта, Indirect Prompt Injection), разбираются до всякой очереди. Здесь не локализуют вину — здесь останавливают конвейер. Оба прочтения кейса с письмами (разобран выше) сходятся в одном: сначала остановить, потом спорить.
Шесть вопросов от дешёвых к дорогим
Данные доехали? Счётчики загрузки, уникальность идентификаторов, контрольное равенство «чанков в базе == чанков чанкера». 6861 точка из 10 414 при зелёном логе научила меня: «пропусков нет» в логе и «данные доехали» — разные утверждения.
Что вернул провайдер на самом деле? Сырой ответ до любой обработки: незакрытый
<think>, JSON, утопленный в сопроводительной прозе, обрыв по лимиту токенов. Если лог начинается уже с разобранного JSON — вы разглядываете не отказ, а его след.Что лежало в промпте в момент ошибки? Не съело ли сжатие критичное: основания и ограничения (потеря обоснований при сжатии, Context Rationale Erosion), саму цель (дрейф цели, Goal Drift).
Не зелёнит ли оценщик? Знаменатели, границы сверки,
any()вместоall(), пары сif failed: continue. Половина из 14 дефектов моего аудита жила именно здесь — в моих же тестах.Не врёт ли память и поиск? Устаревшая редакция документа, загрязнение памяти (Pollution). Замечание, опирающееся на отменённый пункт нормы, выглядит ровно как правильное — худший вид ошибки для юридического отчёта.
Только теперь модель. Промпт и описания инструментов → детерминированный барьер → смена модели. Систематический остаток, переживший все пять ступеней, — единственный честный аргумент за пост-тренинг.
Что делать завтра
Заведите сырые логи рёбер: запрос, ответ, парсинг, контекст на каждый инцидент. Без них ступени 2 и 3 — гадание.
Заведите журнал разметки инцидентов из трёх полей: ребро, сторона вины, вид ремонта. Ценность не в отдельной строке, а в распределении, которое проступит через месяц.
Поставьте детерминированный барьер на самый дорогой класс ошибок: валидация формата и цитат до вердикта; отказ барьера — статус
needs_human, и дорогой вердиктирующий вызов не происходит вовсе.Проведите аудит собственных метрик на ложную зелень — по чек-листу «знаменатель и границы сверки».
Ремонтная попытка — ровно одна, дальше типизированная ошибка с сырым текстом: вторая попытка не чинит формат, а легитимизирует мусор.
Прогоните пять последних инцидентов через каталог из 41 режима (имена — на рис. 2 первоисточника, определения — в Appendix B) и посмотрите, где сгустки: расклад по рёбрам подсказывает, куда вложить следующую неделю.
Два вопроса, которые заранее жду в комментариях, закрою сразу. Чем это отличается от обычной отладки? Механикой отладки одного инцидента — ничем: те же логи, те же знаменатели. Разница в том, что остаётся после: у отказа появляются ребро и сторона вины, а значит, инциденты складываются в распределение, и через месяц видно не пять историй, а место, где система течёт систематически. Сколько это стоит в токенах? Ремонтная попытка одна, а при отказе барьера вердиктирующий вызов не происходит — дорогой шаг пропускается, а не повторяется.
Если сжимать всю эту работу в одну фразу: смена модели меняет вероятности, обвязка — классы отказов. Новая версия модели уменьшит частоту выдуманных ссылок, но класс «модель иногда галлюцинирует цитату» не исчезнет — а барьер, ловящий его целиком, уже стоит в конвейере.
А у вас отказы чаще по модели или по обвязке — и как вы это узнали, а не почувствовали?
Приложение: как получена каждая цифра
Код закрытый, поэтому вместо ссылки на репозиторий — методика. И сразу оговорюсь, чем эта таблица не является: доказательством. Ни репозитория, ни журналов вы не видите, так что формально это самоотчёт. Она даёт другое — воспроизводимость: каждая цифра сведена к команде или строке в журнале, а не к ощущению, и в своём проекте вы получите свои числа теми же способами.
Все числа проекта в статье получены так:
Цифра в статье |
Чем измерена |
Где источник |
|---|---|---|
65 действующих нормативных документов |
Подсчёт по полю статуса в манифесте НТД. Всего в манифесте 73 записи: 6 заменённых, 1 отменённый и 1 принятый, но вступающий в силу только 01.09.2028, — в индекс они не идут, правило «индексируем только действующие» |
|
522 автотеста (юнит и интеграционные) |
|
вывод команды на текущем коммите |
10 414 чанков на выходе чанкера |
Отчёт пересборки индекса уже после исправления: 65 документов, 10 414 чанков, 0 mojibake, пропусков нет |
запись в журнале изменений проекта за день пересборки |
6861 точка из 10 414 (потеря 34%) |
Сравнение числа точек в базе с числом чанков на выходе чанкера: 6861 — состояние базы до исправления, 10 414 — после. Отсюда процент: (10 414 − 6861) / 10 414 = 34,1% |
та же запись журнала изменений |
«половина дефектов — в оценочных тестах» |
Разбор списка находок по месту: боевой код или тест, которым он проверялся |
тот же список починенного в журнале изменений |
14 дефектов состязательного аудита |
Разбор находок аудита перед коммитом: агенты-искатели по четырём измерениям, каждую находку добивают скептики-верификаторы; в журнале изменений — поимённый список починенного |
запись «починка находок аудита» в журнале изменений |
И разница, которую стоит держать в голове: числа первоисточника — 41 режим, 36/5 по сторонам вины, каппы судей — проверяются любым читателем прямо в статье на arXiv. Мои — только описанной методикой.
P.S. Нашли фактическую ошибку — скажите в комментариях: правки внесу прямо в текст с пометкой UPD и благодарностью.
Комментарии (3)

Innesiya
08.09.2026 05:30Пересчитала ансамбль судей в абсолютных числах: одиночный GPT-5.5 дает 0.80 на всех 40 примерах, это 32 верные метки; трое из четырех — 0.83 при покрытии 90%, то есть около 30, а единогласие — 0.96 при 68%, уже 26. Точность растет, а верно размеченных случаев становится меньше, причем воздержание приходится ровно на спорную атрибуцию. Отдельно смущает, что E1-E40 — те же проработанные примеры, на которых таксономию и собирали, а судьям выдали и определения, и первоисточник: 0.76 тогда меряет воспроизводимость разметки, а не перенос на незнакомые отказы. В статье есть прогон судей на примерах, не участвовавших в построении каталога?
ivanes_ap
Зачем высирать столько нейрослопа?
zaaaa Автор
Можно поконкретнее?