关于 tanstack-ai
TanStack AI 是用于在 JavaScript、TypeScript、PHP 和 Python 应用中构建 AI 功能的模块化 SDK。它提供多种提供方适配器、流式生成、工具工作流、结构化输出和界面钩子。
主要功能
- 01适配多种 AI 提供方
- 02流式文本生成
- 03带审批流程的工具调用
- 04基于 Zod 的结构化输出
- 05多模态内容支持
- 06React 与 Solid 界面钩子
适用场景
- 01为应用添加流式聊天
- 02生成经 Schema 校验的结构化数据
- 03要求敏感工具调用先获审批
- 04构建使用工具的 Agent 循环
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ tanstack-skills/ tanstack-skills --skill tanstack-ai安装后在 Claude Code 中输入/tanstack-ai确认已加载。
详细介绍
概览
TanStack AI 是一款模块化、与提供商无关的 AI SDK,提供支持 tree-shaking 的适配器,可用于 OpenAI、Anthropic、Gemini、Ollama 等。它提供流式优先的文本生成、支持审批工作流的工具调用、基于 Zod schema 的结构化输出、多模态内容支持,以及用于聊天/补全 UI 的 React hooks。
核心: @tanstack/ai
原生客户端: @tanstack/ai-client(与框架无关)
React: @tanstack/ai-react
Solid: @tanstack/ai-solid
适配器: @tanstack/ai-openai、@tanstack/ai-anthropic、@tanstack/ai-gemini、@tanstack/ai-ollama
语言: TypeScript/JavaScript、PHP、Python
状态: Alpha
安装
npm install @tanstack/ai @tanstack/ai-react
# Or for framework-agnostic vanilla client:
npm install @tanstack/ai @tanstack/ai-client
# Provider adapters (install only what you need):
npm install @tanstack/ai-openai
npm install @tanstack/ai-anthropic
npm install @tanstack/ai-gemini
npm install @tanstack/ai-ollama
PHP 安装
composer require tanstack/ai tanstack/ai-openai
Python 安装
pip install tanstack-ai tanstack-ai-openai
核心:generate()
import { generate } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai/adapters'
const result = await generate({
adapter: openaiText({ model: 'gpt-4o' }),
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: 'Explain React hooks in 3 sentences.' },
],
})
// Streaming with async iteration
for await (const chunk of result) {
process.stdout.write(chunk.text)
}
提供商适配器
import { openaiText } from '@tanstack/ai-openai/adapters'
import { anthropicText } from '@tanstack/ai-anthropic/adapters'
import { geminiText } from '@tanstack/ai-gemini/adapters'
import { ollamaText } from '@tanstack/ai-ollama/adapters'
// OpenAI
const openai = openaiText({ model: 'gpt-4o' })
// Anthropic
const anthropic = anthropicText({ model: 'claude-sonnet-4-20250514' })
// Google Gemini
const gemini = geminiText({ model: 'gemini-pro' })
// Ollama (local)
const ollama = ollamaText({ model: 'llama3' })
// Runtime adapter switching
const adapter = process.env.AI_PROVIDER === 'anthropic' ? anthropic : openai
React Hooks
useChat
import { useChat } from '@tanstack/ai-react'
function ChatUI() {
const { messages, input, setInput, handleSubmit, isLoading } = useChat({
adapter: openaiText({ model: 'gpt-4o' }),
})
return (
<div>
{messages.map((msg) => (
<div key={msg.id}>
<strong>{msg.role}:</strong> {msg.content}
</div>
))}
<form onSubmit={handleSubmit}>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Type a message..."
/>
<button type="submit" disabled={isLoading}>
Send
</button>
</form>
</div>
)
}
useCompletion
import { useCompletion } from '@tanstack/ai-react'
function CompletionUI() {
const { completion, input, setInput, handleSubmit, isLoading } = useCompletion({
adapter: openaiText({ model: 'gpt-4o' }),
})
return (
<div>
<form onSubmit={handleSubmit}>
<textarea
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Enter prompt..."
/>
<button type="submit" disabled={isLoading}>Generate</button>
</form>
{completion && <div>{completion}</div>}
</div>
)
}
Solid.js Hooks
import { createChat } from '@tanstack/ai-solid'
function ChatUI() {
const chat = createChat({
adapter: openaiText({ model: 'gpt-4o' }),
})
return (
<div>
<For each={chat.messages()}>
{(msg) => (
<div>
<strong>{msg.role}:</strong> {msg.content}
</div>
)}
</For>
<form onSubmit={chat.handleSubmit}>
<input
value={chat.input()}
onInput={(e) => chat.setInput(e.target.value)}
placeholder="Type a message..."
/>
<button type="submit" disabled={chat.isLoading()}>
Send
</button>
</form>
</div>
)
}
原生客户端
无需 React 或 Solid 即可与框架无关地使用:
import { createAIClient } from '@tanstack/ai-client'
import { openaiText } from '@tanstack/ai-openai/adapters'
const client = createAIClient({
adapter: openaiText({ model: 'gpt-4o' }),
})
// Subscribe to state changes
client.subscribe((state) => {
console.log('Messages:', state.messages)
console.log('Loading:', state.isLoading)
})
// Send a message
await client.send('Hello, world!')
// Clear conversation
client.clear()
流式传输
流式策略
import { generate } from '@tanstack/ai'
// Default: stream chunks as they arrive
const result = await generate({
adapter: openaiText({ model: 'gpt-4o' }),
messages: [...],
stream: true,
})
for await (const chunk of result) {
// Process each chunk
console.log(chunk.text)
}
可用的流式策略:
- Batch - 收集所有数据块后再交付
- Punctuation - 在句子边界处进行流式传输
- WordBoundary - 在单词边界处进行流式传输
- Composite - 组合多种策略
服务器发送事件(SSE)
// Server-side SSE endpoint
import { createReplayStream } from '@tanstack/ai'
export async function handler(req: Request) {
const stream = createReplayStream({
adapter: openaiText({ model: 'gpt-4o' }),
messages: await req.json(),
})
return new Response(stream, {
headers: { 'Content-Type': 'text/event-stream' },
})
}
结构化输出
import { generate } from '@tanstack/ai'
import { convertZodToJsonSchema } from '@tanstack/ai'
import { z } from 'zod'
const RecipeSchema = z.object({
name: z.string(),
ingredients: z.array(z.object({
item: z.string(),
amount: z.string(),
})),
steps: z.array(z.string()),
cookTime: z.number(),
})
const result = await generate({
adapter: openaiText({ model: 'gpt-4o' }),
messages: [{ role: 'user', content: 'Give me a pasta recipe' }],
schema: convertZodToJsonSchema(RecipeSchema),
})
// result is typed as z.infer<typeof RecipeSchema>
console.log(result.name, result.ingredients)
工具调用
基本工具
import { generate } from '@tanstack/ai'
const result = await generate({
adapter: openaiText({ model: 'gpt-4o' }),
messages: [{ role: 'user', content: 'What is the weather in NYC?' }],
tools: {
getWeather: {
description: 'Get weather for a location',
parameters: z.object({
location: z.string(),
unit: z.enum(['celsius', 'fahrenheit']).optional(),
}),
execute: async ({ location, unit }) => {
const data = await fetchWeather(location, unit)
return data
},
},
},
})
支持审批工作流的工具调用
import { ToolCallManager } from '@tanstack/ai'
const manager = new ToolCallManager({
tools: {
deleteUser: {
description: 'Delete a user account',
parameters: z.object({ userId: z.string() }),
requiresApproval: true, // Requires human approval
execute: async ({ userId }) => {
await deleteUser(userId)
return { success: true }
},
},
},
onApprovalRequired: async (toolCall) => {
// Present to user for approval
return await showApprovalDialog(toolCall)
},
})
Agent 式循环
const result = await generate({
adapter: openaiText({ model: 'gpt-4o' }),
messages: [{ role: 'user', content: 'Research and summarize the topic' }],
tools: { search, summarize, writeReport },
maxIterations: 10, // Limit agent loop iterations
})
多模态内容
// Images
const result = await generate({
adapter: openaiText({ model: 'gpt-4o' }),
messages: [{
role: 'user',
content: [
{ type: 'text', text: 'What is in this image?' },
{ type: 'image_url', image_url: { url: 'https://example.com/photo.jpg' } },
],
}],
})
// Image generation with DALL-E
import { openaiImage } from '@tanstack/ai-openai/adapters'
const image = await generate({
adapter: openaiImage({ model: 'dall-e-3' }),
messages: [{ role: 'user', content: 'A sunset over mountains' }],
})
// Image generation with Gemini Imagen
import { geminiImage } from '@tanstack/ai-gemini/adapters'
const image = await generate({
adapter: geminiImage({ model: 'imagen-3' }),
messages: [{ role: 'user', content: 'A futuristic cityscape at night' }],
})
思考模型(推理 Token)
支持具备扩展推理/思考能力的模型:
import { generate } from '@tanstack/ai'
import { anthropicText } from '@tanstack/ai-anthropic/adapters'
const result = await generate({
adapter: anthropicText({ model: 'claude-sonnet-4-20250514' }),
messages: [{ role: 'user', content: 'Solve this complex math problem step by step...' }],
thinking: {
enabled: true,
budget: 10000, // Max thinking tokens
},
})
// Access thinking/reasoning output
console.log('Thinking:', result.thinking)
console.log('Response:', result.text)
// Streaming with thinking tokens
for await (const chunk of result) {
if (chunk.type === 'thinking') {
console.log('[Thinking]', chunk.text)
} else {
process.stdout.write(chunk.text)
}
}
消息实用工具
import { generateMessageId, normalizeToUIMessage } from '@tanstack/ai'
// Generate unique message IDs
const id = generateMessageId()
// Normalize provider-specific messages to UI format
const uiMessage = normalizeToUIMessage(providerMessage)
可观测性
const result = await generate({
adapter: openaiText({ model: 'gpt-4o' }),
messages: [...],
onEvent: (event) => {
// Structured, typed events
switch (event.type) {
case 'text':
console.log('Text chunk:', event.data)
break
case 'tool_call':
console.log('Tool called:', event.name)
break
case 'error':
console.error('Error:', event.error)
break
}
},
})
AI 开发工具
TanStack AI 内置专用开发工具面板,用于调试 AI 工作流:
import { TanStackDevtools } from '@tanstack/react-devtools'
import { AIDevtoolsPanel } from '@tanstack/ai-react/devtools'
function App() {
return (
<TanStackDevtools
plugins={[
{
id: 'ai',
name: 'AI',
render: () => <AIDevtoolsPanel />,
},
]}
/>
)
}
AI 开发工具功能:
- 消息检查器 - 查看带有元数据的完整对话历史
- Token 用量 - 跟踪每个请求的输入/输出 Token 数量和费用
- 流式传输可视化 - 实时查看流式数据块
- 工具调用调试 - 检查工具调用、参数和结果
- 思考/推理查看器 - 调试思考模型产生的推理 Token
- 适配器切换 - 在开发过程中测试不同的提供商
- 请求/响应日志 - 全面检查 HTTP 请求/响应
TanStack Start 集成
// Shared implementation between AI tools and server functions
import { createServerFn } from '@tanstack/react-start'
import { generate } from '@tanstack/ai'
const aiChat = createServerFn({ method: 'POST' })
.validator(z.object({ messages: z.array(messageSchema) }))
.handler(async ({ data }) => {
const result = await generate({
adapter: openaiText({ model: 'gpt-4o' }),
messages: data.messages,
})
return result
})
部分 JSON 解析器
用于增量到达的流式结构化输出:
import { parsePartialJson } from '@tanstack/ai'
// Parse incomplete JSON during streaming
const partial = parsePartialJson('{"name": "Pasta", "ingredients": [{"item": "flour"')
// Returns: { name: "Pasta", ingredients: [{ item: "flour" }] }
最佳实践
- 仅导入所需适配器 - 支持 tree-shaking 的设计可最大限度减小打包体积
- 使用 Zod schema 的结构化输出,确保 AI 响应类型安全
- 在 Agent 式循环中设置
maxIterations,防止执行失控 - 对具有破坏性的工具调用使用
requiresApproval - 在异步迭代外层使用 try/catch,妥善处理流式传输错误
- 使用服务端函数保护 API 密钥安全(切勿在客户端暴露密钥)
- 在开发过程中使用
onEvent实现可观测性和调试 - 在运行时切换适配器,以进行 A/B 测试或实现回退策略
- 使用部分 JSON 解析,在流式传输期间渐进式更新 UI
- 在提供商之间切换时规范化消息
常见问题
- 在客户端代码中暴露 API 密钥(应使用服务端函数)
- 未处理流式传输错误(异步迭代可能抛出异常)
- 在 Agent 式循环中忘记设置
maxIterations(循环可能无限运行) - 导入所有适配器,而不是仅导入所需的适配器(导致打包体积膨胀)
- 提取数据时不使用结构化输出(字符串解析不可靠)
- 每次渲染时都创建新的适配器实例(应使用 memoize 或在模块级别定义)
评论
支持 Markdown