开发工程 / 工作流案例

Agent Harness 的结构解析

初级到中级 首次搭建后持续迭代 @akshay_pachaar
结果

把“搭 agent”从写 prompt 转成搭基础设施 | 编排、记忆、工具、状态和容错一起设计

适合谁

准备把聊天式 LLM 做成生产可用 agent 的工程团队 / 独立开发者

您已经搭建了一个聊天机器人。也许您还用一个 ReAct 循环接上了几个工具。演示没问题,但一旦试图构建生产级系统,问题就全冒出来了:模型忘了三步前做了什么,工具调用悄无声息地失败,上下文窗口填满了垃圾信息。

问题不在模型本身,而在模型周围的一切。

LangChain 用行动证明了这一点:他们只改动了 LLM 外围的基础设施(同一模型、同一权重),就在 TerminalBench 2.0 上从未进前 30 名直接跃升至第 5 名。另一个独立研究项目通过让 LLM 自行优化基础设施,达到了 76.4% 的通过率,超越了人工设计的系统。

这套基础设施现在有了专属名称:Agent Harness。

什么是 Agent Harness?

这个词在 2026 年初正式定名,但概念早已存在。Harness 是包裹 LLM 的完整软件基础设施:编排循环、工具、记忆、上下文管理、状态持久化、错误处理和护栏。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》中精准地做了类比。原始 LLM 就像一个没有 RAM、没有磁盘、没有 I/O 的 CPU。上下文窗口相当于 RAM(快但有限),外部数据库充当磁盘存储(大但慢),工具集成相当于设备驱动程序,而 harness 就是操作系统。Millidge 写道:“我们重新发明了冯·诺依曼架构”——因为它是任何计算系统都自然适用的抽象。

三个工程层次

围绕模型有三个同心圆级别的工程:

  • 提示工程:设计模型接收的指令。
  • 上下文工程:管理模型看到的内容及其时机。
  • Harness 工程:涵盖以上两者以及整个应用基础设施:工具编排、状态持久化、错误恢复、验证循环、安全执行和生命周期管理。

Harness 不是提示的包装器,它是实现自主 Agent 行为的完整系统。

生产级 Harness 的 12 个组件

综合 Anthropic、OpenAI、LangChain 以及更广泛的实践者社区,一个生产级 Agent Harness 包含十二个不同的组件。我们来逐一分析。

1. 编排循环

这是心跳。它实现了 Thought-Action-Observation (TAO) 循环,也就是 ReAct 循环。循环运行过程:组装提示、调用 LLM、解析输出、执行任何工具调用、将结果反馈回去、重复直到结束。

从机制上看,它往往只是一个 while 循环。复杂性在于循环所管理的一切,而非循环本身。Anthropic 将其运行时描述为“笨循环”,所有智能都存在于模型之中,harness 只负责管理轮次。

2. 工具

工具是 agent 的双手。它们被定义为注入 LLM 上下文的模式(名称、描述、参数类型),让模型知道有哪些可用。工具层负责注册、模式校验、参数提取、沙箱执行、结果捕获,以及将结果格式化为 LLM 可读的观察。

Claude Code 提供六大类工具:文件操作、搜索、执行、网络访问、代码智能和子 Agent 生成。OpenAI 的 Agents SDK 支持函数工具(通过 @function_tool)、托管工具(WebSearch、CodeInterpreter、FileSearch)以及 MCP 服务器工具。

3. 记忆

记忆在多个时间尺度上运作。短期记忆是单次会话中的对话历史。长期记忆跨会话持久化:Anthropic 使用 CLAUDE.md 项目文件和自动生成的 MEMORY.md 文件;LangGraph 使用按命名空间组织的 JSON 存储;OpenAI 支持基于 SQLite 或 Redis 的 Session。

Claude Code 实现了三层层级:轻量级索引(每条约 150 字符,始终加载)、按需拉取的详细主题文件、以及仅通过搜索访问的原始转录。一个关键设计原则:agent 将自己的记忆视为“提示”,并在行动前对照实际状态进行验证。

4. 上下文管理

