# ГЛАВА 9. МНОГОШАГОВОЕ МЫШЛЕНИЕ И РАЗРЕЗАНИЕ ЗАДАЧ

---

Представьте, что вы купили шкаф в IKEA. В коробке — 87 деталей, 14 видов болтов и инструкция на 32 страницы. Никому не придёт в голову сказать: «Ну, вот тебе все детали — собери шкаф». Вместо этого инструкция разбита на пронумерованные шаги: сначала каркас, потом полки, потом двери. Каждый шаг — понятный, проверяемый, опирается на результат предыдущего.

С языковыми моделями — та же история. «Напиши мне полное приложение с авторизацией, базой данных, тестами и деплоем» — это как бросить все 87 деталей на пол и ожидать шкаф. Работает? Иногда. Надёжно? Нет.

Вот конкретный пример. Допустим, вы хотите добавить в веб-приложение фичу — страницу профиля пользователя с редактированием аватара. В одном промпте это звучит так:

> «Добавь страницу профиля пользователя: API-эндпоинт для получения и обновления профиля, загрузку аватара в S3, валидацию формы на фронте, компонент React с превью изображения и тесты.»

Модель выдаст что-то — но API может не совпадать с фронтом, валидация будет неполной, а тесты не покроют edge-cases. Это не потому что модель «глупая», а потому что вы попросили её собрать шкаф за один присест.

Разбейте на шаги: (1) схема API, (2) реализация эндпоинтов, (3) интеграция с S3, (4) React-компонент по контракту API, (5) тесты. Каждый шаг проверяем, каждый — с чистым фокусом. Именно к такому устройству пришли лучшие агентные инструменты 2026 года — даже если их внутренние planner/state-machine детали нам чаще видны только по внешнему поведению.

---

## 9.1. Почему модели плохо держат длинные цепочки зависимостей

### Ограничение: глубина ≠ длина

Transformer обрабатывает всю последовательность за один прямой проход (forward pass). Количество «шагов вычисления» определяется числом слоёв, а не длиной контекста. Для Llama 3 70B это 80 последовательных трансформаций. Это значит, что **любая** задача решается за те же 80 шагов — независимо от её сложности.

Для простых задач (перевод слова, компиляция формулы) 80 шагов — более чем достаточно. Для сложных задач (планирование, многошаговая дедукция, оптимизация) — критически мало.

### Эффект: ошибки накапливаются

В одном промпте с 10 взаимозависимыми шагами:
- Вероятность ошибки на шаге: ~5–15% (зависит от задачи).
- Если вероятность ошибки на каждом шаге около 10%, то десятишаговая цепочка останется полностью корректной лишь примерно в трети прогонов.

Каждый шаг строится на предыдущем. Ошибка на шаге 3 инвалидирует шаги 4–10. И модель не может это обнаружить, потому что авторегрессионное декодирование идёт только вперёд ([Глава 4](04_causal_reading_and_the_power_of_the_first_frame.md)).

### Решение: вынести состояние наружу

Вместо одного огромного промпта — серия коротких промптов с **явной передачей состояния** между шагами:

```
[Промпт 1: Анализ] → Результат 1 →
[Промпт 2: План на основе Результата 1] → Результат 2 →
[Промпт 3: Реализация шага 1 из Плана] → Результат 3 →
[Промпт 4: Верификация Результата 3] → OK / Retry
```

Каждый промпт — чистый контекст, фокус на одной задаче, минимальная длина.

> **Контекст 2026:** Современные reasoning-модели (GPT-5.x с `reasoning.effort`, Claude Opus 4.6 с adaptive thinking, DeepSeek-R1) выполняют больше внутренней работы до ответа — это chain-of-thought на стороне модели. O-серия OpenAI (o1, o3) интегрирована в GPT-5.x как единый параметр `reasoning.effort` (none — по умолчанию, low, medium, high, xhigh). GPT-5.4 не использует reasoning по умолчанию (none); для активации мышления требуется явная установка параметра. Детали внутреннего planning-процесса раскрыты не полностью. Поэтому инженерный вывод остаётся прежним: если задача требует менять файлы, вызывать API, запускать тесты или координировать инструменты, внешняя явная декомпозиция надёжнее и наблюдаемее внутреннего «мышления» модели.

