В наше время известное изречение Линуса Торвальдса «Talk is cheap. Show me the code.» можно переиначить в виде «Code is cheap. Show me the spec.» Меня зовут Алекс Гусев и в этой публикации я постараюсь показать, почему я так считаю.
У меня есть несколько статей на Хабре, объединённых общей темой: ADSM (Agent Driven Software Management). По сути, это моя попытка формализовать свой личный опыт в Spec-Driven Development (SDD) в какое-то подобие методологии. Под катом я поделюсь результатами применения SDD-подхода (в его ADSM виде) к разработке простого приложения — помощника в создании плейлистов в Spotify. И покажу, что будет, если на базе одного и того же контекста (спецификации) сгенерировать код одним и тем же агентом (Codex, GPT-5.4) с разным уровнем reasoning’а (high, medium, low).

Предыстория
Нам для одного из семейных мероприятий понадобился плейлист на 4-5 часов на определённую тему. ChatGPT хорошо справился с задачей и выдал список из 100 музыкальных произведений с названиями и авторами. Оставалось сформировать плейлист для Spotify. Раньше мы делали это вручную и времени уходило порядком, но сейчас такие вещи легко поддаются автоматизации через ИИ-агентов.
Я уверен, что кто-то может навайбкодить подобное приложение за полчаса, а то и за десять минут. Но во-первых, я не умею вайбкодить, во-вторых, я умею SDDевелопить. Поэтому, на создание первой версии приложения у меня ушло 2 часа чистого времени.
История
До того, как я занялся реализацией этого проекта, я вообще был не в курсе о каких-либо возможностях интеграции Spotify с внешними приложениями. ChatGPT подсказал мне адрес https://developer.spotify.com/ и объяснил, что и где нужно прописать, чтобы зарегистрировать своё приложение.
Оказалось, что аутентифицироваться в Spotify нужно по протоколу OAuth. А для этого нужно иметь свой домен и TLS-сертификат. Домен у меня был, сертификат делается через Let’s Encrypt. Я уже давно пишу только на JavaScript, поэтому выбор ЯП был безальтернативен. Как и выбор платформы — только TeqFW, только хардкор!
Создал приватный репозиторий на GitHub’е, склонировал на локалку. Добавил в контекст (./ctx/spec/) типовой код для nodejs-приложений на базе моей библиотеки @teqfw/di. Где-то около часа с небольшим я в VSCode обсуждал в диалоге с Codex-агентом детали будущей реализации — как запускать, как конфигурировать, какие зависимости тянуть. Агент всё это аккуратно фиксировал в контексте проекта (каталог ./ctx/docs/). Затем я попросил агента создать ./package.json, bootstrap-файл ./bin/cli.mjs и головной скрипт приложения ./src/Main.mjs. После чего попросил создать в две итерации: 1) интеграционные тесты и код для получения и сохранения токена аутентификации через веб-сервер; 2) загрузку и парсинг текстового файла с музыкальными композициями, поиск произведений в Spotify и формирование плейлиста (тоже интеграционные тесты и исходники). Соответствие формата es6-модулей требованиям своей платформы я верифицировал по скиллу teq-esm-validator.
Я проверял работу приложения по частям (каркас — просто запуск; получение токена аутентификации; разбор файла и поиск композиций; создание плейлиста и добавление в него найденных композиций). Итого, чуть больше, чем через два часа чистого времени в моём Spotify этим приложением был создан новый плейлист из 80+ композиций. Остальные композиции из списка не были обнаружены в Spotify.
Последствия
Я время от времени вижу в комментах на Хабре, что коллеги высказывают мысль, что LLM-агенты неприменимы в разработке, потому что от них нельзя получить детерминированный результат. Но для меня до сих пор программирование — это всё ещё отчасти искусство. Если бы Леонардо да Винчи рисовал свою Джоконду десять раз, то он бы нарисовал десять разных картин, на которых была бы изображена одна и та же женщина. Если любой программист десять раз реализует достаточно сложное приложение, то это будет десять разных приложений с одним и тем же, заданным, функционалом.
«детерминированность результата» != «детерминированность кода«
Для демонстрации этой идеи я опубликовал оригинальный код, созданный Codex-агентом (GPT-5.4, high reasoning) под версией 1.0.0. Только код, контекст я специально вырезал. Затем я попросил Codex-агента (GPT-5.4, medium reasoning) удалить папки ./src/ & ./test/ и на основе того же самого, неизменённого контекста из папки ./ctx/ создать с нуля тесты и исходники (для экономии я оставил прежние package.json и boostrap-файл). Получилась версия 2.0.0. Затем то же самое проделал на GPT-5.4, low reasoning — версия 3.0.0.
Промпт для перегенерации исходников
Удали все файлы из каталогов src, test. Подними в package.json версию до 3.0.0. Ознакомься с документами контекста (./ctx/). Посмотри, как запускается приложение. Создай интеграционные тесты для продукта (ctx/spec/code/platform/teqfw/quality/testing/overview.md). После этого создай полнофункциональный код продукта (согласно правилам платформы TeqFW), проверь по интеграционным тестам. Проверь код в src/ через скилл teq-esm-validator. Исправь найденные ошибки и снова проверь по интеграционным тестам. Собери юнит-тесты для проверки исходников (ctx/spec/code/platform/teqfw/quality/testing/unit.md). Обнови README.md с учётом, что это третья версия приложения, созданная агентом Codex GPT-5.4 на reasoning-уровне Low. Не надо поднимать прошлую реализацию из git-истории. Проектируй с нуля. В этом смысл этой итерации.
Вот сводка по созданным исходникам, сделанная агентом:
|
Версия |
Файлы в src |
Каталоги в src |
Строк всего |
Код |
Комментарии |
Пустые |
|---|---|---|---|---|---|---|
|
1.0.0 |
23 |
9 |
1546 |
983 |
404 |
159 |
|
2.0.0 |
18 |
10 |
1436 |
844 |
462 |
130 |
|
3.0.0 |
20 |
10 |
993 |
665 |
274 |
54 |
Можно зайти по ссылкам и посмотреть на получившийся код — он не идентичен. Можно установить любую из версий, получить токен аутентификации со Spotify и создать плейлисты — работает одинаково.
Замечания
У меня ушло довольно много времени (месяцы) на создание спецификаций для моего стиля разработки (./ctx/spec/code/platform/teqfw/) и я всё ещё продолжаю развитие этой документации. Но это часть контекста, переиспользуемая между всеми моими проектами. И мне потребовалось пару часов на описание продукта (создание документов в пространстве ./ctx/docs/). Но на генерацию тестов и кода каждой из версий у агента ушло в районе 10 минут. И что интересно, вне зависимости от reasoning-уровня у меня ушло порядка 4% недельной квоты от plus-подписки на ChatGPT на генерацию каждой из версий.
Все три версии затупили с созданием плейлиста в Spotify. Dry-запуск они проходили и треки искались, но при попытке добавления треков в плейлист все три раза агент использовал устаревший API и приходилось ему каждый раз указывать на эту ошибку. Если бы я не старался делать более-менее чистый эксперимент, я бы внёс в когнитивный контекст требование использовать новый API от Spotify, но я специально выполнял генерацию кода на одном и том же контексте. Так что помимо детерминированности результирующего функционала также проявилась и детерминированность ошибок прочтения контекста агентом.
Третья версия, которая делалась low-reasoning агентом, не справилась с запуском веб-сервера. Вернее, справилась — веб-сервер стартовал, но приложение сразу же его глушило, не дожидаясь получения токена аутентификации от Spotify. На уровнях high & medium такой проблемы не возникло.
Для понимания соотношения объёма документов контекста (ctx) к результирующему коду (см. таблицу выше):
|
Файлы в ctx |
Каталоги в ctx |
Строк всего |
Пустых |
|---|---|---|---|
|
53 |
27 |
5378 |
1869 |
Что касается объёма в байтах, то сводка такая:
|
Файлы в ctx |
src v1 (high) |
src v2 (medium) |
src v3 (low) |
|---|---|---|---|
|
152Kb |
48Kb |
42Kb |
36Kb |
Да, это моя осознанная позиция: документы контекста по объёму должны быть в разы больше результирующего кода.
Скиллы
Отдельно нужно выделить скиллы. Моя платформа использует позднее связывание исходников в момент выполнения. Все зависимости внедряются через конструктор. А это значит, что во всех файлах из каталога ./src/ нет статических импортов. Ни одного. Это довольно нетрадиционный подход к JS-кодированию и агенты очень плохо в него умеют.
Когда я столкнулся с упорным желанием агентов создавать классический исходный код (с ранним связыванием кода при помощи статических импортов), мне пришлось сделать свой скилл — teq-esm-validator. Его, кстати, тоже делал Codex-агент по той же методологии ADSM. После этого было достаточно в промпте указать, что нужно использовать этот скилл для проверки исходников, и проблема со связыванием очень сильно уменьшилась. По крайней мере, в этом проекте с плейлистом в Spotify она не возникла ни разу.
Заключение
Я сравниваю поведение LLM-агентов при генерации кода с поведением дождевой воды, которая следуя изгибам рельефа, собирается в струйки, в ручьи, в реки и стремится к океану. Так же и агент генерирует код — следует по пути наименьшего сопротивления. Документы контекста в этой аналогии играют роль плотин и каналов, а скиллы и тесты я бы сравнил с насосами, забрасывающими воду на другой уровень (шлюзование). Оттуда вода опять может течь вниз, но уже по другому пути.
Основные затраты в таком подходе — это инфраструктура (те самые плотины, каналы, шлюзы). Но зато потом, после создания этой инфраструктуры, вода в большинстве случаев попадёт туда, куда было задумано строителями. Код в моём представлении — это не конечный артефакт, а производный. Результат взаимодействия когнитивного контекста и агента.
Именно исходя из этих соображений я и считаю, что контекст проекта (те самые 53 файла в ./ctx/), важнее самого кода (18-23 файла в ./src/). Ведь когда у тебя есть контекст, агент тебе сделает нужный код в течение минут. Даже такой экзотический, как TeqFW.
Вы можете свободно изучать код всех трёх версий — он дешёвый. Но если вы хотите увидеть контекст проекта — стучите в личку. Я дам контекст бесплатно, в обмен на обратную связь о возможности применимости данного подхода в ваших проектах.
P.S.
И немножко прекрасного. ИИ-агенты спокойно вытягивают «бойлерплейт» и делают ненужными множественные зависимости в ./node_modules/:
Им ничего не стоит захардкодить Web API и перехардкодить его в случае изменений. В моём приложении всего две зависимости для режима runtime (мои собственные библиотеки) и ещё две зависимости для dev-режима (разрешение типов Node.js).
ссылка на оригинал статьи https://habr.com/ru/articles/1023900/