加载中...
  • ReAct 的工程实现:思考、行动、观察与停止条件loading

    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 接入现有体系

    • c9b8a40:实现 ReActAgent,建立基于观察迭代行动的循环。
    • c0d4e5c:把 ReActAgent 纳入 Agent 模块并增强函数调用支持。

    核心算法可以很短,难点是它与已有工具注册、消息实体、事件队列和权限边界正确连接。Agent 的可靠性主要来自循环周围的工程系统。

    本文目录
    本文目录