### Chain-of-Thought: внутренняя декомпозиция модели

Прежде чем переходить к внешней декомпозиции (следующие секции), стоит разобрать приём, который заставляет модель декомпозировать задачу **внутри одного вызова** — chain-of-thought (CoT) prompting.

**Zero-shot CoT.** Простейший вариант — добавить в конец промпта фразу «Let's think step by step» (или «Давай рассуждать пошагово»). Это активирует в модели паттерн последовательного рассуждения, который часто приводит к более корректным ответам на задачах с логикой, арифметикой и планированием. Исходная работа (Kojima et al., 2022) показала рост accuracy на бенчмарке MultiArith с 17.7% до 78.7% для text-davinci-002.

**Few-shot CoT.** Более надёжный вариант — дать модели примеры, где рассуждение уже расписано пошагово (Wei et al., 2022). Модель имитирует формат рассуждения из примеров. Это работает лучше zero-shot, потому что примеры калибруют не только глубину рассуждения, но и формат ответа. Практический вывод важен для кода: демонстрации нужны не столько ради «правильной мысли», сколько ради фиксации формы результата — какие файлы перечислить, как показать дифф, где вывести тест-план и как оформить финальный патч.

**Structured CoT.** Для production-задач полезно формализовать шаги: `<step_1>Определи ключевые переменные</step_1> <step_2>Проверь граничные условия</step_2> <step_3>Сформулируй ответ</step_3>`. Это даёт контроль над глубиной и позволяет программно парсить промежуточные шаги.

**Когда CoT помогает, а когда нет:**

| Помогает | Не помогает |
|----------|-------------|
| Арифметика, логика, дедукция | Простое извлечение фактов |
| Задачи с >2 шагами рассуждения | Классификация с очевидным ответом |
| Планирование и принятие решений | Генерация креативного текста |
| Задачи с ограничениями, которые легко нарушить | Задачи, где модель и так достигает >95% accuracy |

**Связь с reasoning-моделями.** В GPT-5.x параметр `reasoning.effort` и в Claude adaptive thinking CoT встроен в модель — она рассуждает «про себя» без явного промпта. Но для обычных моделей (и для контроля над промежуточными шагами) CoT-промптинг остаётся ключевым инструментом. Внешняя декомпозиция (§9.2+) — это следующий уровень: когда одного внутреннего рассуждения недостаточно, и нужно разбить задачу на несколько вызовов с явной передачей состояния.

### Практика для кодовых задач: включайте рассуждение выборочно

Свежие работы 2024–2026 годов дают полезную инженерную коррекцию: длинное пошаговое рассуждение нужно не всегда. Для математики, логики, миграций схем, сложных рефакторингов и отладки падающих тестов CoT действительно помогает. Для простого переименования функции, добавления поля в DTO, копирования типового эндпоинта или обновления README оно чаще только тратит токены и размывает фокус.

| Тип задачи в репозитории | Режим | Почему |
|--------------------------|-------|--------|
| Переименование, мелкий CRUD, текстовая правка | Прямое исполнение + тесты | Почти нет скрытого поиска |
| Новый endpoint по существующему шаблону | Короткий план на 3–5 пунктов | Нужно удержать контракт, но не строить длинную цепочку рассуждений |
| Баг с неясной причиной, сложный SQL, миграция, многофайловый рефакторинг | Явный план + 3–5 кандидатов решения + верификатор | Ошибка дорого стоит, нужен поиск по пространству патчей |
| Алгоритмическая задача, парсер, ограничения, где легко нарушить инвариант | CoT или Plan-and-Execute | Важны промежуточные проверки и соблюдение ограничений |

