Chapter 10 · Reasoning Models
Chapter goals:
- Understand the internal "reasoning" (thinking) phase of language models and its impact on answer quality
- Master the cross-provider portable top-level
reasoningparameter and its six tiers- Learn to separately handle reasoning and text-delta stream parts in
streamText- Understand the precedence rules between
reasoningandproviderOptions- Know how to migrate from provider-specific configs to the portable
reasoningparameter
10.1 What Is the Reasoning Phase
Many language models perform an internal "reasoning" phase (also called "thinking") before producing their final response. AI SDK provides a top-level reasoning parameter on both generateText and streamText to control this behavior across all providers in a portable way.
10.2 Basic Usage
import { generateText, createGateway } from 'ai';
// Method 1: 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?',
});
// Method 2: Custom OpenAI-compatible Provider (choose one)
// 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'); // Use your server's actual model nameThe reasoning parameter accepts the following values:
| Value | Behavior |
|---|---|
'provider-default' | Use the provider's default reasoning behavior (the default when omitted) |
'none' | Disable reasoning |
'minimal' | Minimal reasoning |
'low' | Fast, concise reasoning |
'medium' | Balanced reasoning |
'high' | Thorough reasoning |
'xhigh' | Maximum reasoning |
10.3 Streaming Output
The reasoning parameter works identically in streamText. Stream parts are divided into reasoning and text-delta categories, which can be handled separately:
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 Precedence Rules
The top-level reasoning parameter and provider-specific providerOptions never merge. If you set reasoning-related options in providerOptions, they take full effect and the top-level reasoning parameter is ignored:
import { generateText, createGateway } from 'ai';
const { text } = await generateText({
model: gateway('anthropic/claude-sonnet-4.6'),
reasoning: 'low', // Ignored because providerOptions takes precedence
providerOptions: {
anthropic: {
thinking: { type: 'enabled', budgetTokens: 2000 },
},
},
prompt: 'Solve this math problem.',
});10.5 Migration from Provider-Specific Configs
Anthropic
Previously configured via thinking:
const { text } = await generateText({
model: gateway('anthropic/claude-sonnet-4.6'),
providerOptions: {
anthropic: {
thinking: { type: 'enabled', budgetTokens: 12000 },
},
},
prompt: 'How many people will live in the world in 2040?',
});Migrate to the portable parameter:
const { text } = await generateText({
model: gateway('anthropic/claude-sonnet-4.6'),
reasoning: 'medium', // Replaces budgetTokens: 12000
prompt: 'How many people will live in the world in 2040?',
});Google
Previously configured via includeThoughts:
const { text } = await generateText({
model: gateway('google/gemini-3-flash-preview'),
providerOptions: {
google: { thinkingConfig: { includeThoughts: true } },
},
prompt: 'Explain the Riemann hypothesis in simple terms.',
});const { text } = await generateText({
model: gateway('google/gemini-3-flash-preview'),
reasoning: 'medium',
providerOptions: {
google: { thinkingConfig: { includeThoughts: true } }, // Non-reasoning options stay in providerOptions
},
prompt: 'Explain the Riemann hypothesis in simple terms.',
});OpenAI
Previously configuring both reasoningEffort and reasoningSummary:
const { text } = await generateText({
model: gateway('openai/o3'),
providerOptions: {
openai: { reasoningEffort: 'high' },
},
prompt: 'Explain quantum entanglement.',
});const { text } = await generateText({
model: gateway('openai/o3'),
reasoning: 'high', // Replaces providerOptions.openai.reasoningEffort
providerOptions: {
openai: { reasoningSummary: 'auto' }, // Provider-specific features unrelated to reasoning strength stay in providerOptions
},
prompt: 'Explain quantum entanglement.',
});Note: providerOptions can still be used alongside reasoning for provider-specific features unrelated to reasoning strength. But if providerOptions contains reasoning-strength/budget settings (e.g., reasoningEffort, thinking, thinkingConfig.thinkingBudget), they完全优先 and the top-level reasoning parameter is ignored.
Chapter Summary
- Many models have an internal "reasoning" phase before producing the final response; AI SDK unifies control via the top-level
reasoningparameter - Six tiers:
none/minimal/low/medium/high/xhigh, plusprovider-default - In streaming,
reasoningparts andtext-deltaparts can be handled separately providerOptionsreasoning settings完全优先 over the top-levelreasoning; they do not merge- Each provider maps
reasoningto its native API; unsupported providers emit anunsupportedwarning - When migrating, keep provider-specific non-reasoning options in
providerOptions; switch reasoning strength to the portable parameter
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. When omitting the reasoning parameter, what is the model's default behavior?
2. When providerOptions sets openai.reasoningEffort, what happens to reasoning: 'low' at the top level?
3. In which scenarios should you continue using providerOptions instead of the top-level reasoning parameter?
4. What happens when a reasoning-unsupported provider (e.g., Mistral) receives the reasoning parameter?
🛠️ Hands-On Exercises
- Call
generateTexton the same math problem withreasoning: 'low','medium', and'high'; compare the returnedreasoningtext length and answer quality. - Implement a terminal program with
streamText+reasoning: 'high': print the reasoning section with a gray prefix, and the main text normally (refer to the stream part handling in 10.3). - Migrate old code using
providerOptions.anthropic.thinking.budgetTokensto the top-levelreasoningparameter, and write a comment explaining what scenarios still require keepingproviderOptions.