拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Vercel AI SDK实战:从流式聊天到自建AI Gateway

最近在技术社区里Vercel AI SDK和AI Gateway是出现频率很高的两个关键词。前者是一套面向大模型应用的开源 TypeScript 工具库后者则是把模型请求统一收口、缓存、限流、记日志的网关层。很多同学看完官方文档的第一反应是概念能看懂但不知道从哪里开始玩。这篇文章会带大家走一条比较完整的动手路线先用create-next-app创建一个 Next.js 项目然后接入 Vercel AI SDK实现一个可以流式返回结果的聊天接口和页面接着聊聊 AI Gateway 的核心价值并自己在项目里实现一个最小可运行版本。零散踩过坑的开发者可以把它当配置手册刚入门的新手也能照着一步步把 Demo 跑起来。先补充一句重要提醒Vercel 官方云端 AI Gateway 产品本身迭代很快接入方式、免费额度、模型支持列表都可能变化。所以本文的重点放在“网关应该解决什么问题 如何自建一个最小可运行实现”上而不是让你依赖某篇旧文章里的固定 URL 去接入云端产品。1. 背景与核心概念AI SDK 和 AI Gateway 分别解决什么问题1.1 从一个高频痛点说起做 AI 应用时很多人第一版代码是这样写的const response await fetch(https://api.xxx.com/v1/chat/completions, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${process.env.API_KEY}, }, body: JSON.stringify({ model: xxx, messages }), });单独看没有问题但项目一多问题就暴露了每个模型厂商的请求格式、鉴权方式、返回结构都略有不同换一个模型就要改一遍调用层代码。如果前端直接调用模型接口API Key 很容易被暴露在浏览器里。没有统一的缓存、限流、失败重试、请求日志每次模型调用都像“裸奔”。想把 OpenAI 切换到 Anthropic、Google Gemini 或其他 OpenAI 兼容服务改造成本很高。Vercel AI SDK和AI Gateway分别站在不同层解决上面这些痛点。1.2 Vercel AI SDK一套统一的模型调用层通俗理解Vercel AI SDK 是“模型厂商封装层”的上层统一接口。它把不同大模型服务商的差异封装起来让你用几乎相同的代码调用不同模型。开发者只需要选择对应的 provider 包比如ai-sdk/openai、ai-sdk/anthropic再传入模型 ID 即可。它提供的核心能力包括generateText非流式生成完整文本。streamText流式生成文本适合实现打字机效果。generateObject按 JSON Schema 生成结构化对象。useChat等前端 Hooks帮助快速接入聊天 UI。工具调用Tool Calling与 Agent 循环支持。这套设计让“换模型”变成了一件成本很低的事情甚至可以把模型 ID 放在环境变量里运行时动态切换。1.3 AI GatewayAI 请求的交通枢纽AI Gateway 更像是一个位于“应用”和“模型服务商”之间的代理层。它的职责不是帮你写模型调用代码而是统一管理所有模型请求。在企业级 AI 应用中网关通常负责统一入口所有模型请求走同一个网关地址而不是散落在各个服务里。API Key 统一管理网关沉淀密钥下游应用不需要直接接触各家厂商的 Key。缓存相同请求直接命中缓存减少重复计费。限流与配额避免某个应用或某个用户把预算打爆。日志与观测记录每次请求的模型、Token 消耗、延迟、错误类型。降级与重试主模型不可用时自动切换到备用模型。Vercel 官方也提供 AI Gateway 云产品把上述能力托管起来。如果你在看官方资料建议直接以官方文档为准避免使用半年前的旧教程。1.4 两者的关系不是二选一AI SDK 和 AI Gateway 解决的是不同层的问题实际项目中经常配合使用浏览器 / App ↓ 你的业务服务内部调用 Vercel AI SDK 编写代码 ↓ AI Gateway缓存、限流、日志、统一密钥 ↓ OpenAI / Anthropic / Google / 其他模型服务商这篇文章后续的实战部分会先用 AI SDK 写一个聊天 Demo然后自己在 Next.js 里扮演一层“最小 AI Gateway”。2. 环境准备与版本说明2.1 前置条件在开始动手前你需要准备以下环境Node.js建议使用 18.18 或更高的 LTS 版本。AI SDK 的最新版本对 Node 版本有一定要求版本过低会出现依赖安装或运行错误。npm / pnpm / yarn任一包管理器即可下文以 npm 为例。Vercel 账号可以等部署时再注册免费账号就够用。一个大模型 API Key本文以 OpenAI 兼容接口为例。如果你暂时没有官方 Key也可以使用国内或海外提供 OpenAI 兼容接口的服务但要注意合规与服务条款。注意Node.js 和 Next.js 的具体版本变化较快本文示例不会把某一个版本写死。你会发现下面的代码在较新的 Next.js App Router 项目中可以直接运行如果跑不起来优先检查你的框架和 AI SDK 是否处于同一个大版本。2.2 初始化 Next.js 项目在终端执行npx create-next-applatest ai-gateway-lab命令执行后交互式提示一般会让你选择 TypeScript、ESLint、Tailwind CSS、src 目录等选项。建议按下面的组合选择选项推荐选择TypeScriptYesESLintYesTailwind CSS随意本文代码不依赖它App RouterYessrc directoryYesTurbopack可选这样会生成一个使用 App Router 的现代 Next.js 项目。进入项目目录cd ai-gateway-lab2.3 项目最终结构预览本文会创建以下文件你可以先有一个整体印象ai-gateway-lab/ ├── .env.local └── src/ └── app/ ├── api/ │ ├── hello-ai/ │ │ └── route.ts │ ├── chat/ │ │ └── route.ts │ └── gateway/ │ └── route.ts ├── layout.tsx └── page.tsx后面每个文件都会给出完整代码。3. AI SDK 核心用法拆解3.1 Provider先选择你的模型服务商Vercel AI SDK 把“模型服务商”抽象成provider。不同厂商需要安装不同的 provider 包例如npm install ai-sdk/openai如果要用 Anthropic就安装ai-sdk/anthropic如果要用其他模型服务可以看官方 provider 文档不建议凭记忆猜包名。ai-sdk/openai默认导出已经配置好的openai实例最基础的用法是import { generateText } from ai; import { openai } from ai-sdk/openai; const result await generateText({ model: openai(gpt-4o-mini), prompt: 用一句话解释什么是 Vercel AI SDK, }); console.log(result.text);这里的openai(gpt-4o-mini)表示“使用 OpenAI 兼容服务商下的 gpt-4o-mini 模型”。你看到的generateText是 AI SDK 提供的一个顶层函数作用是让模型生成完整文本。3.2 流式输出与普通输出的区别普通接口用generateText等服务端完整生成后再一次性返回。但聊天应用更常见的体验是“打字机式输出”也就是一个字一个字往外蹦。这时候应使用streamTextimport { streamText } from ai; import { openai } from ai-sdk/openai; const result streamText({ model: openai(gpt-4o-mini), prompt: 给我讲一个程序员冷笑话, }); // 在 Next.js 路由中通常返回给前端使用 return result.toUIMessageStreamResponse();注意streamText返回的不是普通字符串而是一个流式结果对象。服务端必须通过特定方法把这个流交给网络层前端才能一段段收到内容。3.3 useChat前端的聊天 Hook如果你不打算自己维护 messages 数组和流式解析逻辑可以使用 AI SDK 提供的前端 HookuseChat。它帮你封装了下面这些繁琐环节维护消息列表messages。管理输入框内容input。发送请求并逐步接收流式文本。暴露加载状态isLoading和停止方法stop。在最新版本中React 相关 Hook 从ai-sdk/react导出。如果你看到旧文章写import { useChat } from ai/react说明那篇文章使用的是旧版本 AI SDK。我们会在下一节把这三个核心知识点串成一个完整 Demo。4. 实战从 0 到 1 做一个流式聊天 Demo4.1 安装依赖在项目根目录安装 AI SDK 相关依赖npm install ai ai-sdk/openai ai-sdk/react安装完成后可以打开package.json看一下版本。只要你使用的是 AI SDK 最新大版本下面代码基本通用。4.2 配置环境变量创建.env.local文件写入你的模型配置OPENAI_API_KEY你的_API_Key OPENAI_MODELgpt-4o-mini # 如果你使用 OpenAI 兼容接口可以在这里覆盖 baseURL # OPENAI_BASE_URLhttps://你的兼容服务地址/v1配置说明OPENAI_API_KEY模型服务商提供的密钥。这个文件不要提交到 Git 仓库。OPENAI_MODEL默认模型 ID方便以后切换而不改代码。OPENAI_BASE_URL当服务商提供 OpenAI 兼容接口时使用。如果你直连 OpenAI不需要配置这一项因为ai-sdk/openai默认会指向 OpenAI 官方地址。在 Next.js 中只有以NEXT_PUBLIC_开头的环境变量才会暴露给浏览器。OPENAI_API_KEY没有这个前缀所以它只存在于服务端这是保证 Key 不泄露的基本前提。4.3 第一个接口非流式调用 generateText先创建一个最简单的接口验证环境变量和模型调用链路是否正常。文件路径src/app/api/hello-ai/route.tsimport { generateText } from ai; import { openai } from ai-sdk/openai; export async function POST(req: Request) { const body await req.json(); const prompt String(body.prompt ?? 你好); try { const result await generateText({ model: openai(process.env.OPENAI_MODEL ?? gpt-4o-mini), prompt, }); return Response.json({ text: result.text }); } catch (error) { console.error(generateText 调用失败:, error); return Response.json( { error: 模型调用失败请检查 API Key 与模型 ID }, { status: 500 } ); } }启动本地开发服务器npm run dev再用 curl 模拟一次请求curl -X POST http://localhost:3000/api/hello-ai \ -H Content-Type: application/json \ -d {prompt:用一句话介绍你自己}预期会返回类似下面的 JSON{ text: 我是一个人工智能助手可以回答问题、编写代码并提供学习建议。 }实际文本由模型生成内容不一定完全一致。只要能拿到 JSON说明环境配置成功。这也是一个非常方便的“无头测试”方式不需要打开浏览器用 curl 就能确认模型服务商、Key、prompt 是否能正常连通。4.4 编写流式聊天接口generateText适合工具脚本和非交互式场景。聊天页面需要流式输出所以我们要写一个新的路由使用streamText。文件路径src/app/api/chat/route.tsimport { openai } from ai-sdk/openai; import { streamText } from ai; // Vercel Serverless 环境最长执行 30 秒本地开发时该配置不影响 export const maxDuration 30; export async function POST(req: Request) { const { messages } await req.json(); const result streamText({ model: openai(process.env.OPENAI_MODEL ?? gpt-4o-mini), system: 你是一位耐心的技术助手。回答请使用中文并尽量条理化避免冗长。, messages, }); return result.toUIMessageStreamResponse(); }这段代码里有三个关键点messages由前端发送过来是完整的对话历史模型需要依据上下文回答。system用来设定 AI 的人设或回答规则。toUIMessageStreamResponse()是 AI SDK 推荐在较新版本中配合useChat使用的响应方法能把流式结果转换为前端可以消费的协议格式。如果你使用的是旧版 AI SDK 3.x这里大概率没有toUIMessageStreamResponse方法需要参考官方迁移文档调整。4.5 编写聊天页面接下来把前端页面替换成聊天界面。文件路径src/app/page.tsxuse client; import { useChat } from ai-sdk/react; export default function ChatPage() { const { messages, input, handleInputChange, handleSubmit, isLoading, stop } useChat({ api: /api/chat, }); return ( main style{{ maxWidth: 720, margin: 0 auto, padding: 24, fontFamily: sans-serif, }} h1Vercel AI SDK 流式聊天 Demo/h1 div style{{ minHeight: 320, border: 1px solid #e5e7eb, borderRadius: 8, padding: 16, }} {messages.length 0 ? ( p style{{ color: #6b7280 }}先和模型打个招呼吧。/p ) : ( messages.map((m) ( div key{m.id} style{{ marginBottom: 12 }} div style{{ fontWeight: 600, color: m.role user ? #2563eb : #111827, }} {m.role user ? 你 : AI} /div div style{{ whiteSpace: pre-wrap, lineHeight: 1.7 }} {m.content} /div /div )) )} /div form onSubmit{handleSubmit} style{{ display: flex, gap: 8, marginTop: 16 }} input value{input} onChange{handleInputChange} placeholder输入消息后回车 style{{ flex: 1, padding: 8px 12px, borderRadius: 6, border: 1px solid #d1d5db, }} / button typesubmit disabled{isLoading || !input.trim()} style{{ padding: 8px 16px, borderRadius: 6, border: none, background: #2563eb, color: #fff, cursor: pointer, }} {isLoading ? 思考中… : 发送} /button button typebutton onClick{stop} disabled{!isLoading} style{{ padding: 8px 12px }} 停止 /button /form /main ); }这里主要依赖useChat提供的能力messages聊天记录数组。input、handleInputChange输入框绑定。handleSubmit提交表单并调用/api/chat。isLoading是否正在等待模型响应。stop手动中断当前流式响应。4.6 运行与验证在浏览器打开http://localhost:3000输入一句话并发送你应该能看到文本像打字机一样逐字出现。打开浏览器 DevTools 的 Network 面板还能看到/api/chat的响应是text/event-stream类型的流式数据。到这一步你已经完成了一个最小可用的 AI SDK 聊天应用。如果想测试不同模型只需要修改.env.local里的OPENAI_MODEL然后重启开发服务器即可。你会发现业务代码完全不用动这就是 provider 抽象带来的收益。5. 手写一个最小 AI Gateway 并试玩5.1 为什么需要 AI Gateway上面的 Demo 直接调用了模型服务商。单机开发没问题但一旦系统有多个服务、多个团队、多个模型就会出现几个经典问题问题直接调用模型时的表现密钥分散每个服务都要保存模型厂商 API Key泄露面大重复计费多个用户问同一个热门问题时每次都真实调用模型无统一日志出了问题难以定位是哪个服务、哪个模型、什么参数导致的无法限流某个异常流量可能打爆当天的预算切换供应商困难需要修改每个调用方的代码AI Gateway 的解决思路就是在业务代码和模型服务商之间增加一层代理。所有请求先到网关网关
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门