Практический шаблон для кодового агента выглядит так:

1. **Краткий план, а не эссе.** Сначала попросите 3–5 шагов: какие файлы менять, какие инварианты не ломать, чем проверять результат.
2. **Патч вместо рассуждения ради рассуждения.** После плана агент должен выдать конкретный дифф, список файлов или модулей, а не ещё одну страницу объяснений.
3. **Внешний верификатор обязателен.** `pytest`, типизация, линтер, проверка схемы и минимальный smoke test дают больше пользы, чем ещё один абзац CoT.
4. **Останавливайтесь рано.** Если минимальный дифф проходит проверки, не запускайте дополнительный цикл «подумай ещё», если только задача не требует оптимизации по явной метрике.

Это хороший мост между этой главой и [Главой 8](08_multiple_hypotheses.md): для сложного кода обычно побеждает не самый длинный внутренний монолог модели, а связка «короткий план -> несколько кандидатов -> внешний верификатор -> минимальный проходящий патч».

### Continuous latent reasoning: не всё мышление обязано быть текстом

CoT предполагает, что модель «думает» тем же носителем, которым отвечает, — токенами естественного языка. Но это не единственный вариант. В работе **Coconut (Chain of Continuous Thought)** предлагается подавать на следующий шаг не сэмплированный текстовый токен, а **последнее скрытое состояние** модели как непрерывный latent input.

Зачем это нужно? Текст заставляет модель рано коммититься к одной формулировке. Латентный шаг позволяет дольше удерживать несколько альтернатив одновременно, откладывать развилку и подводить поиск ближе к terminal state, прежде чем переводить рассуждение обратно в слова. На задачах, где важны planning, backtracking и combinatorial search, такой режим иногда ведёт себя ближе к BFS, чем к обычному линейному CoT.

Для инженера тут два вывода. Первый: reasoning не обязан быть текстовым, поэтому «попросить модель расписать мысли» — не всегда лучший proxy её внутреннего вычисления. Второй: в production по-прежнему выигрывает внешняя декомпозиция, потому что latent reasoning плохо аудитируется, не оставляет удобного журнала промежуточных решений и пока остаётся research frontier.

---

## 9.2. Декомпозиция как инженерный паттерн

Декомпозиция — это инструкция IKEA для языковой модели. Вы не собираете шкаф целиком — вы сначала собираете каркас, потом прикручиваете полки, потом навешиваете двери. Каждый этап — самостоятельный, проверяемый (каркас стоит ровно?), и опирается на результат предыдущего.

### Принцип Single Responsibility для промптов

Каждый промпт выполняет **одну задачу** и возвращает **один результат**:

| Антипаттерн | Паттерн декомпозиции |
|-------------|---------------------|
| «Проанализируй данные, найди аномалии, предложи исправления, напиши код» | 1. Анализ → 2. Поиск аномалий → 3. Предложение исправлений → 4. Кодогенерация |
| «Сгенерируй API с авторизацией, валидацией, базой данных и тестами» | 1. Схема API → 2. Auth middleware → 3. Validation → 4. DB layer → 5. Tests |

### Формализация: DAG задач

Задачу можно представить как **направленный ациклический граф** (DAG):

```
[Анализ требований]
       │
       ▼
[Дизайн архитектуры]
       │
   ┌───┴───┐
   ▼       ▼
[API]   [DB Schema]
   │       │
   └───┬───┘
       ▼
[Интеграция]
       │
       ▼
[Тестирование]
```

Независимые узлы (API и DB Schema) можно выполнять параллельно. Зависимые — строго последовательно. Каждый узел — отдельный промпт.

---

## 9.3. Паттерны разбиения задач

### Паттерн 1: Mode-Architect (6 шагов)

Для проектирования сложных систем:

