Agent Harness 深度解析
有一个 100 行代码的 Python Agent,在 SWE-bench Verified 上获得了 74–76% 的评分——仅比资金雄厚的团队构建的最先进系统低 4–6 个百分点。执行循环本身并不是复杂性所在。世界级的团队会投入 6 到 12 个月的时间来围绕该循环构建基础设施。这种基础设施有一个名字:Harness。
公式很简单:Agent = Model + Harness。Model 负责推理,Harness 负责其他一切——工具执行、上下文管理、安全管控、错误恢复、状态持久化以及人在回路(human-in-the-loop)工作流。如果你花了几个月的时间优化 Prompt 和模型选择,却交付了脆弱的 Agent,那么你一直在优化错误的东西。
什么是 Harness(以及它不是什么)
这个术语容易与邻近的概念混淆。以下是值得保持的区别:
脚手架 (Scaffolding) 在 Agent 运行前进行组装——编写系统提示词、注册工具 Schema、设置子 Agent 注册表。这是设置阶段。
Harness 是运行时(Runtime)。它编排执行循环,分发工具调用,随着会话增长管理上下文,执行安全检查,在轮次之间持久化状态,并呈现结果。脚手架只运行一次;Harness 持续运行。
框架 (Frameworks)(如 LangChain、LangGraph、smolagents)提供构建块。Harness 将它们组装成一个针对你的用例具有特定偏好的运行时(opinionated runtime),并带有特定的默认设置。你可以基于框架构建 Harness,也可以从头开始构建——那个跑分 74% 的 100 行 Agent 完全是从头开始构建的。
编排器 (Orchestrators) 控制 Agent 逻辑——何时调用模型,如何路由决策。Harness 提供这些编排器所依赖的能力:工具、记忆、执行环境、权限执行。
执行循环
每一个生产级的 Agent 框架——OpenAI Agents SDK、Claude Agent SDK、LangGraph、Vercel AI SDK、smolagents——都趋向于同一个核心循环:
while not done:
response = call_llm(messages)
if response.tool_calls:
results = execute_tools(response.tool_calls)
messages.append(results)
else:
done = True
return response
这就是 Thought-Action-Observation(也称为 ReAct)。模型进行推理,请求工具,获取结果,再次推理。每一轮循环称为一个 轮次 (turn)。当模型返回没有工具调用的响应时,循环终止。
这个核心很简单。让它在生产环境中难以运行的是循环默认不处理的事情:
- 当工具调用失败时会发生什么?
- 当上下文在任务中途填满时会发生什么?
- 当 Agent 请求破坏性操作时会发生什么?
- 当任务需要暂停以进行人工审核时会发生什么?
- 如何在数千个并发会话中分摊成本?
Harness 回答了所有这些问题。
核心组件
工具 (Tools)
工具是被注入到上下文中并在模型请求时由 Harness 分发的函数模式 (schemas)。Harness 处理注册、Schema 验证、沙箱执行和结果格式化。
这里有一个应该改变你工作优先级的数据:工具输出占 Agent 在上下文中实际看到内容的 67.6%。系统提示词占 3.4%。工具定义占另外 10.7%。如果你一直在迭代系统提示词而忽略了工具输出格式,那么你就是在优化 Agent 3% 的上下文,而忽视了 68% 的部分。
其影响是直接的。冗长的工具输出——例如在摘要即可满足时提供完整文件内容,或带有冗余字段的原始 API 响应——是导致上下文腐烂(context rot)的最快路径。紧凑、结构化的工具输出可以更久地保留工作记忆并降低成本。
上下文管理 (Context Management)
上下文腐烂是真实且可衡量的。研究一致表明,当有用内容被埋在不断增长的上下文窗口中间时,即使是额定支持百万级 Token 上下文的模型,性能也会下降 30% 以上。这种退化不是线性的——通常在 256k Token 左右会有一个阈值,无论标称的上下文限制是多少,可靠性都会急剧下降。
在生产环境中有效的五种策略:
压缩 (Compaction):定期总结对话历史。保留架构决策、关键发现和开放性问题。丢弃冗余的工具输出和已经被执行过的中间推理。一种方法 (ACON) 证明,通过优先处理推理轨迹而非原始输出,可以在保留 95% 以上准确率的同时减少 26–54% 的 Token。
观察遮蔽 (Observation masking):保持推理链可见,但隐藏旧的工具输出。模型需要知道它做出了什么决定;它不需要重新阅读三轮之前读过的原始文件。
即时检索 (Just-in-time retrieval):存储轻量级标识符(文件路径、文档 ID)而不是完整内容。在执行时加载数据,而不是在会话开始时将所有内容预加载到上下文中。
结构化笔记 (Structured note-taking):让 Agent 维护外部记忆文件 ——进度日志、任务列表、决策文件。这通过文件系统将工作记忆外部化,使其在不消耗上下文的情况下跨会话持久存在。
子 Agent 委派 (Sub-agent delegation):为子任务派生专门的 Agent。每个 Agent 都会获得一个新的上下文窗口。只有它们最终的 1,000–2,000 Token 摘要会返回给父级。这就是你运行那些会溢出任何上下文限制的任务的方式。
错误处理
复合错误数学(compounding-error math)的结论令人清醒。一个包含 10 个步骤、每步可靠性为 99% 的过程,其端到端成功率约为 90%。达到 20 步时:约为 82%。达到 50 步时:约为 60%。这就是为什么决定你的智能体能否发布的是可靠性工程,而非模型质量。
四类错误需要不同的响应方式:
- 瞬态错误(网络超时、503s):使用指数退避(exponential backoff)和抖动(jitter)进行重试。
- LLM 可恢复错误(错误的数据类型、格式错误的调用):将错误作为工具执行结果返回,以便模型在下一轮对话中自我纠正。
- 用户可修复错误:中断循环并将问题呈现给用户,等待人工输入。
- 致命错误:立即抛出,不要重试。
治理框架(harness)最糟糕的反模式是将所有错误一视同仁——要么盲目重试所有错误(导致无限循环),要么将所有错误都推给用户(导致告警疲劳)。
