Чтобы отлаживать код с ИИ, дайте агенту способ воспроизвести баг, полную ошибку и логи и чёткое правило: сначала найти корневую причину, потом что-то менять. Агент для программирования вроде Claude Code или Codex умеет запускать ваши тесты, читать стеки вызовов, искать нужный коммит в истории git и добавлять логирование, поэтому из него выходит сильный напарник для отладки. Ошибается он тоже предсказуемо: гадает, когда не может запустить падающий случай, и «чинит» симптомы, перехватывая ошибки или ослабляя тесты.
Это руководство описывает рабочий процесс, который использует первое и защищает от второго: воспроизвести, передать доказательства, сузить поиск, объяснить, исправить, закрепить тестом и вовремя остановиться.
Почему агенты ошибаются при отладке
Большинство плохих исправлений от ИИ появляются по нескольким одним и тем же причинам:
- Нет воспроизведения. Агент читает код, строит теорию и вносит правку. Ничто не доказывает, что теория верна.
- Неполные доказательства. Вы вставляете последнюю строку ошибки. Полезный кадр стека, тремя уровнями ниже, до модели так и не доходит.
- Исправление симптома. Проверка на null,
try/catchили повторная попытка убирают ошибку, а плохое состояние, которое её вызвало, остаётся. - Перенос ворот. Тест падает, и агент правит тест.
- Длинные засорённые сессии. После пяти неудачных попыток разговор полон неверных теорий, и модель продолжает строить на них.
Каждый шаг ниже направлен против одной из этих причин.
Шаг 1: сначала воспроизведите баг
Прежде чем агент тронет код, ему нужна команда, которая показывает баг. Это может быть падающий тест, вызов curl, скрипт или страница в браузере. Суть в том, чтобы любой, включая агента, мог её запустить и увидеть сбой.
Если такая команда у вас уже есть, поставьте её в начало запроса:
Вот что падает:
pnpm vitest run src/billing/invoice.test.ts -t "applies discount once"
Ожидалась сумма 90, получилось 81. Пока не меняй код.
Запусти тест, подтверди, что видишь тот же сбой, и расскажи, что видишь.
Если воспроизведения нет, сделайте его первой задачей:
Пользователи сообщают, что двойное сохранение черновика создаёт два черновика.
Напиши падающий тест, который это воспроизводит. Ничего не исправляй.
Остановись, когда тест будет падать по правильной причине.
«По правильной причине» — это важно. Тест, который падает из-за опечатки в самом тесте, ничего не доказывает. Попросите агента показать вывод сбоя и объяснить, почему он совпадает с описанием бага. Для плавающих багов пусть агент запустит воспроизведение в цикле (например, 50 раз) и сообщит, как часто оно падает, чтобы потом можно было понять, помогло ли исправление на самом деле.
Шаг 2: дайте агенту все доказательства
Агенты хорошо читают длинный и шумный вывод. Не обрезайте его за них. Дайте:
- полный стек вызовов, а не только сообщение;
- точную команду и её полный вывод;
- нужные логи за время сбоя;
- что недавно менялось: обновление зависимости, деплой, слитая ветка;
- детали окружения, если они могут иметь значение: ОС, версия среды выполнения, флаги функций.
Вставлять всё в чат не обязательно. Сохраните вывод в файл и укажите агенту на него или передайте его напрямую через конвейер. В режиме print в Claude Code:
pnpm test 2>&1 | tail -n 200 > /tmp/test-output.txt
cat /tmp/test-output.txt | claude -p "Explain the root cause of this failure. Don't edit files."
В интерактивной сессии и Claude Code, и Codex по ! выполняют команду оболочки и добавляют её вывод в разговор, например !pnpm test src/billing. Для огромных логов попросите агента найти через grep ID запроса или код ошибки, а не читать весь файл: это сильно экономит контекстное окно.
Шаг 3: сузьте поиск с git bisect
Когда что-то раньше работало, а теперь нет, теория не нужна. git bisect находит первый плохой коммит двоичным поиском и умеет работать полностью автоматически, поэтому это идеальная работа для агента.
Сначала напишите небольшой скрипт, который завершается с кодом 0, когда код в порядке, и с ненулевым кодом, когда нет:
#!/bin/sh
# check.sh
pnpm install --frozen-lockfile >/dev/null 2>&1 || exit 125
pnpm vitest run src/billing/invoice.test.ts -t "applies discount once"
Дальше git пройдёт историю сам:
git bisect start
git bisect bad HEAD
git bisect good v2.3.0
git bisect run ./check.sh
git bisect reset
Коды выхода — это договор, и официальная документация git bisect определяет их так: 0 значит хороший, любой код от 1 до 127, кроме 125, значит плохой, 125 значит «этот коммит проверить нельзя, пропусти его», а всё, что выше, прерывает bisect. Поэтому шаг установки выше завершается с кодом 125: коммит, который даже не устанавливается, нужно пропустить, а не считать плохим.
Запрос, который передаёт всё это агенту:
Тест скидки в счёте проходит на теге v2.3.0 и падает на main.
Напиши скрипт проверки для git bisect run (exit 125, если коммит
не собирается), запусти bisect, затем git bisect reset.
Назови первый плохой коммит и объясни, какая строка в его diff
вызывает сбой. Пока ничего не исправляй.
Сначала убедитесь, что рабочее дерево чистое, или делайте это в отдельном git worktree, чтобы переключения bisect не мешали вашей работе. Если самого тестового файла в старых коммитах не было, скопируйте его в путь вне репозитория, и пусть скрипт запускает эту копию.
Шаг 4: добавьте логирование, потом уберите его
Когда стек вызовов не объясняет состояние, которое привело к ошибке, агенту нужно увидеть значения во время выполнения. Попросите точечное временное логирование:
Добавь временные логи, которые выводят товары в корзине, список скидок и
промежуточную сумму на каждом шаге applyDiscounts(). Начинай каждую строку
с [DEBUG-1234], чтобы потом их найти и удалить. Запусти
падающий тест и покажи мне строки логов.
Весь фокус в префиксе. Когда баг понятен, одна команда помогает всё убрать:
git grep -n "DEBUG-1234"
Агенты неплохо работают и с отладчиками, если те управляются скриптами: node --inspect с точкой останова неудобен для терминального агента, но короткая сессия python -m pdb, дополнительная проверка assert или разовый скрипт, вызывающий функцию с падающими входными данными, обычно дают тот же ответ быстрее.
Шаг 5: корневая причина до исправления
Это самое важное правило. Попросите агента объяснить баг до того, как он напишет исправление, и прочитайте объяснение:
Прежде чем менять код, объясни корневую причину:
1. Какое состояние неверно и где оно впервые становится неверным?
2. Почему код приводит к этому состоянию?
3. Почему существующие тесты этого не поймали?
Затем предложи минимальное исправление и дождись моего OK.
Хороший ответ указывает на конкретную строку и конкретное условие («скидка применяется и в addItem, и в checkout, с тех пор как коммит a1b2c3 перенёс вызов»). Слабый ответ расплывчат («возможно, есть проблема с обработкой скидок») или сразу переходит к защитной заплатке. Если ответ слабый, агент ещё не нашёл причину: верните его к шагу 3 или 4.
Здесь пригодится режим планирования в Claude Code: агент может читать и выполнять команды только для чтения, но не правит файлы, пока вы не одобрите. Запустите его через claude --permission-mode plan или нажимайте Shift+Tab, пока не переключитесь в него. Подробно он описан в статье режим планирования в Claude Code. В Codex похожую роль выполняет /plan.
Шаг 6: исправьте и закрепите регрессионным тестом
Теперь пусть агент исправит баг, но с ограничениями:
Внеси исправление. Правила:
- Не правь и не пропускай существующие тесты.
- Не перехватывай и не глуши ошибку.
- Добавь регрессионный тест, названный по багу, который падает без
исправления и проходит с ним. Докажи оба случая: откати исправление, запусти
тест, верни исправление, запусти снова.
- В конце запусти весь набор тестов.
Именно часть «докажи оба случая» делает тест надёжным. Регрессионный тест, который прошёл бы и до исправления, — просто украшение. Подробнее о том, как получать от агента полезные тесты, — в статье как писать модульные тесты с ИИ.
Затем сами просмотрите diff и поищите типичные исправления симптомов:
| Что видно в diff | Почему это подозрительно |
|---|---|
Новый try/catch, который пишет в лог и продолжает работу | Ошибка спрятана, плохое состояние осталось |
Опциональная цепочка или ?? default в месте падения | Отсутствие данных считается нормой, а не поводом спросить, почему их нет |
| Повторные попытки или увеличенные таймауты | Часто маскируют состояние гонки |
Тип расширен до any или unknown | Компилятор замолкает, а тип не исправлен |
| Изменено ожидание в тесте | Ворота перенесли |
Иногда что-то из этого и есть правильное исправление. Вопрос в том, объяснил ли агент, почему.
Баги в браузере: дайте агенту браузер
Баги интерфейса трудно описать текстом: кнопка, которая ничего не делает, вёрстка, которая ломается после клика, ошибка, видная только в консоли. С Playwright MCP агент может открыть страницу и посмотреть сам. Добавьте его в Claude Code:
claude mcp add playwright npx @playwright/mcp@latest
или в Codex через ~/.codex/config.toml:
[mcp_servers.playwright]
command = "npx"
args = ["@playwright/mcp@latest"]
Инструменты вроде browser_navigate, browser_click, browser_snapshot, browser_console_messages и browser_network_requests позволяют агенту воспроизвести баг шаг за шагом, прочитать ошибки консоли и увидеть, какой вызов API упал. Запрос для отладки:
Запусти dev-сервер. Открой http://localhost:5173/settings, измени
отображаемое имя и нажми Save. Сообщи об ошибках в консоли и о сетевом
запросе сохранения, со статусом и телом ответа. Пока не исправляй.
Когда причина ясна, попросите агента превратить шаги в тест Playwright, чтобы баг не вернулся. Подробнее о настройке — в статье тестирование в браузере с ИИ-агентом.
Баги, которые видны только в CI
Когда тесты проходят локально, но падают в CI, разница обычно в окружении: часовой пояс, локаль, параллельность, недостающие переменные окружения, другая версия Node или Python, порядок тестов. Дайте агенту лог CI и файл workflow и попросите перечислить различия между CI и вашей машиной, прежде чем гадать. Запуск набора тестов в случайном порядке или с часовым поясом CI (TZ=UTC pnpm test) часто воспроизводит сбой локально. Если падения CI стали рутиной, статья автоисправление сбоев CI с ИИ показывает, как автоматизировать этот цикл.
Когда остановить агента
Агент будет пытаться ещё долго после того, как пора остановиться. Прерывайте его, когда:
- Два-три исправления не сработали. Каждая новая попытка построена на той же неверной теории.
- Diff расползается. Начал с
invoice.ts, а теперь правит конфигурацию, несвязанные модули или lock-файлы. - Он трогает тесты. Подгонка проверки под неверный вывод никогда не исправляет баг.
- Он не может воспроизвести баг, но всё равно его «исправляет».
- Объяснение меняется от хода к ходу без новых доказательств.
Что делать вместо этого:
- Остановите ход (Esc в Claude Code и Codex).
- Откатите его изменения. Сделайте коммит перед началом отладки, чтобы
git restore .илиgit stashвернули вас назад; варианты описаны в статье как отменить изменения Claude Code. - Запишите, что узнали: какие теории оказались неверными и почему.
- Начните новую сессию с воспроизведением, фактами и отброшенными теориями. Чистый контекст с тремя хорошими фактами лучше длинного с десятью плохими догадками.
Иногда правильный ход — задать вопрос поуже: на «Список cart.items уже неверен в момент вызова checkout()?» ответить проще, чем на «почини баг в оформлении заказа».
Отладка с AgentVera
AgentVera — десктопное приложение для macOS, Windows и Linux, которое запускает Claude Code, Codex, Gemini CLI и других CLI-агентов рядом друг с другом в настоящих терминалах. Несколько его инструментов хорошо ложатся на описанный процесс:
- Отправка агенту: выделите ошибку в панели терминала, консоли браузера или логах Docker и отправьте её агенту по ⌘⇧L или нажмите значок Fix на перехваченной ошибке. Длинные логи обрезаются до 12 000 символов с сохранением конца, где обычно и находится стек вызовов.
- Браузер агента: Chrome с отдельным профилем, которым агенты управляют через Playwright MCP; вкладки транслируются в реальном времени, так что вы видите, как агент воспроизводит баг.
- Контрольные точки: каждый ход сохраняется в скрытую ссылку git, так что можно увидеть, что изменила неудачная попытка, и отменить этот ход, не трогая ваши ветки и stash.
- Две теории параллельно: запустите двух агентов в отдельных worktree из панели Git, дайте каждому свою гипотезу и оставьте то исправление, которое выдержит проверку.
- Verify: на Pro и Team критерии вроде «регрессионный тест падает без исправления и проходит с ним» проверяет отдельный проверяющий агент только для чтения, когда заканчивается ход агента.
Когда баг исправлен, запишите, что узнали, там, где это найдёт следующий человек; об этой стороне — статья написание документации с ИИ.
Подведём итог
Отладка с ИИ-агентом работает, когда вы относитесь к ней как к отладке с толковым коллегой: начинайте с воспроизведения, делитесь всеми доказательствами, сужайте поиск через git bisect, добавляйте логирование, чтобы видеть реальные значения, и требуйте корневую причину до исправления. Завершайте каждый баг регрессионным тестом, который на ваших глазах упал и прошёл. А когда агент начинает гадать, остановите его, откатите изменения и начните заново с тем, что уже узнали.