Отладка кода с ИИ: практичный рабочий процесс

Как отлаживать код с ИИ надёжно: сначала воспроизведение, затем падающий тест и логи для агента, git bisect, поиск корневой причины и тест, закрепляющий исправление.

Solviera Teknoloji 9 мин чтения

Чтобы отлаживать код с ИИ, дайте агенту способ воспроизвести баг, полную ошибку и логи и чёткое правило: сначала найти корневую причину, потом что-то менять. Агент для программирования вроде 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-файлы.
  • Он трогает тесты. Подгонка проверки под неверный вывод никогда не исправляет баг.
  • Он не может воспроизвести баг, но всё равно его «исправляет».
  • Объяснение меняется от хода к ходу без новых доказательств.

Что делать вместо этого:

  1. Остановите ход (Esc в Claude Code и Codex).
  2. Откатите его изменения. Сделайте коммит перед началом отладки, чтобы git restore . или git stash вернули вас назад; варианты описаны в статье как отменить изменения Claude Code.
  3. Запишите, что узнали: какие теории оказались неверными и почему.
  4. Начните новую сессию с воспроизведением, фактами и отброшенными теориями. Чистый контекст с тремя хорошими фактами лучше длинного с десятью плохими догадками.

Иногда правильный ход — задать вопрос поуже: на «Список 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, добавляйте логирование, чтобы видеть реальные значения, и требуйте корневую причину до исправления. Завершайте каждый баг регрессионным тестом, который на ваших глазах упал и прошёл. А когда агент начинает гадать, остановите его, откатите изменения и начните заново с тем, что уже узнали.

Вопросы

ИИ действительно умеет отлаживать код или просто гадает?

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

Что дать агенту, когда я сообщаю о баге?

Точную команду или тест, который падает, полную ошибку со стеком вызовов, что вы ожидали вместо этого, и всё, что недавно менялось. Воспроизведение в одну строку лучше длинного описания симптома.

Может ли агент сам запустить git bisect?

Да. Дайте ему хороший и плохой коммит и скрипт, который завершается с кодом 0, когда код работает, и с кодом 1, когда не работает. git bisect run будет переключаться между коммитами и запускать скрипт, пока не найдёт первый плохой. Код выхода 125 говорит git пропустить коммит, который нельзя проверить.

Как не дать ИИ-агенту сделать исправление, которое лишь прячет баг?

Попросите назвать корневую причину простыми словами до любых изменений кода, запретите править или пропускать существующие тесты и требуйте регрессионный тест, который падает без исправления. Проверяйте diff на блоки try/catch, повторные попытки и расширенные типы, которые глушат ошибку, а не устраняют её причину.

Когда остановить агента и отлаживать самому?

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

Соберите своих агентов за одним столом.

Скачайте AgentVera бесплатно; ваши установленные CLI уже готовы к работе.

Другие статьи