Appearance
控制平面、执行平面与 Agent 协作模式
前置:Agent、Workflow 与 Harness:控制权、执行权与系统边界
核心问题:为什么“模型决定做什么”和“系统真正执行什么”必须分层,Manager、Handoff、Agent-as-Tool 又分别改变了哪一种控制权?
把“决定”和“执行”分开
先建立两个平面:Control Plane 决定系统准备怎么运行,Execution Plane 把已经允许的动作变成真实结果。
1. Control Plane
Control Plane 负责“做什么、由谁做、能不能做”的控制信息,例如:
- 选择哪个 Agent / Model;
- 当前允许暴露哪些 Tool;
- budget、deadline、approval policy;
- 是否 handoff;
- Run 现在应该继续、等待还是终止。
这些决定可以参考模型建议,但最终必须落成 Runtime 能验证的 policy / state。
2. Execution Plane
Execution Plane 负责真正产生外部效果,例如:
- 调 Model;
- 执行 shell / HTTP / DB / file Tool;
- 与 sandbox / MCP / browser 交互;
- 返回原始结果。
Execution Plane 不应该因为模型文本里写着“已经授权”就越过 Control Plane。
3. 为什么必须分开
假设模型看见一个 delete_file Tool,并输出:
text
请删除 /workspace/config.yaml正确链路是:
text
Model proposal
→ Control/Runtime 检查 capability + policy
→ 允许后才进入 Execution Plane
→ Tool 执行
→ ObservationTool 可见性不是授权;模型提出动作也不是执行许可。
4. Single Agent 先作为默认心智模型
先假设只有一个 active agent:
text
User
→ Active Agent / Model
→ Runtime
→ Tools
→ Observation
→ Active Agent / Model后面学到 Manager、Agent-as-Tool、Handoff 时,只需要继续问一个问题:top-level control ownership 有没有变化?
- Agent-as-Tool:通常没有,Manager 仍拥有顶层控制权;
- Handoff:active agent ownership 发生转移。
这里先理解两种模式对 top-level control ownership 的影响,完整协议、Context Policy 与 Multi-Agent failure handling 放在 Advanced。
Advanced / Canonical 深入内容
1. 为什么要把“做决定”和“真正执行”拆开
一个 Agent 系统越接近真实生产环境,就越不能把“模型生成了一个动作”理解成“系统已经执行了这个动作”。
假设模型提出:
json
{
"action": "deploy",
"environment": "production"
}这条输出最多只能证明:
模型希望部署。
它不能证明:
- 当前用户有生产权限;
- 目标环境允许变更;
- 变更窗口已经开放;
- deploy command 已经执行;
- rollout 成功;
- 失败后已经回滚。
因此系统必须至少存在两类职责:
text
决定“应该做什么”
↓
验证、调度、真正执行“允许做的事”这条边界可以用 Control Plane / Execution Plane 描述。Anthropic Managed Agents 的 Brain / Hands / Session 解耦,以及常见的 Single Agent、Manager、Handoff、Agent-as-Tool 协作模式,提供了进一步的工程参照。
需要先说明:这些术语没有一套跨所有框架完全统一的行业定义。本文采用的是面向 Shadow Harness 的工程定义,并用 Anthropic、OpenAI 当前实现作为参考,而不是把某个 SDK 的对象模型当成标准。
2. Mental Model:控制权、能力与连续性是三个不同问题
先看一张总图:
text
Control Plane
┌────────────────────────────────┐
│ routing / policy / budget │
User Goal ───▶│ plan / approval / identity │
│ agent selection / scheduling │
└──────────────┬─────────────────┘
│ authorized intent
▼
Execution Plane
┌────────────────────────────────┐
│ model call / shell / file │
│ HTTP / DB / browser / sandbox │
│ real side effects │
└──────────────┬─────────────────┘
│ observation
▼
State / Trace / Artifacts如果换成 Anthropic Managed Agents 的表达,可以得到另一种有用视角:
text
Brain = 推理与决策
Hands = 可产生真实结果/副作用的执行环境
Session = 跨调用持续存在、可被查询的运行连续性
Harness = 组织 brain 调用、context 与 tool routing 的工程层这两个视角不是一一对应:
Brain不等于整个 Control Plane;Hands很接近 Execution Plane 的一部分,但执行面还可能包含模型调用、网络服务等;Session是连续性边界,不是控制面或执行面的同义词。
理解它们的目的,是让系统各层可以独立替换、独立扩容、独立隔离、独立恢复。
3. 核心机制
3.1 Control Plane:决定“如何运行”
Control Plane 保存和执行的是控制决策,而不是具体业务 I/O。
典型职责包括:
text
任务路由
Agent / Model 选择
Policy
Permission decision
Approval requirement
Budget
Deadline
Retry policy
Scheduling
Capability exposure例如:
python
@dataclass(frozen=True)
class ExecutionPolicy:
max_turns: int
max_tool_concurrency: int
require_approval_for: frozenset[str]
allowed_namespaces: frozenset[str]这个对象的 owner 应该是 Runtime / Policy subsystem,而不是模型。
模型可以说:
“我需要调用
prod.deploy。”
Control Plane 则决定:
text
当前 Run 是否暴露这个 capability?
当前 identity 能否使用?
是否必须等待审批?
是否还有 cost/deadline budget?生命周期
Control Plane 的状态通常跨多个 Tool Call,甚至跨整个 Run:
text
Run created
↓
resolve identity / policy
↓
expose capabilities
↓
model proposes action
↓
policy re-check
↓
schedule
↓
repeat until terminalPolicy 还应具备版本,方便追踪:
text
为什么昨天允许,今天拒绝?如果无法回答采用了哪个 policy/version,审计就不完整。
3.2 Execution Plane:把允许的意图变成真实 Observation
Execution Plane 的职责是实际执行:
- shell command;
- filesystem read/write;
- HTTP call;
- DB query/transaction;
- browser/computer action;
- external API;
- sandbox process。
它的输入不应该是任意自然语言,而应该是经过验证的 execution request:
python
@dataclass(frozen=True)
class ToolExecutionRequest:
run_id: str
tool_call_id: str
tool_name: str
arguments: dict
deadline_at: datetime
identity_ref: str输出则应该是可记录的事实:
python
@dataclass(frozen=True)
class ToolExecutionResult:
tool_call_id: str
status: str
output_ref: str | None
error_code: str | None
started_at: datetime
ended_at: datetime为什么要隔离
执行面是 blast radius 最大的区域。
一个 Search Tool 出错,可能只是返回错误答案;一个 Shell / Database / Deployment Tool 出错,可能修改真实系统。
因此执行面需要:
text
filesystem boundary
network boundary
credential boundary
resource limit
timeout
process isolation
audit不能只依靠 Prompt:
“请不要执行危险操作。”
3.3 Brain / Hands / Session:为什么要进一步解耦
Anthropic 在 2026 年 Managed Agents 的工程分享里描述了一个重要演化:早期把 harness、模型调用和执行环境绑得较紧,后来逐步把“brain”和“hands”拆开,并把 session 作为 durable interface。
这个拆分解决的不只是代码洁癖,而是三个实际问题。
Brain:推理能力可以替换
Brain 可以是:
text
Model A
Model B
different model version
different reasoning policy如果 Brain 与 workspace/container 强绑定,每换模型都可能需要重新准备环境。
解耦后:
text
existing session/workspace
↑
new brain ────────┘同一份工作状态可以被新的推理实例继续使用。
Hands:执行环境可以独立存在
Hands 可能持有:
text
repo checkout
generated files
running processes
build cache
local artifacts这些东西的生命周期不应天然等同于一次 inference。
例如模型 context reset,不代表仓库应该重新 clone。
Session:连续性不等于模型上下文
Session 保存的是一个可以持续查询、恢复或继续的运行边界。
它可以包含:
- messages / events;
- references;
- workspace identity;
- progress state。
但模型的当前 Context 只是 Session 中被选择出来的一小部分。
因此:
text
Session durable
≠
entire Session always injected into modelContextManager 仍然需要做 selection / compaction。
3.4 Single Agent:最简单的控制权模型
Single Agent 的优点是只有一个主要 decision owner:
text
User
↓
Agent A
├─ Tool 1
├─ Tool 2
└─ Final适合:
- 单一领域;
- tool surface 可控;
- 不需要强 context isolation;
- 任务拆解可以在一个模型上下文完成。
它的价值常被低估。很多任务在引入 multi-agent 之前,首先应该建立 Single Agent baseline。
如果 Single Agent 已经达到高成功率,多 Agent 只会增加:
text
handoff failure
context duplication
token
latency
trace complexity3.5 Manager / Agent-as-Tool:总控保留对话所有权
OpenAI Agents SDK 当前明确区分一种 manager-style orchestration:
Manager Agent 把 specialist agent 暴露成 tool 调用,并继续保留用户对话与最终答案的控制权。
执行结构:
text
User
↓
Manager
├─ call ResearchAgent as tool
│ └─ result
├─ call CodeAgent as tool
│ └─ result
└─ Manager synthesizes final answer这里的关键是:
text
specialist returns bounded result
manager still owns top-level conversation这很适合:
- 需要统一最终格式;
- 多个专家结果需要融合;
- 子任务边界清晰;
- 希望共享 top-level policy/guardrail。
但 Manager 可能成为 bottleneck:所有结果都回到它的 Context,Context 压力和协调成本会集中到一个地方。
3.6 Handoff:把 active agent 的控制权转移给专家
Handoff 的语义不同。
OpenAI Agents SDK 当前的 handoff 模式中,triage agent 可以把对话转给 specialist;specialist 成为后续 active agent。
可以简化理解为:
text
User
↓
Triage Agent
↓ handoff
Refund Agent
↓
continues interaction它适合:
- 用户已经进入明确领域;
- 专家应该直接继续对话;
- 希望专家拥有自己的 instructions/context focus;
- 不需要 manager 每轮重新转述。
Handoff 的关键风险是:
text
转移了什么 context?
哪些 policy 仍然继承?
谁拥有 final output?
如何 trace active_agent 的变化?所以 handoff 必须成为 Runtime 中的显式事件,而不是只在自然语言里说:
“现在请另一个 Agent 接手。”
4. 如何选择:控制平面、Manager、Handoff 与 Agent-as-Tool
这些模式不是成熟度等级,而是不同控制权结构。
4.1 Manager vs Handoff
优先 Manager / Agent-as-Tool,当:
- top-level agent 必须统一最终答案;
- specialist 是有界子任务;
- specialist 不需要直接面对用户;
- 需要汇总多个专家输出。
优先 Handoff,当:
- 领域已经明确切换;
- specialist 应继续后续交互;
- 让 manager 中转反而浪费 token;
- specialist 需要更独立的 context/instructions。
4.2 Code Orchestration vs LLM Orchestration
OpenAI 当前文档也明确区分:
text
LLM orchestration
模型决定下一 agent / tool
Code orchestration
代码决定 agent 执行顺序二者可以混用。
例如:
text
代码先进行 deterministic authentication
↓
模型判断 support category
↓
代码把高风险退款统一送 approval
↓
handoff 给对应 specialist这通常比“所有 routing 都交给模型”更可靠。
4.3 什么时候不要 Multi-Agent
如果你的目标只是:
text
search → summarize增加 Manager + Researcher + Critic 不一定有意义。
必须先问:
context isolation、并行、专长差异或 ownership 转移,是否真的解决了单 Agent 的一个已测量问题?
没有 Eval 证据,就不要因为“看起来更 Agentic”而增加系统拓扑。
5. 真实执行案例:代码修复任务如何把 Brain、Hands 与控制权拆开
用户要求:
“修复仓库中的登录问题,修改完运行测试;如果需要修改部署配置,先让我批准。”
Step 1:Control Plane 创建 Run Policy
text
allowed:
read_file
search_code
apply_patch
run_test
approval_required:
change_deployment_config此时还没有任何真实文件被修改。
Step 2:Brain 选择调查动作
模型提出:
json
{
"tool": "search_code",
"arguments": {"query": "login token"}
}这是 decision,不是执行事实。
Step 3:Execution Plane 执行搜索
Runtime 校验 Tool 和参数后,把请求交给 workspace。
结果:
text
auth/service.py:82该 Observation 被写入 Trace。
Step 4:Brain 决定修改
模型读取代码后调用:
text
apply_patchExecution Plane 写文件,返回:
text
patch_status = APPLIED
artifact_ref = workspace://diff/17只有现在才能说“patch 已应用”。
Step 5:测试失败,Brain 改变策略
text
pytest exit_code = 1模型根据 stderr 决定继续修改,而不是 Runtime 自己“理解业务”。
Step 6:模型尝试修改 deployment config
Control Plane 识别:
text
risk = HIGHRuntime 不执行,转为:
text
WAITING_APPROVALStep 7:进程重启
Brain context 消失,但:
- workspace 仍包含 patch;
- Session/RunState 保存 pending approval;
- Trace 保存之前的 Tool Execution;
- artifact ref 仍可重新读取。
新的 Brain 实例恢复后,不需要重新 clone 仓库,也不应该重复 apply 已成功的 patch。
Step 8:用户拒绝部署配置修改
Runtime 记录:
text
approval = REJECTED模型获得 Observation 后选择无需部署配置的替代方案。
完成证据
任务完成不能只靠模型说“修好了”,至少应存在:
text
workspace diff
test exit_code = 0
RunState = SUCCEEDED
trace shows no unauthorized deployment edit6. 最小实现:把 Control 与 Execution Contract 拆开
python
from dataclasses import dataclass
from typing import Protocol
@dataclass(frozen=True)
class ActionIntent:
name: str
arguments: dict
@dataclass(frozen=True)
class AuthorizedAction:
name: str
arguments: dict
identity_ref: str
class PolicyEngine(Protocol):
async def authorize(
self,
intent: ActionIntent,
run_context,
) -> AuthorizedAction:
...
class Executor(Protocol):
async def execute(
self,
action: AuthorizedAction,
):
...Runtime:
python
intent = await model.decide(context)
action = await policy.authorize(
intent,
run_context,
)
result = await executor.execute(action)
state.apply(result)
trace.record(result)这里最值得注意的是:
text
ActionIntent和:
text
AuthorizedAction不是同一个类型。
这样可以从类型层面提醒开发者:
模型请求并不天然拥有执行资格。
7. Shadow Harness 中如何落地
建议至少拆成:
text
orchestration/
├── router.py
├── handoff.py
└── agent_tool.py
policy/
├── capability_policy.py
├── approval_policy.py
└── budget_policy.py
execution/
├── executor.py
└── sandbox_adapter.py
runtime/
├── runner.py
└── active_agent.py
state/
├── run_state.py
└── session_store.py关键 domain events:
text
AGENT_SELECTED
HANDOFF_REQUESTED
HANDOFF_COMPLETED
TOOL_REQUESTED
ACTION_AUTHORIZED
APPROVAL_REQUIRED
TOOL_STARTED
TOOL_SUCCEEDED
TOOL_FAILED这样 Trace 才能回答:
是模型选错了 Agent,还是 Policy 拒绝了动作,还是 Executor 真正失败?
8. Production Engineering:真正需要守住的边界
8.1 Identity 不要下沉成模型文本
不要把 credential 放进 Prompt:
text
API key = ...Execution Plane 应通过 credential reference / secret broker 获取最小权限凭证。
8.2 Policy 必须在执行前重新检查
即使 Tool 在 Context 中被暴露,也不意味着一定允许执行。
原因包括:
- user identity 变化;
- resource state 变化;
- high-risk arguments;
- budget 变化。
因此:
text
tool visible
≠
tool call authorized8.3 Handoff 要有 Context Policy
不能默认把所有历史、secret、tool result 全传给下一个 Agent。
需要决定:
text
what history?
what artifacts?
what tools?
what user identity?
what policy?8.4 Multi-Agent 必须有成本与失败预算
每增加一个 Agent 调用,都增加:
- model latency;
- token;
- failure probability;
- trace depth。
所以 Multi-Agent 是架构选择,不是免费抽象。
9. Failure Modes
9.1 模型可以绕过 Control Plane 直接调用执行器
错误表现。 Agent code 持有 shell/database client,模型产生 Tool Call 后直接执行。
为什么危险。 Permission、approval、budget 和 audit 都可以被绕过,执行面成为隐式后门。
修复方向。 所有有副作用 Action 必须经过统一 Policy/Runtime contract,再进入 Executor。
验证方式。 Fake Model 请求未授权 prod.deploy,断言 Executor 调用次数为 0,Trace 中存在明确拒绝事件。
9.2 把 Tool 可见性当成执行授权
错误表现。 只要某 Tool schema 被提供给模型,就认为当前用户一定可执行。
为什么危险。 Tool exposure 只是 capability discovery;实际 args、resource 和 identity 仍可能触发更严格权限。
修复方向。 暴露阶段和执行阶段分别做 capability filter 与 authorization。
验证方式。 允许看到 delete_file,但对 protected path 请求必须在 execution authorization 阶段拒绝。
9.3 Handoff 后丢失或泄露 Context
错误表现。 specialist 接手后缺少必要任务事实,或者拿到了不应看到的 secret/tool result。
为什么危险。 前者导致任务质量下降,后者扩大数据泄露范围。
修复方向。 为 Handoff 定义显式 Context Transfer Policy,只传目标、必要历史、artifact refs 和允许的 capabilities。
验证方式。 构造含敏感字段的上游 Context,断言 specialist 输入只包含 allowlist 字段。
9.4 Manager 成为无限 Context 汇聚点
错误表现。 所有 specialist 都返回完整日志/文档,Manager Context 越来越大。
为什么危险。 token、latency 和 context pollution 快速上升,最终 manager 反而无法稳定整合结果。
修复方向。 specialist 返回结构化结果 + artifact reference;Manager 只按需读取细节。
验证方式。 10 个 specialist 并行执行,断言 manager 输入 token 增长符合预算而不是与原始输出总量线性增长。
9.5 Brain 与 Hands 生命周期强绑定
错误表现。 每次模型重启/context reset 都重新创建 workspace、重新 clone repo。
为什么危险。 TTFT、成本增加,长任务进度丢失,恢复行为变成重复工作。
修复方向。 为 workspace/session 建独立 durable identity,让 Brain 可以重新连接已有 Hands。
验证方式。 模拟 Brain crash,重新创建 model client,断言原 workspace diff 和 artifacts 仍可读取且没有重复初始化。
10. 如何验证:Testing 与 Evaluation
10.1 Deterministic Test:未授权动作绝不进入 Executor
Scripted Model:
text
request prod.deployPolicy:
text
deny断言:
text
executor.calls == 0
run.status != SUCCEEDED because of fake execution
trace contains ACTION_DENIED10.2 Deterministic Test:Handoff 真正改变 active agent
输入触发 refund:
text
triage → handoff refund_agent断言:
text
active_agent == refund_agent
next model request uses refund instructions而不是只检查最终回答里出现“refund”。
10.3 Deterministic Test:Agent-as-Tool 不夺走 top-level ownership
Manager 调用 specialist 后:
text
specialist returns ToolResult断言下一 top-level turn 仍属于 manager。
10.4 Recovery Test:Brain 重启不重建 Hands
保存 workspace/session ref,销毁 model client,再恢复。
断言:
- workspace id 不变; -已有文件修改仍存在; -已成功 Tool Execution 不重复。
10.5 Evaluation:什么时候 Multi-Agent 真有收益
对同一 Eval Set 比较:
text
Single Agent
Manager + specialists
Handoff specialists记录:
- task success;
- tool/agent selection accuracy;
- token;
- latency;
- unnecessary handoffs;
- recovery failure。
只有语义任务质量这部分需要真实模型 Eval。
11. 常见问题(Q&A)
Q1:Control Plane 和 Runtime 是同一个概念吗?
不是必然。
Control Plane 是一种职责划分:它关心 policy、routing、budget、approval、scheduling 等“如何运行”的决策。Runtime 是推进一次 Run 的执行内核。
在 Shadow Harness 中,Runtime 会承载部分 Control Plane 能力,但也会驱动 Execution Plane。两者存在交集,不应该机械画成两个完全独立进程。
Q2:Brain / Hands / Session 和 Control / Execution Plane 能直接一一对应吗?
不能。
Brain 主要是推理决策;Hands 主要是执行环境;Session 是连续性边界。Control Plane 则还包括 Policy、routing、identity、budget 等不属于 Brain 的确定性逻辑。
这些模型的价值在于观察不同维度,而不是做名词替换。
Q3:Manager 和 Handoff 最关键的区别是什么?
谁保留 top-level conversation ownership。
Manager/Agent-as-Tool 中,specialist 返回一个 bounded result,Manager 继续整合并回答。
Handoff 中,active agent 发生切换,specialist 接管后续对话/turn。
Q4:Agent-as-Tool 算不算 Multi-Agent?
从系统组成看,它确实调用了多个 Agent;但设计时更重要的是控制权结构,而不是数量。
Agent-as-Tool 的 specialist 更像一个有语义能力的子程序:有明确 input/output contract,完成后把结果交还 Manager。
Q5:为什么 Tool 已经展示给模型,执行时还要做一次权限检查?
因为“模型知道有这个能力”和“当前这次具体调用被授权”是两件事。
参数、资源、用户身份、风险等级都可能改变最终权限判断。只在 Tool exposure 时过滤一次,不能替代 execution-time authorization。
Q6:为什么要让 workspace/session 比 Brain 活得更久?
长任务中模型 Context 可能因为压缩、重启、升级而更换,但真实工作产物——文件、patch、build cache、artifacts——仍然需要延续。
把生命周期分开,才能让新的 Brain 接管已有工作,而不是每次从零开始。
Q7:什么时候 Handoff 比 Agent-as-Tool 更合适?
当 specialist 不只是完成一个 bounded subtask,而是应该真正接管后续用户交互时。
例如客服 triage 后进入退款专家,后面几轮都围绕退款处理,Handoff 通常比 Manager 每轮中转更自然。
Q8:Multi-Agent 是否天然比 Single Agent 强?
不是。
Multi-Agent 增加 coordination、context transfer、token、latency 和 failure surface。只有当专业隔离、并行、context isolation 或 ownership transfer 带来可测量收益时才值得引入。
12. Control Ownership:四个稳定判断
text
1. Model proposal ≠ execution authorization
2. Control decision ≠ real side effect
3. Brain lifecycle ≠ workspace/session lifecycle
4. Multi-Agent 的本质问题是 control ownership,而不是 Agent 数量如果把它们放回 Shadow Harness:
text
Model / Agent
↓ proposes
Control Plane / Runtime Policy
↓ authorizes + schedules
Execution Plane
↓ performs
State / Trace / Artifact
↓ proves what actually happened而当多个 Agent 出现时,再追问:
text
谁拥有当前 turn?
谁拥有最终答案?
哪些 Context 被转移?
谁能产生真实副作用?只要这四个问题清楚,Manager、Handoff、Agent-as-Tool 就不会混成“多调用了几个模型”。
13. Sources
OpenAI Agents SDK — Agent orchestration
https://openai.github.io/openai-agents-python/multi_agent/OpenAI Agents SDK — Agents
https://openai.github.io/openai-agents-python/agents/OpenAI Agents SDK — Handoffs
https://openai.github.io/openai-agents-python/handoffs/OpenAI Agents SDK — Tools / Agents as tools
https://openai.github.io/openai-agents-python/tools/Anthropic — Scaling Managed Agents: Decoupling the brain from the hands
https://www.anthropic.com/engineering/managed-agents
自测
- 模型能看到
delete_fileTool,但当前用户没有删除权限。Control Plane 和 Execution Plane 分别应该做什么? - Manager 调用一个 Agent-as-Tool 与直接 Handoff 给另一个 Agent,top-level control ownership 有什么不同?
- 如果 Execution Plane 接受模型文本里的“已经授权”并直接执行,系统失去的是能力发现、授权判断还是执行能力?为什么?