Agent Harness 的工程结构:控制权放在哪里
选择 Agent 框架时,最容易陷入功能表:谁支持更多模型、更多工具、更多 Memory、更多 Multi-Agent 模式。
这些功能当然重要,但更早的问题是:下一步由谁决定,状态由谁保存,失败以后谁负责。
同样一个退款任务,可以把控制交给模型、普通代码、状态图或持久化运行时。四种实现都能完成 Demo,遇到权限、暂停和崩溃时却会表现得完全不同。
Harness 设计的核心不是组件数量,而是控制权的放置。
一、三种平面:决策、控制与执行
Section titled “一、三种平面:决策、控制与执行”为了看清 Harness,可以先分成三个平面。
Decision Plane
Section titled “Decision Plane”模型理解目标、选择工具、生成参数、提出计划或 Handoff。
它擅长处理开放语言和不确定判断,不适合单独承担权限、事务和完成证明。
Control Plane
Section titled “Control Plane”程序、图或策略引擎决定哪些动作可达、是否需要审批、预算是否允许、错误怎样恢复、什么时候停止。
控制平面承接业务责任。
Execution Plane
Section titled “Execution Plane”工具、浏览器、终端、数据库、队列和沙箱真正改变环境。
执行平面必须返回结构化 Observation,并处理超时、幂等和资源隔离。
很多 Agent 故障的根源,是三个平面被压进一段 Prompt:模型既提议动作,又解释权限,还根据自己的解释宣布成功。
二、一套 Harness 的七个模块
Section titled “二、一套 Harness 的七个模块”第 2 讲从职责解释 Harness,这一讲从工程模块重新组织。
1. Model Gateway
Section titled “1. Model Gateway”统一模型调用、认证、重试、流式输出、Token 统计和能力差异。网关可以提供共同接口,但不能抹掉 Tool Call、结构化输出和缓存语义差异。
2. Context Builder
Section titled “2. Context Builder”从目标、状态、Memory、检索和工具目录构建当前输入。它还负责预算、压缩、来源和不可信内容隔离。
3. Agent Runner
Section titled “3. Agent Runner”执行 Agent Loop:调用模型、解析候选动作、调度工具、回填 Observation、处理 Handoff 和终态。
4. Tool Runtime
Section titled “4. Tool Runtime”验证参数、检查授权、执行动作、整形结果,并管理超时、并发、幂等和副作用。
5. State and Session
Section titled “5. State and Session”保存会话、任务状态、Checkpoint、工件和审批。消息历史只是其中一类数据。
6. Policy and Guardrails
Section titled “6. Policy and Guardrails”执行最小权限、路径/域名白名单、内容过滤、预算、人工批准和取消。
7. Telemetry
Section titled “7. Telemetry”记录 Trace、Span、事件、错误、成本和完成证据,为 Evaluation 和故障诊断提供数据。
模块可以合并在一个进程里,也可以拆成服务。分层的目的不是增加部署,而是让责任能被定位。
三、四种控制模型
Section titled “三、四种控制模型”Model-driven:模型决定大部分下一步
Section titled “Model-driven:模型决定大部分下一步”这种 Harness 提供工具和循环,让模型动态规划。
优势是代码少、适应开放任务快;风险是行为变化大,重复和误用工具更难提前发现。smolagents、Strands 的典型用法接近这条路线。[1][2]
适合探索、研究和低风险任务。进入写操作前,需要独立 Policy Gate。
Code-driven:普通代码拥有流程
Section titled “Code-driven:普通代码拥有流程”应用用 if、函数和异常处理组织模型与工具。OpenAI Agents SDK、PydanticAI 都强调与普通 Python 组合。[3][4]
优势是团队熟悉、单元测试容易、控制明确;复杂分支和长时恢复则需要自行组织。

图 1:OpenAI Agents SDK 代表少量原语与普通代码编排的路线。来源见文末。
Graph-driven:状态和边拥有可达路径
Section titled “Graph-driven:状态和边拥有可达路径”LangGraph、Microsoft Agent Framework Workflow 把状态、节点和边显式化。[5][6]
模型在节点内做开放判断,图决定下一步可以去哪里。它适合审批、循环、恢复和复杂分支,代价是图设计与迁移成本。

