Agent Harness 解析:智能体架构深度拆解
你搭过一个聊天机器人,接入了ReAct循环,挂了几个工具,演示效果不错。
但当你要把它做成生产级产品时,问题随之而来:
- 模型记不住三步前做了什么
- 工具调用静默失败
- 上下文窗口被垃圾填满
问题不在模型。在模型周围的一切。
什么是 Agent Harness?
定义:Harness 是包裹LLM的完整软件基础设施——编排循环、工具、记忆、上下文管理、状态持久化、错误处理、安全护栏。
LangChain的Vivek Trivedy:"如果你不是模型本身,你就是harness。"
Agent vs Harness 的区别:
- Agent:涌现出来的行为,是用户交互的那个有目标、会用工具、能自我纠正的实体
- Harness:产生这种行为的机器
当有人说"我做了个agent",他们其实是做了个harness,然后把它对准了一个模型。
脚手架比喻
裸LLM = 没有内存、没有硬盘、没有I/O的CPU
- 上下文窗口 = 内存(快但有限)
- 外部数据库 = 硬盘(大但慢)
- 工具集成 = 设备驱动
- Harness = 操作系统
我们重新发明了冯·诺依曼架构,因为这是任何计算系统的自然抽象。
三个工程层级
| 层级 | 职责 |
|---|---|
| 提示词工程 | 设计模型接收的指令 |
| 上下文工程 | 管理模型看到什么、什么时候看到 |
| Harness工程 | 包含前两者,再加上工具编排、状态持久化、错误恢复、验证循环、安全执行、生命周期管理 |
生产级Harness的11个组件
1. 编排循环
核心心跳。实现"思考-行动-观察"(TAO)循环,也叫ReAct循环:
- 组装提示词
- 调用LLM
- 解析输出
- 执行工具调用
- 把结果反馈回去
- 重复直到完成
Anthropic把他们的运行时描述为一个"笨循环"——所有智能都住在模型里,Harness只管理轮次。
2. 工具
工具是agent的手。以schema形式定义(名称、描述、参数类型),注入到LLM的上下文中。
Claude Code提供六类工具:文件操作、搜索、执行、网络访问、代码智能、子agent生成。
OpenAI Agents SDK支持:函数工具、托管工具(WebSearch、CodeInterpreter、FileSearch)、MCP服务器工具。
3. 记忆
在多个时间尺度上运作:
| 类型 | 说明 | 实现方式 |
|---|---|---|
| 短期记忆 | 单次会话内的对话历史 | 对话历史 |
| 长期记忆 | 跨会话持久化 | CLAUDE.md、MEMORY.md、JSON Store、SQLite/Redis Session |
Claude Code三层记忆:
- 轻量级索引(每条约150字符,始终加载)
- 按需拉取的详细主题文件
- 只能通过搜索访问的原始记录
关键设计原则:agent把自己的记忆视为"提示",在行动前会对照实际状态进行验证。
4. 上下文管理
核心问题:上下文腐烂。当关键内容落在窗口中间位置时,模型性能下降超过30%("迷失在中间"现象)。
生产级策略:
| 策略 | 说明 |
|---|---|
| 压缩 | 接近上限时对对话历史进行摘要(保留架构决策和未解决的bug,丢弃冗余的工具输出) |
| 观察屏蔽 | 隐藏旧的工具输出,但保留工具调用可见 |
| 即时检索 | 维护轻量级标识符,动态加载数据(用grep、glob、head、tail,而非加载完整文件) |
| 子agent委托 | 每个子agent进行大范围探索,但只返回1000-2000 token的压缩摘要 |
Anthropic目标:找到能最大化期望结果概率的最小高信噪token集合。
5. 提示词构建
分层组装:系统提示 → 工具定义 → 记忆文件 → 对话历史 → 当前用户消息。
OpenAI Codex优先级栈:
- 服务器控制的系统消息(最高优先级)
- 工具定义
- 开发者指令
- 用户指令(级联的AGENTS.md文件,32 KiB上限)
- 对话历史
6. 输出解析
现代Harness依赖原生工具调用——模型返回结构化的tool_calls对象,而非需要解析的自由文本。
Harness检查:
- 有工具调用?执行并循环
- 没有工具调用?那就是最终答案
7. 状态管理
| 框架 | 实现 |
|---|---|
| LangGraph | 状态建模为流程图节点,用reducer合并更新,检查点在超步边界触发 |
| OpenAI | 四种策略:应用内内存、SDK session、服务端Conversations API、轻量级previous_response_id链接 |
| Claude Code | git提交作为检查点,进度文件作为结构化草稿纸 |
8. 错误处理
关键洞察:每步成功率99%的10步流程,端到端成功率只有约90.4%。错误会快速累积。
LangGraph四种错误类型:
| 类型 | 处理方式 |
|---|---|
| 瞬时错误 | 带退避重试 |
| LLM可恢复错误 | 将错误作为ToolMessage返回让模型调整 |
| 用户可修复错误 | 中断请求人工输入 |
| 意外错误 | 向上冒泡用于调试 |
Stripe生产Harness:把重试次数上限设为两次。
9. 护栏与安全
OpenAI三层护栏:
- 输入护栏(运行在第一个agent上)
- 输出护栏(运行在最终输出上)
- 工具护栏(每次工具调用都运行)
Anthropic架构:权限执行与模型推理分离——模型决定尝试什么,工具系统决定允许什么。
Claude Code三阶段:项目加载时的信任建立 → 每次工具调用前的权限检查 → 高风险操作的明确用户确认。
10. 验证循环
这是玩具demo和生产agent的分水岭。
Anthropic推荐三种方式:
- 基于规则的反馈(测试、代码检查、类型检查器)
- 视觉反馈(通过Playwright截图用于UI任务)
- LLM作为评判者(独立的子agent评估输出)
Claude Code创始人Boris Cherny:给模型一种验证自身工作的方式能将质量提升2到3倍。
11. 子agent编排
| 模式 | 说明 |
|---|---|
| Fork | 父上下文的字节级复制 |
| Teammate | 独立终端面板,通过基于文件的邮箱通信 |
| Worktree | 每个agent拥有独立的git工作树和隔离分支 |
OpenAI支持agent作为工具(专家处理有限子任务)和移交(专家接管完整控制权)。
循环如何运转:七步演练
| 步骤 | 动作 |
|---|---|
| 1 | 提示词组装:系统提示 + 工具schema + 记忆文件 + 对话历史 + 用户消息 |
| 2 | LLM推理:发送给模型API,生成输出token |
| 3 | 输出分类:纯文本→结束;有工具调用→执行;有移交→更新当前agent |
| 4 | 工具执行:验证参数→检查权限→沙盒执行→捕获结果 |
| 5 | 结果打包:格式化为LLM可读消息,错误作为错误结果返回 |
| 6 | 上下文更新:追加到对话历史,接近窗口限制时触发压缩 |
| 7 | 循环:返回第1步 |
终止条件:模型无工具调用响应、超轮次限制、token预算耗尽、护栏断路器触发、用户中断、安全拒绝。
主流框架对比
| 框架 | Harness实现特点 |
|---|---|
| Claude Agent SDK | 单一query()函数暴露Harness,"笨循环"运行时,收集-行动-验证循环 |
| OpenAI Agents SDK | Runner类支持异步/同步/流式三种模式,"代码优先"(原生Python表达工作流逻辑,非图DSL),Codex三层架构(Core + App Server + 客户端界面) |
| LangGraph | Harness建模为显式状态图,两节点通过条件边连接,Deep Agents内置工具、规则、文件系统、子agent生成、持久记忆 |
| CrewAI | 基于角色的多agent架构(Agent + Task + Crew),Flows层增加确定性骨架管理路由和验证 |
| AutoGen | 对话驱动的编排方式,三层架构支持五种模式:顺序、并发、群聊、移交、amagentic |
小结
Harness不会消失——模型能力越来越强,但让LLM变得有用的非模型基础设施永远是必需的。
关键要点:
- 区分Agent和Harness:Agent是涌现行为,Harness是产生行为的机器
- 生产级需要全套组件:编排、工具、记忆、上下文、状态、错误、安全、验证、子agent
- 上下文管理是核心难题:"迷失在中间"问题需要压缩、屏蔽、即时检索、子agent委托等策略
- 验证循环是分水岭:玩具demo vs 生产agent的关键区别
整理于 2026-05-23