先记住这个答案
max_tokens 是生成阶段允许输出的最大 token 数。当生成达到该数值时,API 会强制终止,并返回 stop_reason 为 "max_tokens"。如果输出被截断,结果往往不完整,例如 JSON 缺少闭合括号。正确处理方式是检查 stop_reason,若为 max_tokens,应增大上限或调整提示词,必要时拼接续写。
- max_tokens 是生成输出的硬上限
- 截断时 stop_reason 为 max_tokens
- 需检查并适当增大上限或分段生成
max_tokens 与 stop_reason 的关系
在生成式大模型 API 中,max_tokens 指定了输出序列的最大 token 长度。模型每次生成一个 token,累计到该上限后必须停止,即使生成的句子尚未结束。API 响应中会包含 stop_reason 字段,其值为 max_tokens 时就明确表示本次输出因达到上限被强制截断,而不是模型自然生成的结束。
如果 max_tokens 设置得比模型默认的合理输出长度小,即使模型有足够能力生成完整答案,也会被提前终止。这种情况下,通常的 finish_reason 或 stop_reason 不会是 end_turn 或 stop,而是 max_tokens,调用方需要据此判断输出是否完整,避免把半截文本当作最终结果使用。
JSON 输出被截断导致解析失败
假设构建一个自动摘要服务,提示词要求模型返回 JSON 格式,包含 "summary" 字段,并设置 max_tokens=100。模型生成到 "{"summary":"这是一段很长的文本摘要" 时已达 100 token 上限,输出被截断,缺少闭合的大括号和引号。接收端用 JSON.parse 解析时必然抛出异常,程序崩溃。
处理方式:首先检查响应中的 stop_reason,发现是 max_tokens 后,应增加 max_tokens 值重新请求,或者将任务拆分为多个步骤,先让模型输出不带格式的完整内容,再单独进行 JSON 格式化。若不想丢弃已生成的部分,也可以记录截断位置,将后续请求作为续写,但需注意上下文衔接。
失效条件与处理代价
max_tokens 不是上下文窗口,它只限制输出长度。当输入提示词本身很长时,上下文窗口剩余空间可能不足以容纳较大的 max_tokens,因此需参考模型文档设置合理上限,否则即使 max_tokens 很大,一旦超出模型的总 token 限制,请求也会被拒绝。
如果模型存在固定风格,例如总是输出详细分析,那么一个固定的 max_tokens 容易频繁触发截断。更稳妥的做法是根据任务类型动态估算所需长度,并用 stop_sequences 在达到关键节点时提前结束,这样既能减少解析失败,又能避免无谓的 token 浪费。
容易答错的地方
- max_tokens 越大越好
- 并非如此。max_tokens 是输出上限,不会直接占用输入上下文空间,但设置过大会因超出总 token 限制而导致请求失败,同时增加 token 成本与响应延迟。模型仅生成完成任务所需的内容,不会因上限大而额外输出。应根据任务合理设置上限。
- 截断后直接拼接续写
- 盲目拼接可能导致语法错误,因为截断位置可能在一个词或一个 JSON 字符串中间。续写时模型没有明确感知边界,容易重复或跳变。更稳妥的做法是重新生成完整的响应,或利用截断前的完整句段作为提示。
面试官还会怎么问?
如何判断一个响应是否被 max_tokens 截断?
检查 API 响应中的 stop_reason 或 finish_reason 字段,若值为 "max_tokens" 则说明达到上限被截断;若为 "stop" 或 "end_turn" 则是自然结束。另外可检查输出是否以标点或闭合符结尾,但最可靠的是依据官方字段。
max_tokens 与 temperature 等参数有交互吗?
max_tokens 控制长度上限,temperature 影响输出随机性。两者独立作用,temperature 并不直接决定生成长度,但高随机性可能偶尔产生更长文本,更易逼近上限。调参时应分别考虑任务需求,不应将两者强行关联。
在流式输出中如何检测截断?
流式输出时,每个 chunk 都可能包含 stop_reason。当收到 stop_reason 为 max_tokens 的 chunk,即可判定该次生成已截断。客户端需要累积所有 chunk,直到遇到明确的结束标记,否则输出不完整。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。