构建约 15 分钟

ReActAgent 推理循环

思考、行动、观察的循环是怎么跑起来的:一轮里发生了什么,什么时候停,额度用完怎么收场。

依据 agent-core 0.1.20 · develop@fbe6a0d9(2026-11-13)核实

ReAct 是什么

ReAct 是让大模型"边想边做"的套路:模型先想下一步该干什么,需要外部信息就调用工具,看到工具结果后再想,直到能回答为止。openJiuwen 里实现这个套路的类叫 ReActAgent,后面讲到的 DeepAgent、团队协作,底下跑的都是它。

源码ReActAgentagent-core/openjiuwen/core/single_agent/agents/react_agent.py:563@fbe6a0d9

搭一个最小的智能体

官方示例的骨架是四步:身份卡、配置、工具、运行。

from openjiuwen.core.single_agent import AgentCard, ReActAgentConfig, ReActAgent
from openjiuwen.core.runner import Runner

card = AgentCard(id="promise_agent", description="订单交期助手")
config = ReActAgentConfig(
    model_client_config=model_client,   # 模型服务地址、密钥
    model_config_obj=model_config,      # 模型名、温度
    prompt_template=[{"role": "system", "content": "你负责回答客户的交期询问。"}],
    max_iterations=5,
)
agent = ReActAgent(card=card).configure(config)

Runner.resource_mgr.add_tool(check_inventory)     # 工具注册到全局资源管理器
agent.ability_manager.add(check_inventory.card)   # 再告诉这个智能体它能用

result = await Runner.run_agent(agent=agent, inputs={"query": "1000 件 A-100 什么时候能交?"})
说明

这段按官方示例 build_react_agent.ipynb 改写,check_inventory 是你自己定义的工具;本站没有连接真实模型运行它。

注意卡片(Card)和配置(Config)是分开的:卡片描述"它是谁",可以序列化、跨进程传递;配置是运行时的东西,比如模型连接。工具也一样,先在 Runner.resource_mgr 里登记实现,再把卡片加给智能体。

一轮里发生了什么

主循环是一个 for 循环,次数上限是 max_iterations(默认 5)。每一轮按这个顺序走:

步骤做什么
1看有没有 Rail 请求了强制结束,有就停
2把运行中插进来的引导指令(steering)写进对话
3调用模型,前后触发 BEFORE_MODEL_CALL / AFTER_MODEL_CALL
4模型没要工具:把回复作为答案返回,循环结束
5模型要了工具:执行这次要的全部工具,每个工具前后触发 Rail 事件
6工具里有需要人工确认的中断,就挂起保存现场
7整轮成功,触发 AFTER_REACT_ITERATION,进入下一轮
源码主循环agent-core/openjiuwen/core/single_agent/agents/react_agent.py:3169@fbe6a0d9

几个细节:

  • 同一轮里的多个工具默认并行执行(parallel_tool_calls=True)。工具之间有先后依赖时,模型自然会分到不同轮里去要。
  • 模型回了空内容,框架会追加一条提示让它重试一次,再空就返回错误,不会把空字符串当答案。
  • 宿主可以钉死上限:max_iterations_hard_limit 由宿主设置,实际上限取两者较小值,智能体自己的配置改不大它。

额度用完怎么收场

循环跑满还没得到答案时,由 on_max_iterations 决定怎么收场:

取值结果
"error"(默认)返回 result_type: error、termination_reason: max_iterations,不带已查到的数据
"return_observations"同样标为 error,但附上本轮所有工具的原始结果,交给调用方处理
"final_answer"在循环外再调一次模型,不给工具,让它用已有证据给出尽力答复,并标注被截断
源码_finish_max_iterationsagent-core/openjiuwen/core/single_agent/agents/react_agent.py:3388@fbe6a0d9

面向客户的场景一般选 "final_answer";面向程序的场景(比如上游还要再加工)选 "return_observations"。默认的 "error" 最保守,适合宁可失败也不要给半成品的场合。

动手:调一调循环

三个任务分别对应迭代上限、额度用完的收场方式、并行工具。

模拟器加载中…

小结

  • 一轮 = 一次模型调用 + 这次要的全部工具;模型不再要工具,循环就结束。
  • max_iterations 要留出"最后作答"的那一轮。
  • 额度用完的默认行为是返回错误,想要尽力答复要显式设 on_max_iterations="final_answer"。
  • 循环里的每个关键点都有 Rail 事件,下一步的 DeepAgent 和 Rail 关卡都建立在这个循环上。

源码出处

链接指向固定提交,仓库后续更新不影响这里的行号。

过关测验

  1. 1. ReActAgent 的"一轮"指的是什么?

  2. 2. max_iterations 用完了,on_max_iterations 是默认值,调用方会拿到什么?

  3. 3. on_max_iterations="final_answer" 时,最后那次模型调用能不能再调工具?

通关条件

  • ○ 完成模拟器任务(0/3)
  • ○ 测验全部答对