尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Vercel AI SDK与AI Gateway:统一模型接入与访问策略的工程实践

Vercel AI SDK与AI Gateway:统一模型接入与访问策略的工程实践 现在做 LLM 应用最“快乐”的时刻往往是第一次调通 API 的那五分钟。你写一个 Prompt拿到一段文本把它像奖杯一样打印到终端里。真正的麻烦是从第二个模型开始的厂商 A 的 SDK 有自己的方法名厂商 B 的消息数组要带不同的角色字段流式协议各家实现不一致错误码更是五花八门。业务代码里开始长出一排长长的 switch没过多久你就会发现要修的其实是当时“模型接入”这件事设计得太草率了。Vercel 生态里的 AI SDK 和 AI Gateway恰好分别回应了两种不同层级的痛点。先给一个判断AI SDK 做的是“模型调用接口的统一”让应用代码不必跟着某一家模型厂商的 SDK 风格走AI Gateway 做的是“模型访问策略的统一”把路由、缓存、失败转移、密钥注入从业务代码里抽到网关层。这篇文章会帮你理清两者的边界把一个最小可运行的生成式 AI 示例跑通再把它扩展到流式输出、结构化输出、工具调用最后落到何时引入 AI Gateway、以及生产环境下最容易踩的坑。这不是一篇逐行讲完官方文档的教程而是一份能直接指导你做技术选型的路线图。1. 为什么模型接入会变成一个工程问题一个成熟的 LLM 项目不会只调用一个大模型。真实场景里你可能有 OpenAI 的模型做复杂推理有开源模型做低成本分类也有一个国产模型负责需要私有化部署的敏感数据。只接一个模型的代码是最好写的但“切换到第二个模型”时问题才开始暴露。不同厂商的差异并不只是“换一个 API Key”请求体格式不同。有的用messages有的在系统提示里塞额外的参数。流式协议不同。有的走 SSE有的返回分段 JSON有的则只支持一次性返回完整文本。错误模型不同。限流、内容过滤、上下文过长各家返回的状态码字段并不统一。编程语言 SDK 不同。Python、TypeScript 的维护方不同使用习惯自然也被带着走。这些问题放在一个 Demo 里不算什么但放到产品里就变成维护成本。你会在业务代码里看到if (provider openai)这种分支而分支一旦多起来代码的可读性会快速下降。更麻烦的是团队里不同成员分别维护不同模型厂商的接入最终没有一个人能说清整个系统的模型调用链路。这里真正的工程诉求是模型是可替换的模型调用代码不能跟着每一家 SDK 一起变。这个诉求就是 Vercel AI SDK 出现的核心背景。AI SDK 本身并不依赖 Vercel 的托管平台。确切地说它是一个可以在 Node.js、Next.js、Hono、Cloudflare Workers 等环境自由使用的 TypeScript 工具库。很多人误会它只有和 Next.js 一起使用时才有意义实际上它把模型调用抽象成了一套统一的接口底层通过 Provider 机制去对接不同厂商。2. AI SDK 与 AI Gateway 分别解决什么问题2.1 先把两个概念放在正确的位置Vercel AI SDK 是应用开发层的工具。它提供generateText、streamText、generateObject这些高层函数让你用几乎相同的代码去调用 OpenAI、Anthropic、Google 或任何实现了 Provider 接口的模型服务。它的价值在应用代码内部。Vercel AI Gateway 则是访问策略层。当你的请求从应用发出之后不直接到达模型厂商而是先经过一个网关。网关可以替你完成密钥注入、请求缓存、失败转移、速率限制、日志观测等。它的价值在应用代码之外。用一个通俗类比AI SDK 像“同声传译”把各家模型的语言翻译成你熟悉的 TypeScriptAI Gateway 更像“企业总机”你不关心电话最终转给哪个部门只需要打统一号码由交换机按策略分配。这两个产品经常被放在一起讨论并不是因为它们功能重叠而是因为它们分别处于调用链路的不同位置加在一起正好覆盖了从“易用性”到“可控性”的完整路径。维度Vercel AI SDKAI Gateway定位应用开发者库网关策略层解决的核心问题模型接口不统一模型访问策略不统一典型能力文本生成、流式输出、结构化输出、工具调用路由、缓存、重试、失败转移、统一密钥部署位置与服务端代码一起独立服务或托管网关面向使用者应用开发工程师平台、基础设施或后端工程师2.2 几个术语需要先形成共识在 AI SDK 的上下文里第一个需要理解的概念是 Provider。Provider 不等同于模型它是“模型服务商的接入器”。官方把 OpenAI、Anthropic、Google 等分别封装成openai()、anthropic()、google()每个 Provider 内部管理着自己的请求地址、鉴权和协议转换。第二个概念是 Model。你在代码里写的openai(gpt-4o-mini)就是在 Provider 上选择具体模型。AI SDK 的调用函数并不关心你是哪个厂商只关心你传进来的 model 是否符合 LanguageModel 接口。因此从应用代码角度说换模型的成本可以被压缩到一行把openai()换成别的 Provider 实例即可。前提是你在业务层不要直接使用仅由某个厂商支持的“私货字段”。AI Gateway 需要理解的核心则是“策略”二字。网关不负责生成模型输出它负责决定“该把请求发给谁”“能不能用缓存”“失败以后怎么办”。如果只接了一个模型、没有流量压力、也不需要跨团队审计那么先不上 Gateway 完全没问题。3. Vercel AI SDK 环境准备与最小示例3.1 环境准备AI SDK 目前以 TypeScript 为主需要 Node.js 运行时。建议使用 Node 18 或者更高版本因为流式处理和原生 fetch 在较新版本中会稳定很多。我这里采用一个非常轻量级的方式不直接创建一个完整 Next.js 项目而是先用 Node 脚本跑通核心调用。这样能让你把注意力集中在 AI SDK 本身。命令如下mkdir ai-sdk-playground cd ai-sdk-playground npm init -y npm install ai ai-sdk/openai dotenv npm install -D typescript tsx types/node创建.env文件# 请勿把该文件提交到 Git 仓库 OPENAI_API_KEY你的模型服务密钥如果你使用的不是 OpenAI 官方服务而是一个兼容 OpenAI 接口的网关或自建模型服务也可以在这个阶段先按官方 Provider 的最小配置跑通后续再把请求地址收敛到网关层。3.2 第一个可运行脚本generateText新建demo-generate.tsimport dotenv/config; import { generateText } from ai; import { openai } from ai-sdk/openai; async function main() { const result await generateText({ model: openai(gpt-4o-mini), prompt: 用一句话介绍什么是流式输出并说明它为什么对用户体验重要。, }); console.log(result.text); } main().catch((err) { console.error(err); process.exit(1); });运行脚本npx tsx demo-generate.ts这个脚本的核心只有几行。generateText接收一个 model 和一个 prompt返回完整的生成结果。如果终端里正常输出了一段模型生成的文本就说明 AI SDK 的核心链路已经打通。3.3 如何判断是否真的成功最容易混淆的是“模型调用成功”和“业务输出正确”两件事。终端输出文本说明前者已经成立但你还应该进一步确认请求确实发到了你预期的模型而不是某个兜底模型。API Key 的权限范围控制了接口访问避免使用了过高权限的密钥。如果发现有超时先确认网络出口到模型服务地址是否稳定而不是怀疑 SDK。4. 从一次性生成升级到流式对话4.1 为什么必须重视流式输出一次性生成虽然代码简单但真实产品更常见的是流式场景。用户发出一个问题后模型需要数秒才能生成完整回答。如果不做流式处理用户在界面上只能看到长时间转圈体验会非常差。流式输出的本质是模型每生成一部分内容服务端就立即把增量推给客户端让用户看到打字机式的效果。AI SDK 提供的streamText是比generateText更常用、也更值得深入掌握的接口。4.2 Node 环境里的最小流式示例新建demo-stream.tsimport dotenv/config; import { streamText } from ai; import { openai } from ai-sdk/openai; async function main() { const result streamText({ model: openai(gpt-4o-mini), prompt: 请用 3 句话解释缓存的作用。, }); for await (const text of result.textStream) { process.stdout.write(text); } console.log(\n--- stream end ---); } main().catch((err) { console.error(err); process.exit(1); });运行npx tsx demo-stream.ts观察终端文本是否是逐字、逐块出现的。如果内容一次性出现说明你的网络环境或运行方式可能把流缓冲住了这在云函数或某些代理环境下比较常见。4.3 在服务端接口里返回流前端的useChat等工具通常通过一个标准接口从服务端读取流。在 Next.js App Router 里可以创建app/api/chat/route.tsimport { streamText } from ai; import { openai } from ai-sdk/openai; export async function POST(req: Request) { const { messages } await req.json(); const result streamText({ model: openai(gpt-4o-mini), messages, }); return result.toDataStreamResponse(); }这段代码的核心意义在于服务端把模型输出转成一个标准的数据流响应前端无需理解各家模型厂商的流式协议只需要对接useChat约定的格式。如果你在 Next.js 项目里运行它可以通过 POST 请求http://localhost:3000/api/chat来验证。这里值得留意的点是toDataStreamResponse的命名和内部实现在不同 SDK 版本中可能有细微差异。以官方文档为准并不丢人关键是理解“服务端对实时流进行二次封装客户端消费统一协议”这一思想。5. 让模型输出变得可编程结构化输出与工具调用5.1 为什么需要结构化输出很多业务系统不能直接接受一段自然语言文本。你需要让模型返回 JSON例如前端要渲染一篇文章时希望拿到title、summary、tags这几个字段。如果只靠 Prompt 描述“请返回 JSON”模型偶尔会在前后加解释文字导致 JSON.parse 失败。AI SDK 的generateObject就是为这个场景设计的。5.2 generateObject 示例从自然语言到可靠 JSON安装zod作为 schema 校验工具npm install zod新建demo-object.tsimport dotenv/config; import { generateObject } from ai; import { openai } from ai-sdk/openai; import { z } from zod; async function main() { const result await generateObject({ model: openai(gpt-4o-mini), schema: z.object({ title: z.string().describe(文章标题), summary: z.string().describe(文章摘要), tags: z.array(z.string()).describe(标签列表), }), prompt: 请为一篇讲 Vercel AI SDK 的技术文章生成标题、摘要和标签。, }); console.log(result.object); } main().catch((err) { console.error(err); process.exit(1); });运行后result.object里的字段类型已经被 TypeScript 推导出来。写错字段或者期望一个不存在的属性时编译器会直接提示。这种方法最直接的好处是你不再需要手工对模型返回文本做正则清洗。模型输出一层层地被验证最终交给业务侧的是一个可信任的结构。这类函数在大量内容生成、实体抽取、意图识别等任务中非常实用。5.3 工具调用让模型拥有“执行动作”的能力生成文本只是 LLM 能力的一半。传统模式下模型只知道训练数据里的知识无法查询实时数据。解决办法是让模型“调用你提供的工具”。工具调用的流程可以这么理解你定义一组函数告诉模型“这些函数分别能干什么参数是什么”模型根据用户问题决定是否需要调用工具、调用哪个、传什么参数。真正执行函数的不是模型而是你的代码这和 RAG 里“模型本身不存储文档”是一个道理。新建demo-tools.tsimport dotenv/config; import { generateText } from ai; import { openai } from ai-sdk/openai; import { z } from zod; const weatherCache new Mapstring, string(); const result await generateText({ model: openai(gpt-4o-mini), prompt: 北京今天下雨吗, tools: { getWeather: { description: 查询指定城市当前天气, parameters: z.object({ city: z.string().describe(城市名称), }), execute: async ({ city }) { const key city.trim(); if (!key) { throw new Error(city is required); } if (weatherCache.has(key)) { return weatherCache.get(key)!; } // 在生产代码中这里应请求你自己可控的天气服务或数据源 const mockCondition key.includes(北京) ? 晴无雨 : 暂不支持该城市; weatherCache.set(key, mockCondition); return mockCondition; }, }, }, }); console.log(模型最终回答:, result.text); console.log(工具调用结果:, result.toolResults);在tools配置里description是给模型看的要写清楚工具职责和适用场景parameters用 zod 严格约束参数execute是真正执行的函数。这里特别提醒模型返回的工具参数是不可完全信任的。它本质上是自然语言理解后的结果存在错误、恶意指令注入的可能。如果你在execute里拼了模型返回的 URL 去请求就可能被诱导访问内部网络地址。正确的做法是执行前做白名单校验、权限校验、超时控制。6. AI Gateway 实用示例路由、缓存与失败转移6.1 网关解决的是“模型调用策略”问题当团队引入多个模型供应商后应用代码本身可能已经把接口统一了但另一些问题会出现不同团队维护各自的 Key密钥散落在环境和配置文件中。模型响应没有统一缓存相同请求反复付费。主供应商限流后没有自动切换到备用供应商的逻辑。想统计全公司模型调用量但不知去哪里审计。这些问题的共同点在于它们不是某个应用内部的问题而是多个应用共享的访问策略问题。AI Gateway 的价值在于把策略从“写死在各应用代码中”变成“网关配置的一部分”。Vercel 的 AI Gateway 有两个层面的产品形态一个是可以直接使用的托管网关服务另一个是带实验性质的开源项目hono/ai-gateway。后者更适合作技术原理展示因为你可以把它部署在自己控制的区域。6.2 用 hono/ai-gateway 做一个带缓存和失败转移的入口下面这个示例参考了开源仓库的常规用法。它的本质是创建一个 Hono 应用把/openai/*路径下的请求代理到 OpenAI同时启用缓存import { Hono } from hono; import { aiGateway } from hono/ai-gateway; const app new Hono(); app.use( /openai/*, aiGateway({ provider: openai, url: (c) new URL(c.req.path.replace(/openai/, /v1/), https://api.openai.com), headers: { Authorization: Bearer ${process.env.OPENAI_API_KEY}, }, cache: force-cache, cacheTtl: 60 * 60, }) ); export default app;配置里真正值得关注的是cache和cacheTtl。启用缓存后如果相同请求近期已经得到过成功响应网关会直接返回缓存结果不再把请求转发给模型厂商。这在高频、重复性 prompt 场景下能明显降低成本。但缓存也是最容易踩坑的地方。如果你在缓存一个包含用户个人数据的 Prompt第二个用户可能读到第一个用户的缓存结果。更稳妥的策略是在缓存规则的 Key 设计时不只依据 Prompt还要把模型、用户维度、语义版本都纳入计算对含动态信息的请求建议直接禁用缓存。如果你想演示失败转移可以参考仓库文档里的 fallback 配置。大致思路是先请求主供应商如果返回限流或服务不可用网关自动把相同请求发给备用供应商。需要提醒的是两种供应商的模型能力可能不一致所以 fallback 更适合文本分类、摘要等不要求特定强模型能力的任务而不是顶尖推理场景。6.3 网关注入密钥的价值在规模不小的团队里经常出现“某同学的电脑上有一串 Key所有服务都靠它跑”的情况。这种模式既不安全也无法审计。通过 Gateway应用侧只需要知道网关地址和网关自己的凭据真正的模型厂商 Key 只存在于网关环境变量中。即使某个服务被入侵泄露的也不是底层模型 Key而是受限的网关注入凭据。这个可见的信任边界是企业级落地的重要基础。7. 到底什么时候该上 AI Gateway不同阶段的技术选型并不是所有项目第一天就要接 AI Gateway。甚至对大多数快速验证想法的项目来说过早引入网关只会增加部署和调试复杂度。下面按项目阶段展开判断。7.1 阶段一Demo 和原型验证特征只有一个模型 Key主要目标是验证 Prompt 效果。这个阶段直接用 AI SDK 就足够。把生成、流式、结构化输出跑通观察模型行为不引入额外服务。因为没有任何访问策略问题需要解决多做一层网关只是增加调试链路。7.2 阶段二产品上线单模型扩充场景特征同一个供应商但调用量变大开始需要提示词版本管理、缓存、场景隔离。这个阶段仍不一定需要 Gateway但架构上要开始留“模型调用收敛在一个 service 层”的余地。例如不要在每个页面直接散落generateText而是封装成内部方法。这能让后续替换供应商成本大大降低。7.3 阶段三多供应商并存出现策略诉求特征需要第二家模型供应商作为备用或者某些请求必须走私有化模型。这是引入 AI Gateway 的合理时机。你可以把网关作为所有模型请求的统一入口把 Key 注入、缓存、重试、失败转移这些原本散落在代码和运维脚本里的逻辑逐步迁移到网关配置中。7.4 阶段四多团队复用需要审计与成本分摊特征多个团队消费模型能力基础设施部门需要统一管理。在这个阶段Gateway 已经不只是技术组件更是组织边界。基础设施部门把“模型能力”包装成内部服务业务部门只需要申请网关访问权限。请求日志在这里成为成本核算和安全审计的基础数据。判断问题答案偏向“暂不上 Gateway”答案偏向“需要 Gateway”有几种模型供应商1 种2 种以上是否需要统一缓存不需要需要且容易定义缓存 Key是否有多个团队共用 Key没有有是否需要集中审计和成本拆分不需要需要是否有团队专职维护基础设施没有有8. 常见问题与排查思路问题现象可能原因排查方式解决方案调用时报 401API Key 错误、权限不足检查环境变量和实际配置是否一致重新生成最小权限 Key并确认 Provider 读取正确流式输出一次性出现代理或服务端缓冲了响应检查代理层是否关闭缓冲确认 SDK 版本调整网络代理配置或增加 flush 逻辑模型返回字段不稳定使用文本输出并手动解析 JSON改为generateObject并声明 schema使用结构化输出替代手工 JSON 解析部署到 Serverless 后超时模型调用时长超过函数限制查看函数超时日志测量首次 token 时间延长超时或在边缘使用流式响应useChat请求 404服务端路由未实现或路径不匹配确认前端请求的 URL 与后端接口一致按 SDK 约定的路径实现接口SDK 和 Provider 版本不兼容安装了不匹配的版本组合查看 SDK 版本迁移说明统一升级相关包固定版本网关缓存命中但内容错误缓存 Key 设计太粗混入用户维度观察缓存命中日志和请求参数将用户 ID、会话维度纳入缓存 Key或禁用缓存一个推荐排查顺序是先看请求有没有真正出去再看响应格式最后看 SDK 版本差异。很多 AI SDK 报错看似是代码问题实际上发生在模型服务商一侧网络链路和模型服务状态也要纳入排查范围。9. 生产环境最佳实践与安全建议9.1 密钥只在服务端出现无论你使用 AI SDK 还是 AI Gateway都不要把模型 API Key 放进前端代码或客户端环境变量。前端只需要请求你自己的后端接口再由后端或网关注入密钥。这里最直接的收益是泄露一个前端密钥不会导致底层模型账号被滥用。9.2 模型名和供应商配置要集中管理在业务代码中直接用字符串openai(gpt-4o-mini)虽然方便但会在多处出现时形成隐性依赖。建议把模型列表收敛到配置中心或环境变量例如MODEL_MAINgpt-4o-mini。这样当模型被替换时不需要全局搜索硬编码。9.3 工具调用必须做权限边界凡是允许模型调用工具的应用都要假设模型可能被诱导调用非预期工具。execute函数内部要做四件事参数校验、白名单校验、超时控制、审计日志。不能让模型返回的字符串直接拼入 Shell 或数据库查询语句。9.4 可观测性优先于缓存在关注成本前先确保每一次模型调用都能回答这些问题这个请求来自哪个业务线用户输入的 prompt 是什么版本实际请求了哪家供应商的哪个模型是否命中缓存token 消耗是多少最终完成状态是什么没有这些数据你无法回答“为什么这个月成本涨了 30%”。可以依托 AI Gateway 的请求日志也可以自己在 service 层埋点重点是形成闭环。9.5 不要让模型服务地址散落各处在部署到不同区域或网络环境时模型服务地址经常需要调整。最合适的做法是把模型访问地址统一收口到网关或配置中心由基础设施团队控制策略业务开发只需要调用统一入口。这既便于切换供应商也便于审计和成本控制。9.6 成本控制要前置在模型调用代码里必须正视这个现实生成式模型的成本与输入输出的 token 数量强相关。业务侧需要设置合理的maxTokens或等效参数避免模型无限制生成长文本。对不要求创意的结构化抽取任务调低temperature能明显提升稳定性。10. 落地建议先统一调用再统一策略回到最初的问题Vercel AI SDK 和 AI Gateway 到底怎么配合才能让开发体验和生产稳健性同时在线我的建议非常简单直接第一优先级是统一模型调用层。无论你未来的模型供应商是什么从第一天开始就通过 AI SDK 这类抽象层发起请求别让自己绑定在某一家 SDK 的内部细节上。第二优先级是在出现第二个供应商或者明确的策略需求时再引入 AI Gateway。网关不是“充门面”的架构组件它应该在缓存、失败转移、审计、密钥管理成为真实痛点时自然出现。先有痛点再上方案而不是先搭一套重架构再去寻找它的使用场景。你如果现在正在写一个还在用原始 HTTP 请求调用大模型接口的项目明天就可以做一次小的重构把生成文本改为经过 AI SDK 的generateText把对话流改为streamText把不稳定的 JSON 返回改为generateObject。你会发现模型的细节渐渐从业务代码中退场真正剩下的问题才是你的产品需要解决的核心问题。
返回列表