# Как эффективно гонять workflow-агентов

Практические уроки из боевых прогонов (competency-review C++ retouch-app, 2026-05-30).
Не теория - то, на чём реально спотыкались и что реально экономит токены/время.

## Главная цифра, от которой всё пляшет

**Один agent() ≈ 95k-150k токенов.** Не «дёшево потому что субагент» - наоборот. Замеры сессии:
- 4 read-only агента, чтение 4 файлов → 380k токенов.
- 6 ревьюеров + verify реального C++ модуля (1600 LOC) → **1.01M токенов**, 6 минут.

Эффективность workflow = **сколько агентов ты НЕ запустил**, а не сколько запустил. Оркестрация
(скрипт) существует чтобы резать лишних агентов, а не плодить.

## 1. Resume - главный рычаг экономии

Самое важное. Прогон **журналируется по agent() вызовам**; повторный запуск того же скрипта
возвращает завершённые агенты **из кэша (0 токенов)**, заново гоняет только изменённое.

Кейс сессии: review-фаза стоила ~1M токенов, verify перезапускали 3 раза. ВАЖНО (эмпирика, не
теория): кэш review **НЕ гарантирован**. Первый resume пришёл за ~0 токенов (review из кэша),
но второй стоил ~976k - кэш инвалидировался.

**Механизм инвалидации** (CN-ресерч, zhihu): при resume attachment-блоки (skills list, MCP
servers, deferred tools, hooks) «уплывают» из `messages[0]` в поздние сообщения → меняется
fingerprint `cc_version` (считается из контента `messages[0]`) → меняется system prompt →
prompt-cache инвалидируется, выжигая квоту. То есть дорогой resume - не из-за правок кода, а
из-за сдвига cache-префикса (вне нашего контроля в скрипте).

Урок: resume МОЖЕТ сэкономить тяжёлую стадию, но это не гарантия - **меряй `subagent_tokens`
каждого прогона**, не считай resume бесплатным по умолчанию. Помни: `agent()` cache key =
(schema, model, isolation, agentType) - смена любого = повторный запуск вызова.

Практика:
- Тяжёлую стадию (review/scan) пиши ПЕРВОЙ и не трогай между итерациями - она закэшируется.
- Итерируй хвост (verify/synthesize/фильтры) - правь промпт, перезапускай, review бесплатен.
- Запуск: `Workflow({scriptPath: "<сохранённый скрипт прогона>", resumeFromRunId: "<runId>"})`.
- Resume работает **только в той же сессии**. Вышел из Claude Code - прогон стартует заново.

## 2. Не перегружай агента контекстом (иначе он молча ломается)

Реальный баг: verify-агент читал 5 C++ файлов перед выводом → **23 из 24 не вызвали
StructuredOutput** («completed without calling tool») → находки потерялись тихо. Промпт-форс
«вызови инструмент» дал лишь 23→22 - почти не помог.

Причина: тяжёлый read-контекст «забивает» агента, он пишет текст и забывает tool-call.

Эффективно:
- **Узкий контекст** на агента: один точечный Read (конкретные строки), не «перечитай всё».
- Передавай агенту уже извлечённое (цитату-evidence от предыдущей стадии), а не «иди найди сам».
- Дроби: 1 агент = 1 находка/1 файл, а не «оцени все 24».

## 3. Фильтруй ПЕРЕД дорогой стадией

Не гоняй verify (дорого) по всему. Кейс: 24 сырых находки → фильтр `severity >= medium` в
коде скрипта → в verify ушло меньше, косметика (low) пошла в отчёт без агентов. Фильтрация -
чистый JS между стадиями, 0 токенов; каждый отсечённый элемент = сэкономленный агент.

```js
const toVerify = unique.filter((f) => RANK[f.severity] >= 1)  // дорогая стадия — только важное
const lowSeverity = unique.filter((f) => RANK[f.severity] < 1) // в отчёт без verify
```

## 4. Тихие фейлы: три, на которых горели

