你也许已经做过一个聊天机器人,甚至用 ReAct 写过一个带少量工具的简单 Agent。它在 Demo 里看起来不错,但一上生产就开始散架:模型忘记三步之前做过什么、工具调用悄无声息地失败、上下文窗口被无用信息塞满。

问题往往不在模型本身,而在模型“外面”的一整套基础设施。

LangChain 就是一个典型例子:他们在 TerminalBench 2.0 上,只改了包裹同一模型的基础设施(模型和权重完全不变),排名就从 30 名开外直接跃升到第 5。另一个研究项目甚至让 LLM 自己优化这层基础设施,拿到了 76.4% 的通过率,超过了人工设计的系统。

这层基础设施,现在有了一个统一的名字:Agent Harness(智能体挽具)

什么是 Agent Harness?

“Agent Harness” 这个术语在 2026 年初才被正式提出,但概念早就存在。它指的是包裹在 LLM 外面的整套软件基础设施:编排循环、工具系统、记忆、上下文管理、状态持久化、错误处理、安全与权限等。

Anthropic 在 Claude Code 文档里说得很直接:SDK 就是“驱动 Claude Code 的 agent harness”。OpenAI 的 Codex 团队也用类似的说法,把“agent”和“harness”等同起来,专指那一整层让 LLM 真正可用的非模型基础设施

LangChain 的 Vivek Trivedy 给了一个很经典的公式:“如果你不是模型,那你就是 harness。”

很多人容易混淆的一点是:

  • “Agent” 是用户看到的涌现行为:有目标、会用工具、能自我纠错的那个“智能体”。
  • “Harness” 是产生这种行为的机械结构

当有人说“我做了一个 Agent”,本质上是:他实现了一套 harness,然后把它接在某个模型上。

LLM = CPU,Harness = 操作系统

Beren Millidge 在 2023 年的文章《Scaffolded LLMs as Natural Language Computers》中,把这个类比讲得很清楚:

  • 一个裸 LLM 就像只有 CPU、没有内存、没有硬盘、没有 I/O 的机器。
  • 上下文窗口是 RAM(快但容量有限)。
  • 外部数据库是磁盘(大但慢)。
  • 工具集成是设备驱动。
  • Harness 就是操作系统。

正如 Millidge 所说:“我们其实是重新发明了一遍冯·诺依曼架构。” 只不过这次的“指令”和“数据”都是自然语言。

三层工程:从 Prompt 到 Harness

围绕模型,大致有三层同心工程:

  • Prompt 工程:写好模型要遵循的指令。
  • 上下文工程(Context Engineering):决定模型在什么时刻看到什么信息。
  • Harness 工程:把前两者连同整个应用基础设施一起打包:工具编排、状态持久化、错误恢复、验证循环、安全策略、生命周期管理等。

Harness 不是“在 prompt 外面再包一层壳”那么简单,而是整套让 Agent 能长期、自主运行的系统

一个生产级 Agent Harness 的 12 个组成部分

综合 Anthropic、OpenAI、LangChain 以及一线实践者的经验,一个真正能上生产的 Agent Harness,至少包含 12 个关键组件。

下面按结构拆开讲。

1. 编排循环(Orchestration Loop)

这是整个系统的“心跳”。它实现的是 Thought–Action–Observation(TAO)循环,也就是常说的 ReAct:

  1. 组装 Prompt;
  2. 调用 LLM;
  3. 解析输出;
  4. 执行工具调用;
  5. 把结果喂回模型;
  6. 直到任务结束为止。

从代码上看,往往就是一个 while 循环。**复杂度不在循环本身,而在循环要管理的一切东西。**Anthropic 把自己的 runtime 形容成一个“很蠢的循环”,所有智能都在模型里,Harness 只负责轮到谁说话、什么时候停。

2. 工具(Tools)

工具是 Agent 的“手脚”。

它们以 schema 的形式定义(名称、描述、参数类型),注入到模型上下文里,让模型知道“我能用什么”。工具层负责:

  • 注册与发现;
  • schema 校验与参数提取;
  • 沙箱执行;
  • 捕获结果;
  • 把结果格式化成模型可读的 Observation。

Claude Code 把工具分成六大类:文件操作、搜索、执行、网络访问、代码理解、子 Agent 生成。

OpenAI 的 Agents SDK 支持:

  • 函数工具(function tools,对应 @function_tool);
  • 托管工具(WebSearch、CodeInterpreter、FileSearch);
  • MCP server 工具。

3. 记忆(Memory)

记忆有不同时间尺度:

  • 短期记忆:单次会话内的对话历史;
  • 长期记忆:跨会话持久化的信息。

Anthropic 用 CLAUDE.md 项目文件和自动生成的 MEMORY.md 文件来存长期记忆;LangGraph 用按命名空间组织的 JSON Store;OpenAI 提供基于 SQLite 或 Redis 的 Session。