这是许多 agent 在不知不觉中失败的地方。核心问题是上下文腐败:当关键内容落在中间窗口位置时,模型性能下降 30% 以上(Chroma 研究,经斯坦福“Lost in the Middle”发现证实)。即使百万级的窗口,随着上下文增长,指令遵循能力也会退化。

生产级策略包括:

  • 压缩:接近限制时总结对话历史(Claude Code 保留架构决策和未解决的 bug,丢弃冗余工具输出)。
  • 观察屏蔽:JetBrains 的 Junie 隐藏旧的工具输出,但保留工具调用可见。
  • 即时检索:维护轻量级标识符,动态加载数据(Claude Code 使用 grep、glob、head、tail 而非加载完整文件)。
  • 子 Agent 委派:每个子 Agent 进行深入探索,但仅返回 1,000 至 2,000 token 的浓缩摘要。

Anthropic 的上下文工程指南指出了目标:找到尽可能少的高信号 token,最大程度提高期望结果出现的概率。

5. 提示词构建

这一步负责组装模型在每个步骤实际看到的内容。它是分层的:系统提示词、工具定义、记忆文件、对话历史以及当前用户消息。

OpenAI 的 Codex 使用严格的优先级堆栈:服务器控制的系统消息(最高优先级)、工具定义、开发者指令、用户指令(级联的 AGENTS.md 文件,32 KiB 限制),然后是对话历史。

6. 输出解析

现代工具链依赖原生工具调用,模型会返回结构化的 tool_calls 对象,而不是需要自行解析的自由文本。工具链会检查:是否有工具调用?执行它们并循环。没有工具调用?那就是最终答案。

对于结构化输出,OpenAI 和 LangChain 都支持通过 Pydantic 模型进行 schema 约束的响应。传统的做法如 RetryWithErrorOutputParser(将原始提示词、失败的补全以及解析错误反馈给模型)仍然可用于边缘情况。

7. 状态管理

LangGraph 将状态建模为类型化的字典,在图的节点间流动,并通过 reducer 合并更新。检查点会在超步边界处创建,从而实现中断后的恢复和时间旅行调试。OpenAI 提供四种互斥策略:应用内存、SDK 会话、服务器端 Conversations API,或轻量级的 previous_response_id 链。Claude Code 采用不同的方式:以 git 提交作为检查点,以进度文件作为结构化的草稿本。

8. 错误处理

这一点为什么重要:一个 10 步流程,如果每步成功率为 99%,最终端到端成功率只有约 90.4%。错误会快速累积。

LangGraph 区分了四种错误类型:临时性错误(带退避的重试)、LLM 可恢复错误(将错误作为 ToolMessage 返回,让模型进行调整)、用户可修复错误(中断并等待人工输入)和意外错误(向上抛出以便调试)。Anthropic 会捕获工具处理器内部的失败,并以错误结果的形式返回,以保持循环运行。Stripe 的生产工具链将重试次数上限设为两次。

9. 护栏与安全

OpenAI 的 SDK 实现了三个层级:输入护栏(在第一个 agent 上运行)、输出护栏(在最终输出上运行)和工具护栏(在每次工具调用时运行)。“绊线”机制会在触发时立即停止 agent。

Anthropic 在架构上将权限执行与模型推理分离。模型决定尝试什么,工具系统决定允许什么。Claude Code 独立控制约 40 个离散的工具能力,分为三个阶段:项目加载时的信任建立、每次工具调用前的权限检查,以及高风险操作的明确用户确认。

10. 验证循环

这是玩具演示和生产级 agent 的区别所在。Anthropic 推荐三种方法:基于规则的反馈(测试、lint 检查、类型检查)、视觉反馈(通过 Playwright 截图处理 UI 任务)和 LLM 作为评判(用一个独立的子 agent 评估输出)。

Claude Code 的创建者 Boris Cherny 指出,让模型拥有验证自身工作的能力可将质量提升 2 到 3 倍。

11. 子 Agent 编排