| Симптом в результате | Реальная причина | Как ловить / лечить |
|---|---|---|
| «0 находок», agent_count>0 но **subagent_tokens=0**, нет transcript | невалидный `agentType` (`'code-reviewer'` не резолвится) | не выдумывать тип: точный неймспейс или вообще без `agentType` |
| дефолтные значения вместо переданных | `args` не дошёл через `scriptPath` | для разовой задачи - inline-скрипт с зашитыми значениями; логировать `args.*` первой строкой |
| находки тихо теряются в pipeline | агент не вызвал StructuredOutput → throw → item=null | узкий контекст (п.2); считать yield; resume потерянных |

Общий корень: **тихий фейл маскируется под «пустой результат»**. Защита - `withRetry`, который
ЛОГИРУЕТ причину (`e.message`), а не голое «исчерпаны». Иначе сбой неотличим от «реально 0».

## 5. schema полезен, но не гарантия

`schema` авто-ретраит НЕВАЛИДНый вывод - но НЕ спасает, когда агент вообще не вызвал tool.
Поэтому: считай долю успешных verify (`verifyFailed` в результате), и при низкой - перезапускай
(resume дёшев). Не считай «confirmed: 1» за «всё чисто» если 22 упали - это `VERIFIED-PARTIAL`.

## 6. Один verify врёт - бери multi-vote для важного

Та же находка (Fisher-Yates) в двух прогонах: один verify-агент сказал FIX, другой - REJECT.
Adversarial-verify с одним голосом шумный. Для уверенности - N независимых скептиков, решение
большинством. Для черновой триажа - одного хватает.

## 7. Билинг-калькуляция ДО запуска

Прикинь число агентов: fan-out по списку N → N агентов на стадию (× ретраи). Умножь на ~100k.
- >10 агентов → обсудить с собой/юзером, нужен ли весь объём.
- `/model` на меньшую модель для рутинных стадий.
- `budget`-guard в loop-флоу: `while (budget.total && budget.remaining() > 50_000)`.
- Стоп без потерь: `/workflows` → `x` (завершённые агенты сохранены).

**Реальные cost-инциденты (community, для калибровки):** 62 Opus-субагента выжгли 5-часовой cap
за **18 минут**; ревью «довольно мелкого пакета» раздулось до **90 агентов** и упёрлось в Max;
Java→C# миграция ~**2 млрд токенов**. «5 параллельных субагентов = 5x расход» (N агентов = N
разговоров с моделью).

**MCP tool discipline** (предусловие лёгкого контекста оркестратора): 200K-контекст схлопывается
до ~70K при избытке включённых tools. Держи ≤10 активных MCP и ≤80 активных tools (конфигурить
можно больше, включать мало). Подробности и источники - `skill references/research-findings-2026-05-30.md`.

## 8. parallel vs pipeline (коротко)

- `pipeline` по умолчанию - items текут через стадии независимо, без барьера (быстрее по wall-clock).
- `parallel` (барьер) - ТОЛЬКО когда следующей стадии нужны ВСЕ результаты разом (dedup по всему
  множеству, синтез-сравнение, early-exit по总count).

## 9. Диагностика прогона (что читать когда «странно»)

- **usage**: `agent_count` vs `subagent_tokens` vs `tool_uses`. 0 токенов при N агентов = не
  стартовали (тип/лимит). Много агентов, мало tool_uses = не читали (плохой target/контекст).
- **output-file** прогона: массив `logs` (твои `log()`) + `result` + `failures`.
- **transcript dir** `subagents/workflows/<runId>/`: `journal.jsonl` + `agent-*.jsonl` по агенту.
- Нет transcript dir вообще = ни один агент не исполнился.

## Чеклист «перед тем как жать запуск»

1. Тяжёлая стадия первой и стабильна (чтобы resume её кэшировал)?
2. Фильтр перед дорогой стадией стоит (не гоним verify по мусору)?
3. Контекст агента узкий (не «перечитай всё»)?
4. `agentType` валиден или отсутствует?
5. `args` точно доходит (или зашит inline)?
6. `withRetry` логирует причину?
7. Число агентов × 100k - в рамках лимита?
8. `node validate.mjs` прошёл?
