# Agent Harness 解剖学
> **来源**:[@akshay_pachaar on X](https://x.com/akshay_pachaar/status/2041146899319971922) · 2026-04-06
>
> 深入剖析 Anthropic、OpenAI、Perplexity 和 LangChain 实际在构建什么。涵盖 orchestration loop、工具、记忆、上下文管理,以及把一个无状态 LLM 转变为有能力的 agent 所需的一切。
---
你搭了一个聊天机器人。可能还接了一个带几个工具的 ReAct loop,跑 demo 没问题。然后你想做点生产级的东西,麻烦就来了:模型忘了三步前自己干过什么,工具调用静默失败,上下文窗口被垃圾塞满。
问题不在你的模型,而在模型周围的一切。
LangChain 验证过这一点:他们只换了包裹 LLM 的基础设施(同一个模型、同一份权重),就在 TerminalBench 2.0 上从 30 名开外冲到第 5。另一项研究项目让 LLM 自己优化基础设施,跑出 76.4% 的通过率,超过了人工手搓的系统。
**这套基础设施现在有了名字:agent harness(智能体支架)。**
---
## 什么是 Agent Harness?
这个术语是 2026 年初被正式定义的,但概念早已存在。Harness 是包裹 LLM 的完整软件基础设施:orchestration loop、工具、记忆、上下文管理、状态持久化、错误处理、护栏。Anthropic 的 Claude Code 文档说得很直白:SDK 就是 **"驱动 Claude Code 的 agent harness"**。OpenAI 的 Codex 团队用同样的说法,明确地把 **"agent"** 和 **"harness"** 这两个词等同,都用来指那个让 LLM 真正可用的 **非模型基础设施**。
我特别喜欢 LangChain 的 Vivek Trivedy 给出的那个经典公式:**"如果你不是模型,那你就是 harness。"**
这里有个常被搞混的区别。"agent" 是涌现出的行为:那个用户面对的、有目标导向、会用工具、能自我纠错的实体。Harness 则是产生这种行为的机器。当有人说"我做了个 agent",他们其实是搭了一个 harness,然后把它指向了某个模型。

Beren Millidge 在 2023 年的论文 [《Scaffolded LLMs as Natural Language Computers》](https://www.beren.io/2023-04-11-Scaffolded-LLMs-natural-language-computers/) 中把这个类比讲得很精确。一个原始的 LLM 就是一颗没有 RAM、没有硬盘、没有 I/O 的 CPU。上下文窗口是 RAM(快但容量小),外部数据库是硬盘存储(大但慢),工具集成则相当于设备驱动。**Harness 就是操作系统。** Millidge 写道:"我们重新发明了冯·诺依曼架构",因为它对任何计算系统来说都是一个自然的抽象。
---
## 三层工程
模型周围有三层同心的工程:
- **Prompt engineering(提示工程)** 打磨模型收到的指令。
- **Context engineering(上下文工程)** 管理模型在何时看到什么。
- **Harness engineering(支架工程)** 涵盖前两者,再加上整套应用基础设施:工具编排、状态持久化、错误恢复、验证回路、安全执行、生命周期管理。
Harness 不是包在 prompt 外面的一层壳。它是让自主 agent 行为成为可能的完整系统。
---
## 生产级 Harness 的 12 个组件
综合 Anthropic、OpenAI、LangChain 以及更广泛的实践者社区,一个生产级 agent harness 有十二个独立的组件。我们逐个看。

### 1. Orchestration Loop(编排循环)
这是心跳。它实现了 Thought-Action-Observation(TAO)循环,也叫 ReAct loop。流程是:组装 prompt、调用 LLM、解析输出、执行工具调用、把结果回喂、重复直到结束。
**机械上看,它通常就是一个 `while` 循环。** 复杂度藏在循环管理的所有东西里,而不是循环本身。Anthropic 把他们的运行时形容为 "dumb loop"——所有智能都活在模型里,harness 只负责管 turn。
### 2. Tools(工具)
工具是 agent 的双手。它们以 schema(名称、描述、参数类型)的形式注入 LLM 的上下文,模型才能知道有哪些工具可用。工具层负责注册、schema 校验、参数提取、沙箱执行、结果捕获,以及把结果格式化成 LLM 能读懂的 observation。
Claude Code 提供了六类工具:文件操作、搜索、执行、网络访问、代码理解、子 agent 派生。OpenAI 的 Agents SDK 支持 function tools(通过 `@function_tool`)、托管工具(WebSearch、CodeInterpreter、FileSearch)以及 MCP 服务器工具。
### 3. Memory(记忆)
记忆运行在多个时间尺度上。**短期记忆** 是单次会话内的对话历史。**长期记忆** 跨会话持久化:Anthropic 用 `CLAUDE.md` 项目文件和自动生成的 `MEMORY.md` 文件;LangGraph 用按命名空间组织的 JSON Store;OpenAI 提供 SQLite 或 Redis 后端的 Sessions。
**Claude Code 实现了一个三层结构**:一个轻量索引(每条约 150 字符,始终加载)、按需调入的详细主题文件、只能通过搜索访问的原始 transcript。一个关键设计原则: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 用 grep、glob、head、tail,而不是把整个文件读进来)
- **Sub-agent delegation(子 agent 委托)**:每个子 agent 充分探索,但只回传 1000 到 2000 token 的浓缩摘要
Anthropic 的上下文工程指南把目标说得很清楚:**找到能最大化期望结果概率的、尽可能小的高信号 token 集合。**
### 5. Prompt Construction(Prompt 构造)
这一步组装模型每一步实际看到的内容。它是分层的:系统 prompt、工具定义、记忆文件、对话历史、当前用户消息。
OpenAI 的 Codex 用了一套严格的优先级栈:服务端控制的系统消息(最高优先级)、工具定义、开发者指令、用户指令(级联的 [AGENTS.md](http://agents.md/) 文件,32 KiB 上限),最后才是对话历史。
### 6. Output Parsing(输出解析)
现代 harness 依赖原生工具调用,模型直接返回结构化的 `tool_calls` 对象,而不是要靠正则去解析的自由文本。Harness 的判断很简单:有工具调用?执行然后继续循环。没有?那就是最终答案。
对于结构化输出,OpenAI 和 LangChain 都通过 Pydantic 模型支持 schema 约束。像 `RetryWithErrorOutputParser` 这样的传统方案(把原始 prompt、失败的补全和解析错误一起回喂给模型)在边角场景下仍然可用。
### 7. State Management(状态管理)
LangGraph 把状态建模为流经图节点的带类型字典,由 reducer 合并更新。检查点在 super-step 边界生成,**支持中断后恢复以及时间旅行式调试**。OpenAI 提供四种互斥的策略:应用层记忆、SDK sessions、服务端 Conversations API,或者轻量的 `previous_response_id` 链式接续。Claude Code 走的是另一条路:用 git commit 当检查点,用进度文件当结构化草稿本。
### 8. Error Handling(错误处理)
这件事为什么重要:**一个 10 步流程,即使每步成功率 99%,端到端成功率也只有约 90.4%。** 错误会快速复利。
LangGraph 把错误分为四类:transient(带退避的重试)、LLM-recoverable(作为 ToolMessage 返回让模型自己调整)、user-fixable(中断等人类输入)、unexpected(向上抛出供调试)。Anthropic 在工具处理器内部捕获失败,把失败作为错误结果返回,让循环继续。Stripe 的生产 harness 把重试次数封顶在两次。
### 9. Guardrails and Safety(护栏与安全)
OpenAI 的 SDK 实现了三个层级:input guardrail(在第一个 agent 上跑)、output guardrail(在最终输出上跑)、tool guardrail(每次工具调用都跑)。一旦 "tripwire" 机制被触发,就立即让 agent 停下。
Anthropic 在架构上 **把权限执行和模型推理拆开**。模型决定"想做什么",工具系统决定"允许做什么"。Claude Code 把约 40 项独立工具能力分别设闸,分三个阶段:项目加载时建立信任、每次工具调用前做权限检查、对高风险操作要求用户明确确认。
### 10. Verification Loops(验证回路)
这是把玩具 demo 和生产 agent 区分开的东西。Anthropic 推荐三种做法:基于规则的反馈(测试、linter、类型检查)、视觉反馈(UI 任务通过 Playwright 截图)、LLM-as-judge(让一个独立的子 agent 来评判输出)。
**Claude Code 的作者 Boris Cherny 提到:给模型一个验证自己工作的途径,质量会提升 2 到 3 倍。**
### 11. Subagent Orchestration(子 Agent 编排)
Claude Code 支持三种执行模型:**Fork**(按字节复制父级上下文)、**Teammate**(独立的终端窗格,通过文件信箱通信)、**Worktree**(独占 git worktree,每个 agent 一条隔离分支)。OpenAI 的 SDK 支持 agents-as-tools(专家处理一个有界的子任务)和 handoffs(专家完全接手)。LangGraph 把子 agent 实现为嵌套的状态图。
---
## Loop 在跑:一步一步走查
知道了组件,我们看它们在一个完整的循环里如何协作。

**Step 1(Prompt 组装)**:harness 拼出完整输入:系统 prompt + 工具 schema + 记忆文件 + 对话历史 + 当前用户消息。重要内容被放在 prompt 的开头和结尾("Lost in the Middle" 的发现)。
**Step 2(LLM 推理)**:组装好的 prompt 送进模型 API。模型生成输出 token:文本、工具调用请求,或者两者都有。
**Step 3(输出分类)**:如果模型只产生了文本,没有工具调用,循环结束。如果请求了工具调用,进入执行阶段。如果请求了 handoff,更新当前 agent 然后重新开始。
**Step 4(工具执行)**:对每个工具调用,harness 校验参数、检查权限、在沙箱环境中执行、捕获结果。只读操作可以并发跑,会改状态的操作串行跑。
**Step 5(结果打包)**:工具结果被格式化为 LLM 可读的消息。错误被捕获并以错误结果的形式返回,让模型可以自我纠正。
**Step 6(上下文更新)**:结果追加到对话历史。如果接近上下文窗口上限,harness 触发 compaction。
**Step 7(循环)**:回到 Step 1,重复直到终止。
**终止条件** 是分层的:模型给出不带工具调用的回复、达到最大 turn 数、token 预算耗尽、护栏 tripwire 触发、用户打断、或者返回了一次安全拒答。一个简单问题可能 1 到 2 个 turn 就完事,复杂的重构任务则可能在多个 turn 之间串起几十次工具调用。
对于跨多个上下文窗口的长任务,[Anthropic 设计了一种两阶段的 "Ralph Loop" 模式](https://www.anthropic.com/research/long-running-Claude):一个 **Initializer Agent** 先把环境准备好(init 脚本、进度文件、特性列表、初始 git commit),之后每一个会话里的 **Coding Agent** 都会读 git log 和进度文件来定位自己,挑出优先级最高的未完成特性,干活、提交、写摘要。**文件系统提供了跨上下文窗口的连续性。**
---
## 真实框架是怎么实现这个范式的

**Anthropic 的 Claude Agent SDK** 把 harness 通过单个 `query()` 函数暴露出来,这个函数创建 agentic loop 并返回一个流式输出消息的异步迭代器。运行时是一个 "dumb loop",所有智能都在模型里。Claude Code 用的是 Gather-Act-Verify 循环:收集上下文(搜文件、读代码)、采取行动(编辑文件、跑命令)、验证结果(跑测试、看输出),重复。
**OpenAI 的 Agents SDK** 通过 `Runner` 类实现 harness,提供三种模式:异步、同步、流式。SDK 是 "code-first" 的:工作流逻辑用原生 Python 表达,而不是图 DSL。Codex harness 在此之上加了三层架构:Codex Core(agent 代码 + 运行时)、App Server(双向 JSON-RPC API)、客户端表面(CLI、VS Code、Web app)。所有表面共享同一个 harness,所以 "Codex 模型在 Codex 表面上的体感比在通用聊天窗口里好"。
**LangGraph** 把 harness 建模为一个显式的状态图。两个节点(`llm_call` 和 `tool_node`),由一条条件边连接:有工具调用就走 `tool_node`,没有就走 END。LangGraph 是从 LangChain 的 `AgentExecutor` 演化来的——后者在 v0.2 被弃用,原因是难扩展且缺多 agent 支持。LangChain 的 **Deep Agents** 明确使用 "agent harness" 这个词:内置工具、规划(`write_todos` 工具)、用于上下文管理的文件系统、子 agent 派生、持久记忆。
**CrewAI** 实现了一种基于角色的多 agent 架构:Agent(围绕 LLM 的 harness,由角色、目标、背景故事、工具定义)、Task(工作单元)、Crew(agent 集合)。CrewAI 的 Flows 层加了一条 "在该确定的地方确定,在该有智能的地方有智能" 的骨架,负责路由和校验,让 Crew 自由协作。
**AutoGen**(正在演变成 Microsoft Agent Framework)开创了对话驱动的编排范式。它的三层架构(Core、AgentChat、Extensions)支持五种编排模式:sequential、concurrent(fan-out / fan-in)、group chat、handoff、magentic(一个管理者 agent 维护一个动态任务账本来协调专家)。
---
## 脚手架的隐喻
脚手架这个比喻不是修辞,而是精确的。施工脚手架是临时基础设施,让工人能够到他们原本够不到的地方去建造。脚手架自己不参与施工,但少了它,工人就上不了高层。

**关键洞见:建筑完工时,脚手架就被拆掉。** 随着模型变强,harness 的复杂度应该下降。Manus 在六个月里被重写了五次,每次都在删掉复杂度。复杂的工具定义被简化成通用 shell 执行。"管理 agent" 变成了简单的结构化 handoff。
这指向一个 **co-evolution(共同进化)原则**:模型现在是带着特定 harness 一起做后训练的。Claude Code 的模型学会了使用它训练时配套的那个 harness。改动工具实现可能让性能下降,正是因为这种紧耦合。
Harness 设计的"未来兼容性测试"是这样的:如果性能可以随着更强的模型一起放大,且不需要增加 harness 的复杂度,那么这个设计就是稳的。

---
## 定义每一个 Harness 的七个决策
**每位 harness 架构师都要面对七个选择:**

1. **单 agent vs 多 agent。** Anthropic 和 OpenAI 都说:先把单 agent 拉到极致。多 agent 系统会带来开销(路由的额外 LLM 调用、handoff 时的上下文丢失)。只有当工具数量超过约 10 个并且互相重叠,或者任务领域明显分离时,才去拆分。
2. **ReAct vs plan-and-execute。** ReAct 在每一步都把推理和行动交错起来(灵活但每步成本更高)。Plan-and-execute 把规划和执行分开。**LLMCompiler 报告比顺序 ReAct 快 3.6 倍。**
3. **上下文窗口管理策略。** 五种生产级方案:基于时间的清空、对话摘要、observation masking、结构化笔记、子 agent 委托。**ACON 的研究显示,通过优先保留推理轨迹而非原始工具输出,可以减少 26% 到 54% 的 token,同时保留 95% 以上的准确率。**
4. **验证回路设计。** 计算式验证(测试、linter)提供确定的真值。推断式验证(LLM-as-judge)能捕捉语义问题,但增加延迟。Martin Fowler 在 Thoughtworks 的团队把这两者描述为 **guides**(前馈,行动前引导)和 **sensors**(反馈,行动后观察)。
5. **权限与安全架构。** 宽松(快但有风险,多数动作自动批准)vs 严格(安全但慢,每次动作都需审批)。怎么选取决于部署语境。
6. **工具范围策略。** 工具越多,性能往往越差。**Vercel 把 v0 的工具砍掉了 80%**,效果反而更好。**Claude Code 通过 lazy loading 实现了 95% 的上下文压缩。** 原则是:当前这一步,只暴露所需的最小工具集。
7. **Harness 厚度。** 多少逻辑放在 harness 里,多少留给模型。Anthropic 押注薄 harness 加上模型变强。基于图的框架押注显式控制。Anthropic 会随着新模型版本把 Claude Code harness 里的规划步骤删掉,因为模型已经把这个能力内化了。
---
## Harness 才是产品
两个用同一个模型的产品,仅仅因为 harness 设计不同,性能可以天差地别。TerminalBench 的证据很清楚:仅替换 harness,就能让 agent 移动 20 名以上的位次。
Harness 不是一个已解决的问题,也不是一个商品化的层。它正是硬工程藏身之处:把上下文当作稀缺资源去管理、设计能在错误复利之前就抓住失败的验证回路、构建提供连续性又不会幻觉的记忆系统、在"该搭多少脚手架"和"该把多少留给模型"之间做架构押注。
随着模型变强,整个领域正朝着更薄的 harness 演进。但 harness 本身不会消失。即使是最强的模型,也需要某个东西来管理它的上下文窗口、执行它的工具调用、持久化它的状态、验证它的工作。
**下次你的 agent 出错时,别怪模型,看看 harness。**
---
收工!
如果你喜欢这篇文章:
来这里找我 → [@akshay_pachaar](https://x.com/akshay_pachaar) ✔️
我每天都会分享关于 AI、机器学习以及 vibe coding 的最佳实践与教程。
---
**原推文链接**: https://x.com/akshay_pachaar/status/2041146899319971922