Agent Dev 101

Модуль 01 · Урок 1.3

Урок 1.3. Почему one-shot development плохо масштабируется

На этой странице
  1. Зачем это нужно
  2. Основная идея
  3. Ключевые термины
  4. Почему one-shot кажется рабочим
  5. Что скрыто внутри большой задачи
  6. Типовые сбои one-shot development
  7. Как one-shot ломает agent loop
  8. One-shot prompt vs task-based workflow
  9. Пример: password reset
  10. Практика: сравнить два подхода
  11. Как понять, что задача слишком большая
  12. Типичные ошибки
  13. Критерии готовности
  14. Краткое резюме
  15. Вопросы для самопроверки
  16. Что дальше

Зачем это нужно

В первых двух уроках мы разобрали две опорные идеи:

  • LLM работает с ограниченным контекстом и может уверенно ошибаться.
  • Coding agent действует итеративно через agent loop: observe, plan, act, observe result.

Теперь нужно понять, почему привычный запрос "сделай всю фичу целиком" ломает эту управляемость.

One-shot development выглядит привлекательно: один prompt, один agent run, много кода. Но в реальной разработке крупная фича почти всегда содержит десятки скрытых product, architecture, UX, data, security и testing решений. Если эти решения не вынесены в specification, design и tasks, агент начинает угадывать.

Главная цель урока - показать, что большая задача должна превращаться не в большой prompt, а в граф маленьких проверяемых задач.

Основная идея

One-shot development - это подход, при котором разработчик дает агенту крупную задачу одной командой и ожидает готовый результат без явной спецификации, декомпозиции и промежуточной проверки.

Пример:

text
Сделай password reset: backend, email, UI, тесты и документацию.

Выглядит понятно. Но внутри этой фразы спрятаны десятки решений:

  • как долго действует token;
  • можно ли использовать token повторно;
  • что отвечать на неизвестный email;
  • нужен ли rate limit;
  • инвалидировать ли старые sessions;
  • какой email template использовать;
  • где хранить audit log;
  • какие API endpoints добавить;
  • какие тесты считать достаточными;
  • какие файлы можно менять;
  • какие architectural boundaries нельзя нарушать.

Если эти решения не сформулированы явно, агент не может "правильно" выполнить задачу. Он может только выбрать вероятный вариант.

Главный тезис:

text
Большая задача
!=
большой prompt

Большая задача должна становиться:

text
Specification
    ↓
Design
    ↓
Task graph
    ↓
Small verified changes

Ключевые термины

Термин Значение
One-shot development Попытка реализовать крупную задачу одним запросом и одним длинным agent run.
Vibe coding Разработка по общему намерению и ощущениям без строгой specification и verification.
Drift Отклонение агента от исходной цели, architecture constraints или allowed scope.
Context pollution Загрязнение контекста лишними деталями, устаревшей информацией и шумом.
Hidden decision Решение, которое необходимо для реализации, но не было явно сформулировано человеком.
Local correctness Код выглядит правильным в одном месте, но ломает поведение системы в целом.
Unrelated change Изменение файла или поведения, которое не требуется текущей задачей.
Task graph Граф маленьких задач и зависимостей между ними.

Почему one-shot кажется рабочим

One-shot хорошо работает на маленьких изолированных задачах:

text
Напиши функцию форматирования даты.

или:

text
Объясни, почему этот тест падает.

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

Проблема начинается, когда задача становится системной:

text
Добавь billing.
Сделай authentication.
Реализуй notifications.
Перепиши dashboard.
Оптимизируй backend.

В этих формулировках не хватает:

  • observable behavior;
  • acceptance criteria;
  • non-goals;
  • architecture constraints;
  • allowed scope;
  • verification commands;
  • order of implementation.

Агенту приходится проектировать, реализовывать, тестировать и принимать product decisions одновременно. Это слишком много ответственности для одного неограниченного loop.

Что скрыто внутри большой задачи

Рассмотрим задачу:

text
Сделай систему уведомлений для проекта.

На первый взгляд это одна фича. На практике внутри нее несколько слоев решений.

Слой Скрытые вопросы
Product Какие события должны создавать уведомления? Нужны ли read/unread states?
UX Где показывать уведомления? Нужен ли badge? Как работает empty state?
API Какие endpoints нужны? Нужна ли pagination?
Data Какая таблица или collection хранит уведомления? Какой retention period?
Security Кто может видеть уведомления? Как проверяется ownership?
Architecture Где находится domain logic: controller, service или event handler?
Delivery Нужны ли email, push, in-app notifications или только in-app?
Testing Какие unit, integration и E2E tests доказывают корректность?
Operations Нужны ли retries, dead-letter queue, observability?

Если все это не определено, агент заполняет пробелы сам. Иногда это выглядит разумно. Но "разумно" не значит "соответствует продукту".

