名称: tanstack-ai 描述: TanStack AI(alpha)供应商无关的类型安全聊天与流式传输,支持OpenAI、Anthropic、Gemini、Ollama。用于聊天API、React/Solid前端与useChat/ChatClient、同构工具、工具批准流程、代理循环、多模态输入或故障排除流式传输和工具定义。
关键词: TanStack AI, @tanstack/ai, @tanstack/ai-react, @tanstack/ai-client, @tanstack/ai-solid, @tanstack/ai-openai, @tanstack/ai-anthropic, @tanstack/ai-gemini, @tanstack/ai-ollama, toolDefinition, client tools, server tools, tool approval, agent loop, streaming, SSE, connection adapters, multimodal, type-safe models, TanStack Start, Next.js API, toStreamResponse, fetchServerSentEvents, chat, useChat, ChatClient, needsApproval 许可证: MIT
TanStack AI(供应商无关的LLM SDK)
状态: 生产就绪 ✅
最后更新: 2025-12-09
依赖: Node.js 18+, TypeScript 5+; React 18+ 用于 @tanstack/ai-react; Solid 1.8+ 用于 @tanstack/ai-solid
最新版本: @tanstack/ai@latest (alpha), @tanstack/ai-react@latest, @tanstack/ai-client@latest, 适配器: @tanstack/ai-openai@latest @tanstack/ai-anthropic@latest @tanstack/ai-gemini@latest @tanstack/ai-ollama@latest
快速开始(7分钟)
1) 安装核心 + 适配器
pnpm add @tanstack/ai @tanstack/ai-react @tanstack/ai-openai
# 根据需要交换适配器: @tanstack/ai-anthropic @tanstack/ai-gemini @tanstack/ai-ollama
pnpm add zod # 推荐用于工具模式
为什么重要:
- 核心是框架无关的;React绑定只是包装了无头客户端。 citeturn1search3
- 适配器抽象了提供商的特性,以便更换模型而无需重写代码。 citeturn1search3
2) 部署流式聊天端点(Next.js 或 TanStack Start)
// app/api/chat/route.ts (Next.js) 或 src/routes/api/chat.ts (TanStack Start)
import { chat, toStreamResponse } from '@tanstack/ai'
import { openai } from '@tanstack/ai-openai'
import { tools } from '@/tools/definitions' // 仅定义
export async function POST(request: Request) {
const { messages, conversationId } = await request.json()
const stream = chat({
adapter: openai(),
messages,
model: 'gpt-4o',
tools,
})
return toStreamResponse(stream)
}
关键:
- 传递工具 定义 到服务器,以便LLM可以请求它们;实现位于其运行时中。 citeturn0search7
- 始终使用流式传输;分块响应保持UI响应并减少令牌浪费。 citeturn0search1
3) 使用 useChat + SSE 连接客户端
// components/Chat.tsx
import { useChat, fetchServerSentEvents } from '@tanstack/ai-react'
import { clientTools } from '@tanstack/ai-client'
import { updateUIDef } from '@/tools/definitions'
const updateUI = updateUIDef.client(({ message }) => {
alert(message)
return { success: true }
})
export function Chat() {
const tools = clientTools(updateUI)
const { messages, sendMessage, isLoading, approval } = useChat({
connection: fetchServerSentEvents('/api/chat'),
tools,
})
return (
<form onSubmit={e => { e.preventDefault(); sendMessage(e.currentTarget.prompt.value) }}>
<textarea name="prompt" disabled={isLoading} />
{approval?.pending && (
<button type="button" onClick={() => approval.approve()}>
批准工具
</button>
)}
</form>
)
}
关键:
- 使用
fetchServerSentEvents(或匹配的适配器)来镜像流式响应。 citeturn0search0 - 保持客户端工具名称与定义相同,以避免“工具未找到”错误。 citeturn0search7
四步设置过程
步骤 1: 安全选择提供商 + 模型
- 添加正确的适配器并设置匹配的API密钥(
OPENAI_API_KEY、ANTHROPIC_API_KEY、GEMINI_API_KEY或 Ollama 主机)。 - 优先使用适配器提供的每模型选项类型,以避免无效选项(例如,仅视觉字段)。 citeturn1search3
步骤 2: 定义工具一次,按运行时实现
// tools/definitions.ts
import { z, toolDefinition } from '@tanstack/ai'
export const getWeatherDef = toolDefinition({
name: 'getWeather',
description: '获取当前城市的天气',
inputSchema: z.object({ city: z.string() }),
needsApproval: true,
})
export const getWeather = getWeatherDef.server(async ({ city }) => {
const data = await fetch(`https://api.weather.gov/points?q=${city}`).then(r => r.json())
return { summary: data.properties?.relativeLocation?.properties?.city ?? city }
})
export const showToast = getWeatherDef.client(({ city }) => {
console.log(`显示 ${city} 的提示`)
return { acknowledged: true }
})
关键点:
needsApproval: true强制对敏感操作进行明确的用户批准。 citeturn0search1- 保持工具单用途且幂等;返回结构化对象而不是抛出错误。 citeturn0search1
步骤 3: 创建连接适配器 + 聊天选项
- 服务器:
toStreamResponse(stream)用于HTTP流式传输;toServerSentEventsStream助手用于服务器发送事件。 citeturn0search3turn0search4 - 客户端:
fetchServerSentEvents('/api/chat')或自定义适配器用于websockets(如果需要)。 citeturn0search0 - 配置
agentLoopStrategy(例如,maxIterations(8))以限制工具递归。 citeturn1search4
步骤 4: 添加可观察性 + 护栏
- 记录工具执行和流块以进行调试;alpha版本暴露钩子,而开发工具正在进行中。 citeturn0search1
- 使用Zod验证输入;快速失败并返回类型化错误对象。
- 在外部API调用中强制超时,以防止代理循环卡住。
关键规则
始终执行
✅ 流式传输响应;避免等待完整完成。 citeturn0search1
✅ 传递 定义 到服务器, 实现 到正确的运行时。 citeturn0search7
✅ 使用Zod模式进行工具输入/输出,以保持跨提供商的类型安全。 citeturn0search1
✅ 使用 maxIterations 限制代理循环,以防止失控工具调用。 citeturn1search4
✅ 对于破坏性或计费敏感的工具,要求 needsApproval。 citeturn0search1
永远不要执行
❌ 在单个请求中混合提供商适配器—每个调用实例化一个适配器。
❌ 从工具抛出原始错误;返回结构化错误载荷。
❌ 发送客户端工具 实现 到服务器(仅定义)。
❌ 硬编码模型能力;依赖适配器类型进行每模型选项。 citeturn0search1
❌ 跳过API密钥检查;在服务器上快速失败并给出有用的消息。 citeturn0search1
已知问题预防
此技能防止 3 个记录的问题:
问题 #1: “工具未找到” / 静默工具失败
原因: 定义未传递给 chat();仅实现存在本地。
预防: 单独导出定义并在服务器 tools 数组中包含它们;保持名称稳定。 citeturn0search7
问题 #2: UI中的流式传输停滞
原因: 服务器响应类型与客户端适配器不匹配(HTTP分块 vs SSE)。
预防: 在服务器使用 toStreamResponse + 在客户端使用 fetchServerSentEvents(或匹配的适配器)。 citeturn0search1turn0search0
问题 #3: 模型选项验证错误
原因: 特定于提供商的选项(例如,视觉参数)发送到不受支持的模型。
预防: 使用适配器提供的类型;依赖每模型选项类型在编译时发现无效字段。 citeturn1search3
配置文件参考
.env.local(完整示例)
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=
GEMINI_API_KEY=
OLLAMA_HOST=http://localhost:11434
AI_STREAM_STRATEGY=immediate
为什么这些设置:
- 保持非活动提供商为空,以避免意外多提供商调用。
AI_STREAM_STRATEGY被示例客户端读取以选择块策略(立即 vs 缓冲)。
常见模式
模式 1: 带有限工具的代理循环
import { chat, maxIterations } from '@tanstack/ai'
import { openai } from '@tanstack/ai-openai'
const stream = chat({
adapter: openai(),
messages,
tools,
agentLoopStrategy: maxIterations(8), // 硬限制
})
何时使用: 任何LLM可以跨工具递归的流程(搜索 → 总结 → 获取详情)。 citeturn1search4
模式 2: 混合服务器 + 客户端工具
// 服务器: 数据获取
const fetchUser = fetchUserDef.server(async ({ id }) => db.user.find(id))
// 客户端: UI更新
const highlightUser = highlightUserDef.client(({ id }) => {
document.querySelector(`#user-${id}`)?.classList.add('ring')
return { highlighted: true }
})
chat({ tools: [fetchUser, highlightUser] })
何时使用: 当模型必须在单个循环中同时获取数据和突变UI状态时。 citeturn0search1
使用捆绑资源
脚本 (scripts/)
scripts/check-ai-env.sh— 在运行开发服务器之前验证所需的提供商密钥是否存在。
示例用法:
./scripts/check-ai-env.sh
参考 (references/)
references/tanstack-ai-cheatsheet.md— 压缩的服务器/客户端/工具模式加故障排除提示。
当Claude应该加载这些时: 调试工具路由、流式传输问题或回忆确切的API调用时。
资产 (assets/)
assets/api-chat-route.ts— 复制/粘贴API路由模板与流式传输 + 工具。assets/tool-definitions.ts— 准备使用的toolDefinition示例与批准 + zod模式。
何时加载参考
加载参考文件用于特定实现场景:
-
适配器比较: 加载
references/adapter-matrix.md当在OpenAI、Anthropic、Gemini或Ollama适配器之间选择时,或调试特定于提供商的特异性时。 -
React集成详情: 加载
references/react-integration.md当实现useChat钩子、处理React组件中的SSE流或管理客户端工具状态时。 -
路由设置: 加载
references/start-vs-next-routing.md当在Next.js vs TanStack Start中设置API路由时,或故障排除流式响应设置时。 -
流式传输问题: 加载
references/streaming-troubleshooting.md当调试SSE连接问题、块传递问题或HTTP流式传输配置时。 -
快速参考: 加载
references/tanstack-ai-cheatsheet.md用于压缩的API模式、工具定义语法或快速故障排除提示。 -
工具架构: 加载
references/tool-patterns.md当实现复杂的客户端/服务器工具工作流、批准流或混合工具模式时。 -
类型安全详情: 加载
references/type-safety.md当使用每模型选项类型、多模态输入或跨适配器调试类型错误时。
高级主题
每模型类型安全
- 使用适配器类型选择每模型的有效选项;避免在
chat()上使用通用any选项。 citeturn1search3 - 对于多模态模型,发送带有正确MIME类型的
parts;不支持的模态在编译时被捕获。 citeturn1search3
工具批准UX
- 通过
useChat中的approval对象暴露;呈现批准/拒绝UI并按工具调用持久化决策。 citeturn0search1 - 对于可审计操作,记录批准决策与工具输入。
连接适配器
- 默认使用
fetchServerSentEvents(SSE) 进行最小设置;切换到自定义适配器用于websockets或HTTP分块。 citeturn0search0 - 在客户端使用
ImmediateStrategy以发出每个块用于打字指示器UI。 citeturn0search0
依赖
必需:
- @tanstack/ai@latest — 核心聊天 + 工具引擎
- @tanstack/ai-react@latest — React绑定(无头使用跳过)
- @tanstack/ai-client@latest — 无头聊天客户端 + 适配器
- 适配器: 之一 @tanstack/ai-openai@latest | @tanstack/ai-anthropic@latest | @tanstack/ai-gemini@latest | @tanstack/ai-ollama@latest
- zod@latest — 工具的模式验证
可选:
- @tanstack/ai-solid@latest — Solid绑定
- @tanstack/react-query@latest — 缓存工具内部获取的数据
- @tanstack/start@latest — 与服务器函数共置AI工具
官方文档
- TanStack AI 概览: https://tanstack.com/ai/latest/docs/getting-started/overview
- 快速开始: https://tanstack.com/ai/latest/docs/getting-started/quick-start
- 工具架构与批准: https://tanstack.com/ai/latest/docs/guides/tool-architecture
- 客户端工具: https://tanstack.com/ai/latest/docs/guides/client-tools
- API参考: https://tanstack.com/ai/latest/docs/api/ai
包版本(已验证 2025-12-09)
{
"dependencies": {
"@tanstack/ai": "latest",
"@tanstack/ai-react": "latest",
"@tanstack/ai-client": "latest",
"@tanstack/ai-openai": "latest"
},
"devDependencies": {
"zod": "latest"
}
}
故障排除
问题: UI从未接收到工具输出
解决方案: 确保工具实现返回可序列化对象;避免返回undefined。通过 clientTools(...) 注册客户端实现。
问题: “缺少API密钥”响应
解决方案: 运行 ./scripts/check-ai-env.sh 并在 .env.local 中设置相关的提供商密钥。在调用 chat() 之前在路由中快速失败。 citeturn0search1
问题: 流式传输在第一个块后停止
解决方案: 确认服务器返回 toStreamResponse(stream)(或SSE助手)并且任何反向代理允许分块传输。
完整设置检查清单
使用此检查清单验证您的设置:
- [ ] 安装了核心 + 一个适配器和zod
- [ ] API路由返回
toStreamResponse(stream),工具 定义 包含在内 - [ ] 客户端使用
fetchServerSentEvents(或匹配的适配器)并注册客户端工具实现 - [ ]
needsApproval路径呈现批准/拒绝UI - [ ] 代理循环限制(例如,
maxIterations) - [ ] 环境密钥用
check-ai-env.sh验证 - [ ] 多模态输入测试如果目标为视觉/音频模型
问题?问题?
- 加载
references/tanstack-ai-cheatsheet.md获取更深入的示例 - 用单个提供商适配器重新运行快速开始步骤
- 查看上面的官方文档以获取API表面更新