DOCAI · 概念 · L1
max_tokens 限制的是什么
它只限制输出侧的 token 上限,不限制输入;输入加输出仍受上下文窗口约束。
它是什么
max_tokens 是请求里的一个数字:这次生成最多允许产出多少 token。它管输出,不管输入。你传一段很长的资料,不会因为 max_tokens 设得小而自动截断输入。
字段名不统一。Anthropic 的 Messages API 用 max_tokens,而且是必填项;OpenAI 的 Chat Completions 历史上用 max_tokens,更新的参数是 max_completion_tokens;Responses API 用 max_output_tokens。名字不同,语义接近:都是给「生成多少」设上限。
它是上限,不是目标。模型可以在达到上限前自然结束;只有真的撞到上限,才叫被截断。不同模型允许的最大值不同,具体数值以模型页为准。
怎么工作
生成按 token 计数,输入 token 加输出 token 一起占用上下文窗口。max_tokens 相当于给输出预留一块额度:
- 输入很短时,输出额度通常能完整用上;
- 输入接近窗口上限时,留给输出的空间变少,可能生成到一半就停;
- 有些实现会在输入端按「窗口减去输出额度」规划空间,所以输出上限设得很大,也可能反过来挤压可用的输入。
超窗行为各家不同:有的直接拒绝请求,有的接受请求、生成到窗口边界才停。Anthropic 在撞到 max_tokens 时返回 stop_reason: "max_tokens";OpenAI 的 Chat Completions 返回 finish_reason: "length";Responses API 在 incomplete_details.reason 里给出 max_output_tokens。看到这些值,基本可以判定不是模型不会写,而是额度用完了。
被截断有三种常见表现:句子断在半截、代码少一个右括号、JSON 少一个收尾花括号。前两种肉眼可见,第三种最危险:解析直接失败,重试也可能照样失败,因为问题不在网络,而在额度。结构化输出和 JSON 模式都绕不过这个上限,它们只约束格式,不负责把内容变短。
流式场景下,停止原因往往在最后一个事件才出现。前面的分片看起来正常,最后突然没有收尾,要按「可能被截断」处理,而不是把半截内容当完整结果入库。处理方式见流式与超时。
常见误解
「max_tokens 限制输入长度。」 不限制。输入超窗是另一类错误。
「设得越大越贵。」 计费按实际生成的 token 算,不是按上限算。设大本身不直接加钱,但会让模型有机会写得更长,也拉高最坏情况下的延迟。
「max_tokens 就是上下文窗口。」 窗口是输入加输出的总容量,max_tokens 只是输出侧的一块。窗口大不代表输出额度可以无限大。
「设大一点就永远不会截断。」 输入加输出仍受窗口约束;输入占满了,输出照样没空间。
怎么按任务留余量
- 分类、抽取字段、短答:留出够写完整答案的余量,别把上限压到刚好。
- 长文、代码、多步推理:适当放宽,并给思考型模型的推理 token 留位置;有些模型的思考 token 也计入这个上限。
- 结构化输出:按最坏情况的字段数量估算,再往上留一点;同时准备「截断后重试」的分支,不要假定一次成功。
- 拿不准时:先用估算 token或 token 计数接口量一遍。
怎么排查
- 看停止原因,区分正常结束、撞上限、内容过滤和工具调用。
- 看输入 token 是否吃掉大部分窗口;如果是,先缩减输入或做检索,而不是继续加 max_tokens。
- 看输出是不是结构化格式;如果是,检查是否在最后一个字段处断掉。
- 流式请求要看最后一个事件和完整拼接结果,不要只检查开头几个分片。
什么时候用得上
当你要控制单次回答的长度、成本或延迟,或者在解析结构化输出前判断会不会被截断时,就要显式设置它并留出余量。
常见误解
很多人以为 max_tokens 是「输入加输出的总预算」,于是拿它当上下文窗口来调。它通常只约束输出;输入按实际长度计费,输入本身超窗时请求会直接失败。