推理模型 API 参数:跨提供方对比
OpenAI reasoning_effort、Anthropic thinking 与 Gemini thinkingBudget 都在控制按输出计费的隐藏推理 token。每个旋钮如何工作、又有何不同。
推理模型多了一个你看不见的步骤:在写下答案之前,模型会产出隐藏的推理 token,而这些 token 花钱、消耗上下文窗口、还增加延迟。每家提供方都给了你一个旋钮来控制这件事发生多少,但这三个旋钮名字不同、取值刻度不同、默认值也不同——OpenAI 上是 reasoning_effort,Anthropic 上是 thinking,Gemini 上是 thinkingConfig。把推理模型用对,主要就是理解这三个旋钮和一个共享事实:推理 token 按输出 token 计费,尽管你从来读不到它们。本文将逐一走过每家提供方的参数、暴露隐藏成本的用量字段,以及抽象在哪里不再对齐。
共享的心智模型
无论哪家提供方,一个推理请求都有相同的解剖结构。你的输入 token 进去。模型生成两类输出:隐藏的推理 token 和可见的答案 token。两者都按输出费率计费,都计入模型的上下文窗口,而只有可见的那些会回到你手里(在大多数模型上,可能附带一份推理的摘要,但绝不是原始推理本身)。每家提供方暴露的旋钮改变的是模型愿意花费多少隐藏 token。对难题和多步骤智能体循环把它调高;对延迟敏感、深度较浅的任务把它调低。下面的一切都是这一主题的变奏。
OpenAI:reasoning_effort 与 reasoning 对象
在 OpenAI 的推理模型上你设置 effort。Chat Completions 接受一个顶层的 reasoning_effort 字符串;Responses API 接受一个 reasoning 对象,其 effort 字段做的是同一件事,并为摘要和上下文控制留出了空间。
from openai import OpenAI
client = OpenAI(base_url="https://your-gateway.example.com/v1", api_key="AVE_GATEWAY_API_KEY")
# Responses API
resp = client.responses.create(
model="gpt-5.6",
input="Prove there are infinitely many primes p with p mod 4 == 3.",
reasoning={"effort": "high", "summary": "auto"},
)
Effort 的取值随模型而定,可以包括 none、minimal、low、medium、high 和 xhigh;默认值因模型而异。较低的 effort 优先考虑速度和更少的 token,较高的 effort 以更高成本产出更周密的输出。隐藏的工作是被计量的:推理 token 出现在 usage 中 output_tokens_details 下的 reasoning_tokens 里,因此即使 token 本身被扣留,你也能盯住这笔看不见的花销。要看模型为什么得出某个结论,请请求一份摘要(summary: "auto" 或 "detailed"),它会在 reasoning 输出项里返回一份被摘要过的推理轨迹——你必须主动选择加入;它默认不包含。
有两个特性对无状态和智能体设置很重要。为了零保留运行,发送 store: false 并把 reasoning.encrypted_content 加进 include 数组;API 会返回加密的推理,你在下一轮把它传回,就能在服务器不存储任何东西的情况下保持连续性。而 reasoning.context(auto、current_turn 或 all_turns)控制模型在一次链式对话中可以借用哪些先前的推理项。
你绝不能忘记的参数是 max_output_tokens。它给总生成 token 设上限——推理加上可见答案——所以如果你把它设得太低,预算可能被隐藏推理完全吞掉,于是你收到一个 status 为 incomplete(incomplete_details 指向 max_output_tokens)且没有可见文本的结果,同时仍要为输入和推理 token 付费。OpenAI 建议在起步时为推理加输出预留慷慨的余量(数万 token 的量级)。为那份余量做预算,与 LLM 上下文窗口管理中描述的是同一种纪律。
Anthropic:从 budget_tokens 到自适应思考
Anthropic 的扩展思考历史上使用一个显式的 token 预算。你用一个 type: "enabled" 的 thinking 对象和一个 budget_tokens 上限来启用它:
import anthropic
client = anthropic.Anthropic(base_url="https://your-gateway.example.com", api_key="AVE_GATEWAY_API_KEY")
msg = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=16000,
thinking={"type": "enabled", "budget_tokens": 10000},
messages=[{"role": "user", "content": "Are there infinitely many primes p with p mod 4 == 3?"}],
)
三条规则管辖 budget_tokens。它设定内部推理的最大 token 数,且必须小于 max_tokens(除非工具的交错思考让这个上限得以变成整个上下文窗口)。模型可能用不满整个预算,在大数值时尤其如此。而推理会作为 thinking 内容块——每个携带一段 thinking 文本和一个 signature——出现在 text 块之前;你为生成的全部思考 token 付费,而不是那份更短的摘要,因此被计费的输出计数不会与你可见看到的相符。
有一个重要的版本分化需要预先规划。budget_tokens 正在被退役:它在一些当前模型上被弃用,并在最新的模型上返回 400(例如 Opus 4.8/4.7 和 Sonnet 5 这一代),这些模型转而使用自适应思考——一个 type: "adaptive" 的 thinking 对象搭配一个 effort 设置,让 Anthropic 在概念上更接近 OpenAI 的 effort 旋钮。当你构建时,按模型分支:把 budget_tokens 发给仍接受它的模型,把自适应/effort 形式发给要求它的模型。网关可以掩盖其中一部分,如下一节所示。
有一条工具使用规则不容商量:在一个工具循环期间,你必须在紧随其后的助手消息里把模型的 thinking 块原封不动地传回,否则 API 会以 400 拒绝该请求。这些块编码了导向那次工具调用的推理,重排或编辑它们会破坏连续性。这与 OpenAI 关于把推理项与函数调用一起返回的建议相呼应,也是为什么 跨提供方的可移植工具调用把推理块的保留当成一个正确工具循环的一部分。
Gemini:thinkingConfig 与 thinkingBudget
Gemini 通过 generationConfig 里的一个 thinkingConfig 控制推理。关键字段是 thinkingBudget,一个给思考的 token 配额,带两个特殊值:-1 让模型动态决定,而(在允许禁用的模型上)0 关闭思考。一个 includeThoughts 标志请求 API 返回一份思考摘要。被消耗的推理会作为一个思考 token 计数出现在 usageMetadata 中,同样按输出计费。
from google import genai
from google.genai import types
client = genai.Client()
resp = client.models.generate_content(
model="gemini-3.5-flash",
contents="Are there infinitely many primes p with p mod 4 == 3?",
config=types.GenerateContentConfig(
thinking_config=types.ThinkingConfig(thinking_budget=-1, include_thoughts=True),
),
)
哪些模型允许你禁用思考,以及确切的预算范围,都随模型层级而异——去查模型页面,而不要假定某个值能跨代沿用。
网关归一化什么、又在哪里止步
在一个 OpenAI 兼容端点背后,网关会把每家提供方的推理参数转发给理解它的上游:reasoning_effort 和 reasoning 对象给 OpenAI,thinking 给 Anthropic,thinkingConfig 给 Gemini。它还把三种不同的隐藏 token 计数折叠成统一的用量视图,因此无论请求由哪家提供方处理,推理请求的真实输出成本都能在日志中看到。
这个网关还提供一项值得了解的便利:它可以解析模型名上的 effort 后缀,并转换为提供方自己的推理参数。在模型 id 后追加 -high、-medium、-low、-minimal、-xhigh 或 -max(例如 claude-opus-4-8-high 或 -thinking 变体),可以让只能设置模型字符串的客户端仍然选择 effort 级别,网关再把后缀映射到目标提供方的对应参数。已注册的模型/effort 变体及其按模型计费的费率会发布在公开的 定价页 上。
要把边界说清楚,因为这些抽象确实不对齐:
- 刻度不同。 OpenAI 的
effort是一个枚举,Anthropic 的旧式budget_tokens是一个绝对 token 计数,而 Gemini 的thinkingBudget是一个带哨兵值的 token 计数。"高 effort"和"10,000 预算 token"并不是彼此的翻译;把一个映射到另一个是启发式,不是等价。 - 默认值不同。 有些模型默认推理,有些不;而默认 effort 是模型特定的。别以为沉默就意味着"不推理"。
- 特性覆盖不同。 加密推理连续性、思考摘要,以及禁用思考,在各家提供方之间支持得参差不齐。网关可以把一个字段透传过去,但它无法让一家提供方去遵守它并不提供的能力。
把网关当成那个给你一个统一计费视图和一条透传路径的层,并在存在真正能力缺口的地方保留提供方特定的逻辑。
实用默认值
几条起步规则能省钱又省延迟:
- 让 effort 匹配任务深度,而不是重要性。 一次困难的抽取比一次冗长却浅显的摘要需要更多推理。Effort 关乎问题结构,而非利害轻重。
- 总是预留输出余量。 对任何推理模型,把最大输出上限设得足够高,让隐藏推理无法把可见答案饿死,否则你会为推理付费却什么都收不到。
- 测量隐藏 token。 在你的用量日志里盯住
reasoning_tokens/ 思考 token;一个推理 token 远超其答案 token 的任务,是降低 effort 或改用非推理模型的候选,这个决定在 选择合适的 LLM 模型中有讲。
常见问题
推理 token 尽管我从没见过,也照样计费吗?
是的。隐藏推理 token 在三家提供方上都按输出 token 费率计费,还占用上下文窗口。这就是为什么被计费的输出计数比可见答案所暗示的更大,也是为什么在你的用量日志里盯住推理 token 字段很重要——那是你在响应体里看不见的真实花销。
为什么我从一个推理模型得到了空的或不完整的响应?
通常是输出上限设得太低、推理把整个预算吃光了。OpenAI 返回一个引用 max_output_tokens 的 incomplete 状态;Anthropic 要求 budget_tokens 小于 max_tokens。提高总输出上限,让隐藏推理无法把可见答案饿死,并在推理路由上预留慷慨的余量。
Anthropic 的 budget_tokens 和 OpenAI 的 reasoning_effort 是一回事吗?
它们服务于同一个目的,但并不等价。reasoning_effort 是一个枚举(low/medium/high 及相关值);budget_tokens 是一个绝对 token 计数。在 Anthropic 最新的模型上 budget_tokens 不被支持,取而代之的是带 effort 设置的自适应思考。网关可以把一个 effort 标签映射到一家提供方的参数上,但这个映射是近似的,不是一一对应的翻译。
如果我的客户端只能发送一个模型名,我怎么设置推理级别?
用网关的 effort 后缀。在模型 id 后追加 -high、-medium、-low、-minimal、-xhigh 或 -max,网关会解析它并为目标提供方应用相匹配的推理参数。这让瘦客户端无需自己发送提供方特定的字段就能挑一个 effort 级别。
找出任务的 effort 拐点
通过网关,用低、中、高三种 effort 分别运行同一个高难度提示词,每次从使用日志记录两个数字:推理 token,以及按你自己的评分标准衡量的答案质量。你通常会找到一个拐点,超过它后更多 effort 不再改善答案,却仍继续消耗 token。把路由固定在该拐点略低的位置——基于你自己任务的这次测量,比任何提供方默认值都更有参考意义。