Agent Harness 拆解

# 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(编排循环)、工具(Tools)、记忆(Memory)、上下文管理(Context Management)、状态持久化(State Management)、错误处理(Error Handling)、guardrails(护栏)。Anthropic 的 Claude Code 文档说得很直白:SDK 就是 **"驱动 Claude Code 的 agent harness"**。OpenAI 的 Codex 团队同一个说法,把 **"agent"** 和 **"harness"** 这两个词直接画等号,都指那层让 LLM 真正可用的**非模型基础设施**。

我特别喜欢 LangChain 的 Vivek Trivedy 那句经典公式:**"如果你不是模型,那你就是 harness。"**

这里有个常被搞混的区别。"agent" 是涌现出来的行为:用户对话的对象,目标导向、会用工具、能自我纠错。Harness 才是产生这种行为的机器。当有人说"我做了个 agent",他实际上是搭了一个 harness,然后把它指向某个模型。

![](https://pbs.twimg.com/media/HFOTX8na4AACHWq.jpg)

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 有十二个独立组件。逐个看。

![](https://pbs.twimg.com/media/HFOXoJ3aYAAGt9F.jpg)

### 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 提供六类工具:文件操作、搜索、执行、网络访问、代码理解、subagent 派生。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 保留架构决策和未解决的缺陷,丢掉重复的工具输出)
- **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(一个独立 subagent 来评判输出)。

**Claude Code 作者 Boris Cherny 提到:给模型一条验证自己工作的途径,质量提升 2 到 3 倍。**

### 11. Subagent Orchestration(Subagent 编排)

Claude Code 支持三种执行模型:**Fork**(按字节复制父级上下文)、**Teammate**(独立终端窗格,靠文件信箱通信)、**Worktree**(独占 git worktree,每个 agent 一条隔离分支)。OpenAI 的 SDK 支持 agents-as-tools(把 agent 当工具用,专家处理一个有界子任务)和 handoffs(交接,专家完全接手)。LangGraph 把 subagent 实现成嵌套的状态图。

---

## Loop 在跑:一步步走

知道了组件,看它们在一个完整循环里怎么配合。

![](https://pbs.twimg.com/media/HFOYY_KbIAAzilX.jpg)

**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 预算耗尽、guardrail 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 和进度文件给自己定位,挑出优先级最高的未完成特性,干活、提交、写摘要。**文件系统提供了跨上下文窗口的连续性。**

---

## 真实框架怎么落这个范式

![](https://pbs.twimg.com/media/HFOZ6DqawAAMSNf.jpg)

**Anthropic 的 Claude Agent SDK** 通过单个 `query()` 函数把 harness 暴露出来。这个函数启动 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` 工具)、用于上下文管理的文件系统、subagent 派生、持久记忆。

**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 维护一个动态任务账本协调专家——这是 AutoGen 自创的词,由 Magnetic + Agentic 拼成)。

---

## 脚手架的隐喻

脚手架这个比喻不是修辞,是精确的。施工脚手架是临时基础设施,让工人能够到他们原本够不到的地方去建造。脚手架本身不参与施工,但少了它,工人就上不了高层。

![](https://pbs.twimg.com/media/HFOahFWa0AEinPz.jpg)

**关键洞见:建筑完工,脚手架就拆掉。** 模型变强,harness 复杂度就该往下降。Manus(国内的通用 agent 产品)在六个月里重写了五次,每次都在删复杂度。复杂的工具定义简化成通用 shell 执行。"管理 agent" 变成了简单的结构化 handoff。

这指向一个 **co-evolution(共同进化)原则**:模型现在是带着特定 harness 一起做后训练的。Claude Code 的模型只会用训练时配套的那套 harness。改动工具实现可能让性能下降,正是因为这种紧耦合。

Harness 设计的"未来兼容性测试"是这样的:性能能随着更强的模型一起放大、且不需要增加 harness 复杂度——设计就是稳的。

![](https://pbs.twimg.com/media/HFOar2zakAA_hnk.jpg)

---

## 定义每个 Harness 的七个决策

**每位 harness 架构师都要面对七个选择:**

![](https://pbs.twimg.com/media/HFOaz7xakAAwJTU.jpg)

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