```
Шаг 1: АНАЛИЗ
├── Вход: описание задачи от пользователя
├── Промпт: "Разбери требования, выдели функциональные и нефункциональные"
├── Выход: структурированный список требований
│
Шаг 2: ТРЕБОВАНИЯ
├── Вход: список требований из Шага 1
├── Промпт: "Формализуй как user stories + acceptance criteria"
├── Выход: спецификация в формате Given/When/Then
│
Шаг 3: АРХИТЕКТУРА
├── Вход: спецификация из Шага 2
├── Промпт: "Предложи архитектуру: компоненты, интерфейсы, зависимости"
├── Выход: диаграмма компонентов + API-контракты
│
Шаг 4: КОНТРАКТ
├── Вход: API-контракты из Шага 3
├── Промпт: "Детализируй каждый контракт: типы, ошибки, edge-cases"
├── Выход: OpenAPI/Pydantic спецификации
│
Шаг 5: РЕАЛИЗАЦИЯ
├── Вход: контракты из Шага 4 (по одному за раз!)
├── Промпт: "Реализуй {component_name} по контракту"
├── Выход: код компонента
│
Шаг 6: ВЕРИФИКАЦИЯ
├── Вход: код из Шага 5 + контракт из Шага 4
├── Промпт: "Сгенерируй тесты и проверь соответствие контракту"
├── Выход: тесты + отчёт о соответствии
```

### Паттерн 2: DevPlan Protocol (параллельные проекции)

Для масштабных проектов, где разные аспекты можно проектировать параллельно:

```
              [Задача]
         ┌──────┼──────┐──────┐
         ▼      ▼      ▼      ▼
      [Данные] [Логика] [UI]  [Тесты]
         │      │      │      │
         ▼      ▼      ▼      ▼
      Schema   API   Routes  Specs
         │      │      │      │
         └──────┴──────┴──────┘
                    │
                    ▼
              [Интеграция]
```

Каждая «проекция» (данные, логика, UI, тесты) генерируется **независимым** промптом в **отдельном контексте**. Затем результаты собираются интеграционным промптом.

**Преимущества**: параллельность, изоляция ошибок, чистые контексты.
**Стоимость**: интеграционный шаг может быть сложным, если проекции несогласованы.

### Паттерн 3: Mode-Code (TodoWrite)

Для пошаговой реализации с явным контролем состояния. Представьте доску Kanban: каждая задача — карточка, которая перемещается между колонками TODO → IN PROGRESS → DONE. Модель видит эту «доску» и точно знает, что сейчас в работе, а что уже сделано:

```
Состояние задачи:
[TODO]         Модуль аутентификации
[IN_PROGRESS]  Модуль валидации → текущий шаг
[DONE]         Модуль базы данных
[DONE]         Схема API

Текущий шаг: Модуль валидации
Контракт: validate_request(data: dict, schema: Schema) -> ValidationResult
Зависимости: Schema из модуля базы данных (DONE)
```

Модель видит **явное состояние** каждой задачи и работает только с текущей. Это предотвращает:
- Потерю контекста между шагами.
- Повторное решение уже решённых задач.
- Параллельный прогресс по нескольким незавершённым задачам (что ведёт к shallow coverage).

---

## 9.4. Как это работает в реальных инструментах 2026 года

Многошаговое мышление — не абстракция из статей. Это основа каждого серьёзного AI-инструмента, которым вы пользуетесь прямо сейчас.

### Agentic coding: Claude Code, Cursor Agent, Windsurf

Когда вы просите Cursor Agent «добавь аутентификацию через OAuth», он не пытается сделать всё за один проход. Под капотом происходит именно то, что описано в этой главе:

```
Шаг 1: Чтение существующего кода (grep, read_file)     → понимание структуры
Шаг 2: Формирование плана изменений                       → список файлов и правок
Шаг 3: Редактирование файлов (по одному)                 → код
Шаг 4: Запуск тестов / линтера                            → верификация
Шаг 5: Исправление ошибок если тесты упали              → цикл retry
```

