调用 Chat Completions API 时,限制模型输出长度是一个常见需求。很多资料会同时出现 max_tokens 和 max_completion_tokens 两个参数名,初学者容易混用。实际上,它们在不同模型上的行为差异很大,尤其是 o 系列推理模型出现后,继续使用 max_tokens 可能导致请求直接失败。

一、两个参数的作用范围与历史定位
在早期 OpenAI 模型中,max_tokens 是限制生成内容长度的标准参数。它指定模型在一次响应中最多可以生成的 token 数量,这些 token 就是最终返回给用户的文本内容。对于 GPT-3.5、GPT-4 等传统模型,生成过程是直接输出可见文本,因此用 max_tokens 控制长度足够直观,调用者也能比较准确地估算成本和延迟。
但随着推理模型出现,问题变得复杂。o 系列模型在输出最终答案之前,会先经过一段隐藏的推理过程,也被称为思维链。这段过程会产生大量 token,这些 token 不会在 message.content 中展示,但会占用实际算力,也会计入 usage 中的完成 token 数量。如果继续使用 max_tokens,API 层面无法识别这些隐藏 token,调用者就无法准确控制推理过程加最终输出的总长度。
为此,OpenAI 引入了 max_completion_tokens 参数。它表示整个完成阶段允许生成的最大 token 数,既包括隐藏的推理 token,也包括用户可见的最终输出。对于普通模型,max_tokens 仍然能够工作,但官方已经将其标记为弃用,并推荐统一改用 max_completion_tokens。如果同时传入这两个参数,API 会直接报错,提示不能同时指定两者。
二、推理模型为什么强制使用 max_completion_tokens
推理模型和普通模型最本质的区别在于,推理模型并不是一次性生成最终答案,而是先在内部进行多步思考。以 o3-mini、o4-mini 为例,这些模型可能会根据问题复杂度生成数百甚至数千个隐藏推理 token,然后再基于推理结果生成简短的最终回答。这些隐藏 token 对调用者不可见,但会计入 usage.completion_tokens,并通过 completion_tokens_details.reasoning_tokens 单独给出。
如果在调用 o 系列模型时仍然传 max_tokens,API 会返回类似如下的错误:Unsupported parameter: 'max_tokens' is not supported with this model. Use 'max_completion_tokens' instead. 这是因为推理模型的输出预算必须覆盖隐藏推理和可见输出两部分,旧的参数无法表达这层含义。若强行忽略警告,部分客户端可能会把 max_tokens 当作无效参数处理,从而不做任何长度限制,导致费用超预期。
还有一个容易忽略的点:reasoning_effort 参数会直接影响隐藏推理 token 的数量。它支持 low、medium、high 三档,级别越高,模型思考得越深入,生成的隐藏 token 也越多。如果 max_completion_tokens 设置得过小,推理过程可能尚未完成就被切断,最终答案不完整,甚至只返回少量空文本。因此针对推理模型,建议把 max_completion_tokens 设置得比普通任务更大,比如 4096 或 8192,同时通过 reasoning_effort 控制思考强度。
三、实际调用中的兼容性与常见报错
从模型兼容性来看,当前普通模型如 GPT-4o、GPT-4.1 同时接受 max_tokens 和 max_completion_tokens。但普通模型也在逐步向新参数迁移,部分新版本模型中 max_tokens 可能只会被忽略,而不是完全报错。推理模型如 o1、o3-mini、o4-mini 则明确只支持 max_completion_tokens,传 max_tokens 会直接失败。
常见的错误场景有三种。第一种是同时传两个参数,API 返回:max_tokens and max_completion_tokens cannot be specified together. 第二种是对推理模型传了 max_tokens,返回 Unsupported parameter。第三种是虽然用了 max_completion_tokens,但数值过小,导致响应中的 finish_reason 为 length,表示因为达到长度上限而被截断。此时需要检查返回内容是否完整,或者适当提高 token 预算。
迁移到新参数并不复杂。对于自己维护的调用代码,可以统一把 max_tokens 替换为 max_completion_tokens。如果业务需要同时兼容普通模型和推理模型,最好根据模型名称决定参数,但更简单的做法是全部使用 max_completion_tokens,因为普通模型同样支持该参数,不会产生兼容问题。
四、代码示例与最佳实践
下面是一个调用推理模型的 Python 示例,使用官方 openai 库。代码中只传 max_completion_tokens,并设置了 reasoning_effort 来控制思维链强度。
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="o3-mini",
messages=[
{"role": "user", "content": "请推导费马小定理的证明思路"}
],
max_completion_tokens=4096,
reasoning_effort="medium"
)
print(response.choices[0].message.content)
print("实际消耗 completion tokens:", response.usage.completion_tokens)
print("其中 reasoning tokens:", response.usage.completion_tokens_details.reasoning_tokens)
如果使用 curl 调用,可以这样发送请求。注意 JSON 数据中不要同时出现 max_tokens 和 max_completion_tokens,否则服务端会拒绝请求。
curl https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "o3-mini",
"messages": [{"role": "user", "content": "解释快速排序的复杂度"}],
"max_completion_tokens": 2048,
"reasoning_effort": "low"
}'
对于普通模型,也可以直接使用 max_completion_tokens。例如调用 GPT-4.1 时,下面的方式仍然有效,而且不需要再关心旧的 max_tokens 参数是否被弃用。
response = client.chat.completions.create(
model="gpt-4.1",
messages=[
{"role": "user", "content": "用 Python 写一个读取 CSV 文件的函数"}
],
max_completion_tokens=1024
)
在真实项目中,建议把 token 限制参数抽成配置项,并根据任务类型设置不同默认值。普通文本生成可以使用 512 到 2048 的预算;复杂推理任务则至少保留 4096 以上,避免因隐藏推理消耗过大而截断最终结果。同时要关注 finish_reason 的值,如果频繁出现 length,说明输出空间不足,需要调整策略或增大 max_completion_tokens。
总体而言,理解 max_completion_tokens 和 max_tokens 的区别,关键在于是否覆盖隐藏推理 token。普通模型仍然兼容旧参数,但新参数已经统一了两类模型的行为。面向未来维护代码时,优先使用 max_completion_tokens,并根据模型是否具备推理能力来调整 token 预算和 reasoning_effort,这样既能避免接口报错,也能更准确地控制成本与输出质量。
OpenAI APImax_completion_tokens推理模型修改时间:2026-09-18 19:41:39