关于 ai-sdk-6
面向现有 AI SDK 6 项目的开发维护技能,强调依据已安装版本查阅文档,并遵循版本特定的 API 行为。
主要功能
- 01解析已安装的 SDK 和提供方版本
- 02查阅匹配版本的文档与类型
- 03采用 v6 Agent 和工具模式
- 04检查流、审批和错误
适用场景
- 01维护固定使用 AI SDK 6 的应用
- 02实现工具或结构化输出
- 03排查聊天传输与流行为
MCP 相关
在处理 MCP 集成时,指导开发者查阅 AI SDK 6 的 MCP 传输与清理文档。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ laguagu/ claude-code-nextjs-skills --skill ai-sdk-6安装后在 Claude Code 中输入/ai-sdk-6确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/agents.mdcore-functions.mdexamples.mdmcp.mdmiddleware.mdtools.mdui-hooks.mdworkflows.md详细介绍
AI SDK 6 维护
此技能仅适用于 ai@6 项目。根据现有清单/锁定文件解析兼容的提供商和 UI 包。主版本未知时使用 ai-sdk,经授权升级时使用 ai-sdk-7。
阅读已解析版本的 ai/docs/、提供商文档以及源码/类型定义,确认对应次要版本的准确内容。在 monorepo 中,根据使用该依赖的应用解析版本。默认网站文档和仓库主分支可能描述的是 v7。ai 从 6.0.32 开始捆绑 docs/;目录树镜像网站路径(映射见 ai-sdk)。如果无法使用已安装的文档,请在 vercel/ai 中选择 ai@<resolved-version> 标签并阅读 content/docs/。
此处的功能链接使用经过核验的 v6 文档快照作为后备;如果有项目对应的发布版本,请使用该版本。此标签用于选择文档,并非应用依赖版本。
与旧版和新版代码不同的边界
- 文本函数使用
system;ToolLoopAgent使用instructions。 - 循环限制使用
stopWhen: stepCountIs(...)。文本函数默认执行一步(执行工具后不提供后续回答);ToolLoopAgent默认执行 20 步。 convertToModelMessages是异步的;请使用await。- 新的 schema 输出请在文本函数中使用
Output;旧版对象函数已弃用。 - 工具使用
inputSchema;由 SDK 执行的审批使用工具级别的needsApproval。V6 不识别 v7 的toolApproval:除非类型检查报错,否则它会被忽略,工具将不经审批直接运行。 - React
useChat管理消息和流状态,不管理表单输入。请使用适当的传输方式和 UI 消息响应协议。 - Core 完成回调为
onFinish;结果中的usage是最后一步的用量,而totalUsage涵盖所有步骤。
使用已确认适用于实际提供商的已配置模型。集成变更后,请进行类型检查,并测试包含相关工具/审批/错误状态的多轮流式交互。
核心结构
已通过 [email protected]、@ai-sdk/[email protected]、[email protected]、React 19 和 TypeScript 5.9 验证:执行 tsc --noEmit,并使用模拟模型完成一次工具步骤和后续回答。字符串模型会通过 AI Gateway 解析。在 v7 中,system、stepCountIs 和 result.toUIMessageStreamResponse() 分别变为 instructions、isStepCount 和
createUIMessageStreamResponse({ stream: toUIMessageStream({ stream: result.stream }) })。
// app/api/chat/route.ts
import { convertToModelMessages, stepCountIs, streamText, tool, validateUIMessages,
type InferUITools, type UIDataTypes, type UIMessage } from 'ai';
import { z } from 'zod';
const tools = {
weather: tool({
inputSchema: z.object({ city: z.string() }),
execute: async ({ city }) => ({ city, celsius: 21 }),
}),
};
export type ChatMessage = UIMessage<never, UIDataTypes, InferUITools<typeof tools>>;
export async function POST(req: Request) {
const { messages } = await req.json();
const uiMessages = await validateUIMessages<ChatMessage>({ messages, tools });
const result = streamText({
model: 'provider/model-id', // configured gateway ID, or a provider instance
system: 'Answer briefly.',
messages: await convertToModelMessages(uiMessages),
tools,
stopWhen: stepCountIs(5),
});
return result.toUIMessageStreamResponse();
}
// app/page.tsx
'use client';
import { useChat } from '@ai-sdk/react';
import { DefaultChatTransport } from 'ai';
import type { ChatMessage } from './api/chat/route';
const transport = new DefaultChatTransport<ChatMessage>({ api: '/api/chat' });
export default function Chat() {
const { messages, sendMessage, status } = useChat<ChatMessage>({ transport });
return (
<form action={(form) => void sendMessage({ text: String(form.get('text')) })}>
{messages.map((m) => <div key={m.id}>{m.parts.map((part, i) =>
part.type === 'text' ? <p key={i}>{part.text}</p>
: part.type === 'tool-weather' && part.state === 'output-available'
? <p key={i}>{part.output.city}: {part.output.celsius} °C</p> : null)}</div>)}
<input name="text" disabled={status === 'submitted' || status === 'streaming'} />
</form>
);
}