AI 应用后端工程化:从原型到可交付系统 · 第 23 篇 · 第六章 · 编排与模型
把 ReAct 从提示词名词还原为一个带消息协议、工具执行、错误反馈和停止条件的循环。
ReAct 经常被解释为“思考、行动、观察”。工程实现中,不需要向用户展示模型的私有思维文本;真正重要的是模型可以提出工具调用,系统执行后返回可靠观察,模型据此决定下一步,并在明确条件下停止。
一个带状态的循环
stateDiagram-v2
[*] --> RequestModel
RequestModel --> Final: 返回最终回答
RequestModel --> ValidateCall: 返回工具调用
ValidateCall --> Execute: 参数与权限通过
ValidateCall --> RequestModel: 返回可修正错误
Execute --> Observe: 工具完成
Observe --> RequestModel: 写入工具结果
Execute --> Failed: 不可恢复错误
RequestModel --> Stopped: 达到预算或轮数
Final --> [*]
Failed --> [*]
Stopped --> [*]
循环每轮保存消息状态,模型请求后只有几类合法结果:最终文本、工具调用、协议错误或可重试异常。把这些状态写清楚,比在 while True 中不断追加字符串更容易测试。
def run_agent(messages, model, tools, max_steps: int = 8):
for step in range(max_steps):
response = model.respond(messages, tools.schemas())
messages.append(response.assistant_message)
if response.final_text is not None:
return response.final_text
if not response.tool_calls:
raise RuntimeError("model returned neither text nor tool calls")
for call in response.tool_calls:
result = tools.execute(call)
messages.append(result.to_tool_message())
raise RuntimeError("agent reached the step limit")
代码只展示骨架,生产实现还要处理取消、流式、并行、审计、用量和持久化。但停止上限从一开始就存在,避免异常循环无限消耗。
观察必须来自真实执行
模型可能假设工具成功,系统不能把这种假设当观察。只有执行器返回的结构化结果才能进入 tool result。结果包含 call ID、成功状态、公开错误和有限数据,模型据此修正下一步。
例如搜索没有结果,应返回空列表和查询条件,而不是自然语言“应该没有”。文件写入返回实际路径与哈希,数据库操作返回稳定资源 ID。观察越可验证,下一步越可靠。
错误也能帮助行动
参数少一个字段时,执行器可以返回可修正错误,模型下一轮补齐;权限拒绝不应诱导模型尝试换路径绕过;外部超时可以由系统重试一次,再把失败交回模型选择替代方案。
错误分类必须由确定性代码完成。不要把内部堆栈交给模型判断是否安全重试,也不要让模型决定自己有没有权限。
防止重复与震荡
Agent 可能连续调用相同工具和参数,得到相同错误。记录最近调用指纹,达到阈值后停止并解释阻塞原因。另一种震荡是 A 工具建议 B、B 又建议 A,需要在状态中记录已尝试路径。
预算可以同时限制步数、Token、工具费用和墙钟时间。不同任务配置不同上限,查询天气不应允许二十轮,复杂研究任务则可能需要更多步骤。
并行调用要由依赖决定
模型一次返回多个独立查询,可以并行执行并按 call ID 回填。创建资源后再更新该资源有数据依赖,必须串行。执行器可以根据工具只读属性和显式依赖判断,不能把所有 call 默认并发。
高风险工具需要确认。循环进入 waiting_approval 状态,保存当前消息和调用参数;用户批准后恢复同一 invocation,而不是重新请求模型导致参数变化。
不展示隐式思维不影响可解释性
系统可以记录“选择了哪个工具、参数是什么、观察是什么、为何停止”等可审计事件,无需暴露模型隐藏推理。面向用户的解释应基于行动和证据,例如“查询了订单 123,接口返回已退款”,比一大段未经验证的内心独白更可靠。
评估也围绕外部行为:是否选择正确工具、参数是否有效、是否在合理步数结束、引用是否来自真实结果。不要用“推理看起来聪明”作为唯一指标。
从 Agent 推广到控制系统
故障排查助手、自动研究和运维编排都使用“观察、行动、再观察”。练习:使用假模型安排三轮响应,第一轮缺参数、第二轮工具成功、第三轮给最终答案;验证消息顺序。再让假模型重复同一失败调用,确认循环检测会停止。
两次提交将 ReAct 接入现有体系
核心算法可以很短,难点是它与已有工具注册、消息实体、事件队列和权限边界正确连接。Agent 的可靠性主要来自循环周围的工程系统。