Агенты и промпты¶
AI — скальпель, не кувалда (VISION). Агент в Axon — это workflow-функция: workflow с config-формой
agent_config(либо ссылка на reusableAgentDefinitionчерезagent_ref). Запускается тем жеWorkflowRunner, проходит через те же policy/budget/approval gates, что и любой другой step. Этот manual: как пишут / публикуют / версионируют prompts и AgentDefinitions, как работаютAgentToolResolverexposure rule, adaptive model routing, validator retry-with-feedback, и где это в Console.
1. Что это и зачем¶
Зачем отдельные prompts и agent definitions¶
Промпт и agent — это переиспользуемые контракты. Если бы каждое workflow описывало свой prompt inline, было бы: - невозможно версионировать (один и тот же email-классификатор в десяти workflow → десять копий, ни одна не «канон»); - невозможно поменять text без публикации всех зависимых definitions; - невозможно гарантировать replay-safety (run, запущенный полгода назад, должен видеть тот же prompt, что был при start).
Поэтому Axon выделяет два immutable versioned DB-сущности:
PromptVersion(таблицаapp.prompt_versions, префикс idpver_<ulid>) — версия prompt template с placeholders. PROMPT-SCOPE.AgentDefinition(таблицаapp.agent_definitions, префикс idagdef_<ulid>) — версия AgentSpec, в которой prompt pinned конкретнымprompt_version_id(неkey:latest). AGENTSPEC + AGENTS-FINISH.
И то и другое — append-only versioned: новая версия — новая строка, старая остаётся archived (но не удалена). Это даёт replay determinism: runtime/replay принимает только pver_* / agdef_* (никаких key:latest).
Транспорт LLM¶
Все LLM-вызовы идут через LiteLLM proxy (deterministic gateway). Бизнес-код использует Pydantic AI / Instructor → LiteLLM. Прямые SDK провайдеров (Anthropic, OpenAI) в бизнес-логике запрещены (CLAUDE.md, ARCHITECTURE-V6 §3 stack). Это нужно: для одного аудит-пути, для adaptive model routing (haiku→sonnet→opus), для observability через Langfuse.
Чем агент не является¶
- Не самостоятельным сервисом. Agent — функция внутри workflow.
- Не отдельным процессом исполнения. Step Runner владеет step semantics; agent — это execution strategy одного
model_call/agent_config. - Не правом обходить policy/approval. Все side effects через connector tools проходят policy gate;
internal/external_*actions — этоtool_call/external_writeworkflow steps, не direct agent tools (см. §4 AgentSpec tool exposure rule).
2. Роли и доступ¶
Из core/models/auth.py. Полная матрица — Roles-And-Permissions.md.
| Действие | Permission | owner | admin | manager | operator | reviewer | read_only | system |
|---|---|---|---|---|---|---|---|---|
Опубликовать prompt version (publish_prompt_version) |
prompt:manage |
✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |
Архивировать prompt version (archive_prompt_version) |
prompt:manage |
✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |
Set active prompt version (set_prompt_version_active) |
prompt:manage |
✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |
Опубликовать AgentDefinition (publish_agent_definition) |
agent_definition:manage |
✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |
Архивировать AgentDefinition (archive_agent_definition) |
agent_definition:manage |
✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |
| Читать prompts / agents | read |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — |
Manager НЕ имеет
prompt:manage/agent_definition:manage. Это сознательное ограничение: prompt content — часть кодовой поверхности (engineers пишут, owner/admin publish'ат). Manager может смотреть список и историю, но не публиковать.systemимеет оба — для seed-flow на старте проекта (см. §7 Lifecycle, project seed agents).Engineer — не RBAC-роль. Engineer пишет AgentSpec/PromptVersionSpec в коде (
modules/agents//modules/prompts/), а publish'ит — owner/admin через Console или CLI. Built-in (origin='system'/'code') agents/prompts публикуются через миграции 040/041 (system actor).
Scope discipline:
- prompt:manage для instance scope требует instance-wide роли (owner/admin). prompt:manage для project scope — той же роли, но в project_scopes конкретного проекта.
- Publish AgentDefinition в project scope, который пинит instance-scoped prompt — разрешено (project AgentDefinition может использовать platform-wide prompt). Обратное — нет: instance AgentDefinition не может пинить project-scoped prompt.
Все мутации идут через CommandEnvelope (sync_apply path) через handlers в core/api/commands/handlers/{prompt_versions,agent_definitions}.py. Backdoor SQL запрещён (VISION инвариант 5).
3. Где это в Console¶
Раздел Prompts (/{project_id}/prompts для project scope; /admin/prompts для instance scope)¶
| Экран | Что на нём |
|---|---|
| Prompts list | таблица: prompt_key, scope (instance/project), latest active version, status (active/archived), origin (system/code/user), updated_at. Кнопка + New prompt (owner/admin). |
| Prompt detail | full content latest active version, placeholders (имя + required + description), description, history (все versions с version, status, published_by, published_at), actions: Publish new version / Archive / Set active (всё через canonical CommandEnvelope; кнопки видны только при prompt:manage). |
| Publish new version | форма: content (textarea, ≤ 32_000 chars), placeholders (parsed из {{ var }} syntax + ручная аннотация description / default), description (≤ 1_000 chars). После submit — POST publish_prompt_version → новая pver_<ulid> → старая active автоматически archive'ится. |
Раздел Agents (/{project_id}/agents для project scope; /admin/agents для instance scope)¶
| Экран | Что на нём |
|---|---|
| Agents list | таблица: agent_key, scope, latest active version, status, origin, model_profile, updated_at. Кнопка + New agent (owner/admin). |
| Agent detail | агент definition: prompt_key (+ link на pinned pver_*), output schema (output_fields / output_schema_jsonschema / output_schema_python — XOR), tool_keys, validators, retries (0-5), model_profile, instructions/input builder keys, deps_overrides. History версий. Actions: Publish new version / Archive (owner/admin). |
| Publish new version | форма AgentSpec → backend валидирует XOR output schema, scope contract (project ↔ project_id), input builder contract, deps_overrides safety, pin prompt_version_id (если задан) или резолвит latest active по prompt_key+scope. |
Console читает только через query API поверх read.prompt_versions / read.agent_definitions projections, никогда напрямую app.*.
4. Концепции (mental model)¶
Scope и shadowing¶
| Scope | Где живёт | Когда видится |
|---|---|---|
instance |
app.prompt_versions / app.agent_definitions с project_id IS NULL |
во всех проектах инстанса (если не перекрыт project-scope сущностью с тем же ключом) |
project |
то же, но project_id заполнен |
только в этом проекте; перекрывает instance-scope сущность с тем же prompt_key / agent_key |
Shadowing rule: при резолве prompt_key="email_classify" в project prj_X:
1. Сначала ищется project-scoped active (scope='project', project_id='prj_X', prompt_key='email_classify');
2. Если нет — instance-scoped active (scope='instance', project_id IS NULL, prompt_key='email_classify');
3. Если нет — LookupError (никаких code-fallback'ов — см. инвариант I-DOMAIN-AGENTSPEC-NO-CODE-FALLBACK-SEEDS, AGENTS-FINISH Bundle A).
Те же правила для AgentDefinition. Для output_schema_ref в model_call — silent fallback на instance scope запрещён, если ref задан как agent_definition:key:<key> в project workflow и project-scope row отсутствует, валидатор отвергает publish с кодом output_schema_ref_instance_scope_not_allowed (явная защита от тихой утечки instance схемы).
Pinning и replay-safety¶
- В коде workflow можно ссылаться на agent / prompt по key:
agent_ref="key:email_classifier",output_schema_ref="agent_definition:key:email_classifier". Это удобно для authoring. - На materialization boundary (
publish_definition/create_workflow/edit_workflow) walker резолвит key → конкретныйagdef_<ulid>и подменяет ссылку pinned формой:agent_ref="agent_definition:id:agdef_01H...". Та же логика дляoutput_schema_ref. - Runtime / replay принимает только pinned формы. Если в
workflow_definitions.definitionпосле publish лежитkey:*— это баг materialization (workflow runner отвергает fail-closed). - Это значит: запущенный полгода назад workflow run при replay/reauthor видит тот же AgentDefinition и тот же PromptVersion, даже если с тех пор вышло 20 новых версий.
Lifecycle prompts¶
publish_prompt_version → новая pver_<ulid> со status='active'
(любая предыдущая active с тем же (scope, project, key) → автоматически archived)
set_prompt_version_active(pver_X) → X.status = 'active'
(любая другая active с тем же ключом → archived)
enforced: X не должна быть pinned ни одной active AgentDefinition... wait, нет:
set_active не имеет pin-protection (новый publish заменяет старый active без проблем,
replay-pins на старую версию работают через id)
archive_prompt_version(pver_X) → X.status = 'archived'
pin-protection:
rejected if X is pinned by any active AgentDefinition
(нужно сначала опубликовать новую версию AgentDefinition без этого pin)
Lifecycle AgentDefinitions¶
publish_agent_definition → валидирует AgentSpec, резолвит prompt_version_id (key:latest → конкретный pver_*),
резолвит nested output_schema_refs (если AgentSpec их использует),
INSERT новой agdef_<ulid> со status='active',
старая active с тем же (scope, project, key) → archived,
outbox: agent_definition.published
archive_agent_definition → status='archived'
(вoркflow с pinned agdef_X продолжают работать;
новые publish_definition / create_workflow с ref на key:X → ошибка)
Output schema: три формы (XOR)¶
AgentSpec обязан иметь ровно одну из:
- output_fields: list[AgentOutputField] — bounded декларативный список полей; runtime материализует bounded object JSON Schema (output_fields_json_schema()). User-origin AgentSpec обычно использует это.
- output_schema_jsonschema: dict — произвольный JSON Schema (engineer-controlled);
- output_schema_python: str — fully-qualified class name (например core.agents.demo1_intent.IntentClassification). Только для origin='system'/'code' — user-origin AgentSpec не может ссылаться на Python class (security boundary: code-owned schema).
AgentSpec tool exposure rule (ARCHITECTURE-V6 §11)¶
AgentToolResolver (core/agents/runtime_registries.py) — gatekeeper между AgentDefinition и tool registry. Правило: direct tools, доступные агенту через AgentSpec runtime, ограничены:
1. side_effect_class="none" — никаких internal/external_low/external_high actions напрямую агенту;
2. executor_profile.allowed_tools (если задан);
3. project.enabled_tools allowlist.
Все три пересечения должны выполниться. Поэтому: если агенту нужно «отправить email», это не direct tool, а отдельный workflow step tool_call (или external_write) с policy gate, approval path, audit trail, idempotency. Agent — это решатель, а не исполнитель сторонних эффектов.
Новая категория «audited read tools» (когда хочется дать агенту GET-like internal action) требует отдельного public contract и не вводится implicit-правилом.
Adaptive model routing (UPGRADE_CHAIN)¶
AdaptiveModelRouter (core/ai/model_router.py) выбирает LLM-модель по сложности шага:
- complexity estimation (core/ai/complexity.py) — две оси: step_type (load_context простой, transform средний, model_call сложный...) + semantic_type (intent_classify простой, plan_generation сложный...). + signal adjustments (tokens, tool count, nested children, reasoning hints).
- Адаптивный режим (routing_mode='adaptive') выбирает дешёвую модель по дефолту, эскалирует на validation failure: haiku → sonnet → opus (UPGRADE_CHAIN). Все вызовы (включая failed) записываются в budget_ledger с selected_model, complexity_score, routing_mode.
- Фиксированный режим (routing_mode='fixed') использует WorkflowConfig.model_profile (наследует ProjectConfig.default_model_profile).
Инвариант I-DOMAIN-AGENTSPEC-ROUTING-UPGRADE-CHAIN (AGENTS-FINISH Bundle B) фиксирует chain в тестах; если кто-то поменяет порядок haiku→sonnet→opus, негативный тест упадёт.
Validator retry-with-feedback¶
Если LLM-ответ не прошёл validator (Pydantic, semantic), runtime делает retry с feedback (текст ошибки добавляется в conversation history → LLM получает шанс самоисправиться). Контролируется:
- AxonAgentSpec.retries (0-5);
- AxonAgentSpec.validator_refs — список валидаторов с фазой исполнения (execution_phase ∈ {'pydantic_output', 'post_acceptance'}).
- Фаза pydantic_output — fail вызывает retry (если retries > 0). Фаза post_acceptance — только логирует, не ретраит (post-fact validation).
Инвариант I-DOMAIN-AGENTSPEC-VALIDATOR-RETRY-FEEDBACK (AGENTS-FINISH Bundle C) гарантирует поведение тестами с offline FunctionModel-mock'ом.
Реактивный runtime resolver: RuntimePromptService¶
core/agents/prompt_runtime.py:RuntimePromptService — DB-backed resolver, который читает prompts из app.prompt_versions (через read.prompt_versions для query path). Используется agent runtime и model_call (когда prompt задан через registry, не inline). До PROMPT-SCOPE был in-memory allowlist в коде; теперь источник — БД, allowlist убран (AGENTS-FINISH Bundle A invariant).
5. Флоу: пошаговые сценарии¶
5.1 Создать prompt в проекте (owner/admin)¶
- Prompts → + New prompt.
- Ввести
prompt_key(snake_case, до 128 chars), scope =project(autopicked = текущий проект), content (текст с placeholders{{ var_name }}), description. - Заполнить metadata placeholders (имя, required, description, default) — параметр
placeholdersмодели. Default разрешён только если AgentSpec, который будет пинить этот prompt, не зависит от default (Stage 1 guard, см. §9). - Submit →
publish_prompt_version→ pre-accept secret scan (reject_secret_like_string— токены/ключи/API URLs отвергаются на boundary) → INSERTpver_<ulid>, старая active с тем же ключом archive'ится. Outboxprompt_version.published. Console обновляет проекциюread.prompt_versions.
5.2 Опубликовать AgentDefinition (owner/admin)¶
- Engineer пишет
AxonAgentSpecв коде (modules/agents/<key>.py) или admin заполняет форму в Console. - Console / CLI отправляет
publish_agent_definition(target_type='agent_definition',sync_apply, project_id или null для instance). - Handler в transaction:
- валидирует AgentSpec (output schema XOR, input builder contract, scope contract, deps_overrides safety, tool_keys uniqueness);
- резолвит prompt: если
prompt_version_idзадан → использует pinned; иначе резолвит latest active поprompt_key+ scope (shadowing project→instance); - резолвит nested
output_schema_refесли AgentSpec ссылается на другой AgentDefinition; - INSERT
agdef_<ulid>, старая active archive'ится. Outboxagent_definition.published.
5.3 Использовать AgentDefinition в workflow¶
- В коде workflow:
axon push→publish_definition→ materialization boundary walker подменяетagent_ref="key:email_classifier"→agent_ref="agent_definition:id:agdef_01H..."(concrete pin) внутри той же транзакции.- Runtime / replay читает pinned
agdef_*, резолвит prompt изRuntimePromptServiceпо pinnedpver_*, материализует output schema, выполняет. - Никаких локальных overrides. Если в
agent_configестьagent_refAND свойsystem_prompt/prompt_template_key/output_schema/validation_rules— publish-time валидатор отвергает как ambiguous configuration. Локальныйtoolsдопустим только как narrowing cap (не расширяет toolset AgentDefinition).
5.4 Использовать output schema через output_schema_ref¶
Когда хочется reusable schema контракт без запуска полноценного agent (просто model_call со structured output):
1. В step config:
Step(step_type="model_call", config={
"system_prompt": "You are an email classifier.",
"output_schema_ref": "agent_definition:key:email_classifier",
})
agdef_* (project scope, shadowing); silent fallback на instance scope запрещён (output_schema_ref_instance_scope_not_allowed).
3. Runtime берёт output_fields_json_schema() из pinned agdef и применяет к LLM-ответу. Step Runner владеет step semantics; AgentDefinition — только schema contract.
См. WORKFLOW-ARCHITECTURE.md §4 для polный список валидируемых boundary cases.
5.5 Обновить prompt (новая версия → ротация)¶
- Open Prompt detail → Publish new version.
- Изменить content / placeholders → submit
publish_prompt_version. - Новая
pver_*становится active, старая → archived автоматически. - AgentDefinitions, которые пинят старую версию, продолжают работать. Чтобы перевести их на новую версию, нужен новый
publish_agent_definition(либо явно с новымprompt_version_id, либо безprompt_version_id— handler резолвит latest active). - Архивировать старую prompt version: только если она не pinned ни одной active AgentDefinition (см. §7 pin-protection).
5.6 Дать агенту доступ к новому direct tool¶
- Tool должен иметь
side_effect_class="none"(если internal/external — agent через него не сможет, нужен workflow step). - Добавить
tool_keyвenabled_toolsпроекта (если ещё нет). - Опционально — добавить в
executor_profile.allowed_tools(если профиль ограничивает). - В новом
publish_agent_definitionуказатьtool_keys=[..., "new_tool_key"]. - После publish — agent runtime через
AgentToolResolverотдаст агенту новый tool (если все три гейта пройдены).
6. Справочник опций¶
6.1 PromptVersionSpec (core/models/prompt_specs.py)¶
| Поле | Тип | Ограничения |
|---|---|---|
prompt_key |
str | snake_case, ≤ MAX_PROMPT_KEY_LENGTH=128 |
scope_type |
'project' \| 'instance' |
project_id обязателен для project, NULL для instance |
content |
str | ≤ MAX_PROMPT_CONTENT_LENGTH=32_000 |
placeholders |
list[PromptPlaceholderSpec] |
≤ MAX_PLACEHOLDERS_PER_PROMPT=32, имена unique, имя ≤ 64 chars |
description |
str | None | ≤ MAX_DESCRIPTION_LENGTH=1_000 |
origin |
'system' \| 'code' \| 'user' |
system/code только для seed/migration actor |
PromptPlaceholderSpec: name, required: bool, description: str, default: str | None (≤ 1_000 chars). См. core/models/prompt_specs.py:63-156.
6.2 AxonAgentSpec (core/models/agent_specs.py)¶
| Поле | Тип | Описание |
|---|---|---|
agent_key |
str | regex (см. AGENT_KEY_RE) |
prompt_key |
str | reference на prompt (резолвится в pinned prompt_version_id на publish) |
prompt_version_id |
str | None | explicit pin (если задан, скипает резолв latest active); префикс pver_ |
output_fields / output_schema_jsonschema / output_schema_python |
XOR — ровно одно | output schema |
prompt_template_vars |
dict[name → AgentPromptTemplateVar] |
bindings для placeholders prompt'а |
input_template |
AgentInputTemplate | None |
required если input_builder_key='template' (default) |
tool_keys |
list[str] | unique; будут отфильтрованы AgentToolResolver по AgentSpec exposure rule |
validator_refs |
list[AgentValidatorRef] |
каждый с execution_phase ∈ {'pydantic_output', 'post_acceptance'} |
retries |
int 0-5 | retry с feedback при validator fail в фазе pydantic_output |
model_profile |
str | None | LiteLLM alias или ProjectConfig default; вместе с routing_mode='fixed' определяет model |
scope_type / project_id |
scope contract | project ⇔ project_id required; instance ⇔ project_id=None |
origin |
'system' \| 'code' \| 'user' |
output_schema_python запрещён для user-origin |
deps_overrides |
dict | None | только из SAFE_DEPS_OVERRIDE_KEYS; runtime-owned keys reject'ятся |
6.3 Команды (CommandEnvelope)¶
| Команда | path | target_type |
scope | Permission |
|---|---|---|---|---|
publish_prompt_version |
sync_apply |
prompt_version |
project XOR instance | prompt:manage |
archive_prompt_version |
sync_apply |
prompt_version |
project XOR instance | prompt:manage |
set_prompt_version_active |
sync_apply |
prompt_version |
project XOR instance | prompt:manage |
publish_agent_definition |
sync_apply |
agent_definition |
project XOR instance | agent_definition:manage |
archive_agent_definition |
sync_apply |
agent_definition |
project XOR instance | agent_definition:manage |
target_type prompt_version / agent_definition — в CONDITIONAL_SCOPE_TARGET_TYPES (allow project_id NULL для instance, required для project).
6.4 Read projections¶
read.prompt_versions(alembic 042) — list/detail/history для Console, redacted (content виден; secrets отрезались уже на pre-accept).read.agent_definitions(alembic 039+) — list/detail/version для Console.- Refreshers:
PromptVersionRefresher, agent definition refresher; подписаны наprompt_version.*/agent_definition.*outbox events.
7. Жизненный цикл и обслуживание¶
Seed prompts + agents. Migrations 040 (prompt seeds) и 041 (agent seeds) инициализируют instance-scoped built-in:
- prompts: канонические system prompts для triage / planner / reviewer / conversation / monitor + demo1.intent_classify + demo1.draft_response_v3;
- AgentDefinitions: triage / planner / reviewer / conversation (project-seed pattern — каждый проект получает свои 4 копии через ensure_project_seed_agent_definitions() внутри create_project transaction); monitor — instance-scoped (scope='instance', project_id IS NULL, origin='system').
Per-project seed. core/storage/repositories/agent_definition_seeds.py:PROJECT_AGENT_SEEDS — список template AgentDefinitions, которые create_project handler разворачивает в новый проект (с pinned pver_* на seed prompt versions). Это гарантирует, что новый проект «работает из коробки» без ручного publish.
Версионирование. Append-only. version int monotonically increases per (scope, project_id, agent_key). Status: ровно одна active per ключ, остальные archived. Archived row не удаляется (compliance + replay безопасность для pinned references).
Pin-protection (на archive prompt):
- archive_prompt_version(pver_X) → handler проверяет, что pver_X не pinned ни одной active AgentDefinition. Если pinned → reject с prompt_pinned_by_active_agents и списком agdef_*.
- Решение: сначала опубликовать новую версию AgentDefinition (без pin'а на pver_X), затем архивировать prompt.
Reactivation. set_prompt_version_active(pver_X) — позволяет вернуть конкретную старую версию в active. Pin-protection здесь не действует (новый active заменяет старый без проблем; pinned references на старую версию продолжают работать через id).
Observability.
- Langfuse traces: каждый LLM-вызов → trace со prompt_version_id, agent_definition_id, selected_model, complexity_score, routing_mode, validator outcomes;
- budget_ledger rows для каждого LLM-вызова (включая failed validation retries);
- Console / API возвращает degraded / stale маркер для read projections если refresher отстал.
8. Траблшутинг¶
| Симптом | Причина | Что делать |
|---|---|---|
publish_prompt_version → 422 «secret-like string in content» |
pre-accept secret scan нашёл токен / API key / credential URL в prompt content | Убрать секреты из текста (а заодно из draft — secrets никогда не должны попадать в prompts) |
archive_prompt_version → 409 prompt_pinned_by_active_agents |
Версия pinned одной или несколькими active AgentDefinition (replay-safety) | Опубликовать новую AgentDefinition без pin'а на эту prompt version, затем повторить archive |
publish_agent_definition → 422 «output_fields XOR output_schema_jsonschema XOR output_schema_python (exactly one required)» |
Указано 0 или 2+ output schema форм | Указать ровно одну |
publish_agent_definition → 422 «output_schema_python is code-owned and forbidden for user-origin specs» |
user-origin AgentSpec ссылается на Python class | Использовать output_fields или output_schema_jsonschema |
publish_agent_definition → 422 «Unsafe deps_overrides keys: [...]» |
Попытка переопределить runtime-owned dep или unknown key | Использовать только ключи из SAFE_DEPS_OVERRIDE_KEYS |
publish_agent_definition → 422 «user-origin AgentSpec must use input_builder_key='template'» |
user-origin ссылается на code-only input builder | Использовать input_builder_key='template' + input_template (или сделать origin='code' если есть permission) |
publish_definition (workflow) → output_schema_ref_not_resolvable / output_schema_ref_instance_scope_not_allowed |
Workflow в project_X ссылается на AgentDefinition по key:*, project-scope row отсутствует, silent fallback на instance запрещён |
Опубликовать AgentDefinition в project_X с тем же key, либо явно указать agent_definition:id:agdef_* если хочешь instance |
Workflow runner → agent_definition_not_found |
После start workflow AgentDefinition был archived (run hold pinned ref на archived row — это норма, но в случае key:* — пытается резолвить latest active, которой нет) | Run видит pinned id, не key — обновить ref в новой версии workflow definition |
| Agent ignores tool | Tool либо не side_effect_class="none", либо не в enabled_tools проекта, либо не в executor_profile.allowed_tools |
См. §4 exposure rule, исправить уровень |
| Operator хочет audited read tool для агента | Это требует отдельный public contract (не «давайте дадим internal action») | Либо переделать в tool_call workflow step с policy gate, либо открыть отдельный backlog для «audited read tools» public contract |
| Adaptive routing постоянно эскалирует до opus | Сложность шага оценена как очень высокая, либо validator постоянно fail'ит и заставляет escalate | Проверить Langfuse: что валится валидатор? Уточнить prompt / schema / validator rules; либо force routing_mode='fixed' с конкретным model_profile |
Run failed → UnexpectedModelBehavior после retries=N попыток |
LLM не смог удовлетворить validator после ретраев с feedback | Увеличить retries (≤ 5), смягчить validator, или поменять model_profile / agent_ref |
9. Ограничения и инварианты¶
- No code-owned fallback seeds (
I-DOMAIN-AGENTSPEC-NO-CODE-FALLBACK-SEEDS, AGENTS-FINISH Bundle A). Built-in agents / prompts seed'ятся только через migrations 040-041 (system actor). In-memory dictbuilt_in_specs.pyудалён;AgentSpecResolverподнимаетLookupErrorесли row нет;AgentPromptResolverне имеетfallback:*consumer. - Adaptive routing upgrade chain (
I-DOMAIN-AGENTSPEC-ROUTING-UPGRADE-CHAIN, AGENTS-FINISH Bundle B): порядок haiku → sonnet → opus фиксирован; перестановка ломает тесты. - Validator retry-with-feedback (
I-DOMAIN-AGENTSPEC-VALIDATOR-RETRY-FEEDBACK, AGENTS-FINISH Bundle C): фазаpydantic_outputретраит с feedback (≤ retries), фазаpost_acceptanceтолько логирует. - Pinning обязателен для runtime / replay.
agent_ref="key:*"иoutput_schema_ref="agent_definition:key:*"допустимы только до materialization. После — pinned id (agdef_*/pver_*). Любойkey:*в runtime payload → fail-closed. - AgentSpec tool exposure rule. Direct agent tools — только
side_effect_class="none"∩ project allowlist ∩ executor profile.internal/external_*actions — это workflow steps (tool_call/external_write), не direct tools. - Output schema python class — только для system/code origin. User-origin не может ссылаться на Python class (security boundary).
- Secrets никогда в prompts.
core/security/credential_scan.reject_secret_like_stringотбивает на pre-accept. - Scope contract. project ⇔ project_id обязателен; instance ⇔ project_id=None. Cross-project leak запрещён на DB level (composite checks).
- Shadowing project→instance — explicit-only для
output_schema_ref. Silent fallback на instance запрещён; нужно либо опубликовать project-scope AgentDefinition, либо явно использоватьagent_definition:id:*(что pinned, не нужно shadowing). - AI не обязателен ни для одного уровня. Workflow без агентов — first-class citizen (Степень 1: step-based, 55% реальных задач). AI добавляется по необходимости (VISION «лестница сложности»).
- Объяснимость (VISION инвариант 9). Каждое автоматическое решение объяснимо: для AI — до уровня features/circuits/attribution graphs (interpretability — V6.1+ backlog).
10. Связанные мануалы и каноны¶
- Workflows.md —
model_call/agent_config/agent_ref/output_schema_refв step config, Publish Flow. - Connectors-Credentials.md — connector tools и почему
internal/external_*— это steps, не direct agent tools. - Approvals.md — approval path для side effects, которые агент может запросить (но не выполнить напрямую).
- Budgets-And-Cost.md —
budget_ledgerзаписи для LLM-вызовов, model routing cost impact. - Security-And-Audit.md — audit trail для
prompt_version.*/agent_definition.*events, secrets scanning. Model-Routing-And-Budgets.md(planned) — детально про adaptive routing, complexity estimation, fallback chain.- Каноны:
ARCHITECTURE-V6.md§10 (AI-агенты), §11 (AgentSpec tool exposure rule), Appendix A (commands);WORKFLOW-ARCHITECTURE.md§4 (output_schema_refpinning);CONCEPT-AGENTSPEC.md,CONCEPT-PROMPT-SCOPE.md;core/models/{agent_specs,prompt_specs}.py;core/agents/{spec_resolver,runtime,runtime_registries,prompt_runtime,model_router}.py; alembic 039-042;tests/invariant_registry.yaml(три инварианта AGENTS-FINISH).