Типовые сбои one-shot development

Потеря требований

Агент начинает с правильной цели, но по мере работы забывает часть требований.

Например, пользователь попросил:

text
Не менять существующий API response.

Но во время реализации агент добавляет новое поле в response, потому что так проще для UI. Локально UI работает, но внешний API contract сломан.

Architecture drift

Без явных architecture constraints агент выбирает путь наименьшего сопротивления.

Пример:

text
controller -> database

вместо:

text
controller -> service -> repository -> database

Код может пройти тесты, но нарушить архитектуру проекта. Через несколько таких изменений система становится непредсказуемой.

Локально правильный, глобально неправильный код

Агент исправляет симптом в одном месте, но ломает инвариант системы.

Пример:

  • token reset начинает работать;
  • но старые sessions не инвалидируются;
  • audit log не пишется;
  • rate limit обходится через другой endpoint.

Каждый отдельный фрагмент выглядит нормально. Поведение продукта в целом неверное.

Unrelated changes

Большая задача создает соблазн "заодно улучшить" соседний код:

  • переименовать helper;
  • обновить dependency;
  • переформатировать файлы;
  • переписать компонент;
  • изменить структуру response.

Unrelated changes опасны не потому, что они всегда плохие. Они опасны потому, что усложняют review и rollback.

Случайные зависимости

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

Например:

text
Добавляет новый date library

хотя проект уже использует стандартный helper formatDate.

Причина часто проста: агент не нашел существующий pattern или решил, что новый dependency ускорит реализацию.

Повторная реализация существующих механизмов

В большом scope агент может не заметить, что в проекте уже есть:

  • email service;
  • validation middleware;
  • error format;
  • audit logger;
  • permission helper;
  • API response wrapper.

В результате появляются две реализации одного механизма. Это увеличивает maintenance cost и риск расхождения поведения.

Отсутствие тестов

One-shot prompt часто формулируется через фичу, а не через проверку. Агент может написать код и кратко сказать:

text
Добавил тесты.

Но без traceability непонятно:

  • какие acceptance criteria покрыты;
  • какие edge cases пропущены;
  • запускались ли тесты;
  • доказывают ли они именно нужное поведение.

Context pollution

Чем дольше agent run, тем больше в контексте:

  • старых планов;
  • промежуточных ошибок;
  • исправленных гипотез;
  • длинных logs;
  • частичных решений;
  • устаревших assumptions.

К концу большого run агент может опираться на информацию, которая уже неактуальна.

Как one-shot ломает agent loop

Во втором уроке agent loop выглядел так:

text
Observe -> Plan -> Act -> Observe Result -> Continue or Stop

В one-shot режиме loop становится слишком широким:

flowchart TD A[Huge task] --> B[Huge implicit plan] B --> C[Many file edits] C --> D[Partial tests or no tests] D --> E[More fixes] E --> F[More context noise] F --> G[Hard-to-review diff] G --> H[Unclear completion]

Проблема не в том, что agent loop плохой. Проблема в том, что один loop пытается вместить слишком много разных решений.

Управляемый вариант:

flowchart TD A[Feature idea] --> B[Specification] B --> C[Design] C --> D[Task graph] D --> E[Task 1] D --> F[Task 2] D --> G[Task 3] E --> H[Test and review] F --> I[Test and review] G --> J[Test and review] H --> K[Integration] I --> K J --> K K --> L[Acceptance]

Здесь каждая task имеет свой маленький loop и свой критерий завершения.

One-shot prompt vs task-based workflow

Критерий One-shot prompt Task-based workflow
Требования Часто скрыты в общей фразе Зафиксированы в specification
Scope Размытый Явный allowed scope
Решения Агент угадывает Человек утверждает product/architecture decisions
Контекст Большой и шумный Минимальный и релевантный
Изменения Большой diff Маленькие проверяемые diffs
Тесты Часто добавляются в конце Связаны с acceptance criteria
Review Сложный и утомительный По одной задаче
Rollback Дорогой Можно откатить один change
Риск drift Высокий Ниже за счет boundaries

Task-based workflow медленнее выглядит на старте, но быстрее приводит к надежному результату. Это тот случай, где немного дисциплины экономит много разборов после.

Пример: password reset

Плохой one-shot запрос:

text
Добавь password reset во всем приложении.

Лучше сначала извлечь решения:

text
Goal:
Пользователь может запросить reset password по email и установить новый пароль по одноразовому token.

Non-goals:
- Не меняем login flow.
- Не добавляем social login.
- Не меняем email provider.

Questions:
- Сколько действует token?
- Что показывать для неизвестного email?
- Инвалидировать ли старые sessions?
- Какой rate limit?
- Какие audit events нужны?

Потом сделать маленькие задачи:

