先别急着接官网API,也别一上来就喊微调。我见过太多团队,花两周把业务代码写好了,最后卡在“怎么把模型服务稳定地交到产线手里”这件事上。不是模型能力不行,而是调用链路太裸奔:没鉴权、没限流、没缓存、没降级,甚至把密钥直接写在前端代码里。这种架构放在 Demo 里没事,一旦日调用量上万,每一条报错都会变成事故。这篇文章我就以“搭一套企业级 AI 中台”为主线,把手上的全套实践思路、核心代码片段和压测数据摊开来讲。这套方案覆盖文本推理、图像生成和视频生成三类主力模型,适合正在从单点调用走向平台化的团队参考。
1. 先想清楚:你的团队到底要不要上 AI 中台
很多朋友一听“中台”两个字就头大,觉得是过度设计。确实,如果只是写个小工具自己用,直接在代码里调 SDK 就行,没必要折腾。但判断标准其实很简单:当你同时满足下面任意两条,就该认真考虑搭一个统一的模型接入层了。
第一条,模型不止一个。业务方今天用文本模型做客服摘要,明天用图像模型做海报素材,后天又冒出来一个视频模型的需求。每个模型都有自己的接口格式、鉴权方式、费率标准,如果每个项目组各自接入,排查问题的时候会疯掉。
第二条,调用量有明显的峰谷。早上十点是业务高峰,凌晨几乎没流量。模型服务按调用量计费,如果不对缓存和配额做统一管理,月底账单会很吓人。
第三条,安全和合规有硬要求。密钥不能下发到业务端,日志要能审计,敏感词过滤要统一处理,这些在单点调用里很难实现。
第四条,你需要对模型能力做灰度切换。同一个需求,今天用模型 A,明天想换模型 B 做对比,总不能让每个业务方自己改一遍代码吧。
我实际接触下来,只要团队超过三个人同时在做 AI 功能,统一接入层的收益就非常明显。它不光是省事,更关键的是把“模型供应商”和“业务方”解耦了。供应商换了、模型版本升级了、价格调整了,业务方完全无感。中台帮你把这层差异全部吞掉。
2. 整体设计:六层架构,把模型调用管起来
先看整体分层。我的设计思路是参考传统 API 网关的做法,但针对 AI 调用的特点做了改造。整套系统从下往上分别是接入层、路由层、策略层、模型适配层、数据层、观测层。
接入层是业务方看到的部分,统一暴露一个 RESTful 接口,比如 POST /v1/chat/completions,POST /v1/images/generations,POST /v1/videos/generations。业务方不需要关心背后接的是哪家供应商,只需要按照我们定义的协议传参。
路由层是最核心的模块。它负责三件事:模型选择、供应商分配、版本管理。模型选择说的是根据业务方指定的模型标识,比如 “text-model”,去配置中心查到当前应该映射到哪个供应商的哪个模型版本。供应商分配则是把流量按照权重或负载均衡策略分发到多家供应商,避免单点依赖。版本管理是保证业务方永远用的是稳定版本,中台升级模型不影响上游。
策略层是所有“非功能需求”的集散地。限流、熔断、重试、降级、敏感词过滤、内容审核都在这层做。这层做得越厚,业务的稳定性越高。我后面会单独展开。
模型适配层是连接外部模型服务的桥梁。它把我们的统一协议转换成各供应商的原始请求格式,再把返回结果解析成统一结构。这层说白了就是一堆适配器,每个供应商一个实现。
数据层承载三块:调用日志、审计流水、数据指标。所有请求的入参、出参(需要脱敏)、耗时、令牌消耗、费用估算都落在存储里。数据层不是辅助模块,它是整个中台持续优化和问题定位的基础。
观测层是线上运维的眼睛。Prometheus 指标采集 + 日志检索 + 告警规则,确保任何异常能在五分钟内被发现。
这几层放到一个项目中,实际代码量并没有想象中那么大。核心的网关进程大概两三千行代码就能跑起来,加上适配器和配置管理,总计不超过五千行。重要的是结构清晰,每层干每层的事。
| 层级 | 核心职责 | 关键依赖 |
|---|---|---|
| 接入层 | 统一协议、鉴权 | API 网关、Token 校验 |
| 路由层 | 模型映射、供应商分配 | 配置中心、负载均衡 |
| 策略层 | 限流、熔断、重试、审核 | Redis、Sentinel 一类组件 |
| 适配层 | 协议转换、供应商对接 | 各模型 SDK / HTTP 客户端 |
| 数据层 | 日志、审计、指标存储 | ClickHouse / Elasticsearch |
| 观测层 | 监控、告警、链路追踪 | Prometheus / Grafana |
3. 核心子系统怎么落地:每一步都别含糊
3.1 统一鉴权与密钥管理
裸奔的第一个坑就是密钥直出。我见过生产环境里把供应商密钥写在前端配置文件里的情况,那基本等于把银行卡密码贴在防盗门上。中台必须做到供应商密钥不出中台服务,业务方使用独立的 AccessKey / SecretKey 调用。
做法是给每个接入方发一对业务密钥,在中台内部做映射。业务方调用的时候带上自己的 AccessKey,中台校验通过后,再从中台自己的密钥池里取供应商密钥去调用上游。这样即使业务方账号被盗,黑客拿到的也只是中台的业务密钥,无法直接消耗上游费用。
另外,密钥要做到动态轮转。供应商密钥每隔一段时间自动更换,中台只保留当前生效的版本和上一个版本,保证切换期间不造成调用中断。这块我用了一个简单的密钥表结构,包含密钥版本号、加密后的密钥内容、生效时间、失效时间。取密钥时永远选有效时间包含当前时间的最新版本。
3.2 模型路由:别在产品代码里写死模型名
路由设计上,我强烈建议业务侧不要直接传供应商的模型 ID,而是传业务语义模型名。什么意思?业务方说“我要用文本总结模型”,中台通过配置知道“文本总结模型”对应的供应商模型是哪一个。今天映射到模型 A,明天模型 B 上线了且效果更好,中台只要改一行配置,业务方什么都不用动。
这种方式下来的收益在模型迭代周期特别短的今天非常明显。我团队在这上面吃过亏,最早直接在代码里写死了模型名,后来供应商发布新版模型,我们想切换一部分流量做对比,只能让业务方配合改代码发版,一个简单的灰度实验搞了两周。改造之后,同样的事情只需在配置中心加一条规则。
路由规则支持按权重分配和按标签分配。按权重适合灰度,比如新模型 10% 流量,老模型 90% 流量。按标签适合 A/B 测试,比如指定某个业务方只走新模型。两种策略可以叠加,先按标签圈定范围,再在范围内按权重切流。
3.3 缓存策略:文本、图像、视频要区别对待
AI 调用的缓存和普通接口缓存完全不同。普通接口缓存一个 JSON 就行,AI 调用要面对语义重复和生成成本高的问题。我的做法是设置三层缓存。
第一层是精确匹配缓存,适合结果固定、入参完全一致的场景。比如固定的 Prompt 生成固定尺寸的图片,这种没什么好说的,直接按参数做 Key 存结果。
第二层是语义缓存。针对文本调用,两段意思相同但表述不同的 Prompt,可以命中同一条结果。实现上是用向量数据库存储 Prompt 的 embedding,查询时计算余弦相似度,超过阈值就返回缓存结果。这个阈值要调得保守,0.92 以上才算命中,否则容易返回驴唇不对马嘴的答案。
第三层是流式缓存。SSE 流式返回的场景,我们不能等整个流结束再缓存,那样客户端体验就断了。正确做法是把完整的流式输出按增量片段追加到缓存存储,同时给客户端转发。下次相同请求直接读取缓存并按流式格式返回。这块实现的时候注意顺序要保持一致,否则客户端解析会出问题。
图像和视频生成,因为生成结果是大文件,缓存要落到对象存储上,数据库里只存文件 Key 和元信息。过期策略也要单独设置。图像可以保留较长时间,视频文件大、占存储,建议只保留七到十五天。
3.4 限流、熔断与降级:稳定性三件套
限流不能只做单机版 QPS 限制,要做分布式配额。同一个业务方的调用可能从多个实例进来,必须在 Redis 里做全局计数。我的方案是对每个业务方、每个模型维度设置独立的配额窗口,比如每分钟 1000 次文本调用,超出后直接返回 429 错误码,同时带上Retry-After头告知客户端什么时候能重试。
熔断是防止上游供应商故障拖垮中台的保险丝。我采用滑动窗口统计连续错误率和 P95 延迟。当错误率超过 30% 或 P95 延迟超过设定的阈值(比如 5 秒),熔断器打开,后续请求直接走降级逻辑。熔断期间要放少量探测请求试探上游恢复情况,恢复后逐渐放量,避免瞬间冲垮。
降级策略要提前设计好。文本模型降级可以返回预设模板,比如“当前服务繁忙,请稍后再试”;图像模型降级可以返回静态占位图;视频模型降级直接拒绝并提示非高峰时段再试。降级方案不追求完美,但一定要有,线上最怕的是没有预案地裸奔。
3.5 可观测性:没有监控的中台上线就是裸奔
可观测性三件套:日志、指标、链路追踪。
日志要记录每次调用的完整上下文:业务方唯一标识、模型名、入参摘要、出参摘要、耗时、令牌消耗、费用估算。入参出参必须做脱敏,姓名、手机号、身份证号这类信息在写入日志前就要替换掉。我建议日志存储选 ClickHouse,写入快,查询聚合能力强。
指标要覆盖四个黄金信号:请求量、错误率、延迟分布、饱和度。延迟分布特别要看 TP50、TP95、TP99 三个分位数,TP50 代表大多数用户的体验,TP99 代表最差的那批体验。很多供应商的模型服务在高峰期的 TP99 会飙到 TP50 的三到五倍,没有监控根本感知不到。
链路追踪用标准的 traceId 贯穿中台与业务方。业务方传入 traceId,中台透传到上游日志,这样一次调用从头到尾的路径都串得起来。排查问题的时候输入一个 traceId,就能看到业务方到中台再到供应商的完整链路。
4. 手把手实操:从零跑通一套最小可用中台
4.1 技术选型与基础环境
先说选型,我的方案偏向轻量易维护。开发语言用 Python,因为 AI 生态最成熟,适配各供应商 SDK 最方便。网关框架用 FastAPI,性能够用、代码量少、自带 OpenAPI 文档。数据存储方面,Redis 用来做限流、熔断、语义缓存的向量检索(加 RediSearch 模块),PostgreSQL 用来存配置和审计数据的结构化部分,ClickHouse 用来存日志。
如果你的团队更擅长 Java,把 Web 层换成 Spring Boot 也没问题,核心的设计思路是通用的。下面代码我会给 Python 版本,简洁直观,方便理解。
4.2 统一协议定义
先定义中台对外的统一请求结构。以文本调用为例:
{ "model": "text-model", "messages": [ {"role": "system", "content": "你是客服助手。"}, {"role": "user", "content": "我的订单什么时候发货?"} ], "stream": false, "temperature": 0.7, "max_tokens": 1024 }字段model是业务语义模型名,不是供应商的真实模型 ID。中台路由层拿到这个字段后,从配置中心查出真实映射。
4.3 网关核心代码(节选)
网关入口做四件事:鉴权、限流、路由、调用。
from fastapi import FastAPI, Header, HTTPException import httpx app = FastAPI() # 配置中心拉取的路由表,实际项目中会放在 Redis/配置中心 ROUTE_TABLE = { "text-model": {"provider": "openai-like", "model": "gpt-5-class-model", "weight": 1.0} } @app.post("/v1/chat/completions") async def chat_completions( payload: dict, x_ak: str = Header(..., alias="X-AK"), x_ts: str = Header(..., alias="X-TS"), ): # 第1步:鉴权 await validate_ak(x_ak, x_ts) # 第2步:全局限流 await check_quota(x_ak, payload["model"]) # 第3步:语义缓存命中检查 cached = await semantic_cache.get(payload["messages"]) if cached: return cached # 第4步:路由到指定供应商的适配器 route = get_route(payload["model"]) adapter = get_adapter(route["provider"]) response = await adapter.chat(payload, route["model"]) # 第5步:写审计日志 await audit_log(x_ak, payload, response) return response代码里validate_ak、check_quota、semantic_cache、get_adapter都是我抽出来的模块,实际落地时拆成独立文件,方便单测。
4.4 模型适配器写法
适配器的核心是把统一协议翻译成供应商的协议。以下是一个供应商适配器的简化示例:
class OpenAILikeAdapter: def __init__(self, base_url, api_key): self.base_url = base_url self.api_key = api_key self.client = httpx.AsyncClient(base_url=base_url) async def chat(self, payload: dict, real_model: str): # 构建供应商需要的请求体 upstream_payload = { "model": real_model, "messages": payload["messages"], "stream": payload.get("stream", False), "temperature": payload.get("temperature", 0.7), "max_tokens": payload.get("max_tokens", 1024), } headers = {"Authorization": f"Bearer {self.api_key}"} resp = await self.client.post("/chat/completions", json=upstream_payload, headers=headers) resp.raise_for_status() return resp.json()如果有三家供应商,就写三个适配器类,都实现同一个chat方法。路由层通过工厂模式获取对应适配器,业务完全不感知底层换了哪家。这个设计是整套架构的核心,一定要保证接口抽象干净。
4.5 测试环境验证流
代码写完后,我是按这个顺序验证的:
- 先跑单测,用 Mock 的供应商服务返回假数据,验证鉴权、路由、缓存逻辑。
- 再联调,连真实的供应商服务,单个请求打通端到端。
- 然后压测,确认系统在预期并发下稳定。
- 最后上灰度,接少量真实业务流量再逐步放大。
5. 压测实录:数据说明一切
我拿这套架构跑过一轮相对完整的压测,环境是两台 8C16G 的云服务器,一台跑中台,一台跑压测工具。压测工具用 Python 写的异步脚本模拟真实请求,数据是按文本模型调用场景设计的。
| 场景 | 并发数 | 总请求量 | 平均耗时(ms) | TP95(ms) | 错误率 | 吞吐(req/s) |
|---|---|---|---|---|---|---|
| 文本-无缓存 | 50 | 5000 | 1840 | 3120 | 0.0% | 27 |
| 文本-精确缓存 | 50 | 5000 | 6 | 9 | 0.0% | 820 |
| 文本-语义缓存 | 50 | 5000 | 38 | 74 | 0.0% | 130 |
| 带限流保护 | 200 | 5000 | 2560 | 4100 | 0.0% | 26 |
| 触发熔断 | 200 | 2000 | — | — | 19.5% | 回到降级逻辑 |
结论很直接。第一,没有缓存的裸调用,吞吐被模型供应商的响应速度锁死,中台本身开销占比很小。第二,加上缓存之后,吞吐提升了三十倍以上,但这是建立在缓存命中率高的场景下。实测精确缓存命中率 60% 的常规客服问答场景,整体成本能下降差不多四成。第三,限流器在 200 并发下能把超配额的请求全部拦住,没有出现击穿的情况。
压测过程中也暴露出一个问题:默认的重试策略太激进,上游供应商一旦返回限流错误,请求如果立即重试会造成雪崩。我把重试策略改成了指数退避加抖动,初始等待 200ms,每次翻倍,加上 0.2 到 0.5 的随机抖动,实测错误率明显下降。
有朋友问我压测数据会不会有水分,我承认这个结果受网络环境影响很大,不同供应商、不同机型差距能到百分之几十。但趋势是有参考价值的:缓存是运维成本的大头,限流熔断是稳定性的压舱石。压测的目的不是要一个好看的数字,而是要在上线前找到承载上限和设计盲区。
6. 生产环境避坑清单:每个坑我都踩过
第一坑:把全部重试压力集中到第一层。业务方收到 429,就会自己疯狂重试,如果中台也重试,供应商会被双重打爆。正确做法是业务方的重试要退避,中台内部重试要限次数且不对客户端隐藏。
第二坑:语义缓存的 embedding 生成也会消耗费用和时间。如果每次请求都先调 embedding 接口再做向量检索,那成本可能比省下的还多。我的做法是先用一个轻量参数签名做第一层过滤,只有参数完全相同且是常见问题的那批请求才走语义缓存。
第三坑:视频生成是异步任务,不能用同步请求的思路去做。视频模型通常返回一个任务 ID,需要轮询或回调获取结果。中台要设计成异步任务编排,把创建任务、查询状态、获取结果三个阶段拆开。这块如果同步实现,超时会让你怀疑人生。
第四坑:日志脱敏没做到位。我在测试环境收到过带身份证号的输入,如果不脱敏直接入库,合规这一关就会出问题。脱敏规则要前置,进入日志层之前就要替换掉敏感字段。
第五坑:密钥轮转必须留缓冲。密钥过期时间不要设成当前时刻,要保留五分钟的重叠窗口,避免因为时钟偏移导致大量鉴权失败。我在上线时用过一次瞬时切换,结果压测请求中大约百分之一出现了 401,排查半天才发现是轮转问题。
第六坑:别忽略冷启动。部署新版本中台时,缓存是空的,全部请求会同时打到上游供应商,造成短时间的高负载。我的做法是部署前先把热点数据预热,或者灰度放量,让缓存逐步建起来。
7. 常用问题速查与排查思路
问题:某个业务方调用突然全部 429。 排查方向:先在观测层看这个 AK 的配额使用曲线,再查 Redis 里配额计数是否异常,最后看是不是有人误配了限流规则。
问题:同一条 Prompt,有时候返回快有时候返回慢。 排查方向:看是否命中了缓存。命中缓存毫秒级返回,未命中的情况要等上游模型生成,两者差距几十倍是正常的。建议在返回头里加一个X-Cache: HIT/MISS标记,方便排查。
问题:上游供应商服务不稳定,明明重试了还是大量失败。 排查方向:查看熔断器状态。如果熔断器已打开,重试是在中台内部处理的,客户端会直接拿到降级结果。需要调整熔断阈值和探测频率,而不是继续加大重试次数。
问题:某个模型的调用费用异常飙升。 排查方向:看指标里的费用维度。重点查是否存在缓存命中率下降、是否有大量高 token 请求、是否有异常用户在做批量调用。费用指标一定要在观测层建立每日汇总面板,否则月底账单出来才反应过来就晚了。
问题:压测时或高峰期内存占用持续上涨。 排查方向:优先看流式响应是否正确释放了连接。SSE 流式请求如果没有在客户端断开时取消上游请求,会造成连接泄漏。我给所有流式请求加了一个超时中间件,超过设定时间强制断开。
8. 最后聊点实操体会
整个中台做下来,我最深的感受是:架构设计里最难的从来不是技术,而是取舍。缓存命中率和最终一致性怎么平衡,限流的严格程度和业务容忍度怎么匹配,熔断触发的阈值怎么设定才不误伤,这些没有一个标准答案,必须根据自己团队的实际情况反复调。
我个人建议,第一次搞中台不要追求大而全,把统一鉴权、模型路由、日志审计、基础限流这四样先做扎实,剩下的一步步迭代。一套能跑的简单架构,永远比一堆停留在文档里的复杂设计有用。等业务量真正上来、痛点真正暴露了,再针对性加语义缓存和熔断降级,每个组件加得有理有据,运维压力也可控。这套思路落地之后,我团队后续接入新模型的时间从按天算降到了按小时算,这大概是中台模式最值钱的部分。