Claude Code работает аналогично: читает файлы, строит план, вносит правки, запускает `bash` для проверки, и итерирует до успеха. Это не магия — это state machine с циклом plan → act → observe → plan.

### Plan-and-Execute в фреймворках

Паттерн Plan-and-Execute формализован в LangGraph, CrewAI и AutoGen. Суть: один вызов LLM создаёт план (список шагов), другой — исполняет их по одному, третий — пересматривает план после каждого шага. Этот паттерн становится agent loop в [Главе 10](10_agent_not_chat.md).

Цикл выглядит так: `planner(state) → plan` → `executor(step) → result` → `replanner(plan, results) → updated plan`. Planner генерирует список шагов, executor выполняет текущий шаг с доступом к инструментам, replanner корректирует план по результатам.

> **Промпт для ИИ:** «Напиши на Python реализацию паттерна Plan-and-Execute с использованием LangGraph (StateGraph). Три узла: planner (создаёт план из списка шагов), executor (выполняет текущий шаг с доступом к tool use), replanner (корректирует план по результатам). State: task, plan, current_step, results. Покажи определение графа и пример запуска.»

### Супер-агенты: многочасовые многошаговые пайплайны

ChatGPT Deep Research и Claude Code демонстрируют многошаговые работы, длящиеся десятки минут и часы: поиск по 50+ источникам, синтез в отчёт, итеративное уточнение. Это те же принципы декомпозиции, но масштабированные на сотни шагов с управлением памятью через checkpoint-файлы, сжатие истории и структурированное состояние.

Devin (и аналоги) идёт ещё дальше: он создаёт полноценную среду разработки, пишет код, запускает его, читает логи, исправляет, коммитит — всё автономно. Но под капотом — всё тот же цикл: план → шаг → наблюдение → коррекция.

---

## 9.5. Когда планировать, а когда исполнять

### Матрица решений

| Характеристика | Планируй | Исполняй сразу |
|---------------|----------|-----------------|
| Количество шагов | >3 | 1–3 |
| Зависимости между шагами | Есть | Нет или минимальные |
| Требуется верификация | Да | Нет |
| Цена ошибки | Высокая | Низкая |
| Задача новая/незнакомая | Да | Нет |
| Чёткая спецификация | Нет → нужен план | Да → можно исполнять |

### Analysis Paralysis: когда планирование вредит

**Antipattern: бесконечное перепланирование.**

```
✗ "Создай план. Проверь план. Улучши план. Оцени план по 5 критериям. 
    Пересмотри план на основе оценки. Создай альтернативный план. 
    Сравни два плана. Выбери лучший. Детализируй выбранный план..."
```

Проблемы:
1. Каждая итерация планирования **расходует контекст** и деньги.
2. Модель начинает **зацикливаться**: план → оценка → корректировка → оценка... без продвижения.
3. Потеря деталей: после 3-й итерации планирования конкретика из первых шагов стирается.

### Правило 80%

> **Переходите к исполнению при ~80% ясности.** Не ждите идеального черновика. Если вы писали статью и ждали идеального плана, вы бы никогда не начали писать. Оставшиеся 20% выявятся в процессе — и это нормально. Планирование не может предусмотреть всё, а реализация «заземляет» — выявляет конкретные проблемы, которые абстрактный план пропустил.

### Конкретная эвристика

```python
def should_plan(task):
    score = 0
    if task.steps > 3: score += 2
    if task.has_dependencies: score += 2
    if task.requires_verification: score += 1
    if task.error_cost == "high": score += 2
    if task.is_novel: score += 1
    
    if score >= 4: return "plan_first"
    if score >= 2: return "lightweight_plan"
    return "execute_directly"
```

---

## 9.6. Управление состоянием между шагами: доска проекта

