从回答问题到完成任务
假设你要做一个采购助手,用户问:“仓库里还有多少支黑色签字笔?不够 20 支的话,需要补多少?”
完成这个任务,需要查询库存,再根据结果计算。设计应用时,不能预先假定库存是多少,也不能让模型凭空填写查询结果。
ReAct 提供了一种组织方式:让模型根据已有信息决定下一步行动,获取外部反馈,再调整后续步骤。它把推理与行动交替组织起来,使任务能够随着新信息逐步推进。(react-lm.github.io)
ReAct 到底是什么
ReAct 来自 Reasoning 与 Acting,可以理解为“推理与行动相结合”。这里的推理负责分析任务、判断缺少什么信息;行动负责与外部环境交互,例如搜索资料、查询数据库。两者通过反馈连接起来。(doi.org)
经典表达包含三个部分:
- Thought(思考):分析当前状态,确定下一步目标。
- Action(行动):发出具体操作请求。
- Observation(观察):接收操作产生的真实结果。
模型读取观察结果后,继续判断,直到能够回答或完成任务。这种交替可以按任务需要安排,不要求每次行动前都输出一大段推理。(research.google)
在下面的应用设计中,我们只保留简短的行动说明,方便调试;执行器真正依赖的是工具名称、参数和返回结果。
为什么需要这个循环
只依靠模型已有知识进行推理,无法直接取得外部环境中的新信息;只安排一串动作,又可能缺少对目标、进度和异常的判断。ReAct 将两者结合,让观察结果影响下一步决策。(research.google)
回到采购助手:如果查询返回多个同名商品,就应先确认规格;如果只找到一个商品,就可以继续读取库存。这种路径需要根据结果选择。
不过,步骤明确的任务可以直接写成固定流程。引入自主决策通常会增加调用成本和等待时间,因此应从简单方案开始,在确实需要灵活调整路径时再使用 Agent。(anthropic.com)
把循环拆成可实现的程序
建议先搭一个小型执行器,明确三方职责:
- 模型选择下一步动作,输出结构化请求。
- 程序检查请求,调用允许使用的工具。
- 工具返回结果,程序将结果加入上下文,再次调用模型。
这对应了 ReAct 中“推理指导行动、环境反馈支持后续推理”的过程。(research.google)
为这个示例约定两种输出:action 表示调用工具,final 表示结束并回答。工具请求必须包含名称和参数;结束时必须给出答案。把这些约定连同工具用途、参数含义一起交给模型。
一个查库存的小例子
以下数据完全用于演示。假设工具 get_stock 返回黑色签字笔的可用库存为 8 支,一次成功执行可以写成:
用户:黑色签字笔够 20 支吗?不够需要补多少?
行动说明:查询该商品的可用库存。
Action:get_stock(item="黑色签字笔")
Observation:{"item": "黑色签字笔", "available": 8}
Final:目前有 8 支,不足 20 支,还需要补 12 支。
这里将“可用库存”设为明确字段,避免把已被其他订单占用的数量也算进去。本例只计算缺口,不执行采购。
下面是简化的 Python 伪代码,函数需要按实际模型接口实现:
tools = {"get_stock": get_stock}
history = [user_message(question)]
for _ in range(6):
step = model_next(history, tool_specs)
if step["type"] == "final":
answer = step["answer"]
break
# 检查工具白名单、参数类型及访问权限
validate_action(step, tools)
try:
result = tools[step["tool"]](**step["args"])
except ToolError:
result = {"error": "查询失败,请调整请求或停止"}
history.append(action_message(step))
history.append(observation_message(result))
else:
answer = "达到执行上限,暂未完成查询。"
这个示例把最大轮数设为六轮。动作和结果都写入历史,因此下一次模型调用能看到上一轮发生了什么。实际接入时,还应按所用接口的消息格式,将工具结果与对应的调用关联。
开发时先处理这些坑
建议把下面几项作为这个小项目的实现要求:
观察结果必须来自执行器。 模型提出查询请求后,由程序调用工具,再注入返回值。不要让模型自行续写一段“查询成功”,然后把它当成真实库存。
工具描述要具体。 对 get_stock,说明商品如何匹配、库存单位是什么、查不到时返回什么。清晰的工具定义与参数说明,是可靠使用工具的重要基础。(anthropic.com)
停止条件要写进程序。 除了轮数限制,再设置超时和重复调用检查。同样的参数连续失败时,结束并说明缺失信息,避免无意义地继续查询。
将查询与修改分开授权。 本例只开放读取库存。如果以后加入采购功能,应在程序层检查数量、预算和用户授权,不能仅凭模型输出就提交订单。
用失败样例验证流程。 除了“库存为 8”,再测试商品不存在、返回多个规格、工具超时等情况。验收时检查最终答案是否有真实结果支持,而不只看文字是否流畅。
小结
理解 ReAct,可以抓住一个循环:根据当前信息选择行动,取得真实反馈,再决定下一步。它让推理与环境交互共同推动任务完成。(doi.org)
入门时,可以先做上面的只读库存助手:一个工具、一种任务、明确的停止条件。跑通后逐步增加异常处理和工具种类。每扩展一步,都检查模型做了什么、工具实际返回什么,以及最终答案是否与结果一致。
参考来源
- 选题参考:小林面试笔记 · 同主题文章(本文为本站原创撰写,未转载原文)