Skip to content

第 10 章 · 推理模型

本章目标:

  • 理解语言模型的内部「推理」(thinking)阶段及其对回答质量的影响
  • 掌握跨 provider 可移植的顶层 reasoning 参数及六个档位
  • 学会在 streamText 中分别处理 reasoning 与 text-delta 流片段
  • 理解 reasoning 参数与 providerOptions 的优先级规则
  • 了解如何从 provider 专属配置迁移到可移植的 reasoning 参数

10.1 什么是推理阶段

许多语言模型在产出最终回复之前,会先进行一个内部的「推理」阶段(有时也称为 "thinking")。AI SDK 在 generateTextstreamText 上提供了顶层的 reasoning 参数,用一个可移植的设置控制所有 provider 的这种行为。

10.2 基本用法

ts
import { generateText, createGateway } from 'ai';

// 方式一:Vercel AI Gateway
const gateway = createGateway({ apiKey: process.env.AI_GATEWAY_API_KEY ?? '' });

const { text, reasoning, reasoningText } = await generateText({
  model: gateway('anthropic/claude-sonnet-4.6'),
  reasoning: 'medium',
  prompt: 'How many people will live in the world in 2040?',
});

// 方式二:自定义 OpenAI 兼容 Provider(二选一即可,同样适用于自定义 provider)
// import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
// const myProvider = createOpenAICompatible({
//   name: 'my-provider',
//   baseURL: process.env.OPENAI_COMPATIBLE_BASE_URL ?? '',
//   apiKey: process.env.OPENAI_COMPATIBLE_API_KEY ?? '',
// });
// const model = myProvider('claude-sonnet-4.6'); // 按服务端实际模型名填写

reasoning 参数接受以下取值:

取值行为
'provider-default'使用 provider 的默认推理行为(省略时的默认值)
'none'关闭推理
'minimal'最少量推理
'low'快速、简洁的推理
'medium'平衡的推理
'high'充分的推理
'xhigh'最大程度推理

10.3 流式输出

reasoning 参数在 streamText 中的用法完全相同。流片段分为 reasoningtext-delta 两类,可以分开处理:

ts
import { streamText, createGateway } from 'ai';

const gateway = createGateway({ apiKey: process.env.AI_GATEWAY_API_KEY ?? '' });

const result = streamText({
  model: gateway('google/gemini-3-flash-preview'),
  reasoning: 'high',
  prompt: 'Explain the Riemann hypothesis in simple terms.',
});

for await (const part of result.stream) {
  if (part.type === 'reasoning') {
    process.stdout.write(part.textDelta);
  } else if (part.type === 'text-delta') {
    process.stdout.write(part.textDelta);
  }
}

10.4 优先级规则

顶层 reasoning 参数与 provider 专属的 providerOptions 永远不会合并。如果你在 providerOptions 中设置了推理相关选项,它们完全生效,顶层 reasoning 参数被忽略:

ts
import { generateText, createGateway } from 'ai';

const gateway = createGateway({ apiKey: process.env.AI_GATEWAY_API_KEY ?? '' });

const { text } = await generateText({
  model: gateway('openai/gpt-5.4'),
  reasoning: 'low', // 被忽略,因为设置了 providerOptions.openai.reasoningEffort
  providerOptions: {
    openai: {
      reasoningEffort: 'high', // 这个优先生效
    },
  },
  prompt: 'Explain quantum entanglement.',
});

这一设计让你默认使用可移植的 reasoning 参数,只在需要 provider 专属特性(如精确的 token 预算)时才退回 providerOptions

10.5 Provider 支持情况

reasoning 参数由以下 provider 支持:OpenAI、Anthropic、Google、xAI、Groq、DeepSeek、Fireworks 和 Amazon Bedrock。每个 provider 把该值翻译成自己的原生推理 API:

  • 有些 provider 原生支持全部六档;另一些会收敛到更少的档位(发生收敛时会发出 warning)
  • 有些 provider 用数值 token 预算而非枚举来控制推理;此时顶层 reasoning 值会被映射为按模型最大输出 token 百分比计算的预算
  • 不支持推理的 provider(如 Mistral、Perplexity、Cohere)发出 unsupported warning 并忽略该参数

