Insights·2026-08-23

stop_reason —— 不看它,就会把被截断的答案当成完整答案

Anthropic 认证考试列出的第四个智能体反模式,是回应一到手就直接使用。LLM 无法执行工具,它只会告诉你「用这些参数调用这个工具」,真正调用的是你的代码。所以回应到达时先看 stop_reason:是 tool_use 就执行工具、把结果喂回去、再转一圈;是 end_turn 就跳出。麻烦的是第三种:因 token 用尽而停下的回应读起来同样像模像样,不看 stop_reason,你就会把截断的答案当成完整答案。

stop_reason을 안 보면 잘린 답을 완성된 답으로 쓴다 — 명령과 단계를 담은 요약 도식

为什么是循环,为什么是现在 —— 1966 年的证明

进入反模式之前,先说清这为什么在现在成为问题。

计算的早期,编程语言急剧增加,人们争论谁的语言能做更多事。1966 年,科拉多·伯姆与朱塞佩·雅可比尼用一个证明结束了争论:任何计算只需要三样东西——按顺序执行、按条件分支,以及循环。

把如今的 AI 代进去,画面就清晰了。抛出一次提示、拿到一个回答,那是顺序;加上条件分支,很多人也已经在做。缺的是循环——把回答再喂回去,再拿一个,再喂回去。

智能体之所以感觉不同,一部分是模型变强了,但从结构上说,正是这第三件被补上的时刻。而循环一出现就随之而来的新错误,就是这个反模式。

先拆一个误解 —— LLM 无法执行工具

展示模型只负责指示调用哪个工具,实际调用由自己的代码完成,结果再送回模型的示意图。

我们常说「AI 搜索了网页」「AI 读取了文件」,从字面上讲,这并不成立。

LLM 除了按概率预测下一个词,什么也做不了。就算把工具交给它,它也执行不了。它能做的,只是非常聪明地告诉你「用这些参数调用这个工具」。

真正去调用的是你的代码。请求搜索 API、打开文件、拿到结果再交回给模型,全都是你这边的事。

这个区分之所以重要,是因为「模型停下的理由」有好几种这一事实正是由此而来。答完了停下、为了要工具而停下、因为长度到顶而停下,是三件不同的事,但表面上都只是「回应来了」。

stop_reason —— 分成三条路

所以回应到达时,不是先读正文,而是先看一个叫 stop_reason 的字段。模型为什么停下,就写在那里。

stop_reason含义代码该做什么
tool_use为了请求调用工具而停下执行工具、把结果附加进消息,再循环一圈
end_turn话说完了停下跳出循环,使用答案
max_tokens因长度上限被截断不是完整答案 —— 重新请求或按失败处理

循环长这样

写成代码很短。在 while 循环里调用模型,按 stop_reason 分支,是 tool_use 就 continue 再转一圈。

值得注意的是,执行工具那一行在模型调用之外。模型决定要调用什么,调用的是你的代码。

agent-loop.py
while True:
    resp = client.messages.create(
        model="claude-opus-5",
        messages=messages,
        tools=tools,
    )

    # 用答案之前,先看它为什么停下
    if resp.stop_reason == "tool_use":
        result = run_tool(resp)          # 调用工具的是你的代码
        messages.append(result)          # 把结果喂回去,再转一圈
        continue

    if resp.stop_reason == "max_tokens":
        raise RuntimeError("答案被截断了 —— 不要当成完整答案")

    break                                # end_turn 就跳出

最危险的是第三种 —— 截断的答案看不出被截断

对比图:漏看 tool_use 会让智能体停住而立刻被发现,而因 max_tokens 截断的回答看起来正常,会悄悄出错。

漏掉 tool_use,智能体就什么也不做地停住,很快就会发现。麻烦的是 max_tokens。

因 token 用尽而停下时,回应照样会来,而且作为文字读起来是通顺的。即便从中间被切断,也只是最后一句结束得有点别扭,正文里不会附带一个「到这里被截断」的标记。

所以不看 stop_reason,你会把它当成完整答案拿去用。你要十条,拿到六条,这六条就直接进入下一步。悄悄出错的地方就在这里。

不写代码的人也有对应的场景。如果你在聊天机器人里要一张长表或长列表,结果结束得半途而废,那多半是长度上限,而不是模型只知道这么多。打一句「继续」,剩下的就出来了。

跳出循环之后 —— 人该介入的位置

以 end_turn 跳出之后,正是人该介入的位置。

演讲里说,在这一步要检查置信度。结果看起来不错就直接用,否则交给人。也就是把自动化的终点定义为「自动 + 交接条件」,而不是「全自动」。

不设这个条件,智能体在没把握时也会给出答案——因为它不会停下来说自己不知道,而是会把空白填得像模像样。

今天可以试的一件事

如果你写代码,去看看接收模型回应的地方有没有在看 stop_reason。没有的话,先加上 max_tokens 那一条分支。这一行会把无声的失败变成有声的失败。

如果你不写代码,回想一下最近有没有哪次 AI 的回答半途而止。那多半是长度上限,而不是模型的极限。下次先打一句「接着写」。

下一篇是最后一篇:百万 token 的窗口开了,为什么还是不该全塞进去。