Claude Code 的记忆是三层结构:

  1. 轻量索引(每条约 150 字符,始终加载);
  2. 详细主题文件,按需拉取;
  3. 原始对话记录,只通过搜索访问。

一个非常重要的设计原则是:Agent 把自己的记忆当“提示”,在真正行动前必须再对照真实状态做一次验证。

4. 上下文管理(Context Management)

很多 Agent 静悄悄地失败,问题就出在这里。

核心难题是“上下文腐烂(context rot)”:

  • 研究表明,当关键信息落在上下文中间位置时,模型性能会下降 30% 以上(Chroma 的实验 + Stanford《Lost in the Middle》);
  • 即便是百万 token 的上下文,随着长度增加,指令遵循能力也会明显变差。

生产环境常用策略包括:

  • 压缩(Compaction):接近上限时对历史对话做摘要。Claude Code 会保留架构决策和未解决的 bug,丢弃重复的工具输出;
  • Observation Masking:例如 JetBrains 的 Junie,只隐藏旧的工具输出,但保留工具调用本身;
  • 即时检索(Just-in-time Retrieval):只保留轻量标识符,需要时再动态加载数据。Claude Code 倾向用 grepglobheadtail 之类的工具,而不是一次性把整个文件塞进上下文;
  • 子 Agent 汇总:每个子 Agent 可以在自己的上下文里“疯狂探索”,但最终只返回 1000–2000 token 的精炼总结。

Anthropic 的上下文工程指南把目标概括为:找到那一组最小但高信号的 token 子集,最大化任务成功概率。

5. Prompt 构造(Prompt Construction)

这一步决定模型在每一轮“真正看到什么”。典型结构是分层的:

  • 系统提示(system prompt);
  • 工具定义;
  • 记忆文件;
  • 对话历史;
  • 当前用户消息。

OpenAI Codex 使用严格的优先级栈:

  1. 服务器控制的 system message(最高优先级);
  2. 工具定义;
  3. 开发者指令;
  4. 用户指令;
  5. AGENTS.md 文件(有 32 KiB 限制);
  6. 对话历史。

6. 输出解析(Output Parsing)

现代 Harness 基本都依赖“原生工具调用”:模型直接返回结构化的 tool_calls 对象,而不是一段需要正则去抠的自然语言。

Harness 的逻辑很简单:

  • 有工具调用 → 执行工具 → 回到循环;
  • 没有工具调用 → 这就是最终回答。

对于需要结构化输出的场景,OpenAI 和 LangChain 都支持用 Pydantic 等 schema 约束模型输出。老派的做法(比如 RetryWithErrorOutputParser:把原始 Prompt、失败的输出和解析错误一起再喂回模型)仍然可以在边缘场景使用。

7. 状态管理(State Management)

LangGraph 把状态建模为在图节点间流动的“类型化字典”,通过 reducer 合并更新。在所谓的 super-step 边界做 checkpoint,可以支持中断恢复和“时间旅行式”调试。

OpenAI 提供四种互斥的状态策略:

  • 应用自己管理内存;
  • SDK Session;
  • 服务器端 Conversations API;
  • 轻量的 previous_response_id 链接。

Claude Code 走的是另一条路:用 git commit 做 checkpoint,用进度文件(progress file)做结构化草稿本。

8. 错误处理(Error Handling)

为什么这件事如此关键?因为:

一个 10 步流程,如果每一步成功率是 99%,整体成功率只有约 90.4%。

错误会快速叠加。

LangGraph 把错误分成四类:

  • 瞬时错误:重试 + 退避;
  • LLM 可恢复错误:把错误作为 ToolMessage 返回给模型,让它自己调整;
  • 用户可修复错误:中断流程,等待人类输入;
  • 意料之外的错误:向上抛出,便于调试。

Anthropic 在工具处理器内部捕获异常,把它们包装成“错误结果”返回给模型,保证循环不断。Stripe 的生产 Harness 通常把重试次数限制在 2 次以内。

9. 安全与护栏(Guardrails & Safety)

OpenAI SDK 在三层上做护栏:

  • 输入护栏:在第一个 Agent 上运行;
  • 输出护栏:在最终输出上运行;
  • 工具护栏:在每一次工具调用上运行。

一旦触发“绊线(tripwire)”,Agent 会立刻被停止。

Anthropic 在架构上把“权限执行”和“模型推理”分开:

  • 模型负责“想做什么”;
  • 工具系统负责“能不能做”。

Claude Code 把大约 40 个离散的工具能力分别做权限控制,分三层:

  1. 项目加载时建立信任;
  2. 每次工具调用前做权限检查;
  3. 高风险操作必须显式征求用户确认。

10. 验证循环(Verification Loops)