Claude Code 支持三种执行模式:Fork(父上下文的字节级精确副本)、Teammate(单独的终端面板,基于文件的邮箱通信)和 Worktree(独立的 git 工作树,每个 agent 隔离分支)。OpenAI 的 SDK 支持 agent 作为工具(专业 agent 处理有边界的子任务)和交接(专业 agent 完全接管控制权)。LangGraph 将子 agent 实现为嵌套的状态图。

循环运转:逐步演示

现在你已经了解了各个组件,让我们追踪它们在一个单一循环中如何协同工作。

  • 步骤 1(提示词组装): 工具链构建完整的输入:系统提示词 + 工具 schema + 记忆文件 + 对话历史 + 当前用户消息。重要上下文被放置在提示词的开头和末尾(“迷失在中间”研究结论)。
  • 步骤 2(LLM 推理): 组装后的提示词发送给模型 API。模型生成输出 token:文本、工具调用请求,或两者都有。
  • 步骤 3(输出分类): 如果模型只产生文本而没有工具调用,循环结束。如果它请求工具调用,则进入执行阶段。如果请求交接,则更新当前 agent 并重新启动。
  • 步骤 4(工具执行): 对于每次工具调用,工具链验证参数、检查权限、在沙盒环境中执行并捕获结果。只读操作可以并发执行,修改操作则串行执行。
  • 步骤 5(结果打包): 工具结果被格式化为 LLM 可读的消息。错误被捕获并以错误结果返回,以便模型自我修正。
  • 步骤 6(上下文更新): 结果被追加到对话历史中。如果接近上下文窗口限制,工具链会触发压缩。
  • 步骤 7(循环): 返回步骤 1。重复直到终止。

终止条件是多层次的:模型产出了没有工具调用的响应、超过最大轮次限制、token 预算耗尽、护栏绊线触发、用户中断,或者返回了安全拒绝。一个简单的问题可能需要 1 到 2 轮。一个复杂的重构任务可以在多轮中链式调用数十次工具。

对于跨越多个上下文窗口的长期任务,Anthropic 开发了一个两阶段的“Ralph 循环”模式:初始化 Agent 设置环境(初始化脚本、进度文件、功能列表、初始 git 提交),然后编码 Agent 在后续每个会话中读取 git 日志和进度文件来定位自身,选择优先级最高且未完成的功能,进行工作、提交并编写摘要。文件系统提供了跨上下文窗口的连续性。

实际框架如何实现该模式

Anthropic 的 Claude Agent SDK 通过一个 query() 函数暴露工装,该函数创建 Agent 循环并返回一个异步迭代器用于流式传输消息。运行时是一个"傻瓜循环",所有智能都存在于模型中。Claude Code 采用"收集-行动-验证"循环:收集上下文(搜索文件、读取代码)、采取行动(编辑文件、运行命令)、验证结果(运行测试、检查输出)、重复。

OpenAI 的 Agents SDK 通过 Runner 类实现工装,支持三种模式:异步、同步和流式。该 SDK 是"代码优先"的:工作流逻辑用原生 Python 表达,而非图 DSL。Codex 工装在此基础上扩展为三层架构:Codex Core(Agent 代码 + 运行时)、App Server(双向 JSON-RPC API)和客户端界面(CLI、VS Code、Web 应用)。所有界面共享同一个工装,这也是为什么"Codex 模型在 Codex 界面上的体验比普通聊天窗口更好"。

LangGraph 将工装建模为显式的状态图。两个节点(llm_calltool_node)通过条件边连接:如果存在工具调用,路由到 tool_node;如果没有,路由到 END。LangGraph 源自 LangChain 的 AgentExecutor,后者在 v0.2 中被弃用,因为难以扩展且缺乏多 Agent 支持。LangChain 的 Deep Agents 明确使用了"Agent 工装"这一术语:内置工具、规划(write_todos 工具)、用于上下文管理的文件系统、子 Agent 生成和持久化记忆。

CrewAI 实现了基于角色的多 Agent 架构:Agent(围绕 LLM 的工装,由角色、目标、背景故事和工具定义)、Task(工作单元)和 Crew(Agent 集合)。CrewAI 的 Flows 层添加了"确定性骨架,在关键处注入智能",管理路由和验证,而 Crews 处理自主协作。