Представьте доску управления проектом (Kanban в Jira или Notion). Каждая карточка — задача. Каждая колонка — статус. Вы можете открыть доску через месяц и сразу понять, где проект. Управление состоянием LLM-пайплайна работает точно так же: модель должна видеть явную «доску» с текущим статусом каждой задачи.

### Проблема: контекст не является памятью

Context window — это **рабочая память** (как RAM), не долговременная. Между вызовами API состояние полностью теряется (если не передать явно).

### Решение 1: Structured State Object

Передавайте состояние между шагами как структурированный объект — dataclass или dict с полями: описание задачи, требования, архитектура, контракты, реализации, результаты тестов, текущий шаг, список ошибок. Каждый шаг читает нужные поля, вызывает модель с промптом, построенным по текущему состоянию, и записывает результат обратно в объект.

> **Промпт для ИИ:** «Напиши на Python dataclass `PipelineState` для управления состоянием LLM-пайплайна. Поля: task_description (str), requirements (list[str] | None), architecture (dict | None), contracts (list | None), implementations (dict[str, str] | None), test_results (dict[str, bool] | None), current_step (str, default "analysis"), errors (list[str]). Добавь функцию `run_step(state, step)`, которая строит промпт по текущему состоянию, вызывает модель и обновляет state. Используй dataclasses и field(default_factory=list).»

### Решение 2: File-Based State

Для IDE-интегрированных агентов (Copilot, Cursor, Cline):

```
project/
├── .ai/
│   ├── plan.md          # Текущий план
│   ├── state.json       # Состояние выполнения
│   ├── decisions.md     # Принятые решения
│   └── errors.md        # Ошибки и их разрешение
├── src/
│   └── ...
└── tests/
    └── ...
```

Модель читает `.ai/state.json` в начале каждого вызова и обновляет его после завершения.

### Решение 3: Conversation History (с компрессией)

Для диалоговых систем ключевая задача — сжатие истории без потери ключевых решений. Подход: сохранять системный промпт и последние N сообщений, а середину суммаризировать через LLM в компактное описание контекста.

> **Промпт для ИИ:** «Напиши на Python функцию `compress_history(messages: list[Message], max_tokens: int) -> list[Message]`. Логика: всегда сохранять первое (system) и последние 3 сообщения. Если середина превышает max_tokens — суммаризировать её через LLM в одно сообщение с ролью system. Используй tiktoken для подсчёта токенов.»

### Решение 4: Checkpoint-файлы (для длинных сессий)

Супер-агенты и многочасовые пайплайны не могут хранить всё в контексте. Вместо этого они записывают промежуточные результаты в файлы — checkpoint'ы. Класс `CheckpointManager` сохраняет результат каждого шага в JSON-файл, а метод `build_context_for_step` собирает только нужные checkpoint'ы для текущего шага по списку зависимостей.

> **Промпт для ИИ:** «Напиши на Python класс `CheckpointManager(project_dir)`. Методы: `save(step, data)` — сохраняет dict в `{project_dir}/.ai/checkpoints/{step}.json`; `load(step)` — загружает или возвращает None; `build_context_for_step(step, dependencies: list[str])` — собирает результаты зависимых шагов в строку контекста. Используй pathlib и json.»

Это позволяет модели на шаге 47 загрузить только результаты шагов 2 и 45, а не перечитывать всю историю.

---

## 9.7. Автоматизация переходов между шагами

### State Machine для пайплайна

Пайплайн реализуется как конечный автомат (state machine) с шестью состояниями и явными правилами перехода:

```
analyze ── success ──→ plan ── success ──→ implement ── success ──→ verify ── pass ──→ done
  │                      │                       │                      │
  ├─ unclear → retry   ├─ needs_revision       ├─ partial → retry   ├─ fail → implement
  └─ failure → failed  │  → retry              └─ failure → plan    └─ critical → plan
                        └─ failure → failed

                       (max 3 retry на любом шаге → failed)
```

