Неделя 5. Runtime и оркестрация workflow
- Что уже умеем
- Вызывать модель через `ModelClient`, проверять структурированный ответ и tool proposal.
- Какую проблему решаем
- Между вызовами теряется состояние, провайдер протекает в логику.
- Что нового появится
- Runtime вокруг известного model call: State, Workflow, RunPolicy и HumanGate.
- Что получится в конце
- Workflow с конечным бюджетом и тестами на mock.
🧭 Где мы: LLM → Context / State → Tools → [Runtime / Orchestration] → Policy / Permissions → Evaluation / Observability.
Что меняем в Capstone
Week 5. Формализуем runtime: выносим State → Role → Transition → RunPolicy → HumanGate в отдельные компоненты. RunPolicy задаёт конечный budget, HumanGate останавливает side effects.
Вспомни прошлую неделю
- Что делает
ModelClientмежду workflow и provider SDK? - Где в Capstone tool proposal проходит validation до исполнения?
Материал
🤔 Predict
Вызов модели трижды завершился timeout, а лимит попыток исчерпан. Должен ли runtime продолжать вызывать модель, пометить запуск blocked или завершить его как ошибку выполнения?
В Week 4 мы научились вызывать модель через ModelClient. Теперь строим runtime вокруг этой capability: сохраняем состояние между ролями, задаём переходы кодом, ограничиваем бюджет и останавливаем опасные side effects до исполнения. Реализуем это на обычном Python; новый framework не нужен.
Основной проход недели: State → Workflow → RunPolicy → HumanGate. ModelClient остаётся известной зависимостью, которую runtime вызывает внутри шага.
Обязательное ядро: State, Workflow, RunPolicy, HumanGate и runtime, который связывает их. Поля State, условия переходов и лимиты должны быть проверяемы тестами; модель остаётся за интерфейсом из Week 4.
Компоненты
Не обязательно строить инфраструктуру целиком. Каждый компонент вводится только против конкретной проблемы:
| Компонент | Какую проблему решает | Объём |
|---|---|---|
State |
факты о прогрессе теряются между ролями | обязательное ядро |
ModelClient |
provider differences не должны попадать в логику workflow | изучен в Week 4; используется runtime |
Workflow |
переходы между ролями зависят от того, как модель сформулировала текст | обязательное ядро |
HumanGate |
опасное действие должно ждать подтверждения, а не выполняться сразу | обязательное ядро |
RunPolicy |
лимиты вызовов и повторов иначе не соблюдаются | обязательное ядро |
RoleRunner |
сборка сообщений для роли | упрощённая реализация, артефакты в памяти или файлах |
ArtifactStore |
prompts, outputs, diff и test results нужно хранить долго и с redaction | расширение |
Один проход через эти компоненты
Теперь те же пять абстракций на одном реальном шаге — узле planner:
Workflow: решить, что делать дальше; условие перехода — заполнены acceptance_criteria
↓ передаёт не текст, а поле state
State: {issue, acceptance_criteria[2], allowed_paths[], status: planning}
↓ собирает сообщение из state, инструкции роли и правил формата
RoleRunner → ModelClient: один вызов; на выходе — JSON по схеме или явная ошибка
↓ схема невалидна / пустой ответ / timeout во время вызова
RunPolicy: один ограниченный повтор; после исчерпания — failed, дальше не идём
↓ scope не подтверждён человеком
HumanGate: needs_approval, запись не выполняется
Один вызов — одно решение: где хранится факт, кто зовёт модель, что проверяется до вызова и что происходит после. Когда все пять компонентов на месте, этот проход одинаков для любой роли: planner, analyst, reviewer отличаются только содержимым state и инструкцией.
Бюджет (обязательное ядро) и model routing (расширение)
Лимит вызовов — не оптимизация, а граница отказа: без конечного числа повторов цикл «попробовать ещё раз» превращается в зависший процесс, который выглядит как работа.
Зафиксируйте один провайдер и модель, установите конечные лимиты вызовов, времени и повторов. Не допускайте тихого переключения на другой или платный endpoint.
Расширение: добавьте routing — детерминированное правило, какая модель или обычный код обрабатывает какой тип шага:
| Тип шага | Начальный выбор | Условие эскалации |
|---|---|---|
| Извлечение полей, нормализация, классификация | Маленькая локальная модель или обычный Python-код | Формат не прошёл schema validation или низкая уверенность |
| Анализ кода, планирование, сложный review | Привычная более сильная coding-модель; локальная — только после собственного eval | Не хватает доказательств, повторяется ошибка, высокий риск |
| Высокорисковое изменение / неоднозначные требования | Human gate до вызова implementer | Не эскалировать автоматически без лимита/разрешения |
| Простые проверки и маршрутизация | Python-правила, тесты и allowlist | Не вызывать LLM там, где достаточно детерминированной проверки |
Платный API для local-first пути не требуется. Облачный fallback необязателен и потенциально платен: он должен быть явно включён, иметь лимит и не получать приватный контекст без отдельного разрешения. Условия локального прогона — модель и тег, квантование, num_ctx, wall-clock, число вызовов, память — фиксируются по странице о выборе модели.
Расширение: сравните две модели или провайдера на одном наборе задач; routing должен иметь явные лимиты и завершать execution error как failed, возвращать needs_input для неоднозначности и blocked только при отказе policy до вызова.
Состояние задачи
State из недели 3 теперь становится конкретной структурой. Минимальный набор полей, который реально используется в capstone:
run_id
issue
acceptance_criteria[]
allowed_paths[]
plan
human_plan_approved
repo_evidence[]
test_plan[]
proposed_patch
commands_requested[]
commands_approved[]
test_results[]
review_findings[]
iteration_count
status: planning|needs_approval|implementing|testing|blocked|failed|done
blocked — policy не допустила действие до исполнения; failed — model/tool/runtime execution уже начался, но завершился ошибкой или исчерпал retry budget.
Секреты, .env, токены и содержимое credentials не должны попадать в промпты, артефакты логов или commit. Используйте .gitignore, redaction и отдельный учебный репозиторий.
Практика
Соберите первую цепочку без автоматического shell:
issue → planner → schema validation → человек утверждает план
→ read-only analyst → один отчёт
На выходе программа печатает артефакт и предлагает следующий шаг; она не меняет код. Добавьте тесты на invalid schema, provider timeout и needs_input.
🎉 What you can do now
Вы можете ограничить выполнение конечным бюджетом, сохранить состояние между шагами и остановить запуск на HumanGate до side effect.
Rule
Явные state, адаптер внешнего сервиса и конечные retry-бюджеты полезны в любом интеграционном workflow.
Результат недели: Capstone checkpoint
Week 5. Runtime + policy работают: State → Role → Transition → RunPolicy → HumanGate, конечный budget на mock.
Проверь себя
- Какую проблему решает runtime поверх
ModelClient? - Чем
RunPolicyотличается отHumanGate? - Где в Capstone сохраняется состояние и где останавливается side effect?
✅ Definition of Done
- Объяснить, зачем runtime нужен поверх
ModelClient, и различать обязанностиRunPolicyиHumanGate. - Реализовать переходы workflow по полям State, а не по свободному тексту модели.
- Тестом проверить invalid schema, timeout, конечный retry budget и
needs_input. - Показать, что исчерпание retry завершает выполнение как
failed, а policy rejection до tool execution даётblocked; незакрытый HumanGate не допускает side effect.
→ Дальше: runtime управляет переходами и остановками; в Week 6 сузим, какие инструменты и действия ему вообще разрешено выполнять.
Навигация
| ← | Week 4: Model provider |
| → | Week 6: Tools / Policy / Security |