read.fallenpal归档
精翻 · X 长帖

Agent Harness 解剖:把无状态 LLM 变成可用 Agent 的完整基础设施

原作者 Akshay原文 2026-04-06Carla / Hermes 译

真正决定 Agent 上限的,往往不是模型本身,而是包在模型外面的 harness:编排循环、工具、记忆、上下文管理、状态持久化、容错、验证与安全控制。理解这层系统,才真正接近生产级 Agent。

作者:Akshay(@akshay_pachaar)
原帖日期:2026-04-06 21:31
查看原帖

你已经做出了一个 chatbot。也许你还接上了一个带少量工具的 ReAct 循环。做 demo 的时候,一切都挺顺。等你真正开始做 production-grade 的东西,问题就全冒出来了:模型会忘掉三步前自己做过什么,tool call 会静默失败,context window 会被垃圾塞满。

问题不在模型本身。

问题在模型周围的一切。

LangChain 已经把这件事证明得很清楚了。他们只改了包在 LLM 外面的基础设施,同一个模型、同一组权重,TerminalBench 2.0 的排名就从前 30 名之外直接跳到第 5。另一项研究甚至让 LLM 去优化这层基础设施本身,最后做到 76.4% 的 pass rate,超过了人工设计的系统。

现在,这层基础设施有了一个名字:agent harness。

什么是 Agent Harness

这个术语在 2026 年初被正式明确下来,但概念本身早就存在了。Harness 就是包在 LLM 外面的整套软件基础设施:orchestration loop、tools、memory、context management、state persistence、error handling 和 guardrails。

Anthropic 的 Claude Code 文档说得很直接:SDK 就是“the agent harness that powers Claude Code”。OpenAI 的 Codex 团队也用同样的表述,明确把“agent”和“harness”放在同一个讨论框架里,指向那层让 LLM 真正变得有用的非模型基础设施。

LangChain 的 Vivek Trivedy 有一句我特别喜欢的公式:

“If you're not the model, you're the harness.”

这里最容易让人混淆的,是 agent 和 harness 的区别。

“Agent”是最终呈现出来的涌现行为:一个以目标为导向、会用工具、能自我修正的实体。用户与之交互,感知到的是 agent。

“Harness”是把这种行为生产出来的整套机制。

所以当有人说“我做了一个 agent”,真正的意思通常是:我做了一套 harness,再把它接到某个模型上。

Beren Millidge 在 2023 年的文章《Scaffolded LLMs as Natural Language Computers》里把这个类比讲得非常准确:原始 LLM 像一颗没有 RAM、没有磁盘、没有 I/O 的 CPU。Context window 像 RAM,快,但很有限。外部数据库像磁盘,容量大,但慢。Tool integrations 像设备驱动。Harness 就是操作系统。

他说得很到位:我们其实重新发明了一次冯·诺依曼架构,因为对于任何计算系统来说,这都是一种非常自然的抽象。

工程分成三层

围绕模型的工程,可以分成三个同心层:

Harness 不是 prompt 外面的一层薄包装。

Harness 是让 autonomous agent behavior 成为可能的完整系统。

生产级 Harness 的 12 个组件

综合 Anthropic、OpenAI、LangChain 以及更广泛的实践者讨论,一个生产级 agent harness 里,至少有 12 个清晰可辨的组件。

1. Orchestration Loop

这是心跳。

它实现的是 Thought-Action-Observation,也就是 TAO cycle,通常也叫 ReAct loop。整个循环的运行方式是:组装 prompt,调用 LLM,解析输出,执行 tool calls,把结果喂回去,重复,直到完成。

从机械结构上看,它经常只是一个 while loop。

真正复杂的地方不在 loop 本身,而在 loop 需要管理的那一切。Anthropic 甚至把自己的 runtime 形容成一个“dumb loop”:所有 intelligence 都在模型里,harness 只负责管理 turn。

2. Tools

Tools 是 agent 的手。

它们通常以 schema 的形式定义:名字、描述、参数类型。然后这些 schema 会被注入到 LLM 的上下文里,让模型知道自己能调用什么。