**Состояния:** analyze, plan, implement, verify — рабочие; done и failed — терминальные. Каждое рабочее состояние имеет несколько возможных исходов: success (переход к следующему этапу), повторная попытка (тот же этап) и failure (откат к предыдущему этапу или завершение). Если переход ведёт к тому же состоянию (retry), счётчик попыток увеличивается; после трёх неудачных попыток пайплайн переходит в состояние failed.

> **Промпт для ИИ:** «Напиши на Python state machine для LLM-пайплайна. Используй enum `PipelineStep` с состояниями: analyze, plan, implement, verify, done, failed. Определи словарь TRANSITIONS, где каждому состоянию сопоставлены возможные исходы (success, failure, partial, needs_revision, unclear, pass, fail, critical) и соответствующие следующие состояния. Класс `Pipeline` хранит текущий шаг, объект состояния (PipelineState) и счётчик retry (max 3 на шаг). Метод `advance(result)` находит следующее состояние по TRANSITIONS, обрабатывает retry-логику и обновляет шаг. Используй dataclass для PipelineState.»

---

## 9.8. Восстановление после ошибок в многошаговых пайплайнах

Что происходит, когда шаг 3 падает? В одном промпте — катастрофа: модель продолжит генерировать шаги 4–10 на основе ошибочного результата (авторегрессия идёт только вперёд — [Глава 4](04_causal_reading_and_the_power_of_the_first_frame.md)). В многошаговом пайплайне это решаемая задача.

### Стратегии восстановления

| Стратегия | Когда применять | Пример |
|-----------|---------------------|--------|
| **Retry** | Недетерминированная ошибка, модель может справиться с другого раза | Сгенерированный код не компилируется — повторить с ошибкой в контексте |
| **Retry с изменённым контекстом** | Ошибка закономерна, нужна дополнительная информация | Нет типов библиотеки — добавить документацию в контекст |
| **Откат (rollback)** | Ошибка инвалидирует весь подход | Архитектурное решение не работает — откат к этапу планирования |
| **Эскалация** | Автоматика не справляется | 3 retry упали — передать человеку |

### Практический пример: retry с обратной связью

Ключевой принцип: **ошибка — это информация**. В retry-попытке текст ошибки подмешивается в контекст следующего вызова. Если после N retry модель не справляется — откат к предыдущему шагу (rollback) или эскалация человеку.

> **Промпт для ИИ:** «Напиши на Python функцию `run_step_with_recovery(state: PipelineState, step: str, max_retries=3)`. Логика: на каждой попытке вызвать `run_step`, проверить результат через `validate_step_output`. Если ошибка — добавить её текст в `state.errors` и в контекст следующей попытки. После max_retries — откат к шагу plan (для implement/verify) или эскалация через исключение `EscalateToHuman`.»

Именно так работают Claude Code и Cursor, когда тесты падают: они читают вывод терминала и исправляют код на основе конкретной ошибки.

---

## 9.9. Частые ошибки в многошаговом дизайне

| Ошибка | Почему плохо | Как исправить |
|--------|--------------|------------------|
| **Слишком мелкие шаги** | Расход на координацию превышает экономию от разбиения | Каждый шаг должен производить осмысленный артефакт (файл, схему, тест) |
| **Неявное состояние** | Модель «забывает» решения предыдущих шагов | Передавайте явный state object или файл состояния |
| **Нет верификации между шагами** | Ошибки копятся, модель строит на гнилом фундаменте | Проверяйте выход каждого шага перед передачей дальше |
| **Бесконечное планирование** | Контекст исчерпывается, конкретика стирается | Правило 80%: начинайте делать после 2-3 итераций планирования |
| **Один контекст на всё** | Шум от предыдущих шагов мешает текущему | Новый контекст для каждого шага + явное состояние |
| **Retry без информации об ошибке** | Модель повторяет ту же ошибку | Всегда передавайте текст ошибки и stack trace в retry-промпт |

---

## Практический вывод

### Чек-лист декомпозиции