AutoGen(正演变为 Microsoft Agent Framework)开创了对话驱动的编排。其三层架构(Core、AgentChat、Extensions)支持五种编排模式:顺序、并发(扇出/扇入)、群聊、移交和 magentic 模式(管理 Agent 维护一个动态任务账本,协调各专家)。

脚手架隐喻

脚手架隐喻并非装饰,而是精确的。建筑施工脚手架是临时基础设施,让工人能够建造本来够不到的结构。脚手架本身不负责建造,但没有它,工人就上不了高层。

关键洞察:建筑完工后脚手架会被拆除。随着模型改进,工装复杂度也应降低。Manus 在六个月内重建了五次,每次重写都在精简复杂度。复杂的工具定义变成了通用的 shell 执行。"管理 Agent"变成了简单的结构化移交。

这指向了共同进化原则:模型现在是在特定工装的循环中经过后训练的。Claude Code 的模型学会了使用它训练时所针对的特定工装。由于这种紧密耦合,改变工具实现可能会导致性能下降。

工装设计的"未来验证测试":如果在不增加工装复杂度的前提下,性能随更强大的模型提升而提升,则该设计是合理的。

定义每一个工装的七大决策

每位工装架构师都面临七个选择:

  1. 单 Agent 与多 Agent。Anthropic 和 OpenAI 都表示:优先最大化单 Agent。多 Agent 系统会增加开销(额外的 LLM 调用用于路由、移交时的上下文丢失)。只有当工具过载超过约 10 个重叠工具,或存在明确分离的任务领域时,才拆分。
  1. ReAct 与规划-执行。ReAct 在每一步中交错进行推理和行动(灵活但单步成本更高)。规划-执行将规划与执行分离。LLMCompiler 报告称,相比顺序 ReAct,速度提升了 3.6 倍。
  1. 上下文窗口管理策略。五种生产级方法:按时间清除、对话摘要、观察掩码、结构化笔记和子 Agent 委派。ACON 研究表明,通过优先保留推理轨迹而非原始工具输出,可减少 26% 到 54% 的 token,同时保持 95% 以上的准确率。
  1. 验证循环设计。计算验证(测试、linter)提供确定性事实。推理验证(LLM-as-judge)能捕获语义问题,但会增加延迟。Martin Fowler 的 Thoughtworks 团队将其框架化为"指南"(前馈,在行动前引导)与"传感器"(反馈,在行动后观察)。
  1. 权限与安全架构。宽松型(快速但有风险,自动批准大多数操作)与严格型(安全但缓慢,每个操作都需要批准)。选择取决于部署上下文。
  1. 工具范围策略。工具越多,性能往往越差。Vercel 从 v0 中移除了 80% 的工具,结果更好。Claude Code 通过懒加载实现了 95% 的上下文缩减。原则:暴露当前步骤所需的最小工具集。
  1. 工装厚度。多少逻辑放在工装中,多少留给模型。Anthropic 押注于薄工装和模型改进。基于图的框架押注于显式控制。Anthropic 会定期从 Claude Code 的工装中删除规划步骤,因为新模型版本已将这一能力内化。

工装即产品

两个使用相同模型的产品,仅因工装设计不同,性能可能天差地别。TerminalBench 的证据很明确:仅改变工装就让 Agent 的排名变动了 20 多个位置。

工装不是一个已解决的问题,也不是一个通用层。它正是硬核工程所在:将上下文作为稀缺资源进行管理,设计能在失败累积前就捕获它们的验证循环,构建既能提供连续性又不产生幻觉的记忆系统,以及做出关于构建多少脚手架、留多少给模型的结构性赌注。

随着模型能力的提升,这个领域正朝着更轻量的马具(Harness) 发展。但马具本身不会消失。即便是最强大的模型,也需要某种机制来管理其上下文窗口、执行工具调用、持久化状态并验证其工作。

下次你的 Agent 失败时,别怪模型。看看马具。

以上就是本期内容!

如果你喜欢这篇文章:

关注我 → @akshay_pachaar ✔️

我每天都会分享关于 AI、机器学习以及 Vibe Coding 最佳实践的教程与见解。

相关案例