在大屏或电脑上体验更佳——动画和操作区域更宽敞。
输入

Agent 循环

Agent 循环把模型调用、工具执行和结果回传连起来。一个 while 循环请求模型,执行模型要求的工具,把结果追加到对话,再请求模型。模型返回文本而非工具请求时,正常循环结束。运行框架还用轮次上限防止无限执行。

模型决定请求哪个工具、传入哪些参数,以及何时返回回答;代码读取回复并执行对应分支。循环本身不需要理解问题内容,但需要保存完整的对话记录,并处理失败和预算耗尽。

工具调用展示一次工具交互中的请求与回传,ReAct 循环从模型推理的角度解释同一过程。本课聚焦包含 call 在内的整个控制流。多步示例回放 ReAct 课程记录的 claude-opus-5-5 运行,单次回答来自同一模型的另一条记录;它们是筛选后的真实运行记录。

Agent 循环如何工作

每轮执行四个步骤:调用模型,发送截至目前的 messages;检查回复的 stop_reason;若为 tool_use,则派发这条回复请求的全部工具(当前模型常常一次请求多个),再把所有结果作为一条消息追加到 messages,进入下一轮。本课简化代码把非 tool_use 的回复作为文本返回。

messages 保存这次运行中模型能看到的历史。在本课模拟的无状态 API 中,模型调用之间没有自动保留的会话状态,问题、助手回复和工具结果都需要重新发送。遗漏结果、调换顺序或没有保存模型自己的工具请求,都会改变下一次调用看到的上下文。

本课展示两个正常停止原因:stop_reason: tool_use 表示模型请求工具,stop_reason: end_turn 表示模型返回回答。代码读取这些标志,不靠猜测文本是否“看起来完成”来提前终止循环。

如果模型一直请求工具,while 不会自行退出。因此,生产框架应设置预算。本课的形式是 for turn in range(max_turns),智能体 SDK 也以最大轮数或迭代次数提供同一个旋钮。达到轮次上限仍未回答,就强制退出并返回 None。上限是运行框架的控制,不代表模型已经完成任务。

Agent 循环逐步演示

默认使用 multi-step 任务,max_turns = 10。问题是:Aurora Run 的导演出生于哪一年?模型需要先查电影,再查导演的出生年份。

  1. 开始:messages 只有用户问题,turn = 0。
  2. 第 0 轮,调用:模型回复 stop_reason: tool_use,请求 search["Aurora Run"]。助手消息追加到 messages。
  3. 检查:stop_reason 为 tool_use,进入工具执行分支。
  4. 派发:代码执行搜索。第一页说明:Aurora Run 是 Henrik Dahl 于 1998 年出版的小说,作者生于 1951 年;2011 年电影由 Mara Voss 执导。这里的 1951 是小说家的出生年份,并不是问题所问的导演年份。
  5. 追加:工具结果进入 messages,turn 增加到 1,循环再次调用模型。
  6. 第 1 轮,调用:模型再次返回 stop_reason: tool_use,请求 search["Mara Voss"],没有把干扰值 1951 当成答案。
  7. 检查、派发、追加:第二页说明 Mara Voss 是挪威电影导演,生于 1974 年。结果进入 messages,turn 增加到 2。
  8. 第 2 轮,调用:模型看到两条结果,返回文本 1974,停止原因为 stop_reason: end_turn。
  9. 检查:读取 end_turn,进入回答分支。
  10. 退出:返回 "1974"。两次工具调用对应三次模型调用。

切到 one-shot,默认问题是法国首都。模型首次调用就返回 stop_reason: end_turn · "Paris",没有工具请求,也没有第二轮。相同循环只执行一次。

再把多步任务的 max_turns 改为 2。循环完成第 0、1 轮后,for 范围耗尽,来不及进行第三次模型调用。虽然上下文中已有答案所需资料,循环仍返回 None。红色预算计量表示预算用完,不表示模型给出了答案。

需要多少次模型调用

本课运行中每条回复只请求一个工具,因此完成 N 次工具调用后再生成回答,需要 N + 1 次模型调用。多步示例是两个工具、三次模型调用;单次回答是零个工具、一次模型调用。模型在一条回复中请求多个互不依赖的工具时,它们共用一次调用,所以一般而言 N 计的是工具请求的轮数,而不是工具个数。这里的两次搜索无法合并为一轮:第二次查询依赖第一次的结果。总调用次数受 max_turns 限制。

每次调用都重新发送完整 messages。工具结果和助手消息逐轮增加,后续请求的上下文通常比早期更长。长任务的成本因此不只取决于调用次数,还取决于各次请求携带多少内容。有些 API 可以在服务端替你保存对话、按 ID 串联调用,但每次调用读到的仍是不断增长的完整上下文。

边界情况

  • 工具没有找到结果:例如 “No matching page found.”,仍是可追加到 messages 的观察结果。模型可据此修改查询。循环对命中与未命中使用同一条回传路径。
  • 首次调用就回答:stop_reason 直接为 end_turn,循环执行一次,没有工具调用。
  • 预算耗尽:达到 max_turns 仍在请求工具,返回 None。应说明预算内未得到回答,不能编造结果。
  • 工具请求格式错误:工具不存在或参数无法解析时,派发层需要捕获错误并回传错误结果,让模型有机会在下一轮修正。
  • 其他停止原因:回复也可能因达到输出 token 上限而停止(max_tokens,其中的工具请求可能被截断),因模型拒绝而停止(refusal),或因服务端工具的长回合暂停而停止(pause_turn,把对话发回即可继续)。本课的 != "tool_use" 判断会把这三种都当作最终回答返回;生产循环需要分别处理。

常见错误

  • 凭自己的文本判断提前结束:本课正常分支依据 stop_reason。仅因回复“看起来完成”而截断,会跳过模型请求的后续步骤。
  • 把任务推理硬编码进循环:为每道问题写工具选择的 if/else,会把通用运行框架变成固定流程。模型提出工具请求,运行框架负责执行与约束。
  • 忘记调用间无状态:删掉工具结果、乱序消息或漏存助手请求,下一轮看到的对话就不完整。
  • 先执行工具,再检查 stop_reason:先判断是否为工具请求,再派发;否则可能把最终文本当成工具调用。
  • 逐个回传并行结果:一条回复请求多个工具时,应全部执行,并在下一次调用前把所有结果放进一条消息回传。多数 API 会拒绝缺少某个工具结果的请求。
  • 没有 max_turns:模型最终会停止并不是保证。需要预算来限制反复请求。

本课的简化范围

这里展示基本控制流。生产框架还需要流式响应、并发执行互不依赖的工具调用、模型请求的错误处理与重试、其他停止原因的处理,以及随 messages 增长的上下文管理:在上下文窗口填满前清除旧的工具结果,或把早期轮次压缩成摘要。这个循环也不一定要自己写:SDK 的工具运行器和智能体框架可以代为执行,托管的智能体服务则在提供方一侧运行它。

记录中的搜索工具只有四页资料,用于展示检索交互。这套“调用、检查、派发、追加、再调用”的结构是理解框架的起点,不是完整的生产实现规范。