| # | Правило | Действие |
|---|---------|----------|
| 1 | **Одна задача = один промпт** | Разбивайте на атомарные шаги |
| 2 | **Явное состояние между шагами** | JSON, dataclass, файл — но явно |
| 3 | **DAG зависимостей** | Определите, что от чего зависит |
| 4 | **Параллелизм где возможно** | Независимые шаги → параллельные вызовы |
| 5 | **Правило 80%** | Не планируйте бесконечно |
| 6 | **Автоматизируйте переходы** | State machine с retry/fallback |
| 7 | **Макс. 3 retry на шаг** | После 3 попыток → escalate или fallback |

### Задания

**Задание 1. Декомпозиция реальной задачи.** Возьмите задачу из текущего проекта, которую вы обычно решаете одним промптом (например, «добавь фичу X»). Разбейте её на DAG из 4–6 шагов по принципу Single Responsibility. Для каждого шага напишите отдельный промпт и определите зависимости. Выполните пошагово, передавая результат предыдущего шага как контекст. Сравните результат с попыткой решить задачу за один промпт. Ожидаемый результат: более корректный код, меньше ошибок на стыках.

**Задание 2. CoT vs прямой ответ.** Возьмите 10 задач разной сложности (от простого перевода до многошаговой логики). Для каждой задачи запустите два варианта промпта: (a) прямой запрос, (b) тот же запрос + «Рассуждай пошагово». Сравните accuracy. Определите порог сложности, начиная с которого CoT даёт заметное улучшение. Ожидаемый результат: эмпирическое понимание, когда CoT оправдан, а когда это лишние токены.

**Задание 3. Checkpoint-пайплайн.** Реализуйте мини-пайплайн из 3–4 шагов с checkpoint-файлами (используйте промпт из §9.6). Намеренно «сломайте» шаг 2. Убедитесь, что пайплайн: (a) обнаруживает ошибку, (b) передаёт текст ошибки в retry, (c) после 3 неудачных retry откатывается к шагу 1. Ожидаемый результат: работающий recovery-механизм для LLM-пайплайна.

---

## Источники
- Wei, J., et al. (2022). "Chain-of-Thought Prompting Elicits Reasoning in Large Language Models." NeurIPS.
- Kojima, S., et al. (2022). "Large Language Models are Zero-Shot Reasoners." NeurIPS.
- Wang, L., et al. (2023). "Plan-and-Solve Prompting: Improving Zero-Shot Chain-of-Thought Reasoning." ACL.
- Khot, T., et al. (2023). "Decomposed Prompting: A Modular Approach for Solving Complex Tasks." ICLR 2023.
- Zhou, D., et al. (2023). "Least-to-Most Prompting Enables Complex Reasoning in Large Language Models." ICLR.
- Hao, S., et al. (2025). "Training Large Language Models to Reason in a Continuous Latent Space." arXiv:2412.06769.
- Gan, Z., et al. (2026). "Beyond the Black Box: A Survey on the Theory and Mechanism of Large Language Models." arXiv:2601.02907.
- Sprague, Z., et al. (2025). "To CoT or not to CoT? Chain-of-Thought Helps Mainly on Math and Symbolic Reasoning." arXiv:2503.16411.
- Wang, X., & Zhou, D. (2024). "Chain-of-Thought Reasoning Without Prompting." arXiv:2402.10200.
- LangGraph Documentation (2025). "Plan-and-Execute Agent." https://langchain-ai.github.io/langgraph/
- Anthropic (2025). "Building effective agents." https://docs.anthropic.com/en/docs/build-with-claude/agents
- OpenAI (2025). "A practical guide to building agents." https://platform.openai.com/docs/guides/agents

---

**Навигация:**
- Назад: [Глава 8. Несколько гипотез лучше одной](08_multiple_hypotheses.md)
- Далее: [Глава 10. Агент ≠ Чат: разные режимы, разные правила](10_agent_not_chat.md)