💡 无论你用 Vercel AI Gateway 还是自定义 OpenAI 兼容 Provider,reasoning 参数的语义保持一致——是否真正生效取决于底层模型与网关背后的 provider 能力。

10.6 从 providerOptions 迁移

如果你目前通过 providerOptions 控制推理,可以迁移到顶层 reasoning 参数以获得跨 provider 的可移植性。

Anthropic

之前:

ts
const { text } = await generateText({
  model,
  providerOptions: {
    anthropic: {
      thinking: { type: 'adaptive', effort: 'high' },
    },
  },
  prompt: 'How many people will live in the world in 2040?',
});

之后:

ts
const { text } = await generateText({
  model: gateway('anthropic/claude-opus-4.6'), // gateway 实例见 10.2;同样适用于自定义 provider
  reasoning: 'high',
  prompt: 'How many people will live in the world in 2040?',
});

对于较旧的 Anthropic 模型:

ts
const { text } = await generateText({
  model: gateway('anthropic/claude-sonnet-4-20250514'),
  reasoning: 'medium', // 替代 budgetTokens: 12000
  prompt: 'How many people will live in the world in 2040?',
});

如果需要强制精确的 token 预算(如恰好 12000 tokens),继续使用 providerOptions 而不是顶层 reasoning 参数。

Google

之前通过 includeThoughts 配置:

ts
const { text } = await generateText({
  model: gateway('google/gemini-3-flash-preview'),
  reasoning: 'medium',
  providerOptions: {
    google: { thinkingConfig: { includeThoughts: true } }, // 与 reasoning 无关的选项保留在 providerOptions
  },
  prompt: 'Explain the Riemann hypothesis in simple terms.',
});

OpenAI

之前同时设置 reasoningEffortreasoningSummary

ts
const { text } = await generateText({
  model: gateway('openai/o3'),
  reasoning: 'high', // 替代 providerOptions.openai.reasoningEffort
  providerOptions: {
    openai: { reasoningSummary: 'auto' }, // 与推理力度无关的专属特性仍可用 providerOptions
  },
  prompt: 'Explain quantum entanglement.',
});

注意:providerOptions 仍然可以和 reasoning 并用于推理力度之外的 provider 专属功能。但如果 providerOptions 中包含推理力度/预算类设置(如 reasoningEffortthinkingthinkingConfig.thinkingBudget),它们完全优先,顶层 reasoning 参数被忽略。

本章小结

  • 许多模型在生成最终回复前有内部「推理」阶段;AI SDK 用顶层 reasoning 参数统一控制
  • 六个档位:none / minimal / low / medium / high / xhigh,外加 provider-default
  • 流式输出中 reasoning 片段与 text-delta 片段可分别处理
  • providerOptions 中的推理设置完全优先于顶层 reasoning,二者不合并
  • 各 provider 将 reasoning 映射到各自的原生 API;不支持的 provider 发出 unsupported warning
  • 迁移时保留 provider 专属的非推理选项在 providerOptions,推理力度改用可移植参数

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. 省略 reasoning 参数时,模型的默认行为是?

2. 当 providerOptions 中设置了 openai.reasoningEffort 时,顶层 reasoning: 'low' 会怎样?

3. 哪些情况下应继续使用 providerOptions 而非顶层 reasoning 参数?

4. 不支持推理的 provider(如 Mistral)收到 reasoning 参数时会?

🛠️ 动手实践

  1. 分别用 reasoning: 'low''medium''high' 对同一道数学题调用 generateText,对比返回的 reasoning 文本长度与答案质量。
  2. streamText + reasoning: 'high' 实现一个终端程序:把 reasoning 部分打印为灰色前缀,正文正常输出(参考 10.3 的流片段处理)。
  3. 把一段使用 providerOptions.anthropic.thinking.budgetTokens 的旧代码迁移为顶层 reasoning 参数,并写一条注释说明什么场景下必须保留 providerOptions