text
T1. Описать spec и acceptance criteria.
T2. Добавить storage/model для reset token.
T3. Добавить token generation service.
T4. Добавить request reset endpoint.
T5. Добавить reset password endpoint.
T6. Добавить tests для expired/used/invalid token.
T7. Добавить UI form.
T8. Добавить E2E happy path.

Каждая задача должна иметь:

  • goal;
  • inputs;
  • allowed scope;
  • acceptance criteria;
  • verification command.

Детально оформлять specification и tasks мы будем в следующих модулях. Сейчас важно увидеть направление: сначала сужаем неопределенность, потом пишем код.

Практика: сравнить два подхода

Возьмите одну фичу, например:

text
Система уведомлений

Сделайте два документа.

Документ 1. One-shot prompt

Напишите prompt так, как его обычно формулируют в хаотичной AI-разработке:

text
Сделай систему уведомлений с backend, frontend и тестами.

Затем выпишите минимум 15 скрытых решений, которые агенту придется принять.

Документ 2. Task-based outline

Разложите ту же фичу на этапы:

text
Specification
Design
Tasks
Tests
Review
Acceptance

Для каждой будущей task напишите один проверяемый результат.

Итоговый артефакт:

text
labs/01-one-shot-drift/report.md

Структура отчета:

text
# One-shot drift report

## Feature

## One-shot prompt

## Hidden decisions

## Likely failure modes

## Task-based alternative

## What should be verified externally

Как понять, что задача слишком большая

Задачу нужно дробить, если:

  • в ней больше одного observable result;
  • она требует изменений в нескольких слоях: DB, backend, frontend, tests;
  • есть неутвержденные product decisions;
  • непонятно, какие files are allowed to change;
  • review diff будет сложно прочитать за 10-15 минут;
  • невозможно назвать одну verification command;
  • агент должен одновременно проектировать архитектуру и писать код.

Практическое правило курса:

text
Одна Agent Task = один проверяемый результат.

Это не значит, что каждая задача должна быть микроскопической. Это значит, что ее завершение должно быть доказуемым.

Типичные ошибки

Ошибка 1. "Сделай SaaS"

Задача уровня "создай продукт" не является задачей для coding agent. Это начало product discovery и specification work.

Ошибка 2. "Сначала пусть напишет, потом разберемся"

Код без требований создает ложное ощущение прогресса. Потом приходится выяснять, какое поведение агент вообще реализовал.

Ошибка 3. "Добавь тесты" в конце большого prompt

Тесты, добавленные после большой реализации, часто проверяют уже написанный код, а не исходные acceptance criteria.

Ошибка 4. Не ограничивать allowed scope

Если scope не ограничен, агент может менять соседние модули, конфиги, зависимости и UI без явной необходимости.

Ошибка 5. Путать хороший план с хорошим результатом

Agent может составить разумный план и плохо его выполнить. План нужно отдельно утверждать, а выполнение отдельно проверять.

Ошибка 6. Считать drift проблемой только слабых моделей

Drift возникает не только из-за качества модели. Он возникает из-за слишком широкого scope, шума в контексте и отсутствия промежуточных проверок.

Критерии готовности

После урока студент должен уметь:

  • объяснить, что такое one-shot development и vibe coding;
  • назвать минимум 5 failure modes one-shot подхода;
  • найти hidden decisions внутри большой фичи;
  • объяснить разницу между большим prompt и task graph;
  • сформулировать правило "one Agent Task - one verifiable outcome";
  • подготовить короткий one-shot drift report.

Краткое резюме

One-shot development плохо масштабируется, потому что большая фича содержит слишком много скрытых решений. Когда эти решения не вынесены в specification, design и tasks, агент начинает угадывать, терять требования, нарушать архитектуру, менять лишние файлы и писать непроверяемый код.

Большой prompt не решает проблему большой задачи. Он часто только увеличивает context pollution.

Надежный подход:

text
Big feature
    ↓
Clarify behavior
    ↓
Write specification
    ↓
Design constraints
    ↓
Build task graph
    ↓
Run small agent tasks
    ↓
Verify each result

Это и есть мост к Specification-Driven Development.

Вопросы для самопроверки

  1. Почему фраза "сделай password reset" содержит много скрытых решений?
  2. Чем local correctness отличается от global correctness?
  3. Почему unrelated changes особенно опасны в AI-generated diff?
  4. Как context pollution влияет на длинный agent run?
  5. Что означает правило "одна Agent Task = один проверяемый результат"?

Что дальше

Модуль I дал базовую рамку: LLM ограничена контекстом, coding agent работает через loop, а one-shot development теряет управляемость на больших задачах.

В следующем модуле мы перейдем к Specification-Driven Development. Первый шаг - научиться писать specification как observable behavior: не "сделай хороший authentication", а конкретные требования, edge cases и acceptance criteria, которые можно проверить.

Обновлено 03.10.2026