Tool layer 负责的事情包括:注册工具、校验 schema、提取参数、在 sandbox 里执行、捕获结果、再把结果格式化成 LLM 可以继续消费的 observation。

Claude Code 把工具分成六类:文件操作、搜索、执行、网页访问、代码智能和 subagent spawning。OpenAI Agents SDK 则支持 function tools、hosted tools(像 WebSearch、CodeInterpreter、FileSearch)和 MCP server tools。

3. Memory

Memory 按时间尺度分层工作。

短期记忆,是单个 session 里的 conversation history。长期记忆,会跨 session 持续存在。Anthropic 用的是 CLAUDE.md project files 和自动生成的 MEMORY.md;LangGraph 用 namespace-organized JSON Stores;OpenAI 则支持基于 SQLite 或 Redis 的 Sessions。

Claude Code 的实现非常有代表性:

这里有一个很关键的设计原则:agent 会把自己的 memory 当成“hint”,然后在真正行动前再去和实际状态核对。

4. Context Management

很多 agent 都是在这里无声失败的。

核心问题是 context rot:当关键内容落在上下文中部时,模型性能会明显恶化。Chroma 的研究给出了 30% 以上的退化,Stanford 的 “Lost in the Middle” 也给出了相同方向的证据。就算你有 million-token 窗口,随着上下文变长,instruction-following 依然会开始下降。

生产环境里常见的策略包括:

Anthropic 的 context engineering 指南把目标说得很清楚:找到最小、但信号最强的一组 tokens,把它们摆出来,让 desired outcome 的概率最大化。

5. Prompt Construction

这一层决定模型每一步实际看见什么。

典型结构是分层的:system prompt、tool definitions、memory files、conversation history、当前 user message。

OpenAI 的 Codex 用的是一套非常严格的优先级堆栈:最高优先级是 server-controlled system message,然后是 tool definitions,再往下是 developer instructions、user instructions、级联 AGENTS.md 文件,最后才是 conversation history。

6. Output Parsing

现代 harness 基本都依赖 native tool calling。

模型返回的不再是必须靠正则硬拆的自由文本,而是结构化的 tool_calls 对象。Harness 的判断逻辑也因此很清楚:

如果要 structured outputs,OpenAI 和 LangChain 都支持基于 Pydantic model 的 schema-constrained response。旧式方案像 RetryWithErrorOutputParser 依然存在,但更多属于边缘补充。

7. State Management

LangGraph 把 state 建模成类型化 dictionary,在 graph nodes 之间流动,再通过 reducers 合并更新。Checkpoint 会在 super-step 边界发生,因此可以在中断之后恢复,也可以做 time-travel debugging。

OpenAI 给出了四种互斥策略:application memory、SDK sessions、服务端 Conversations API,以及更轻量的 previous_response_id chaining。

Claude Code 走的是另一条路:git commits 当 checkpoint,progress files 当结构化 scratchpads。

8. Error Handling

这一层为什么重要,可以用一个很简单的算式看出来:一个 10 步流程,如果每一步成功率是 99%,最后端到端成功率也只有大约 90.4%。错误会很快复利。

LangGraph 会把错误分成四类:

Anthropic 会在 tool handler 内部捕获失败,并把失败当作 error result 返回,这样 loop 还能继续。Stripe 的生产 harness 则把 retry cap 设成两次。

9. Guardrails and Safety

OpenAI 的 SDK 在这一层给了三层机制:

其中一个关键机制是 tripwire:一旦触发,agent 会立刻停下来。

Anthropic 在架构上把 permission enforcement 和 model reasoning 分开。模型决定想做什么;tool system 决定什么被允许。Claude Code 会对大约 40 种离散工具能力独立做 gating,并拆成三段:项目加载时建立信任、每次 tool call 前做 permission check、高风险操作再要求明确确认。

10. Verification Loops

这层是 toy demo 和 production agent 的分水岭。

Anthropic 推荐三类验证:

Claude Code 的创建者 Boris Cherny 说得很直接:只要给模型一个验证自己工作的办法,质量往往就能提升 2 到 3 倍。

11. Subagent Orchestration

Claude Code 支持三种执行模型:

OpenAI Agents SDK 则支持两种常见模式:

LangGraph 把 subagents 实现成嵌套 state graphs。

12. 运行时整合

单独列每个组件还不够。真正的 harness 价值,来自这些组件如何在同一个 runtime 里配合运转。Loop、tools、memory、state、verification、safety 和 subagents 不是分开的功能块,而是一台机器里的相互啮合件。

把 Loop 真正走一遍

知道了组件以后,再把一次实际循环走完,很多东西就更具体了。

Step 1:Prompt Assembly

Harness 先把完整输入组出来:system prompt + tool schemas + memory files + conversation history + 当前 user message。

关键内容会尽量放在开头和结尾,因为 “Lost in the Middle” 已经告诉我们,中部位置最容易掉信息。

Step 2:LLM Inference

组好的 prompt 送进模型 API。模型会吐出 output tokens:可能是文本,可能是 tool call request,也可能两者都有。

Step 3:Output Classification

如果模型只返回文本,没有 tool call,loop 结束。

如果模型请求 tool calls,就进入执行阶段。

如果发生 handoff,就更新当前 agent,再重新开始。

Step 4:Tool Execution

Harness 会针对每个 tool call:校验参数、检查权限、在 sandbox 里执行、捕获结果。

只读操作可以并发跑;会改状态的操作通常串行跑。

Step 5:Result Packaging

Tool results 会被打包成 LLM 可读的 message。错误也不会直接炸掉整个系统,而是会被捕获,并以 error result 的形式返回,让模型有机会自我修正。

Step 6:Context Update

结果被追加进 conversation history。

如果快撞上 context window 上限,harness 就触发 compaction。

Step 7:Loop

回到 Step 1,继续,直到结束。

终止条件通常是多层叠加的:

一个简单问题也许只要 1 到 2 个 turn。复杂的 refactoring 任务,可能会串起几十次 tool calls,跨越很多轮。

如果任务会跨越多个 context windows,Anthropic 还发展出一个两阶段的 Ralph Loop:先让 Initializer Agent 建环境,包括 init script、progress file、feature list、初始 git commit;之后每个新的 Coding Agent session 都先读 git log 和 progress file 来定位当前状态,再挑最高优先级的未完成项去做,做完 commit,写总结。这样一来,filesystem 本身就变成跨 context window 的连续性载体。

真实框架是怎么落地这套模式的

Anthropic 的 Claude Agent SDK 通过一个 query() 函数把 harness 暴露出来:它创建 agentic loop,然后以 async iterator 的方式流式返回消息。它的 runtime 很薄,近似就是“dumb loop”,核心智能在模型里。Claude Code 则围绕 Gather-Act-Verify 这个节奏运转:先 gather context,再 take action,然后 verify results,最后继续下一轮。

OpenAI Agents SDK 通过 Runner 类实现 harness,支持 async、sync 和 streamed 三种模式。它是 code-first 的:workflow logic 写在原生 Python 里,而不是图 DSL。Codex harness 在这上面又叠了一层三段架构:Codex Core、App Server、以及 CLI / VS Code / Web app 这些 client surfaces。也正因如此,Codex 模型在 Codex 自己的 surface 上,体验往往比通用聊天框更好。

LangGraph 把 harness 明确建模成 state graph。最简形式下,就是两个节点:llm_calltool_node,中间通过条件边连接:如果有 tool calls,就去 tool_node;没有,就到 END。LangGraph 本身是从 LangChain 的 AgentExecutor 演化出来的,因为后者太难扩展,也缺少 multi-agent support。LangChain 的 Deep Agents 已经明确使用了 “agent harness” 这个术语:它把 built-in tools、planning、filesystem-based context management、subagent spawning 和 persistent memory 都纳进来。

CrewAI 走的是 role-based multi-agent 路线:Agent、Task、Crew 三层清晰分工。它的 Flows 层则提供“deterministic backbone with intelligence where it matters”:路由和验证由确定性流程管理,自主协作交给 Crew。

AutoGen,后来演化成 Microsoft Agent Framework,则更早就把 conversation-driven orchestration 做了出来。它的三层结构——Core、AgentChat、Extensions——支持五种 orchestration pattern:sequential、concurrent、group chat、handoff 和 magentic,其中 magentic 是由一个 manager agent 维护动态 task ledger,再去协调 specialists。