这是区分“玩具 Demo”和“生产 Agent”的关键。

Anthropic 推荐三种验证方式:

  • 规则/程序化反馈:测试、linter、类型检查器等;
  • 视觉反馈:对 UI 任务,用 Playwright 截图再让模型检查;
  • LLM-as-judge:单独的评审子 Agent 对结果打分或给出反馈。

Claude Code 的作者 Boris Cherny 提到:只要给模型一个“验证自己工作”的通路,质量就能提升 2–3 倍。

11. 子 Agent 编排(Subagent Orchestration)

Claude Code 支持三种执行模型:

  • Fork:复制父上下文的字节级快照;
  • Teammate:在单独的终端面板里运行,通过文件信箱通信;
  • Worktree:每个 Agent 拥有自己的 git worktree 和独立分支。

OpenAI SDK 支持:

  • “Agent 作为工具”:把某个专长 Agent 当成一个工具来调用;
  • Handoff:把整个会话控制权交给另一个 Agent。

LangGraph 则把子 Agent 实现为嵌套的状态图。

12. 生命周期与终止条件

一个完整的 Agent 循环,大致会经历:

  1. Prompt 组装;
  2. LLM 推理;
  3. 输出分类(回答 / 工具调用 / Handoff);
  4. 工具执行;
  5. 结果打包;
  6. 上下文更新与压缩;
  7. 回到第 1 步,直到满足终止条件。

常见终止条件包括:

  • 模型输出中不再包含工具调用;
  • 达到最大轮数;
  • token 预算耗尽;
  • 护栏触发;
  • 用户中断;
  • 模型返回安全拒绝。

简单问题可能只需要 1–2 轮;复杂的重构任务可能要跨几十次工具调用、很多轮循环。

对于跨多个上下文窗口的长任务,Anthropic 提出了著名的 “Ralph Loop” 双阶段模式

  • Initializer Agent:初始化环境(脚本、进度文件、功能列表、初始 git commit);
  • Coding Agent:后续每个会话都先读 git log 和进度文件,重新建立“心智模型”,选择最高优先级的未完成功能,工作、提交、写总结。

文件系统在这里扮演了“跨上下文的长期记忆”角色。

主流框架如何落地这个模式

Anthropic:Claude Agent SDK & Claude Code

Claude Agent SDK 用一个 query() 函数暴露整个 Harness:它创建 Agent 循环,并返回一个异步迭代器来流式输出消息。Runtime 本身是“很蠢的循环”,所有智能都在模型里。

Claude Code 则采用 Gather–Act–Verify 三步循环:

  1. Gather:收集上下文(搜索文件、阅读代码);
  2. Act:采取行动(编辑文件、运行命令);
  3. Verify:验证结果(跑测试、检查输出)。

OpenAI:Agents SDK & Codex Harness

OpenAI 的 Agents SDK 用 Runner 类实现 Harness,支持:

  • 异步模式;
  • 同步模式;
  • 流式模式。

SDK 是“代码优先”的:工作流逻辑直接用 Python 写,而不是图形 DSL。

Codex Harness 在此基础上又加了一层三层架构:

  • Codex Core:Agent 代码 + Runtime;
  • App Server:双向 JSON-RPC API;
  • 客户端界面:CLI、VS Code 插件、Web 应用。

所有界面共用同一套 Harness,这也是为什么“Codex 模型在 Codex 界面上用起来明显比在普通聊天窗口舒服”。

LangGraph / LangChain:显式状态图与 Deep Agents

LangGraph 把 Harness 显式建模为一个状态图:

  • 一个 llm_call 节点;
  • 一个 tool_node 节点;
  • 中间用条件边连接:有工具调用就去 tool_node,没有就结束。

它是从 LangChain 早期的 AgentExecutor 演化而来,后者在 0.2 版本被废弃,原因是难以扩展、对多 Agent 支持不好。

LangChain 的 Deep Agents 直接使用了“agent harness”这个说法:

  • 内置工具;
  • 规划(如 write_todos 工具);
  • 用文件系统做上下文管理;
  • 子 Agent 生成;
  • 持久化记忆。

CrewAI:多 Agent 协作

CrewAI 用“角色驱动”的多 Agent 架构:

  • Agent:包裹 LLM 的 Harness,由角色、目标、背景故事和工具定义;
  • Task:工作单元;
  • Crew:一组协作的 Agent。

CrewAI 的 Flows 层提供一个“确定性的骨架 + 关键处的智能”,负责路由和校验,而具体的协作由 Crew 自主完成。

AutoGen / Microsoft Agent Framework:对话驱动编排

AutoGen(正在演化为 Microsoft Agent Framework)开创了“对话驱动编排”的思路。它的三层架构(Core、AgentChat、Extensions)支持五种常见编排模式:

  • 顺序;
  • 并发(扇出/扇入);
  • 群聊;
  • Handoff;
  • “Magentic”:一个管理 Agent 维护动态任务清单,协调各个专家。

