- BrainTools - https://www.braintools.ru -

Чистый контур — агентская прачечная для вашего грязного легаси

Пока не долетело до вентилятора

Мне достался B2B SaaS проект в стадии, о которой мечтает любой техлид: “Почти готово. Релиз через две недели”. Два из трех API-вызовов возвращали HTTP 500.

В коде накопилось несколько поколений агентных исправлений. При обнаружении новой ошибки [1] просили агента разобраться и пофиксить баг. Агент вбивал костыль в виде очередного условия. Состояние объекта определялось по косвенным признакам. В 21 месте обработчик узнавал свой вид через отрицание: не A и не B, значит мой. Агенты видели эти подходы перед собой и продолжали по образцу наматывать нейросопли на этот клубок.

Claude погружался в эту субстанцию с головой. А я снаружи подавал ключи. Когда Claude выныривал, он выглядел как кот после валерьянки. Никогда до этого я не встречал у него такого количества галлюцинаций на столь маленьком контексте. Он не мог внятно ответить на половину вопросов.

После двух дней такого шит-дайвинга я решил, что чинить симптомы бессмысленно. Мы переписали модуль целиком, восстановив намерение авторов по немногочисленным докам и имеющемуся коду. Среду, где агент пишет новый код и не видит старого, мы с Claude назвали «чистый контур». Три дня ушло на контракт переноса: алгоритмы и слепки входов и выходов. Еще два на новую реализацию. Алгоритмы прозой описывали, что надо сделать, а не как надо сделать.

Механизм переноса

Я разделил работу между двумя агентами. Аналитик изучал старый код, запускал систему, снимал слепки входов, выходов и изменений в базе. Результаты он записывал в карточки сценариев, по одной на операцию. Из карточек складывался контракт переноса. В каждой карточке:

  • вход

  • ожидаемый результат

  • артефакты и состояния

  • коды

  • что попадает в снимок

  • чем подтверждено

У каждой строки пометка: [замер], [код] или [дыра].

Исполнитель писал новый код по карточкам. Старого кода он не видел: запрет в задании, отдельная сессия, два запрета в линтере (новый код не вызывает старый, старый не вызывает новый) и сторож заимствований, который сравнивает деревья старого и нового кода и выводит только места совпадений.

Дефекты работающих функций переносили как есть и исправляли в чистом контуре. Неиспользуемые функции не переносили.

Брали целиком пользовательский сценарий: от входного запроса до результата. После успешной сверки переключали вызывающий код на новую реализацию. Старый путь удаляли после приемки.

механизм переноса

механизм переноса

Похожим способом в 1984 году Phoenix Technologies создала BIOS, совместимый с BIOS IBM PC. Одни инженеры изучали оригинал и составляли спецификацию, другие писали реализацию, не видя кода IBM. Этот метод называют clean room design [2].

IBM BIOS и агентский перенос: через границу проходят спецификация и карточки сценариев, исходники остаются снаружи

IBM BIOS и агентский перенос: через границу проходят спецификация и карточки сценариев, исходники остаются снаружи

Через несколько дней мне дали второй проект: Rust-бэкенд и пять Python-служб в отдельных репозиториях. Небольшая фича требовала согласованных изменений в нескольких местах, а контракты на двух языках расходились при зеленых тестах всех шести компонентов. Тем же способом за три дня я перенес сценарии в один Python-монолит и переключил на него маршрутизацию. Шесть репозиториев ушли в архив. Вызовы между сервисами из HTTP с JSON стали вызовами функций, и расхождение контрактов теперь ловит mypy.

Устав чистого контура

Даже в новом коде агент будет вбивать костыли. Поэтому у исполнителя есть устав из 15 правил. Часть из них опытный разработчик сочтет элементарными, часть – спорными.

№

Правило

1

Состояние хранится в поле. Значения и разрешенные переходы объявлены один раз. Ограничение базы строится из того же перечня. Состояние не вычисляется по соседним полям и журналам.

2

Состояние меняет одна функция, атомарно с данными перехода. Она сверяет переход с объявленной таблицей.

3

У ожидания внешнего ответа или фоновой задачи есть состояние сбоя и выход по таймауту.

4

Разрешенные и запрещенные переходы проверяются тестами.

5

Код жизненного цикла сущности находится в одном пакете. Запись ее состояния снаружи запрещена.

6

