了解如何在运行时让用户在 LLM 提供商之间切换,同时保持完整的 TypeScript 类型安全。
使用 TanStack AI,模型直接传递给适配器工厂函数。这为您提供了定义点上的完整类型安全性和自动补全
import { chat, toServerSentEventsResponse } from '@tanstack/ai'
import { anthropicText } from '@tanstack/ai-anthropic'
import { openaiText } from '@tanstack/ai-openai'
type Provider = 'openai' | 'anthropic'
// Define adapters with their models - autocomplete works here!
const adapters = {
anthropic: () => anthropicText('claude-sonnet-4-5'), // ✅ Autocomplete!
openai: () => openaiText('gpt-5.2'), // ✅ Autocomplete!
}
// In your request handler:
const provider: Provider = request.body.provider || 'openai'
const stream = chat({
adapter: adapters[provider](),
messages,
})
每个适配器工厂函数都将其第一个参数作为模型名称,并返回一个完全类型的适配器
// These are equivalent:
const adapter1 = openaiText('gpt-5.2')
const adapter2 = new OpenAITextAdapter({ apiKey: process.env.OPENAI_API_KEY }, 'gpt-5.2')
// The model is stored on the adapter
console.log(adapter1.selectedModel) // 'gpt-5.2'
当您将适配器传递给 chat() 时,它会使用来自 adapter.selectedModel 的模型。这意味着
这是一个完整的示例,展示了一个多提供商的聊天 API
import { createFileRoute } from '@tanstack/react-router'
import { chat, maxIterations, toServerSentEventsResponse } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
import { anthropicText } from '@tanstack/ai-anthropic'
import { geminiText } from '@tanstack/ai-gemini'
import { ollamaText } from '@tanstack/ai-ollama'
type Provider = 'openai' | 'anthropic' | 'gemini' | 'ollama'
// Define adapters with their models
const adapters = {
anthropic: () => anthropicText('claude-sonnet-4-5'),
gemini: () => geminiText('gemini-2.0-flash-exp'),
ollama: () => ollamaText('mistral:7b'),
openai: () => openaiText('gpt-5.2'),
}
export const Route = createFileRoute('/api/chat')({
server: {
handlers: {
POST: async ({ request }) => {
const abortController = new AbortController()
const body = await request.json()
const { messages, data } = body
const provider: Provider = data?.provider || 'openai'
const stream = chat({
adapter: adapters[provider](),
tools: [...],
systemPrompts: [...],
messages,
abortController,
})
return toServerSentEventsResponse(stream, { abortController })
},
},
},
})
相同的模式适用于图像生成
import { generateImage } from '@tanstack/ai'
import { openaiImage } from '@tanstack/ai-openai'
import { geminiImage } from '@tanstack/ai-gemini'
const imageAdapters = {
openai: () => openaiImage('gpt-image-1'),
gemini: () => geminiImage('gemini-2.0-flash-preview-image-generation'),
}
// Usage
const result = await generateImage({
adapter: imageAdapters[provider](),
prompt: 'A beautiful sunset over mountains',
size: '1024x1024',
})
以及用于总结
import { summarize } from '@tanstack/ai'
import { openaiSummarize } from '@tanstack/ai-openai'
import { anthropicSummarize } from '@tanstack/ai-anthropic'
const summarizeAdapters = {
openai: () => openaiSummarize('gpt-5-mini'),
anthropic: () => anthropicSummarize('claude-sonnet-4-5'),
}
// Usage
const result = await summarize({
adapter: summarizeAdapters[provider](),
text: longDocument,
maxLength: 100,
style: 'concise',
})
如果您有使用 switch 语句的现有代码,以下是如何迁移
let adapter
let model
switch (provider) {
case 'anthropic':
adapter = anthropicText()
model = 'claude-sonnet-4-5'
break
case 'openai':
default:
adapter = openaiText()
model = 'gpt-5.2'
break
}
const stream = chat({
adapter: adapter as any,
model: model as any,
messages,
})
const adapters = {
anthropic: () => anthropicText('claude-sonnet-4-5'),
openai: () => openaiText('gpt-5.2'),
}
const stream = chat({
adapter: adapters[provider](),
messages,
})
关键的更改