Современные coding agents уже довольно неплохо умеют писать код.
Даёшь задачу:
Добавь в форму регистрации проверку email.
Агент открывает проект, читает файлы, что-то меняет, запускает тесты и через некоторое время сообщает: Done.
И вот здесь начинается самое интересное.
Потому что «Done» совершенно не обязательно означает, что задача действительно сделана.
Агент мог забыть один из сценариев. Изменить соседнее поведение. Не выполнить часть требований. Написать тесты, которые проверяют не то. Или просто решить задачу немного иначе, чем вы представляли.
Чем сложнее задача, тем сильнее становится эта проблема. И в какой-то момент становится понятно: ещё один хороший промпт её не решает.
Нужен процесс.
От промпта к инженерному процессу
Именно из этой идеи появился Konstruktor.
Konstruktor — небольшой open-source инструмент поверх OpenHands для запуска coding-задач без интерактивного участия человека. Но интересная часть проекта находится не в самом запуске агента.
Главная идея — заставить агента пройти через несколько отдельных стадий работы вместо одного длинного диалога:
задача
↓
намерение
↓
спецификация
↓
ревью спецификации
↓
план реализации
↓
код
↓
проверка требований
↓
исправления
↓
повторная проверка
↓
отчёт
То есть вместо:
PROMPT → AGENT → CODE
получается:
PROBLEM → SPEC → PLAN → BUILD → VERIFY → FIX → VERIFY
Разница кажется небольшой. На практике она меняет практически всё.
Сначала договоримся, что значит «готово»
Одна из проблем работы с LLM заключается в том, что первоначальная задача обычно слишком неоднозначна.
Например:
Добавь email validation.
Что это значит?
Проверять наличие @? Использовать RFC-compatible validator? Проверять email только на frontend или ещё и на backend? Что должно возвращать API? Нужно ли менять существующие тесты? Что должно происходить со старыми пользователями?
Человек обычно уточняет такие вещи по ходу работы. Автономному агенту приходится делать предположения.
Поэтому в режиме plan Konstruktor сначала превращает исходную задачу в спецификацию: с нумерованными требованиями, acceptance criteria и явно обозначенными вещами, которые не входят в задачу. Затем спецификация отдельно проверяется и при необходимости корректируется.
Получается важная вещь: код больше не является единственным описанием того, что решил сделать агент.
До начала реализации существует документ, относительно которого результат потом можно проверить.
План — это тоже артефакт
Следующий шаг — план реализации. Не абстрактное «сначала изучу код, затем внесу изменения», а план на уровне файлов и конкретных изменений.
После выполнения задачи в проекте остаётся набор документов:
docs/specs/<task>/
intent.md
spec.md
plan.md
compliance.md
report.md
И мне эта часть кажется одной из самых важных.
Когда обычный агент заканчивает работу, часто остаётся только Git diff и длинная история его рассуждений. Konstruktor пытается оставить инженерный след:
- что мы хотели сделать;
- какие требования сформулировали;
- как собирались это реализовать;
- чему соответствует полученный результат;
- какие требования не выполнены;
- что в итоге произошло.
Даже если агент ошибся, разобраться в том, где именно он ошибся, становится значительно проще.
Самая важная стадия — не генерация
Но главное начинается после того, как код уже написан.
Konstruktor запускает отдельную стадию verification. Каждый пункт спецификации сопоставляется с фактическим результатом, после чего строится compliance matrix.
Условно:
REQ-001 PASS
REQ-002 PASS
REQ-003 FAIL
REQ-004 PASS
Если что-то не прошло проверку, агент не получает команду «посмотри ещё раз на всё и исправь». Он получает значительно более узкую задачу: исправить только требования, которые не прошли проверку.
После этого verification запускается снова. Количество таких циклов ограничено конфигурацией, поэтому процесс не должен бесконечно пытаться исправить сам себя.
Получается довольно простая петля:
IMPLEMENT
↓
VERIFY
↓
PASS? ─── YES → REPORT
│
NO
↓
FIX FAILED ITEMS
↓
VERIFY
Именно эту часть я считаю интереснее самого coding agent.
LLM сегодня уже умеют генерировать огромное количество кода. Гораздо более сложная задача — понять: соответствует ли этот код первоначальному намерению?
Konstruktor не пытается быть моделью
Есть ещё одно принципиальное решение: Konstruktor сам по себе не является coding agent.
Он использует OpenHands как исполнительный слой. В простом режиме run Konstruktor запускает одну headless-сессию OpenHands, ждёт её завершения, сохраняет события и Git diff.
То есть архитектурно идея выглядит примерно так:
KONSTRUKTOR
│
┌──────────┴──────────┐
│ │
PROCESS STATE
│ │
spec / plan / verify artifacts
│ │
└──────────┬──────────┘
│
OPENHANDS
│
LLM
│
repository
Это сознательное разделение ответственности.
OpenHands умеет работать с окружением и писать код. Модель умеет рассуждать. Konstruktor задаёт процесс, в рамках которого они работают.
Поэтому потенциально сам исполнитель здесь не так важен, как протокол вокруг него.
А почему не один огромный промпт?
Технически можно написать system prompt на несколько страниц: «Сначала составь спецификацию, потом проверь её, затем сделай план, реализуй его, проверь все требования…»
Но у длинной агентной сессии есть неприятное свойство: контекст постепенно загрязняется. Агент помнит собственные решения, собственные предположения и собственную реализацию. В результате проверять самого себя становится сложно.
Если же разделить процесс на стадии, можно менять контекст и роль агента. Один проход пишет спецификацию. Другой её критикует. Следующий реализует. Следующий проверяет результат относительно спецификации.
Это пока далеко не независимое доказательство корректности. Но это уже заметно лучше модели:
— Ты всё сделал?
— Да.
— Точно?
— Точно.
Наблюдаемость тоже важна
Автономность довольно быстро превращается в проблему отладки. Если агент работал сорок минут и закончил странным результатом, хочется понять, что происходило внутри.
Поэтому каждая сессия Konstruktor сохраняет диагностические данные: summary, поток событий, логи агента, Git diff и логи самого harness.
Примерно так:
konstruktor-output/
└── run-.../
├── summary.json
├── events.jsonl
├── agent.log
├── agent-error.log
├── diff.patch
└── harness.log
Это не самая эффектная часть AI-agent проекта. Но если мы хотим когда-нибудь доверять агентам настоящую работу, подобная наблюдаемость, скорее всего, важнее красивого чата.
Один запуск
Для простой задачи можно использовать Konstruktor как headless-wrapper над OpenHands:
konstruktor run \
-t "Write unit tests for utils.py" \
-d ./project
А если задача требует более формального процесса:
konstruktor plan \
-t "Add email validation to the signup form" \
-d ./project
Во втором случае Konstruktor прогонит задачу через весь pipeline спецификации, планирования, реализации и проверки.
И где подвох?
Конечно, Konstruktor пока экспериментальный. И это важно.
По умолчанию используется process sandbox OpenHands, а не полноценная контейнерная изоляция. Такой агент потенциально имеет доступ к ресурсам текущего пользователя. Некоторые режимы sandbox и command policy Konstruktor намеренно запрещает, если не может гарантировать, что OpenHands действительно способен их обеспечить.
Поэтому запускать подобные инструменты на production-системах или рядом с ценными credentials без дополнительной изоляции — плохая идея.
Кроме того, verification всё ещё выполняется LLM. То есть наличие REQ-042 PASS не превращает результат в математически доказанно правильный. Это просто ещё один уровень контроля.
Но инженерия вообще редко состоит из одного идеального механизма проверки. Обычно надёжность появляется из нескольких несовершенных слоёв.
Что хочется проверить дальше
Мне интересен не столько вопрос: «Сможет ли AI полностью заменить разработчика?» Он слишком большой и почти бесполезный.
Гораздо интереснее более практический вопрос:
Какой минимальный процесс нужен агенту, чтобы ему можно было отдать задачу вечером, а утром получить результат, который не нужно полностью переделывать?
Возможно, хороший coding agent — это не модель, которая пишет лучший код. Возможно, это система, которая умеет последовательно:
UNDERSTAND
SPECIFY
PLAN
BUILD
VERIFY
FIX
REPORT
И оставляет после себя достаточно информации, чтобы человек мог понять, что произошло.
Именно это сейчас и пытается делать Konstruktor. Не заменить инженера, а научиться работать немного больше как инженер.