图 2:LangGraph 把 State、Node、Edge 和 Checkpoint 置于核心。来源见文末。
Runtime-driven:持久化运行时拥有生命周期
Section titled “Runtime-driven:持久化运行时拥有生命周期”Temporal、DBOS 等系统把 Workflow 历史、Activity 重试、定时器和恢复变成运行时能力。[7][8]
它们不决定模型该说什么,却决定进程崩溃以后任务怎样继续。适合跨小时、跨天和有副作用的流程。
实际生产系统通常混合四者:Graph 规定大阶段,Code 执行确定逻辑,Model 处理开放节点,Durable Runtime 保存生命周期。
四、状态到底应该归谁
Section titled “四、状态到底应该归谁”状态分散是 Harness 最难排查的问题之一。
同一个任务可能同时存在:
- 模型消息历史中的“当前计划”;
- 应用数据库中的任务状态;
- LangGraph Checkpoint;
- Memory Service 中的用户偏好;
- Durable Runtime 的 Workflow 历史;
- 外部业务系统的真实终态。
它们不能都声称自己是权威。
建议按问题分配:
| 状态 | 权威位置 |
|---|---|
| 订单是否退款 | 订单/支付系统 |
| Workflow 运行到哪 | Durable Runtime 或 Checkpoint Store |
| 当前计划和中间工件 | 任务状态 |
| 用户长期偏好 | Memory Store |
| 模型看到的最近对话 | Session History |
模型上下文应该从权威状态生成,而不是反过来用模型文本覆盖权威状态。
五、Hooks 与 Middleware 为什么重要
Section titled “五、Hooks 与 Middleware 为什么重要”框架常提供 Hook、Middleware、Interceptor 或 Event Handler。它们允许团队在不修改 Agent 逻辑的情况下加入:
- 调用前权限检查;
- 工具参数脱敏;
- 预算计数;
- Trace 属性;
- 模型路由;
- 结果缓存;
- 审批和取消;
- 错误分类。
这类扩展点是 Harness 的控制面。设计时要避免两个极端:所有逻辑塞进 Hook,导致执行顺序不透明;或者完全没有 Hook,只能修改框架内部。
好扩展点应明确时机、输入、是否可修改、错误传播和幂等要求。
六、OpenHarness 为什么值得看,又不能照单全收
Section titled “六、OpenHarness 为什么值得看,又不能照单全收”OpenHarness 等项目尝试把 Toolkit、Memory、Governance、Swarm 和生命周期集中呈现,适合观察一个“完整 Harness”可能包含什么。[9]

图 3:OpenHarness 展示了较完整的能力地图。能力面广不等于每个应用都应启用全部模块。
读这类项目时要分三层:
- 核心运行时哪些是必需的;
- 哪些是可选能力;
- 哪些依赖托管服务或特定基础设施。
完整架构适合学习边界,不适合成为每个项目的默认起点。
七、控制权应该怎样分配
Section titled “七、控制权应该怎样分配”可以采用一条简单原则:
开放、可逆、低风险 -> 模型拥有更多选择确定、不可逆、高风险 -> 代码/图/人工拥有控制跨时间、需恢复 -> 持久化运行时拥有生命周期例如客服 Agent:
- 模型判断用户意图;
- 代码验证身份和金额;
- 图规定退款前必须经过政策检查和审批;
- Durable Runtime 等待人工回复;
- 支付系统保存最终交易事实。
这不是削弱 Agent,而是把不同能力放回适合的位置。
八、真实实验:同一个写操作,两种控制位置
Section titled “八、真实实验:同一个写操作,两种控制位置”本讲的 control_placement.py 模拟模型提出 write_refund。
第一条路径让模型直接提出写动作,但 Policy 发现没有审批,终态是:
{"terminal": "blocked", "reason": "approval_required"}第二条路径由状态图先读取订单、经过审批节点,再执行写入,终态为 success。
完整结果见 experiment-result.json。
实验没有比较谁“更聪明”。它只说明:同一个候选动作,放在不同控制结构里,会得到不同的安全语义。
九、选择框架前的十二个问题
Section titled “九、选择框架前的十二个问题”- 谁拥有 Agent Loop?
- 下一步由模型、代码还是图决定?
- 业务状态保存在哪里?
- 是否支持结构化 Checkpoint?
- 工具授权在哪里执行?
- 有副作用动作怎样幂等?
- 是否支持暂停、取消和人工审批?
- 进程重启后能否恢复?
- Trace 能否跨模型、工具和 Handoff?
- 是否能在框架外使用普通测试工具?
- 托管功能与开源核心怎样划分?
- API 变化时,状态和 Workflow 怎样迁移?
如果这些问题没有答案,“支持多少 Agent 模式”并不是最重要的。
十、这一讲的结论
Section titled “十、这一讲的结论”Harness 设计不是寻找一个包办全部责任的框架,而是明确控制权、状态和失败责任。
模型负责开放判断,代码和图保留确定约束,持久化运行时承接时间,业务系统保存事实。
下一讲深入 Graph 和 State Machine:怎样把 Agent 的不确定性放进显式状态,让循环能验证、有界并且可恢复。
[1] Hugging Face, smolagents. https://github.com/huggingface/smolagents
[2] Strands Agents. https://github.com/strands-agents/harness-sdk
[3] OpenAI Agents SDK. https://github.com/openai/openai-agents-python
[4] PydanticAI. https://github.com/pydantic/pydantic-ai
[5] LangGraph. https://github.com/langchain-ai/langgraph
[6] Microsoft Agent Framework. https://github.com/microsoft/agent-framework
[7] Temporal Python SDK. https://github.com/temporalio/sdk-python
[8] DBOS Transact Python. https://github.com/dbos-inc/dbos-transact-py
[9] OpenHarness. https://github.com/HKUDS/OpenHarness