У отказа свой код из общего перечня. Код не принимает решений по тексту сообщения об ошибке.

7

Неизвестное значение, сбой записи или потеря блокировки дают отказ. Молчаливый успех недопустим.

8

Независимые части результата принимаются отдельно. Обязательность части задает контракт.

9

Вид задания объявлен данными. Обработчик не вычисляет свой вид как «не A и не B».

10

Между старым и новым кодом нет вызовов, кроме явно названных временных исключений. Они удаляются со старым путем.

11

Новый тест или сценарий хотя бы раз должен упасть на соответствующем дефекте. Проверяется видимый результат.

12

Вид объекта хранится явно. Его не угадывают по подписи, префиксу идентификатора или форме строки.

13

Экран получает состояние сущности от сервера и отображает его.

14

Для конкурирующих ответов и действий пользователя объявлено правило старшинства. Порядок прихода ответов не меняет итог.

15

Допустимость действия проверяет сервер. Браузер получает доступные действия и причины отказа из его ответа.

Antigoal rule

Если одну вещь не удалось починить за три попытки, остановись и пересмотри ее устройство. Четвертую заплатку не делай.

Название – ответ на антропиковский /goal, который жжет токены как мартеновская печь, пытаясь добиться цели.

Пересечение с ub-mode

У дяди Боба, недавно вышел skill ub-mode [3]. Два правила совпадают с уставом чистого контура:

  • Attack the Premise: если два исправления с общей предпосылкой провалили одну проверку, разбери предпосылку, прежде чем делать следующее. Это antigoal rule.

  • TDD: увидь, как тест падает по ожидаемой причине. Это правило 11.

ub-mode это skill, и его специально вызывают для выполнения конкретной задачи. Устав чистого контура лежит в репозитории постоянно и читается в каждой сессии.

Слабая модель не всегда соблюдает устав

Правила можно положить в AGENTS.md, и модель прочитает их сама. Слабой модели я вставляю правила в промпт вместе с задачей.

Я сравнил на DeepSeek V4 Flash, 36 запусков, нарушения считал Claude Sonnet вслепую.

Что получила модель

Замечаний

Ничего

36

Образец

31

Образец и правила в AGENTS.md

25

Образец, AGENTS.md и требования в промпте

18

Первый пример. Когда правило «одно значение объявляется один раз» лежало в AGENTS.md, DeepSeek записывал тип события строкой в трех запусках из трех. Когда в задании прямо назвали эту ловушку, ноль из трех.

Второй пример. В старом коде у заказа не было поля статуса. Было строковое поле cancel_reason, причина отмены. Отменен заказ или нет, код решал по тому, заполнено ли это поле. Это проверялось в четырех местах.

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

- if order is None:
+ if order is None or order.cancel_reason is not None:
      return None

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

Затем я дал ту же задачу с правилами из AGENTS.md в промпте и образцом автомата состояний. В задании прямо написал: «Повтори устройство, а не имена». DeepSeek объявил OrderStatus с четырьмя значениями (new, paid, shipped, cancelled), таблицу переходов и одну функцию проверки. Пять разбросанных проверок cancel_reason превратились в одно обращение к статусу.

Результат

Без дополнительных правил

С правилами

С правилами и образцом

Таблица переходов

Нет

Нет

Есть

Проверка завершения

Повторяется в пяти местах

Повторяется в пяти местах

Собрана в одну функцию

Отдельное поле состояния

Нет

Нет

Есть

Затравка кристалла

Образец в последнем опыте [4] работал как затравка, из которой растят кристалл. DeepSeek получил одну хорошую реализацию автомата состояний и повторил ее устройство. Без образца та же модель повторила то, что видела в старом коде: пятую проверку по cancel_reason.

Как образец меняет результат.

Как образец меняет результат.

Автор: blurman

Источник [5]


Сайт-источник BrainTools: https://www.braintools.ru

Путь до страницы источника: https://www.braintools.ru/article/37752

URLs in this post:

[1] ошибки: http://www.braintools.ru/article/4192

[2] clean room design: https://en.wikipedia.org/wiki/Clean_room_design

[3] ub-mode: https://github.com/unclebob/ub-mode/blob/master/SKILL.md

[4] опыте: http://www.braintools.ru/article/6952

[5] Источник: https://habr.com/ru/articles/1101314/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1101314

www.BrainTools.ru

Rambler's Top100