Почему способные агенты всё равно проваливаются
Модуль 1 · AI-агенты и harness engineering
🔑 Главный тезис
Способность модели не равна надёжности исполнения. Когда задача выходит за пределы одного простого промпта, узкое место почти всегда — harness (окружение агента), а не сама модель.
Самая умная лошадь спотыкается на неровной трассе без правильной экипировки. Та же модель — победитель в тестах — будет раз за разом проваливаться в реальных задачах, если окружение не настроено.
🧪 Контролируемый эксперимент
В лекции показан один и тот же проект — создание 2D-игры с нуля — с двумя разными подходами:
❌ Без harness
- Время: ~20 минут
- Стоимость: ~$9
- Результат: нерабочий код
- Агент самостоятельно выводил конвенции, забывал их, нарушал
✅ С полным harness
- Время: ~6 часов
- Стоимость: ~$200
- Результат: играбельная игра
- Harness направлял агента на каждом шаге
🧱 5 защитных слоёв: модель провалов
Каждый провал агента можно отнести к одному из пяти слоёв. Диагностируй слой — и будешь знать, что именно чинить.
Слой 1 — Расплывчатая спецификация задачи
Нет явного, проверяемого Definition of Done. Агент заканчивает, когда ему кажется, что задача решена — без объективного критерия завершения.
Признак: «Реализовать авторизацию» вместо «POST /login возвращает 200 с токеном; тест test_login_ok проходит».
Слой 2 — Неизвестные конвенции / архитектура
Проект имеет неявные правила, которые нельзя вывести из локального контекста файла. Агент нарушает их, не зная об их существовании.
Признак: Агент пишет код, синтаксически верный, но нарушающий скрытые архитектурные соглашения.
Слой 3 — Неполное dev-окружение
Непонятно, как собрать, запустить и протестировать проект. Переменные окружения, зависимости, конфигурация не задокументированы.
Признак: Агент запускает тесты «как придётся» — и они проходят случайно или не проходят по внешним причинам.
Слой 4 — Отсутствие механизмов верификации
Команды-гейты (линтеры, тесты, проверки конвенций) либо отсутствуют, либо есть, но агент их не запускает перед отгрузкой.
Признак: Агент сообщает «готово», но ни одна автоматическая проверка не была запущена.
Слой 5 — Потеря контекста между сессиями
В каждой новой сессии агент заново выводит знания о проекте с нуля. Решения, принятые вчера, неизвестны сегодня.
Признак: Агент задаёт одни и те же вопросы или делает одни и те же выводы снова и снова.
📏 Verification gap
Verification gap — расстояние между «агент сказал "готово"» и «результат реально корректен».
gap = false_done / N
N — количество задач; false_done — сколько раз агент отрапортовал «готово», а внешняя проверка показала провал.
Измеряется на реальном корпусе прогонов.
🔄 Diagnostic loop
Главный механизм улучшения harness — итеративный цикл диагностики:
- Воспроизведи провал — повтори условия, при которых агент ошибся.
- Отнеси к слою — какой из 5 слоёв стал причиной?
- Почини этот слой — только его, не трогай остальные.
- Перезапусти — убедись, что провал не воспроизводится.
- Повтори 3–5× — пока все системные проблемы не устранены.
🧩 Интерактив 1: Отнеси провал к слою
Реальные сценарии из notify-эксперимента (lesson 1). Для каждого — выбери правильный слой.
import urllib.error в channels.py, нарушив скрытую конвенцию «HTTP только через notify.http.post_json». Он не знал об этой конвенции. Какой слой?
scripts/conventions.py существовал в репо, но агент его ни разу не запустил и отгрузил нарушение, считая задачу выполненной. Какой слой?
NOTIFY_ENV=test, но это нигде не задокументировано. Агент запустил их без переменной — они прошли случайно (упали бы в CI). Какой слой?
🧮 Интерактив 2: Калькулятор verification gap
Введи параметры своего корпуса прогонов — и узнай, насколько велик разрыв между «агент сказал готово» и «реально корректно».
🔭 Что дальше?
Теперь ты знаешь, почему агенты проваливаются и как классифицировать провалы. В следующем модуле разберём, из чего harness сделан — конкретные инструменты и практики для каждого из пяти слоёв.
🔧 Из чего сделан harness
5 подсистем — анатомия инженерной инфраструктуры агента
В модуле 1 мы разобрали 5 слоёв провалов — места, где агент ломается. Теперь разберём, чем наполнен хорошо устроенный harness, чтобы эти провалы не случались. Ключевое определение:
Репозиторий — это и есть спецификация harness. Если чего-то нет в репо, для агента этого не существует.
🍳 Кухонная метафора: 5 подсистем
Представьте профессиональную кухню. Повар (агент) блестящий, но без правильной инфраструктуры даже лучший шеф приготовит хаос.
📋 1. Instructions — полка рецептов
AGENTS.md / CLAUDE.md — примерно 100 строк.
Содержит:
- Цель проекта в одну фразу
- Стек и версии зависимостей
- Bootstrap-команды для старта
- Жёсткие ограничения и конвенции
Детали — в docs/, читаются по требованию. Не пытайтесь запихнуть всё в один файл.
🔪 2. Tools — ножи
Адекватный доступ к shell, CLI, сети. Принцип: least-privilege, но не «всё выключено».
Агент, которому запрещено pip install, не может установить
зависимость — он просто застрянет. Инструменты должны соответствовать задаче.
🍳 3. Environment — плита
Самоописываемый рантайм: lock-файлы,
.python-version / .nvmrc, Docker / devcontainer.
Если агент не может воспроизвести окружение самостоятельно — каждый запуск превращается в лотерею версий.
🗂 4. State — стол для заготовок
PROGRESS.md: done / in-progress / blocked.
Пишется в конце сессии, читается в начале следующей.
Мост между сессиями. Без него агент каждый раз начинает с нуля, тратя токены на повторное выяснение того, что уже было сделано.
✅ 5. Feedback — окно ОТК
Явные команды верификации: тесты, типы, линт — и единая точка входа:
make check
python check.py — один вызов запускает все проверкиБез явного Feedback агент не понимает, готов ли результат. Он говорит «готово» — и ошибается.
⚡ Порядок атаки: Feedback first
Когда вы строите harness с нуля — не начинайте с самого очевидного. Начните с того, что даёт максимальный ROI при минимальных затратах:
- Feedback — один скрипт проверки. Агент наконец понимает «готово» vs «сломано».
- Instructions — краткий
AGENTS.md. Контекст проекта с первых секунд. - State —
PROGRESS.md. Память между сессиями. - Environment — lock-файлы и
.python-version. - Tools — разрешения, CLI-доступ. Обычно уже есть, нужна настройка.
🔗 Связь двух линз: слои провалов → подсистемы
В модуле 1 вы научились диагностировать, относя провал к одному из 5 слоёв. Теперь — чинить: каждый фикс попадает в одну из 5 подсистем.
| Слой провала (M1) | Подсистема harness |
|---|---|
| L1 — нет контекста задачи | 📋 Instructions |
| L2 — нарушены конвенции | 📋 Instructions |
| L3 — не воспроизводит окружение | 🍳 Environment + 🔪 Tools |
| L4 — не верифицирует результат | ✅ Feedback |
| L5 — теряет контекст между сессиями | 🗂 State |
📊 Интерактив 1: Эффект harness на реальном проекте
Кейс из практики: TypeScript + React, ~20 000 строк, модель GPT-4o. Модель не менялась. Добавлялись подсистемы harness — и росли результаты.
🧩 Интерактив 2: Слой провала → какая подсистема чинит?
Три сценария — определите, в какую подсистему harness нужно инвестировать.
🔬 Интерактив 3: Ablation-калькулятор
Isometric model control — экспериментальный метод: держите модель постоянной, отключайте (ablate) по одной подсистеме за раз, измеряйте просадку успеха. Так узнаёте, какая подсистема важнее именно для вашего проекта.
🗄️ Репозиторий как система записи
Модуль 3 · Harness Engineering — только то, что попало в репо, существует для агента
Единственный источник истины для агента
Агент работает в изолированном информационном пузыре: он видит системный промпт, текст задачи, файлы репозитория и вывод инструментов. Всё остальное — Slack-треды, Jira-тикеты, Confluence-страницы, устные договорённости — для него не существует.
«Информации, которой нет в репозитории, для агента не существует.»
Это означает: репо должно стать системой записи — авторитетным источником по решениям, ограничениям, текущему состоянию проекта и стандартам проверки. Не вторичным архивом, а единственным местом, куда агент (и любой новый член команды) смотрит за правдой.
Cold-Start Test — пять вопросов
Лучший способ проверить репозиторий — представить, что в него заходит свежая сессия агента, которая не помнит ни одного прошлого разговора. Может ли репо ответить на все пять вопросов?
Назначение, домен, основные пользователи. → README.md
Архитектура, модули, интерфейсы. → ARCHITECTURE.md
Зависимости, команды, env-переменные. → CLAUDE.md
Тесты, lint, критерии приёмки. → AGENTS.md
Что в процессе, что заблокировано, какие решения приняты. → PROGRESS.md
🧮 Interactive 1 — Cold-Start Scorer
Оцени свой репозиторий по каждому вопросу (0 = нет информации, 1 = исчерпывающий ответ). Калькулятор покажет итоговый балл и примерный KVG (Knowledge Visibility Gap).
- Репо с AGENTS.md + PROGRESS.md: 4.7 / 5, KVG 6%
- Базовый репо (только код): 3.2 / 5, KVG 36%
Цель: KVG < 10%. При KVG > 30% агент системно галлюцинирует критичные детали.
Три метрики здоровья репозитория
KVG — Knowledge Visibility Gap
Доля проектно-критичных решений и ограничений, которые живут вне репозитория: в головах, Slack, почте.
KVG = (решения_вне_репо / все_критичные_решения) × 100%
Discovery Cost — стоимость обнаружения
Сколько токенов контекст-бюджета агент тратит, чтобы найти нужное, даже если оно есть в репо. Информация может существовать, но быть закопанной в гигантский файл или рассыпанной по десяткам папок.
ARCHITECTURE.md и CONSTRAINTS.md
в каждом модуле → агент находит контекст за 1 шаг. Один мега-документ → 10+ шагов поиска.
Knowledge Decay Rate — скорость устаревания
Доля документов, которые дрейфуют от кода со временем. Код эволюционирует — документация часто остаётся на месте.
Решение: размещать доки рядом с кодом, который они описывают
(src/payments/ARCHITECTURE.md, а не docs/legacy/payments.md).
Тогда PR, меняющий код, неизбежно проходит мимо документации — и reviewer замечает расхождение.
ACID для управления состоянием агента
Принципы ACID из баз данных применимы к git-репозиторию как к хранилищу состояния агентской работы.
Каждый логический шаг = один git-коммит. Незавершённая работа — в
git stash, не в рабочей директории. Откат всегда возможен.
git add -p # только нужные изменения git commit -m "feat: add retry logic" git stash # если нужно прервать
Верификация (тесты / lint) гейтит каждый коммит. Сломанные состояния не попадают в историю. Pre-commit hook — простейший способ.
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: run-tests
entry: pytest -q
Параллельные агенты используют отдельные ветки или git worktree. State-файлы именуются по агенту, чтобы не конфликтовать.
git worktree add ../agent-b feature/b # agent A: main # agent B: ../agent-b (изолировано)
Кросс-сессионное знание живёт в трекаемых файлах репо, а не в истории чата. История чата исчезает при старте новой сессии.
PROGRESS.md ✓ переживает сессию DECISIONS.md ✓ переживает сессию chat history ✗ исчезает
git init → Atomicity (коммит-юниты) + Isolation (ветки/worktree)
Знание рядом с кодом
Один мега-документ в корне — антипаттерн. Когда репо вырастает, агент тратит весь бюджет на поиск нужного абзаца. Правило:
- Каждый модуль / сервис / библиотека — своя
ARCHITECTURE.mdиCONSTRAINTS.md - Корневой
CLAUDE.md— только навигация и команды запуска/проверки - Корневой
PROGRESS.md— живое состояние: что в работе, что заблокировано, какие решения приняты сегодня
project/
├── CLAUDE.md # навигация + команды
├── PROGRESS.md # текущее состояние
├── src/
│ ├── payments/
│ │ ├── ARCHITECTURE.md ← агент читает сразу при входе в модуль
│ │ ├── CONSTRAINTS.md ← ограничения рядом с кодом
│ │ └── *.py
│ └── auth/
│ ├── ARCHITECTURE.md
│ └── *.py
└── tests/
└── AGENTS.md # критерии приёмки тестов
🧠 Проверь себя
git init на проекте автоматически поднимает какие два измерения ACID?
Дальше — почему один гигантский файл инструкций начинает вредить и как правильно структурировать контекст агента.
М4 📄 Почему один гигантский файл инструкций проваливается
Instruction Bloat, Lost-in-the-Middle и принцип Progressive Disclosure
В М1–М3 мы убедились, что наличие правила в AGENTS.md критически важно.
Теперь разберём оборотную сторону: если продолжать складывать всё в один файл, он начинает вредить.
Файл размером ~300+ строк замедляет агента, снижает точность и размывает приоритеты.
🗻 Феномен Instruction Bloat
Instruction Bloat — когда файл инструкций разрастается настолько, что занимает значительную долю контекстного окна. Эмпирическое правило: файл инструкций > ~10–15% окна контекста начинает вытеснять рабочую информацию о задаче.
AGENTS.md на 600 строк ≈ 4–6 K токенов.
При задаче с большим diff или несколькими файлами инструкции буквально
выдавливают рабочий контент на периферию окна.
bloat_ratio = len_instructions / context_window · 100%
bloat_ratio > 10–15% — пора делить файл.
При 128 K окне это ≈ 13–19 K токенов (~1 900–2 700 слов, ~150–200 строк плотного текста).
📍 Lost in the Middle (Liu et al., 2023)
Исследование показало, что LLM лучше используют информацию в начале и конце длинного контекста. Информация в середине — «тонет». Практический вывод: критичные правила нельзя зарывать в середину длинного файла.
AGENTS.md):
результат — 0 из 15 нарушений. Позиционный эффект не появился на ~300 строках
с современным Sonnet.
Чтобы получить сигнал, нужно: ~1 000+ строк, правило, которое перебивает дефолтное поведение (а не подкрепляет его), более слабая модель или конкурирующая ложная альтернатива в середине.
Вывод: заявление про позицию правила калибровано под раздутые файлы (~600+ строк). На ~300 строках современный Sonnet не теряет правила ни в одной позиции. Зато вывод М1 — присутствие правила важно — остаётся в силе.
📊 Signal-to-Noise Ratio инструкций
Instruction SNR — доля пунктов файла, релевантных текущей задаче.
Если агент работает над добавлением нового канала уведомлений, а в AGENTS.md
37 пунктов, из которых к этой задаче относятся только 30 — SNR = 81%.
Если же он запускает тесты, релевантны только 18–19 пунктов — SNR = 50%.
Низкий SNR — это шум: агент тратит внимание на нерелевантные правила и может применить их некстати («правило про webhook неожиданно применяется к рефакторингу»).
🔢 Интерактив 1 — SNR-калькулятор
Введите число релевантных пунктов и общее число пунктов в файле — получите SNR. В Lesson 4 «всегда-релевантных» через все 5 типов задач оказалось 9 из 37 — это скелет будущего routing-файла (SNR скелета = 100%).
📊 Интерактив 2 — SNR по типам задач
Один и тот же AGENTS.md даёт разный SNR в зависимости от типа задачи.
Среднее по 5 типам ≈ 48% — почти половина инструкций в любой задаче является шумом.
Данные Lesson 4: T1 — добавление канала, T2 — отладка ошибок, T3 — написание тестов, T4 — рефакторинг, T5 — обновление зависимостей. Среднее SNR ≈ 48%.
🗺️ Routing File: таблица вместо прозы
Routing File — короткий файл (50–200 строк), который не содержит деталей, а указывает на тематические документы. По сути это таблица: условие → документ.
## Условия → документация | Условие | Документ | |----------------------------------|------------------------------| | Добавляешь новый канал | docs/channels.md | | Меняешь схему БД | docs/db-migrations.md | | Пишешь или меняешь тесты | docs/testing-guide.md | | Деплой / CI | docs/deploy.md | | Изменения в зависимостях | docs/deps-policy.md | | Любая задача (safety-правила) | docs/safety-critical.md |
Главный routing-файл сам — не длиннее 50–80 строк. Детали — только в тематических доках.
🔭 Progressive Disclosure
Progressive Disclosure — принцип «обзор сейчас, детали по требованию». Routing-файл даёт быстрый ориентир, детальные доки загружаются только когда нужны. Агент не «читает весь учебник» перед каждой задачей — он ищет нужную главу.
AGENTS.md— 600 строк- Все правила в одном месте
- Агент читает всё целиком
- SNR ≈ 30–50% для любой задачи
- Критичные правила тонут в середине
AGENTS.md— 50–80 строк (таблица)- Детали — в отдельных файлах
- Агент читает только нужный doc
- SNR ≈ 80–100% для каждого дока
- Safety-правила — отдельный файл, всегда загружается
📖 Кейс: SaaS-команда, 50 → 600 строк → рефакторинг
Команда начала с AGENTS.md на 50 строк. За год, добавляя правила по одному,
файл вырос до 600 строк. Что произошло:
- Успешность задач: 45% (агент применял правила не к тем контекстам)
- Соблюдение safety-правил: 60% (критичные правила оказались в середине)
- Жалобы команды: «агент игнорирует наши требования к деплою»
После рефакторинга: routing-файл (80 строк) + 6 тематических документов:
- Успешность задач: 45% → 72%
- Соблюдение safety-правил: 60% → 95% (критичные правила вынесены в отдельный doc, который загружается всегда)
docs/safety-critical.md, который routing-файл
явно указывает для любой задачи.
🧪 Интерактив 3 — Проверь понимание
AGENTS.md в routing-файл + тематические доки?Дальше — жизненный цикл сессии: инициализация и преемственность контекста между запусками агента.
Жизненный цикл сессии
Инициализация как отдельная фаза · Преемственность контекста между сессиями
В предыдущих модулях мы разбирали, как агент выбирает задачи и строит план. Теперь — про то, что происходит внутри одной сессии и на стыке сессий: инициализация и передача контекста.
A. Инициализация как отдельная фаза
Типичная ошибка: агент сразу пишет бизнес-код, не заложив фундамент. Инструменты не настроены, тесты не запускаются, пути не созданы — и первый же import рушит всё. Это смешивание Initialization и Implementation.
Аналогия: фундамент и стены
Заливать фундамент и строить стены одновременно — гарантия переделок. Сначала фундамент схватывается, потом стены. Так же с агентом: сначала среда проверяется, потом пишется код.
Bootstrap Contract — 4 обязательных условия
Инициализация считается завершённой, когда выполнены все четыре пункта:
- ✅ Можно запустить — среда поднимается без ошибок
- 🧪 Можно протестировать — хотя бы один тест проходит зелёным
- 📊 Виден прогресс — есть измеримый артефакт (файл, лог, строка в БД)
- 🔗 Можно подхватить — следующий агент (или следующая сессия) понимает, что сделано и что дальше
Makefile / pyproject.toml / AGENTS.md) сокращает инициализацию в разы. Пустая папка — самый медленный вариант.
TTFV — Time To First Verification
Ключевая метрика эффективности инициализации. Чем быстрее агент добился первого зелёного теста, тем меньше риск, что он потратит контекст на неверный фундамент.
TTFV = t(first_green_test) - t(session_start)
🧩 Интерактив: Bootstrap Contract
Проверь понимание четырёх условий Bootstrap Contract.
B. Контекст между сессиями
Каждая новая сессия начинается с чистого контекста. Без структурированного хэндоффа агент читает состояние с нуля и рискует принять решения, уже принятые ранее — и принять их иначе.
Recovery cost
Токены, потраченные на восстановление ментальной модели в начале сессии. Без артефактов преемственности — это чтение всех файлов подряд в надежде понять «что тут вообще происходит».
С хорошим PROGRESS.md и git-чекпойнтами recovery cost стремится к нулю: агент читает один файл и сразу знает, где он.
Context Anxiety
Находка Anthropic: Sonnet 4.5 вблизи лимита контекста проявляет преждевременную сходимость — выбирает более простые решения, пропускает верификацию, торопится закрыть задачу. Это не баг поведения, это рациональный ответ на ресурсное давление.
Continuity Artifacts
Что сделано, что временно, почему выбрано именно это решение. Сохраняет почему, не только что.
Архитектурные решения и их обоснования. Предотвращает повторное открытие велосипеда в следующей сессии.
Чистые коммиты в конце каждой значимой фазы. Следующая сессия может сделать git log --oneline и мгновенно понять хронологию.
Честный вывод: когда PROGRESS.md действительно нужен?
- Lesson 2 ablation: удаление
PROGRESS.mdсломало рефакторинг — шим был помечен как «временный, удалить», но этой пометки не было в коде. Без записи шим выжил как мёртвый груз. - Lesson 5: на code-выразимой задаче arm без
PROGRESS.mdоказался дешевле по всем метрикам — код сам нёс решения.
PROGRESS.md только то, что код выразить не может. Всё остальное — в код.
🧩 Интерактив: Нужен ли тут PROGRESS.md?
Три сценария из реальных воркlogов. Для каждого — определи, нужен ли PROGRESS.md.
_post_with_retry в channels.py; сессия 2 продолжает добавлять каналы.
"message", а не "body", потому что этого требует HTTP-контракт — и НЕТ теста, который это проверяет.
📊 Стоимость дробления: marathon vs несколько сессий
Данные из lesson 5: одна и та же 3-канальная задача решалась тремя способами. Метрика — суммарные токены.
- Задача явно выходит за контекстное окно
- Нужны разные специализации агентов
- Есть независимые подзадачи для параллелизма
- Задача умещается в одну сессию
- Высокая связность — агент несёт весь контекст в голове
- Экономия на хэндофф-артефактах существенна
Дальше — почему агенты берут слишком много задач одновременно и доводят слишком мало до конца (WIP=1).
Overreach и Under-finish: почему WIP=1
Агенты активируют слишком много задач за сессию и завершают слишком мало. Разберём механику и противоядие.
Overreach: слишком много задач в работе
Агент начинает сессию с амбициозного плана: «реализую сразу 5 фич». Каждая задача активируется — создаётся ветка, пишутся первые строки кода. Но к концу сессии ни одна не прошла верификацию. Это overreach: разбросанные частичные реализации вместо одной завершённой фичи.
📊 Кейс: REST API с 8 фичами
Без ограничений (WIP=∞)
- Сессия 1: 5 фич активировано
- ~800 строк, ~12 файлов
- E2E-проход: 20%
- За 3 сессии готово: 3/8 фич
- Итоговый VCR: 37.5%
WIP=1
- Сессия 1: 1 фича активировано
- ~200 строк, ~4 файла
- E2E-проход: 100%
- За 4 сессии готово: 7/8 фич
- Итоговый VCR: 87.5%
Under-finish и VCR
Under-finish — доля активированных задач, которые провалили верификацию несмотря на сгенерированный код. Overreach напрямую порождает under-finish: чем больше задач в работе, тем выше вероятность, что каждая из них не будет доведена до исполняемого доказательства.
VCR = verified_passing / activated
Proof of Completion: исполняемое доказательство
«На глаз» не считается. Задача завершена только тогда, когда существует исполняемое условие, которое можно запустить и которое проходит.
❌ Не доказательство
- «Код выглядит правильно»
- Code review прошёл
- Линтер не нашёл ошибок
- «Я проверил вручную»
✅ Исполняемое доказательство
pytest tests/test_feature.py -v→ PASSEDcurl -s /api/v1/item | jq '.id'→ не nullassert result == expectedв CI- Интеграционный тест, запущенный автоматически
Little's Law: математика WIP
Закон Литтла — фундаментальный результат теории очередей. Для стабильной системы:
L = λ · W
W = L / λ.
Если λ = 1 фич/день и L = 5 (пять задач одновременно), то W = 5 дней на задачу. Держи L = 1 → W = 1 день → вероятность накопления ошибок минимальна.
🧮 Интерактив 1 — Калькулятор времени цикла (Little's Law)
📊 Интерактив 2 — Цена дисциплины WIP=1
Данные из реального эксперимента (lesson 7, worklog): ~700 строк, 6 фич, Sonnet. WIP=1 дороже по инструментам — но ловит то, что гейт пропускает.
⚠ Честный эмпирический вывод
🐛 Test-invisible баги из реального worklog
Баг 1 — неверное наследование исключения:
# Без ограничений — отгружено молча: class DispatchNotFound(Exception): ... # ← НЕВЕРНО # WIP=1 — поймано при внимательном обходе: class DispatchNotFound(NotifyError): ... # ← ВЕРНО # Вызыватели с "except NotifyError" промахиваются мимо # DispatchNotFound — линтер по regex не видит наследование.
Баг 2 — потеря config-оверрайдов при retry:
# retry() пересоздаёт Dispatcher.from_config() со свежими # дефолтами — config-оверрайды исходной отправки теряются. # Тест проходил, потому что тестировал happy-path без оверрайдов.
1. Страховка от test-invisible пробелов — агент фокусируется на одной задаче и замечает тонкие несоответствия.
2. Bisectable git-история — один коммит на фичу, легко откатить и локализовать проблему.
3. Предсказуемое время цикла — по Little's Law W = L/λ, меньший WIP = меньше дней на фичу.
WIP=1 на практике: правила активации
- Одна активная задача за раз. Следующую задачу начинаем только после того, как текущая прошла executable proof of completion.
- Блокировка при VCR < 1.0. Если предыдущая задача не прошла верификацию — не активируем новую, сначала доводим текущую.
- Коммит на каждую фичу. После прохождения верификации — коммит с чётким сообщением. Это и bisectable история, и явная точка завершения.
- Proof of completion прописан заранее. Перед активацией задачи определяем конкретный исполняемый тест — иначе «готовность» остаётся субъективной.
🧠 Проверь себя
📋 Списки фич как структуры данных + многоуровневая валидация
Модуль 7 · AI-агенты и harness engineering
В модулях 1–6 мы говорили о том, что проверять и как строить гейты. Здесь — о том, где хранить скоуп и почему агенты объявляют победу слишком рано. Оба вопроса связаны: плохая структура данных о фичах = слепой гейт = ложная победа.
A. Список фич — структура данных, не планёрка
Типичная ошибка: список фич живёт в чате, трелло или голове менеджера. В harness-подходе список фич — это артефакт в репо, на котором работает автоматика. Он имеет строгую схему, версионируется и является входом для верификационного пайплайна.
🔷 Triplet — обязательная запись
Каждая строка списка фич несёт ровно три поля. Нет хотя бы одного — запись неполна и не может войти в пайплайн:
{ description, verify_cmd, state }
{
"description": "POST /api/send возвращает 200 и записывает сообщение в БД",
"verify_cmd": "pytest tests/test_send.py::test_send_200 -x -q",
"state": "passing"
}
Запись без verify_cmd — это пожелание, не фича. Запись без state — не отслеживается.
🔄 Feature State Machine
Каждая фича проходит 4 состояния. Переход → passing совершается только по успешному результату verify_cmd. Состояние passing — необратимо: регресс означает новый баг, а не откат.
not_started ──→ active ──→ passing (необратимо)
↕
blocked
not_started— фича в скоупе, но работа не начатаactive— в работеblocked— есть блокер (ждёт зависимость / решение)passing—verify_cmdвернула exit 0 в CI; только так
passing. Только harness — после выполнения verify_cmd. Это State Passing Gate: доказательство, не самооценка.📌 SSoT — Single Source of Truth
Вся информация о скоупе исходит из одного списка фич. Это цепочка: source → derived → executable. Каждое звено может дрейфовать — если PROGRESS.md расходится с кодом, harness теряет ориентир.
PROGRESS.md, а не на самом большом файле. Фиксировать нарушение — не «удалить дубли», а явно пометить источник и обеспечить derivation: каждый производный артефакт помечается «сгенерировано из X, не редактируй вручную».📊 State Pressure — метрика готовности
Число фич, не находящихся в passing — это State Pressure. Ноль = проект завершён. Это количественная, объективная метрика готовности — в отличие от субъективного «кажется, всё готово».
pressure = total_features − passing_features
🧮 Калькулятор State Pressure
B. Почему агенты объявляют победу слишком рано
Агенты судят по принципу «код, что я написал, выглядит правильно», а не «система E2E удовлетворяет спеке». Это систематическая ошибка, подкреплённая математикой.
📐 Calibration bias
Guo et al. (ICML 2017) показали: современные нейросети систематически переуверены — заявленная уверенность выше фактической точности. Модель говорит «95% что готово» там, где реальная точность — 70%.
verify_cmd.
📊 Данные из worklog: weak vs strict проверка
Lesson 8 — 11 специально подброшенных багов. Два режима проверки:
clear() внутри send(), но тест делает один send и не видит деградации при следующих вызовах. Вывод: smoke в качестве единственного гейта — операционально бесполезен.
📊 Данные из worklog: false-done и слепота гейта
Lesson 9 — 21 прогон, calibration bias = 24% (5/21 false-done). Ключевой ковариат: покрытие гейта:
🔒 Dual verification-validation gateway
Чтобы победа была честной, нужны два независимых гейта:
«Код реализует спеку?»
unit-тесты, статический анализ, контракты
«Система отвечает E2E-требованиям?»
интеграция, E2E-сценарии, нагрузка
Оба обязательны. L1 без L2 = проверил детали, упустил систему. L2 без L1 = ловишь симптомы, не причины.
🏗️ 3-уровневая валидация
- Синтаксис / статический анализ — lint, type checker, компиляция. Быстро, локально, дёшево. Обязателен всегда.
- Рантайм-поведение — тесты выполняются, приложение стартует, критические пути проходят. Обнаруживает ошибки логики.
- Системное подтверждение — E2E, интеграция, acceptance-критерии. Единственный уровень, который подтверждает работу системы целиком.
Агент может пройти уровни 1 и 2 и всё равно провалить уровень 3. Это не исключение — это норма для сложных систем.
⚡ Completion priority constraint
Строгий порядок приоритетов:
functional → performance → style
🎯 Проверь себя
passing?Дальше — E2E, наблюдаемость рантайма и чистый выход из сессии.
Модуль 8: E2E-тестирование, наблюдаемость рантайма и чистый выход из сессии
Синтез курса: калибруй harness по давлению, а не по моде
A. Только E2E-тестирование меняет результат
Юнит-тесты проверяют каждый компонент в изоляции. Но агент — это система, где компоненты взаимодействуют. Межкомпонентные сбои юнит-тестам не видны:
- Рассогласование интерфейсов — модуль A ожидает строку, B отдаёт dict: тесты обоих зелёные, система сломана.
- Распространение состояния — ошибка в шаге 2 тихо меняет результат шага 4; каждый шаг тестируется независимо и проходит.
- Зависимости окружения — тест мокает файловую систему, но в реальном окружении путь другой.
🔺 3-уровневая архитектура валидации
-
Уровень 1 — Синтаксис / статика
«Код парсится»: линтер, type-checker,python -m py_compile. Это необходимо, но не достаточно. Агент может генерировать синтаксически корректный код, который делает не то. -
Уровень 2 — Рантайм-поведение
Тесты выполняются, приложение стартует, критические пути проходят (юнит + интеграция). Уже намного лучше — но межкомпонентные взаимодействия по-прежнему в слепой зоне. -
Уровень 3 — Системное подтверждение (E2E)
Полный пользовательский сценарий: от входных данных до наблюдаемого результата. Только здесь проверяется, что система работает как целое.
Кейс Anthropic: ретро-игровой редактор
Anthropic сравнил два подхода к одной задаче (идентичный промпт — разработать ретро-игровой редактор):
- Время: ~20 минут
- Стоимость: $9
- Результат: нерабочий редактор
- Время: ~6 часов
- Стоимость: $200
- Результат: полностью играбельный редактор
30× по стоимости — и это оправданная инвестиция: дешёвый прогон даёт сломанный артефакт, дорогой — рабочий. Evaluator-агент в harness выполнял именно E2E-проверку после каждой итерации.
📊 Сравнение стоимости: голый агент vs harness
B. Сделай рантайм агента наблюдаемым
Агент без наблюдаемости работает в режиме «чёрного ящика»: он сам сообщает о своём состоянии, а его самооценка систематически смещена в сторону завершённости. Как в М3 мы говорили об ACID: нельзя доверять агенту, что транзакция завершена, — нужен внешний наблюдатель.
🔍 Инструменты наблюдаемости
- Логи с уровнями — структурированные записи каждого шага агента. Позволяют ретроспективно понять, что именно произошло, а не что агент думал, что произошло.
-
Состояния процессов — явные статусы:
pending/running/done/failed. Нет промежуточных «почти готово». - Health-checks — периодические автоматические пробы: «сервис отвечает?», «файл создан?», «схема БД соответствует?».
- Пробы побочных эффектов — проверяй не только return value, но и то, что изменилось в окружении: файловая система, сеть, внешний сервис.
Практически: добавь в свой check.py (из М2) не только юнит-тесты,
но и минимальный E2E-smoke: запусти приложение, пройди критический путь, убедись,
что output совпадает с ожидаемым. Это и есть наблюдаемость рантайма в минимальной форме.
python check.py --e2e --smoke-only 2>&1 | tail -20
C. Каждая сессия должна оставлять чистое состояние
Как в ACID-Durability (М3): транзакция либо применена полностью, либо откатана. Сессия агента — это транзакция над codebase. Нельзя оставлять half-done состояние, красный гейт или недокументированные решения.
Плохой выход из сессии — это техдолг, который платится при следующем старте: новая сессия тратит время на понимание того, что было сделано, что не сделано, и почему принято то или иное решение. Это потеря контекста, о которой мы говорили в М5.
✅ Чек-лист выхода из сессии
Отметь каждый пункт перед закрытием сессии:
python check.py / гейт зелёный
D. Синтез курса — мета-вывод
🧭 Главный мета-вывод: harness engineering калибруется по давлению
Через все восемь модулей прошла одна нить: методология harness engineering калибрована под режим, где harness-давление реально.
На малом масштабе (≤ ~700 строк, чистый код, сильная модель типа Sonnet, одна сессия) многие количественные заявления лекций не воспроизводятся:
- М4: позиция правила в AGENTS.md не меняет результат
- М5: PROGRESS-файл не ускоряет работу
- М6: выделенный init даёт меньше фич, чем без него
- М7: VCR-дифференциал незначим
- М8: 45%-дифференциал качества не наблюдается
Это null-результаты — они не опровергают методологию. Они говорят о границе её применимости.
- Присутствие ключевых артефактов: verification gate + явный проверяемый Definition of Done. Даже если гейт никогда не краснел — он задаёт контракт, который агент не может молча нарушить.
- Работа с test-invisible конвенциями: то, что гейт физически не ловит — именно там живут все false-done. Стиль, архитектурные решения, неявные ожидания — это нельзя проверить автоматически, но можно сделать явным через документацию и чек-листы.
🧪 Финальный квиз: синтез курса
Готово 🎉
8 модулей пройдены. Что теперь у тебя в инструментарии:
- Видеть, что узкое место — не модель, а harness; относить каждый провал к одному из 5 защитных слоёв.
- Различать 5 подсистем harness (Instructions / Tools / Environment / State / Feedback) и чинить Feedback первым.
- Делать репозиторий системой записи: Cold-Start Test, KVG, ACID-состояние.
- Разбивать раздутый AGENTS.md на routing-файл + topical-доки (SNR, lost-in-the-middle).
- Держать контекст между сессиями: init-фаза, continuity-артефакты, handoff.
- Вводить WIP=1 и executable proof of completion; считать VCR и Little's Law.
- Строить feature lists как структуры данных и многоуровневую валидацию (weak vs strict).
- Требовать E2E, делать рантайм наблюдаемым и оставлять чистое состояние сессии.
- Калибровать методологию по масштабу — отличать заявления, что воспроизводятся, от тех, что работают только под реальным harness-давлением.
Что читать дальше
- Walking Labs — «Learn Harness Engineering». Первоисточник курса: walkinglabs.github.io/learn-harness-engineering
- Liu et al. (2023) — «Lost in the Middle». Эмпирика про деградацию внимания LLM к середине длинного контекста.
- Guo et al. (ICML 2017) — «On Calibration of Modern Neural Networks». Почему нейросети систематически переоценивают свою уверенность.
- Anthropic — инженерные заметки про агентов и контекст. Context anxiety, многоагентные harness, init-фаза.