Agentic 循环有且只有一个可靠的控制机制:stop_reason。其他所有方式——检查文本内容、迭代次数上限、解析自然语言——要么是反模式,要么只能当安全网。搞错这个会导致无限循环、提前终止,或者两者兼得。
驱动循环的两个状态
stop_reason: "tool_use"→ 模型要执行工具。继续循环:执行请求的工具,追加结果,发下一个 API 请求。stop_reason: "end_turn"→ 模型结束了。终止循环:把最终响应返回给用户。
这就是核心控制流。模型决定什么时候继续(通过请求工具)和什么时候停止(通过结束轮次)。循环的职责是尊重这些信号。
文本内容陷阱
最常见的反模式:检查响应是否包含文本内容,然后把它当作完成信号。这行不通,因为文本 block 和 tool_use block 可以共存在同一条响应里。模型经常在工具调用旁边附带解释性文字——“我现在去查一下账单记录……”后面跟着一个 tool_use block。一发现有文本就终止,会在任务做到一半时把 agent 杀掉。
反过来也不行:如果你用文本的存在来继续循环,那它永远不会停,因为每个响应(包括最终摘要)都包含文本。
迭代上限:安全网,不是主控制
把硬性迭代上限当作主要终止机制是反模式。生产数据告诉你会怎样:上限设 20,需要 25+ 次工具调用的复杂任务被不完整地终止了。某个客服系统 7% 的提前终止率意味着真实的客户问题没被解决。
迭代上限的正确角色:一个宽松的安全网(比如 100),用来捕获真正的无限循环,但不干扰正常操作。正常的终止来自 stop_reason: "end_turn"。
处理全部六种 stop_reason 值
生产系统会遇到不只 tool_use 和 end_turn:
| stop_reason | 含义 | 动作 |
|---|---|---|
tool_use | 模型要执行工具 | 继续循环,执行工具 |
end_turn | 模型自然完成 | 正常终止 |
max_tokens | 响应被截断 | 终止并警告截断 |
pause_turn | 轮次在工作中暂停 | 在后续请求中恢复 |
refusal | 策略违规 | 终止并报策略告警 |
stop_sequence | 命中了 stop sequence | 正常终止 |
每种都需要区别处理。把所有非 tool_use 值都当 end_turn 处理会悄悄丢掉截断警告、忽略可恢复的暂停、隐藏策略违规。按类型分别处理能捕获这三类问题。
CI 双约束模式
CI 流水线面临两个对立的要求:agent 必须完整执行(提前终止会漏掉 bug)且必须遵守墙钟超时(CI 任务不能无限跑下去)。方案是:用 stop_reason 做主控制,加一个墙钟超时做硬性兜底。大多数运行在时间限制内通过 end_turn 正常完成。超时触发时,agent 优雅终止并输出部分发现,而不是被硬杀。
一句话总结: 用 stop_reason 作为唯一的循环控制(tool_use = 继续,end_turn = 停止),区别处理全部六种值,迭代上限只做宽松的安全网——绝不做主控制。