脚手架隐喻:Harness 会越来越“薄”吗?

“Scaffolding(脚手架)”这个比喻并不是修辞,而是非常精确的:

  • 脚手架是临时基础设施,让工人能到达原本够不到的地方;
  • 它本身不“盖楼”,但没有它,楼就盖不起来;
  • 楼盖好之后,脚手架会被拆掉。

随着模型能力增强,Harness 的复杂度理应逐步下降。

有团队在半年内重写了五次内部 Agent 系统,每一次重写都在“减法”:

  • 复杂的工具定义被简化成通用 shell 执行;
  • “管理型 Agent” 被替换成简单的结构化 Handoff。

这背后是一个重要的共演原则(co-evolution principle)

现在的大模型,往往是在特定 Harness 在环的情况下做后训练的。

Claude Code 用的模型,就是在那一套特定 Harness 上学会“如何使用工具”的。随意更换工具实现,反而可能让效果变差,因为模型已经对原来的 Harness 形成了“肌肉记忆”。

一个好的 Harness 设计,要通过所谓的“前向兼容测试”:

当你换成更强的模型时,不需要增加 Harness 复杂度,性能就能自然提升。

七个决定,定义你的 Harness 性格

几乎每个 Harness 架构师都要做出下面这七类选择:

  1. 单 Agent 还是多 Agent?
    Anthropic 和 OpenAI 的共识是:先把单 Agent 做到极致。多 Agent 会引入额外开销(路由需要额外 LLM 调用,Handoff 会丢上下文)。只有当工具数量过多(比如 10+ 且高度重叠),或者任务域天然分离时,再考虑拆分。

  2. ReAct 还是 Plan-and-Execute?
    ReAct 在每一步都交替“思考 + 行动”,灵活但每一步都要付出 LLM 成本。Plan-and-Execute 把“规划”和“执行”分开。LLMCompiler 的实验显示,相比顺序 ReAct,Plan-and-Execute 可以带来 3.6 倍的速度提升

  3. 上下文窗口怎么管?
    生产上常见的五种策略:

    • 按时间清理;
    • 对话摘要;
    • Observation Masking;
    • 结构化笔记(把关键信息写入专门的 note 文件);
    • 子 Agent 汇总。
      ACON 的研究表明:优先保留“推理轨迹”而不是原始工具输出,可以在保持 95%+ 准确率的前提下,减少 26–54% 的 token
  4. 验证循环怎么设计?

    • 计算式验证(测试、linter)给出确定性真值;
    • 推理式验证(LLM-as-judge)能抓语义问题,但会增加延迟。
      Thoughtworks 的 Martin Fowler 团队把这类机制分成两种:
    • Guides(导向):前馈,在行动前就给出约束;
    • Sensors(传感):反馈,在行动后观察结果。
  5. 权限与安全架构?

    • 宽松模式:自动批准大部分操作,快但风险高;
    • 严格模式:每一步都要确认,安全但慢。
      具体选择取决于场景:是内部开发工具,还是直接操作生产数据库的 Agent?
  6. 工具暴露策略?
    工具越多,效果往往越差。Vercel 在 v0 里砍掉了 80% 的工具,结果反而更好。Claude Code 通过懒加载实现了 95% 的上下文减载。原则是:只暴露当前步骤真正需要的最小工具集。

  7. Harness 要多“厚”?

    • Anthropic 押注“薄 Harness + 强模型”:能让模型自己学会的,就不要在 Harness 里硬编码;
    • 图式框架(如 LangGraph)则押注显式控制。
      Anthropic 在迭代 Claude Code 时,经常会在新模型上线后,直接删除一整段“规划逻辑”,因为模型已经学会自己规划了。

Harness 本身就是产品力

两款产品用的是同一个模型,最终体验却可以天差地别,差异往往就出在 Harness 设计上。

TerminalBench 的结果已经说明:只改 Harness,不动模型,就能让 Agent 的排名上下浮动 20 多名。

Harness 既不是“已经被解决的问题”,也不是一个可以随便替换的“通用中间层”。真正困难的工程工作都在这里:

  • 把上下文当成稀缺资源来管理;
  • 设计能在错误扩散前就把它们抓出来的验证循环;
  • 搭建既能提供连续性又不诱发幻觉的记忆系统;
  • 在“多搭脚手架”和“相信模型”之间做长期架构押注。

随着模型能力提升,行业整体趋势确实是往“更薄的 Harness”走。但 Harness 本身不会消失:

再强的模型,也需要有人帮它:管理上下文窗口、执行工具调用、持久化状态、验证结果。

下一次你的 Agent 出问题时,先别怪模型,先看看你的 Harness。