《深入理解 AI Agent》之学习笔记-DAY 2(ReAct 循环 + Harness 工程 )
Day 2:ReAct 循环 + Harness 工程
核心知识点
1. ReAct 循环:Agent 的心跳
Day 1 学了 Agent = LLM + 上下文 + 工具,但这三个东西怎么协同工作?答案就是 ReAct 循环(Reasoning + Acting)。
名字只有两个词,但实际循环是三个环节:
想(Reasoning)→ 做(Acting)→ 看(Observing)→ 想 → 做 → 看 → …
直到任务完成。具体来说:
- 想:模型先思考当前应该做什么
- 做:模型调用工具执行行动
- 看:观察工具返回的结果,继续思考下一步
工具调用的四步流程
这是 ReAct 循环中"做"这个环节的展开:
| 步骤 | 做什么 | 谁来做 |
|---|---|---|
| ① 声明工具 | 在上下文里告诉模型有哪些工具可用(名称、用途、参数) | 开发者 |
| ② 模型决定调用 | 模型自主判断:要不要调?调哪个?传什么参数? | 模型 |
| ③ 结果追加 | 工具执行完毕,结果被追加到上下文中 | 框架 |
| ④ 模型继续决策 | 根据结果决定下一步 | 模型 |
书中用了一个查天气的例子,伪代码表示如下:
第一步:声明工具 第二步:模型决定调用
tools: [{ assistant: {
name: "get_weather", tool_calls: [{
parameters: { function: "get_weather",
city: "string" arguments: {city: "北京"}
} }]
}] }
第三步:结果追加到上下文 第四步:模型基于结果回复
tool: { assistant: {
tool_call_id: "call_1", content: "北京今天 28°C,晴。"
content: '{"temp":28}'
} }
关键洞察:开发者只需要定义工具和执行工具调用,"要不要调用、调哪个、传什么参数"的决策完全由模型自主完成。
轨迹(Trajectory):Agent 的记忆
轨迹是 ReAct 循环中最重要的概念——它是 Agent 执行过程中不断积累的消息历史。
Agent 的上下文 = 静态前缀(系统提示词 + 工具定义)+ 轨迹(动态消息历史)
书中用了一个多币种收入汇总的例子来演示轨迹:
轨迹 = [
{role: "user", content: "Q1 2.5M美元, Q2 2.1M欧元, Q3 1.8M英镑, Q4 380M日元, 计算年度总收入"},
# 第1轮 - 模型看到轨迹,决定并行调3个货币转换工具
{role: "assistant",
reasoning: "需要将所有货币转换为USD...",
tool_calls: [
{name: "convert_currency", args: {amount: 2100000, from: "EUR", to: "USD"}},
{name: "convert_currency", args: {amount: 1800000, from: "GBP", to: "USD"}},
{name: "convert_currency", args: {amount: 380000000, from: "JPY", to: "USD"}}
]},
# 工具执行结果追加
{role: "tool", content: "EUR->USD: 2282608.7"},
{role: "tool", content: "GBP->USD: 2278481.01"},
{role: "tool", content: "JPY->USD: 2541806.02"},
# 第2轮 - 模型看到完整轨迹(含工具结果),调代码解释器汇总
{role: "assistant",
reasoning: "已获得转换结果,现在需要汇总计算...",
tool_calls: [{name: "code_interpreter", args: {code: "total = 2500000 + 2282608.7 + ..."}}]},
{role: "tool", content: "Total: $9,602,895.73, Average: $2,400,723.93"},
# 第3轮 - 所有计算完成,生成最终答案
{role: "assistant",
reasoning: "所有计算完成,总结结果...",
content: "FINAL ANSWER: 总收入$9,602,895.73..."}
]
注意:轨迹里没有显示系统提示词和工具定义——它们作为静态前缀,在每次 LLM 调用时自动拼接在轨迹前面。
这个例子只用了 3 次迭代、4 次工具调用就完成了复杂的多步骤任务。精妙之处在于上下文的累积性——每次 LLM 调用都能看到完整的轨迹,这让模型理解当前在任务的哪个阶段、之前做了什么、得到了什么结果。
2. Harness 工程:模型之外的竞争力
Demo 公式:Agent = LLM + 上下文 + 工具
生产公式:Agent = LLM + [上下文 + 工具 + 约束 + 验证 + 纠正] = Model + Harness
为什么需要后面三项?因为一个能跑的 Demo 和一个可靠的产品之间有巨大的鸿沟。模型可能:
- 产生幻觉(编造不存在的工具或参数)
- 选错工具
- 遇到错误时无法自我恢复
书里用退订单的例子说明:
| 没有 Harness | 有 Harness | |
|---|---|---|
| 上下文 | 看不到退款政策 | 系统提示词写明7天退款政策 |
| 工具 | 不知道该调哪个API | 调用 query_order 和 process_refund |
| 约束 | 无 | 校验退款金额不超过订单金额 |
| 验证 | 无 | 校验数据库状态确认退款成功 |
| 纠正 | 无 | API超时则自动重试 |
同一个模型,有无 Harness,结果天壤之别。
Harness 五要素
| 功能 | 一句话职责 | 核心原则 | 实际例子 |
|---|---|---|---|
| 上下文 | 提供感知信息 | 信息充分性:每个决策点都有足够信息 | 系统提示词、知识库、Agent状态栏 |
| 工具 | 提供行动手段 | 接口清晰:命名直观、参数有例子 | MCP工具、代码解释器、搜索工具 |
| 约束 | 设定行为边界 | 故障安全默认值:默认关闭,显式开放 | Claude Code每个工具默认需用户授权 |
| 验证 | 判断操作结果对错 | 输入隔离:只看结构化数据,不看模型自由文本 | Linter检查、类型系统、结果校验 |
| 纠正 | 发现问题时自动修正 | 不暴露中间态:先静默重试,失败再回退 | 静默重试、接续生成、熔断机制 |
五个功能构成一个闭环:上下文与工具支撑决策 → 约束预防错误 → 验证发现偏差 → 纠正闭合循环。
为什么 Harness 才是竞争力
“当各家模型的能力越来越接近、不再是决定性的差异因素时,竞争优势就转移到了模型之外的工程实践。”
LangChain 的实践是很好的例证:Coding Agent 从 52.8% 提升到 66.5%,改变的不是模型,而是 Harness——让 Agent 自动检查执行结果、检测是否陷入重复循环、优化思考策略。
3. 上下文适应的三层机制
Agent 的学习/适应不止发生在训练阶段。按更新的位置和持续时间,有三条互补路径:
| 层次 | 发生位置 | 持续时间 | 优势 | 局限 | 对应章节 |
|---|---|---|---|---|---|
| 上下文适应 | 当前任务内 | 仅本次会话 | 快速、低成本 | 受窗口限制 | 第2章 |
| 外部产物更新 | 跨任务 | 持久保留 | 可审计、可修订 | 需通过上下文使用 | 第3-5、8章 |
| 模型参数更新 | 训练周期 | 永久 | 广泛泛化 | 部署成本高 | 第7章 |
三者协同:上下文负责临场,产物负责积累,参数负责内化。
4. 工作流 vs 自主 Agent
选择原则:从简单到复杂
单个 LLM 调用 → 工作流 → 自主 Agent
↑ ↑ ↑
能解决就别加复杂度 可分解为固定子任务 需要动态决策才用
| 工作流 | 自主 Agent | |
|---|---|---|
| 执行路径 | 预定义代码路径,确定性的 | 根据反馈实时决定 |
| 优势 | 严格控制、安全 | 灵活、能处理未预料情况 |
| 局限 | 缺乏变通 | 成本高、复合错误风险 |
| 适用 | 有严格合规要求的流程 | 开放式问题 |
实践中常混合使用:关键流程用工作流确保可靠性,灵活决策部分切换到自主模式。比如 n8n 可以在同一个系统中同时使用工作流节点和自主 Agent 节点。
更多推荐



所有评论(0)