AI API 接入实践:从直接调用到统一网关管理的一次整理
最近在整理几个 AI 项目的接口调用方式发现一个问题很多项目刚开始接入 AI 能力时都很简单只要拿到一个 API Key写一个请求就能跑起来。但当项目逐渐变多、调用量变大、团队成员开始一起使用时问题就会变得明显。比如API Key 分散在多个项目里不同脚本、不同环境使用不同账号很难统计每个项目到底消耗了多少额度模型切换时需要到处改配置某个 Key 出问题后不容易定位是哪一个项目在用团队多人共用时权限和用量都不好管理。所以这段时间我把 AI 调用这一层重新整理了一下尝试用“统一 API 网关”的方式来管理模型调用、Key、额度和用量。这里记录一下这个过程以及实际使用中遇到的一些场景。一、最开始的调用方式很多 AI 项目的初始接入方式都差不多。比如在后端项目里直接写一个模型调用const response await fetch(https://api.example.com/v1/chat/completions, { method: POST, headers: { Authorization: Bearer ${process.env.AI_API_KEY}, Content-Type: application/json }, body: JSON.stringify({ model: some-model, messages: [ { role: user, content: 帮我总结这段内容 } ] }) });这种写法在 Demo 阶段没有问题。一个项目、一个 Key、一个模型逻辑很清楚。但问题是真实项目往往不是这样长期保持简单。随着业务增加可能会变成project-a 使用一个 Key project-b 使用另一个 Key admin-tool 使用一个 Key batch-script 使用一个 Key 测试环境还有一组 Key 生产环境又有一组 Key一开始只是几个配置项后面慢慢就会变成一堆不太好维护的环境变量。二、直接调用模式的问题我遇到比较明显的问题主要有几个。1. Key 分散排查困难如果每个项目都直接保存上游模型 Key那么后期维护会比较麻烦。比如某天发现额度消耗异常但你不一定能立刻知道是哪一个项目在大量调用。常见情况可能是web-api 服务在调用 cron 定时任务在调用 本地测试脚本也在调用 某个旧项目还没有下线 团队成员本地还有历史 Key这时候只能一个个查日志或者去不同服务里翻配置。如果项目比较多排查成本会很高。2. 团队共享时不好分账个人开发时一个 Key 自己用还好。但团队使用时经常会遇到A 项目调用量比较大 B 项目只是偶尔调用 C 成员在本地频繁测试 D 成员只是用来跑自动化脚本如果大家共用一个 Key最后只能看到总消耗无法判断具体是谁、哪个项目、哪个场景用了多少。这对成本统计和额度管理都不友好。3. 模型切换成本高AI 项目里模型切换是很常见的。比如总结任务用一个模型代码生成用另一个模型长文本分析用更适合长上下文的模型低成本任务切到便宜模型重要任务使用质量更高的模型。如果业务代码里到处写死了模型服务地址和模型名称后面切换时就比较麻烦。比如原来代码里是model: model-a后来想切到model: model-b如果只有一个地方还好如果多个服务、多个任务、多个脚本里都写了就很容易漏改。三、为什么考虑加一层 API 网关我现在更倾向于把 AI 调用拆成三层业务应用层 - API 网关层 - 上游模型服务业务应用层只关心我要调用 AI 我要传入 prompt 我要拿到结果API 网关层负责Key 管理 用量统计 模型分发 额度控制 调用日志 异常排查 权限隔离上游模型服务则专注提供具体的模型能力。这样做的好处是业务代码不用直接关心太多底层细节。四、改造前后的配置对比改造前每个项目可能都有自己的上游配置。例如OPENAI_API_KEYsk-xxxx OPENAI_BASE_URLhttps://api.xxx.com/v1 CLAUDE_API_KEYsk-yyyy CLAUDE_BASE_URLhttps://api.yyy.com/v1 GEMINI_API_KEYsk-zzzz GEMINI_BASE_URLhttps://api.zzz.com/v1项目一多环境变量会越来越乱。改成统一网关之后可以把业务侧配置简化成类似这样AI_GATEWAY_BASE_URLhttps://gateway.local/v1 AI_GATEWAY_API_KEYproject_a_key AI_DEFAULT_MODELdefault-chat-model业务项目只需要知道统一入口和自己的项目 Key。至于后面到底路由到哪个模型、哪个账号、哪个上游服务可以放到网关层管理。五、一个实际场景多个项目共用 AI 能力假设团队里有三个项目项目 A知识库问答 项目 BAI 写作助手 项目 C后台自动摘要脚本如果直接共用一个上游 Key最后只能看到总调用量。更合理的方式是给每个项目分配独立 Keykb_qa_key - 知识库问答 writer_key - AI 写作助手 summary_key - 自动摘要脚本这样后面统计时就可以看到知识库问答今日 12000 次请求 写作助手今日 5300 次请求 摘要脚本今日 800 次请求如果某个项目调用异常也能很快定位。例如某天摘要脚本因为定时任务配置错误循环调用了几千次。如果所有项目共用一个 Key只能看到总量异常如果每个项目独立 Key就可以直接定位到summary_key。六、一个实际场景本地开发和生产环境隔离很多项目会分本地环境、测试环境、生产环境。如果这些环境都共用同一个 Key风险比较高。比较推荐的方式是project_dev_key - 本地开发 project_test_key - 测试环境 project_prod_key - 生产环境这样做有几个好处本地调试不会影响生产统计测试环境可以单独限制额度某个环境出问题时可以单独禁用日志排查时能更快区分来源。比如测试环境误触发了批量任务导致请求量暴增。如果 Key 是独立的可以直接暂停测试环境 Key而不会影响生产服务。七、一个实际场景低成本任务和高质量任务拆分在实际业务里不是所有任务都需要使用同一个模型。例如文章标题生成低成本模型即可 长文总结需要上下文能力更强的模型 代码分析需要代码能力更好的模型 客服问答需要响应速度更快 合同分析需要更稳定、更准确如果都写在业务代码里后期会比较乱。可以在网关层设计不同的调用策略fast-chat - 快速问答 long-summary - 长文总结 code-helper - 代码分析 cheap-task - 低成本批量任务业务侧只需要传入任务类型或模型别名。例如body: JSON.stringify({ model: long-summary, messages: [ { role: user, content: 请总结下面这篇长文... } ] })这样业务代码不用关心long-summary背后具体对应哪个模型。后续如果想调整模型只需要改网关层配置即可。八、一个实际场景批量脚本需要限制额度很多开发者会写 AI 批量脚本比如批量翻译批量摘要批量生成标题批量处理评论批量分析数据。这类脚本有一个特点一旦循环写错消耗会非常快。例如for (const item of list) { await callAI(item.content); }如果list从 100 条变成 10000 条而脚本没有限制就可能直接把额度打满。所以对批量任务我通常会单独创建 Key并设置更保守的使用策略。例如batch_translate_key batch_summary_key batch_title_key这样做的好处是批量任务即使出现异常也不会影响线上主业务。九、一个实际场景旧项目下线后的 Key 清理很多项目开发到后期会出现一些历史服务old-demo test-bot temp-script old-admin-tool这些服务可能已经不用了但里面的 Key 还在。如果没有统一管理很难知道哪些 Key 还在被使用。使用统一网关后可以通过调用记录判断old-demo-key 最近 30 天无调用 temp-script-key 最近 60 天无调用 test-bot-key 昨天仍有少量调用这样清理旧 Key 时会更放心。比如30 天无调用 - 标记观察 60 天无调用 - 准备停用 90 天无调用 - 删除或归档这个流程对安全和成本管理都有帮助。十、业务代码如何保持简单从业务代码角度我希望最终调用方式尽量稳定。例如封装一个统一方法async function callAI({ model, messages }) { const response await fetch(${process.env.AI_GATEWAY_BASE_URL}/chat/completions, { method: POST, headers: { Authorization: Bearer ${process.env.AI_GATEWAY_API_KEY}, Content-Type: application/json }, body: JSON.stringify({ model, messages }) }); if (!response.ok) { throw new Error(AI request failed: ${response.status}); } return response.json(); }业务里调用时只需要const result await callAI({ model: fast-chat, messages: [ { role: user, content: 帮我生成 5 个文章标题 } ] });这样后续即使底层模型服务调整业务代码也不用大面积改动。十一、日志记录也很重要除了 Key 和模型日志也很关键。我一般会关注这些字段request_id api_key_name project_name model status_code prompt_tokens completion_tokens total_tokens latency_ms created_at这些字段能帮助排查很多问题。比如响应慢可以看latency_ms判断是所有请求都慢还是某个模型慢。成本异常可以看total_tokens判断是不是某个任务输入太长。某个项目异常可以按api_key_name或project_name聚合。某个模型错误率高可以按model和status_code统计。这些数据一旦统一记录后期排查会省很多时间。十二、接口异常时如何处理AI 接口调用不可能永远稳定业务上至少要考虑几种情况上游超时 请求限流 额度不足 模型不可用 返回格式异常 网络波动业务侧可以做一些基础处理async function safeCallAI(payload) { try { return await callAI(payload); } catch (error) { console.error(AI call failed:, error.message); return { error: true, message: AI 服务暂时不可用请稍后重试 }; } }但更完整的异常管理适合放在网关层做。例如超时重试 失败记录 错误率统计 异常 Key 暂停 异常模型切换 请求限流这样业务应用可以更专注于自己的逻辑。十三、我总结出来的 Key 命名方式实际管理时Key 命名也很重要。不建议随便叫key1 test demo newkey时间久了会完全不知道用途。比较推荐使用带业务含义的命名prod_kb_qa prod_writer_api test_admin_tool dev_local_script batch_translate_job batch_summary_job如果团队成员较多也可以带上负责人或项目名prod_writer_team_a dev_script_user_zhang test_chatbot_project_b这样排查问题时会更直观。十四、什么时候没必要上网关也不是所有场景都需要统一网关。如果只是个人临时 Demo 一次性测试脚本 调用量非常低 没有团队协作 不需要统计用量 不需要多模型切换那直接调用模型接口也可以。但如果项目开始长期运行或者有多人协作就可以考虑把调用管理单独抽出来。判断标准很简单你是否需要知道谁用了多少 你是否需要随时停用某个 Key 你是否有多个项目共用 AI 能力 你是否经常切换模型 你是否担心某个脚本异常消耗额度 你是否需要长期稳定运行如果这些问题里有多个答案是“是”就说明统一管理会有价值。十五、实践后的感受这次整理下来我最大的感受是AI 接口接入本身并不难难的是长期维护。第一次把接口调通只是第一步。真正上线之后要面对的是 Key 管理、权限隔离、额度统计、异常排查、模型切换和成本控制。以前我会把这些事情分散在不同项目里处理。现在更倾向于把它们集中到 API 网关层。这样做之后业务项目会更轻后期排查问题也更清楚。尤其是团队一起使用 AI 能力时统一入口和独立 Key 的价值会比较明显。十六、总结简单总结一下这次实践Demo 阶段直接调用模型接口即可 项目变多需要统一 Key 和配置 团队协作需要独立 Key 和用量统计 长期运行需要日志、限流和异常处理 多模型场景需要统一入口降低切换成本对于 AI 项目来说API 网关不是必须一开始就上但当项目开始长期运行、多人使用、多模型接入时它会明显降低维护成本。这次我主要体验的是斑马 API https://bmapi.020212.xyz/register?affYU55ECFS8AF2这类统一入口工具整体更适合 AI 产品、自动化脚本、团队共享接口和多模型管理场景。最近正好有新用户体验活动注册后可以获得一个月会员邀请新用户也有额外体验时长。