Идея написать собственного кодинг-агента кажется прозрачной: вызываешь LLM API, получаешь код, выполняешь. На практике вызов модели занимает несколько строк, а всё остальное время уходит на инфраструктуру вокруг него. Разработчик, изучавший архитектуру Claude Code, воспроизвёл агента на Swift и зафиксировал, где именно эта инфраструктура ломается.
В основе любого агента лежат два цикла. Внешний — REPL — принимает пользовательский ввод и передаёт его дальше. Внутренний — Agent Loop — вызывает LLM, получает ответ, выполняет запрошенные инструменты и повторяет итерацию до тех пор, пока модель не вернёт финальный текст. Один запрос пользователя может развернуться в десяток внутренних итераций. Принципиально, что сам цикл не зависит от домена: кодинговым агента делают не структура цикла, а конкретные инструменты — чтение и запись файлов, shell, редактирование — плюс системный промпт.
Первый соблазн — дать агенту единственный инструмент bash и считать задачу решённой: shell умеет всё. Проблема в том, что каждую файловую операцию модель в этом случае генерирует заново в виде команды, без каких-либо гарантий корректности. Один лишний бэкслеш в многострочном sed — и файл повреждён. Специализированные инструменты read_file, write_file, edit_file решают не проблему возможностей, а проблему предсказуемости: у них фиксированный формат ввода-вывода, лимиты на размер и атомарная запись. Модель вызывает инструмент с понятными параметрами вместо того, чтобы каждый раз изобретать команду.
Bash как единственный инструмент ненадёжен: один лишний бэкслеш в sed-команде способен испортить файл, поэтому нужны специализированные read_file, write_file, edit_file.
Даже со специализированными инструментами агент нуждается в sandbox. Модель непредсказуема: она может запросить абсолютный путь или попытаться выйти за пределы рабочей директории через../../. В учебной реализации это закрывается тремя слоями: резолвинг пути с проверкой, что он остаётся внутри workdir; блокировка опасных паттернов вроде rm -rf / и sudo; принудительный allowlist инструментов — даже если модель нагаллюцинирует вызов несуществующего инструмента, он будет отклонён явно, а не упадёт с непонятной ошибкой.
Отдельная проблема возникает на длинных задачах. На коротких модель уверенно держит план. По мере роста контекста внимание модели смещается к свежим данным, и исходные инструкции фактически перестают влиять на поведение. Этот эффект называется instruction-following decay. Решение — Todo tool: список задач, который модель ведёт сама для себя. Каждый вызов возвращает актуальный план как tool_result, то есть он физически оказывается в конце контекста — там, где внимание максимально. Управление вниманием через структуру контекста оказывается эффективнее, чем любые формулировки в системном промпте.
Наконец, единая история сообщений быстро засоряется. Чтобы ответить на вопрос «какой testing framework используется в проекте?», модель читает десяток файлов, грепает директории, вызывает команды — и все промежуточные результаты остаются в контексте навсегда, хотя нужен был только итоговый вывод. Это подводит к архитектуре сабагентов: изолированных контекстов под конкретные подзадачи, результат которых возвращается в основной поток уже в сжатом виде.
