Глава 17. Слой политик и каталог возможностей¶
1. Почему без слоя политик эталонный рантайм остается слишком наивным¶
Даже если у тебя уже есть аккуратный runtime loop, этого все равно недостаточно. Без явного policy layer система остается слишком доверчивой:
- нельзя надежно отличить допустимый run от недопустимого;
- tool calls трудно контролировать одинаково;
- memory writes живут на отдельных договоренностях;
- product-specific ограничения быстро просачиваются в orchestration code.
Поэтому следующий обязательный слой reference implementation это policy layer.
Его задача не в том, чтобы “тормозить систему”. Его задача в том, чтобы решения про доступ, риск и допустимость не были размазаны по случайным if в коде.
2. Policy layer должен отвечать на маленькие и понятные вопросы¶
Слабый policy layer пытается быть “умным мозгом системы”. Сильный policy layer делает наоборот: он решает ограниченный набор ясных вопросов.
Например:
- можно ли запускать этот run вообще;
- можно ли читать этот контекст;
- можно ли вызывать этот capability;
- нужен ли approval;
- можно ли записывать это в memory;
- можно ли вернуть этот результат наружу.
Когда эти вопросы оформлены явно, runtime становится объяснимее, а изменения в guardrails перестают быть хаотичными.
3. Capability catalog нужен не как реестр имен, а как контрактный слой¶
Очень легко скатиться к каталогу, который просто хранит список доступных tools. Но хороший catalog делает больше:
- описывает capability contract;
- хранит risk profile;
- указывает transport и execution mode;
- задает idempotency expectations;
- фиксирует ownership и lifecycle.
То есть capability catalog это не “inventory для удобства”, а центральная точка управления способностями платформы.
Слой политик и каталог возможностей вместе образуют договорное ядро эталонной реализации
flowchart LR
A["Run request"] --> B["Runtime orchestrator"]
B --> C["Policy layer"]
B --> D["Capability catalog"]
C --> E["Allow / deny / approve"]
D --> F["Capability contract"]
E --> G["Execution layer"]
F --> G 4. Что полезно хранить в capability catalog¶
Практически useful набор полей обычно такой:
- capability name;
- owner;
- mode: read / write / high_risk;
- transport: mcp / gateway / sandboxed_exec;
- input schema;
- output shape;
- approval requirement;
- idempotency requirement;
- timeout and retry defaults.
С таким контрактом runtime уже может вести себя предсказуемо, а не подстраиваться под каждый capability ad hoc.
5. Policy decision должен быть объектом, а не просто bool¶
Очень полезная инженерная привычка: policy decision не должен сводиться к True/False.
Чаще полезнее возвращать что-то вроде:
allowdenyapproval_requiredsanitize_and_continueescalate
И дополнительно:
- reason code;
- policy id;
- risk class;
- optional constraints.
Это резко повышает explainability и делает telemetry намного полезнее.
6. Пример policy contract¶
Ниже очень простой, но практичный шаблон:
policy:
run_precheck:
require_tenant: true
deny_if_principal_missing: true
capabilities:
search_docs:
decision: allow
create_ticket:
decision: approval_required
approver: manager
run_shell:
decision: deny
memory_write:
allow_kinds:
- validated_fact
- session_summary
Его сила не в полноте, а в явности. Ты можешь спорить с конкретным правилом и понимать, где оно применяется.
7. Пример capability catalog contract¶
Catalog полезно мыслить примерно так:
capabilities:
search_docs:
owner: knowledge_platform
mode: read
transport: mcp
timeout_seconds: 5
approval: none
create_ticket:
owner: support_platform
mode: write
transport: gateway
timeout_seconds: 15
approval: manager
idempotency_key_required: true
run_shell:
owner: platform_runtime
mode: high_risk
transport: sandboxed_exec
timeout_seconds: 10
approval: always
Такой catalog уже задает operational semantics, а не просто список имен.
8. Простой кодовый каркас policy decision¶
Ниже каркас, который показывает, что runtime получает не просто разрешение, а структурированное решение.
from dataclasses import dataclass
@dataclass
class PolicyDecision:
action: str
reason: str
policy_id: str
def evaluate_capability(name: str) -> PolicyDecision:
if name == "search_docs":
return PolicyDecision(action="allow", reason="low_risk_read", policy_id="cap_001")
if name == "create_ticket":
return PolicyDecision(action="approval_required", reason="write_action", policy_id="cap_014")
return PolicyDecision(action="deny", reason="unsupported_capability", policy_id="cap_999")
Даже такой простой код уже задает правильную форму для telemetry, UI approval flows и расследований.
9. Простой кодовый каркас capability lookup¶
И еще один практичный кусок: runtime не должен знать capability details напрямую, он должен вытаскивать их из catalog.
from dataclasses import dataclass
@dataclass
class CapabilitySpec:
name: str
mode: str
transport: str
timeout_seconds: int
def get_capability(name: str) -> CapabilitySpec | None:
registry = {
"search_docs": CapabilitySpec("search_docs", "read", "mcp", 5),
"create_ticket": CapabilitySpec("create_ticket", "write", "gateway", 15),
}
return registry.get(name)
Это тоже выглядит скучно. И это отлично. Catalog layer как раз и должен быть скучным, стабильным и обозримым.
10. Где policy и catalog чаще всего ломаются¶
Проблемы здесь очень типовые:
- policy rules размазаны по runtime;
- capability contract неполный;
- ownership capability неясен;
- approval logic вшита прямо в orchestration;
- memory policy и execution policy живут как будто отдельно;
- catalog и real adapters расходятся по поведению.
Когда это происходит, reference implementation перестает быть reference и снова превращается в связку договоренностей.
11. Практический чеклист¶
Если хочешь быстро проверить этот слой, пройди по вопросам:
- Есть ли у тебя отдельный policy layer, а не набор
ifпо коду? - Возвращает ли policy structured decision?
- Есть ли единый capability catalog?
- Есть ли у capabilities owner, transport и risk semantics?
- Использует ли runtime catalog, а не прямые вызовы?
- Видны ли policy decisions в telemetry?
Если на несколько вопросов подряд ответ “нет”, skeleton у тебя уже есть, но contract core пока еще не собран.
12. Что читать дальше¶
Следующий логичный шаг в reference implementation: собрать production rollout checklist, чтобы из blueprint и contract core выйти в практический go-live framework.