为什么 Scaffold 这个比喻特别准

Scaffolding 这个比喻不是装饰性的,它非常精确。

施工脚手架本身不完成建筑,但没有脚手架,工人就上不去,也碰不到那些本来够不着的地方。

更关键的一点是:建筑完成以后,脚手架是要被拆掉的。

这直接指向一个核心判断:随着模型能力继续增强,harness 的复杂度应该下降。Manus 在六个月里重写了五次,每次都在删复杂度。复杂工具定义慢慢收缩成更通用的 shell execution。“管理 agent”这类结构,也被更简单的 structured handoff 取代。

这又引出另一个原则:harness 和模型正在协同进化。模型已经开始在特定 harness 环境里接受后训练。Claude Code 的模型,学会的是使用它所配套的那套 harness。工具实现一旦变化,性能反而可能下降,因为两者之间已经耦合得很紧。

一个很好的 future-proofing test 是:如果模型更强以后,不需要继续增加 harness complexity,性能还能往上走,那这套 harness 设计就站住了。

每一套 Harness 都逃不开的 7 个设计抉择

每个 harness architect 都得回答七个问题。

1. 单 Agent 还是多 Agent

Anthropic 和 OpenAI 的建议都很接近:先把单 agent 压到极限。

多 agent 会带来额外开销:路由多一次 LLM call,handoff 带来上下文损失。只有当 tool overload 真的超过大约 10 个重叠工具,或者任务域明显分裂时,再去拆。

2. ReAct 还是 Plan-and-Execute

ReAct 在每一步交织 reasoning 和 action,灵活,但 per-step cost 更高。

Plan-and-execute 则把规划和执行拆开。LLMCompiler 报告过,相比顺序 ReAct,它能带来 3.6 倍加速。

3. 怎么管理 Context Window

生产环境里大致有五类办法:按时间清空、对话总结、observation masking、结构化 note-taking、sub-agent delegation。

ACON 的研究给出过一个很有意思的结果:只要优先保留 reasoning traces,而不是原始 tool outputs,就能减少 26% 到 54% 的 tokens,同时保住 95% 以上的准确率。

4. Verification Loop 怎么设计

计算型验证——测试、linter——能给出确定性的 ground truth。

推断型验证——LLM-as-judge——能抓语义问题,但会增加 latency。

Thoughtworks 团队把它归纳成 guides 和 sensors:前者是 feedforward,在行动前引导;后者是 feedback,在行动后感知。

5. 权限和安全放在哪一层

可以更 permissive,更快,但风险也更高;也可以更 restrictive,更慢,但更安全。

具体怎么取,要看部署语境。

6. 工具怎么收口

工具越多,效果往往越差。

Vercel 在 v0 里砍掉了 80% 的 tools,结果反而更好。Claude Code 借助 lazy loading,把上下文负担压掉了 95%。

原则很简单:只暴露当前这一步真正需要的最小工具集。

7. Harness 到底应该多厚

多少逻辑放在 harness,多少交给模型,这是最根本的架构选择。

Anthropic 更押注薄 harness,把更多能力留给模型内化。Graph-based frameworks 则押注显式控制。Claude Code 随着模型版本升级,也在持续删除 harness 里的 planning steps,因为模型已经能自己完成它们了。

Harness 本身就是产品

两个产品,用完全相同的模型,最后表现也可能天差地别,差异全来自 harness 设计。

TerminalBench 的证据已经足够清楚:只改 harness,就能让 agent 的排名前进 20 多个名次。

Harness 不是已经解决的问题,也不是一层 commodity。

真正艰难的工程,就在 harness 里:

这个领域正在朝更薄的 harness 移动,因为模型在变强。

但 harness 本身不会消失。

再强的模型,也需要有人替它管理 context window、执行 tool calls、持久化 state、验证工作结果。

下次你的 agent 失败时,先别怪模型。

先看看 harness。

本页为精翻阅读版。原文版权归原作者所有,中文译文仅用于学习与研究传播。