使用 AI SDK 构建 SvelteKit 应用:从零运行 `sveltekit-openai` 示例并掌握 Chat、Completion 与结构化输出

使用 AI SDK 构建 SvelteKit 应用:从零运行 `sveltekit-openai` 示例并掌握 Chat、Completion 与结构化输出 使用 AI SDK 构建 SvelteKit 应用从零运行sveltekit-openai示例并掌握 Chat、Completion 与结构化输出【免费下载链接】aiThe AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and agents项目地址: https://gitcode.com/GitHub_Trending/ai/ai导读本指南以官方示例 examples/sveltekit-openai 为主线演示如何在 SvelteKit 应用中集成 AI SDKTypeScript 的 AI 工具包从仓库克隆、依赖安装、环境变量配置到本地启动的完整流程并深入剖析该示例中聊天Chat、文本补全Completion、结构化对象StructuredObject三大核心能力的端到端实现包括服务端工具与客户端工具的协作机制。读完本文你将能够在自己的 SvelteKit 项目中复刻一套支持流式输出、工具调用与类型安全结构化数据的完整 AI 应用。示例概览与运行准备sveltekit-openai是 AI SDK 官方仓库中面向 Svelte/SvelteKit 生态的示例应用它使用ai-sdk/svelte作为前端集成层ai-sdk/openai作为模型提供商适配器展示三种典型 AI 交互模式页面路由核心能力对应 API 路由/chat与/chat/[id]多轮流式对话 服务端/客户端工具调用src/routes/api/chat/server.ts/completion输入自动补全Tab 键接受建议src/routes/api/completion/server.ts/structured-object生成符合 Zod Schema 的结构化 JSONsrc/routes/api/structured-object/server.ts示例采用 monorepo 结构依赖通过 pnpm workspace 关联到仓库内的ai、ai-sdk/openai、ai-sdk/svelte等本地包见 examples/sveltekit-openai/package.json 中的workspace:*引用因此必须先从仓库根目录安装依赖并构建而不是直接在示例目录内单独安装。三步启动示例第一步在仓库根目录安装依赖并构建。README 给出的标准流程是pnpm install pnpm buildpnpm install会根据pnpm-workspace.yaml与根目录的pnpm-lock.yaml一次性安装所有 workspace 包pnpm build会通过 Turbo 任务编排构建ai核心包及其 provider 包。只有完成构建workspace:*引用的ai-sdk/svelte、ai-sdk/openai等本地包才具备可解析的产物。第二步在示例目录创建环境变量文件。在examples/sveltekit-openai下新建.env.local内容如下OPENAI_API_KEYyour key该文件是 SvelteKit 约定会被$env/dynamic/private读取详见下文不会提交到版本库。第三步启动开发服务器。pnpm -F sveltekit-openai devpnpm -F sveltekit-openai表示在 workspace 中筛选名为example/sveltekit-openai的包执行dev脚本等价于进入示例目录运行pnpm dev即vite dev见 package.json 的 scripts 定义。默认地址为http://localhost:5173。工程配置要点Vercel 适配器svelte.config.js 使用sveltejs/adapter-vercel且运行时固定为nodejs24.x说明该示例默认面向 Vercel 的 Node.js 运行时部署Vite 插件vite.config.ts 仅注册sveltekit()插件属于标准的 SvelteKit 工程UI 基础示例基于 Tailwind CSStailwind.config.ts与 shadcn-svelte 风格的bits-ui组件components.json按钮、输入框等 UI 位于src/lib/components/ui与src/lib/components/icons。聊天应用流式对话与服务端/客户端工具协作前端Chat实例页面 src/routes/chat/page.svelte 的核心是实例化ai-sdk/svelte的Chat类const chat new Chat({ // run client-side tools that are automatically executed: async onToolCall({ toolCall }) { // artificial 2 second delay await new Promise(resolve setTimeout(resolve, 2000)); if (toolCall.toolName getLocation) { const cities [New York, Los Angeles, Chicago, San Francisco]; const location cities[Math.floor(Math.random() * cities.length)]; await chat.addToolOutput({ toolCallId: toolCall.toolCallId, tool: getLocation, output: location, }); } }, });从源码看Chat继承自ai包的AbstractChat并将状态包装为 Svelte 5 的响应式$state见 packages/svelte/src/chat.svelte.tsmessages、status、error均为$state驱动因此模板中直接访问chat.messages、chat.status即可获得自动更新。发送消息只需调用chat.sendMessage({ text: input })随后在模板中遍历chat.messages并按message.parts中的 part 类型分派渲染。服务端路由streamText 与 UI 消息流API 端点 src/routes/api/chat/server.ts 演示了完整的“模型调用 工具注册 流式返回”链路import { env } from $env/dynamic/private; import { createOpenAI } from ai-sdk/openai; import { convertToModelMessages, createUIMessageStreamResponse, streamText, isStepCount, toUIMessageStream, } from ai; const openai createOpenAI({ apiKey: env?.OPENAI_API_KEY, }); export const POST async ({ request }: { request: Request }) { const { messages } await request.json(); const result streamText({ model: openai(gpt-4o), messages: convertToModelMessages(messages), stopWhen: isStepCount(5), // multi-steps for server-side tools tools: { /* ... */ }, onError: error { console.error(error); }, }); return createUIMessageStreamResponse({ stream: toUIMessageStream({ stream: result.stream }), }); };要点拆解$env/dynamic/privateSvelteKit 提供的私有环境变量读取接口OPENAI_API_KEY在服务端被createOpenAI消费不会泄漏到浏览器端createOpenAI来自ai-sdk/openai用于构造 OpenAI 客户端apiKey缺省时会回退读取OPENAI_API_KEY环境变量convertToModelMessages将前端 UI 消息UIMessage转换为模型可识别的消息格式实现前后端消息结构的解耦stopWhen: isStepCount(5)限制多步工具调用最多执行 5 轮防止服务端工具循环失控该示例注释明确其为“multi-steps for server-side tools”createUIMessageStreamResponsetoUIMessageStream将streamText的底层流包装为 UI 消息流返回给前端Svelte 的Chat客户端会自动解析该流并逐步更新messages。三类工具的协作模式该端点注册了三个工具示范了服务端工具与客户端工具的完整分工对应 chat/server.ts1. 服务端工具getWeatherInformationgetWeatherInformation: { description: show the weather in a given city to the user, inputSchema: z.object({ city: z.string() }), execute: async ({ city: _ }: { city: string }) { // Add artificial delay of 2 seconds await new Promise(resolve setTimeout(resolve, 2000)); const weatherOptions [sunny, cloudy, rainy, snowy, windy]; return weatherOptions[ Math.floor(Math.random() * weatherOptions.length) ]; }, },提供execute函数后工具在服务端自动执行结果直接回流给模型继续生成。示例中加入了 2 秒人为延迟便于在 UI 上观察input-streaming→input-available→output-available的状态流转。2. 客户端确认工具askForConfirmationaskForConfirmation: { description: Ask the user for confirmation., inputSchema: z.object({ message: z.string().describe(The message to ask for confirmation.), }), },没有execute属于“仅定义参数”的客户端工具当模型调用它时前端会暂停等待用户输入。页面中对应的part.type tool-askForConfirmation分支在state input-available时渲染 Yes/No 按钮点击后调用chat.addToolOutput({ toolCallId, tool: askForConfirmation, output: Yes, confirmed })把用户决策回传给模型。3. 自动执行的客户端工具getLocationgetLocation: { description: Get the user location. Always ask for confirmation before using this tool., inputSchema: z.object({}), },同样无execute但由前端的onToolCall回调自动处理模拟 2 秒后随机返回一个城市并通过addToolOutput写回结果。页面在tool-getLocation分支中分别渲染“Getting location...”与最终位置。渲染层的关键点在 chat/page.svelte 中每种工具都对应一种 part 类型tool-askForConfirmation、tool-getLocation、tool-getWeatherInformation再根据part.stateinput-streaming、input-available、output-available渲染不同阶段的 UI——这是 AI SDK 消息层设计在 UI 上的直观体现。多会话路由/chat/[id]src/routes/chat/[id]/page.svelte 展示了如何按 URL 参数隔离会话import { page } from $app/state; const chat new Chat({ id: page.params.id, // ...同上的 onToolCall });页面底部提供了/chat/1、/chat/2、/chat/3三个入口链接每个 id 对应独立的Chat实例状态。当Chat构造函数不传id时如首页则会话标识由客户端自动生成。根布局中的 AI 上下文src/routes/layout.svelte 在应用根部调用了createAIContext()来自ai-sdk/svelte为整棵组件树建立 AI 相关的共享上下文Chat、Completion、StructuredObject实例依赖该上下文进行状态管理与流处理。文本补全类似 IDE 的自动完成体验/completion页面展示了Completion类的典型用法模型只续写输入不重复提示词本身。服务端prompt 续写src/routes/api/completion/server.ts 的核心在于一条精心设计的系统提示词要求模型“自然续写、不超过 100 词、绝不重复输入”并给出Hello,→Hello, world!等示例约束行为const system Generate a completion for the given prompt. Your completion should never start with the text of the prompt, but should continue the prompt in a natural way. Your completion should provide a maximum of 100 additional words. ... ; export const POST async ({ request }: { request: Request }) { const { prompt } await request.json(); const result streamText({ model: openai(gpt-4o), system, prompt, onError: error { console.error(error); }, }); return createUIMessageStreamResponse({ stream: toUIMessageStream({ stream: result.stream }), }); };注意这里同时传入了system与prompt两个字段而非messages这是streamText为“单轮生成”场景提供的便捷入口。前端防抖提交 Tab 键接受src/routes/completion/page.svelte 的关键逻辑const completion new Completion(); const submit debounced(completion.handleSubmit, 300); function handleKeydown(event: KeyboardEvent): void { if (event.key Tab completion.completion) { event.preventDefault(); completion.input completion.completion; completion.completion ; } submit(event); }防抖debounced(completion.handleSubmit, 300)确保输入停止 300ms 后才请求 API避免每次按键都触发网络请求Tab 接受当补全建议存在时按 Tab 会阻止默认焦点跳转而是把建议文本并入输入框并清空当前建议视觉层叠模板中用一个半透明的前置层把completion.input completion.completion渲染在输入框下层实现“灰色幽灵文本”的补全预览效果。结构化输出用 Zod Schema 约束模型返回/structured-object页面演示如何让模型稳定输出符合 Schema 的 JSON适用于“生成多条通知”这类需要后端直接消费结构化数据的场景。共享的 Zod Schemasrc/routes/structured-object/schema.ts 定义了输出契约import { z } from zod; // define a schema for the notifications export const notificationSchema z.object({ notifications: z.array( z.object({ name: z.string().describe(Name of a fictional person.), message: z.string().describe(Message. Do not use emojis or links.), }), ), });describe()中的说明文字会被注入模型提示指导其生成符合预期的字段内容如“不使用 emoji 或链接”。该 Schema 被服务端路由与前端页面跨模块复用路由通过相对导入../../structured-object/schema.js引用。服务端Output.object 文本流src/routes/api/structured-object/server.ts 使用 AI SDK 的Output类型系统import { Output, createTextStreamResponse, streamText, toTextStream } from ai; const result streamText({ model: openai(gpt-4o), output: Output.object({ schema: notificationSchema }), prompt: Generate 3 notifications for a messages app in this context: context, onError: error { console.error(error); }, }); return createTextStreamResponse({ stream: toTextStream({ stream: result.stream }), });与 Chat 路由不同这里返回的是纯文本流createTextStreamResponsetoTextStream因为前端StructuredObject会在本地完成 JSON 解析不需要 UI 消息包装。前端类型安全的响应式对象src/routes/structured-object/page.svelte 中const structuredObject new StructuredObject({ api: /api/structured-object, schema: notificationSchema, });提交时调用structuredObject.submit(input)模板中通过structuredObject.object?.notifications直接渲染解析后的数组notification?.name/notification?.messageloading状态用于禁用提交按钮structuredObject.clear()用于清空结果。由于前端持有 Zod Schemaobject的字段访问具备完整的类型提示与运行时校验。数据流全景与关键源码定位将三个场景串起来可以得到统一的请求链路前端Chat/Completion/StructuredObject实例ai-sdk/svelte发起请求SvelteKitserver.ts路由接收请求通过streamText调用createOpenAI构造的模型服务端将result.stream包装为 UI 消息流toUIMessageStream或文本流toTextStream流式返回前端消费流并更新 Svelte 5 响应式状态工具调用过程中通过onToolCall/addToolOutput与用户交互结构化输出场景中前端用同一份 Zod Schema 解析并渲染object。进一步探索可参考的源码与测试ai-sdk/svelte包的实现位于 packages/svelte/src其中 chat.svelte.tsChat类与 Svelte 响应式状态、completion.svelte.tsCompletion、structured-object.svelte.tsStructuredObject分别对应示例三大功能配套的*.test.ts文件提供了行为测试用例createOpenAI的模型工厂实现见 packages/openai/srcai-sdk/openaistreamText及工具执行、stopWhen等核心逻辑位于 packages/ai/src 的ai核心包其他框架集成示例可对比 examples 下的next-openai、nuxt-openai、vue、angular、express等目录理解同一套ai核心在不同 UI 框架上的接入方式。结语sveltekit-openai示例虽小却完整覆盖了 AI SDK 在 SvelteKit 场景下的三条主线基于Chat与工具调用的流式对话、基于Completion的输入补全、基于StructuredObject与 Zod 的结构化输出。无论是想快速跑通官方示例还是以此为模板搭建生产级应用都可以按本文的启动流程与源码剖析逐层展开。部署到 Vercel 时仅需保留OPENAI_API_KEY环境变量并依赖 svelte.config.js 中已配置的 Node.js 24 适配器即可。【免费下载链接】aiThe AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and agents项目地址: https://gitcode.com/GitHub_Trending/ai/ai创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考