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 节点。

更多推荐