【大模型基础设施工程】22:大模型网关

一、为什么需要 LLM Gateway

上一篇 21:推理服务化 讲了单一模型从 vLLM/SGLang 到 K8s 的上线路径。但真实企业里,一个业务很少只用一个模型、一个供应商:

  • 研发一次调试用 GPT‑4o,线上跑 DeepSeek‑V3,降级兜底走 Qwen;
  • 文档问答走自建 vLLM 集群,复杂推理走 Anthropic,审核走 Llama Guard;
  • 财务审计要每一次调用都能追溯到"哪个业务线 / 哪个账号 / 花了多少 token / 花了多少钱";
  • 安全合规要求 PII(Personally Identifiable Information,个人身份信息)脱敏、数据不出域、越狱检测。

如果让每个业务自己去调 OpenAI SDK、再各自埋点、各自配置降级与重试,就会出现:

  • SDK 泛滥:同一套鉴权逻辑在十几个服务里各写一遍;
  • 成本黑洞:没人能说清上个月 1000 万元 token 账单里哪个业务花了多少;
  • 安全盲区:开发者把 API Key 直接打进前端、日志里混着用户手机号;
  • 升级地狱 :要把默认模型从 gpt-4o 换成 gpt-4.1,需要改 30 个仓库。

LLM Gateway(AI Gateway)就是解决这些问题的中间层:所有业务以统一协议(通常是 OpenAI Chat Completions 兼容协议)把请求发给网关,网关负责鉴权、路由、配额、缓存、计费、审计、Guardrails,再把请求转发到真实的模型后端。

它与传统 API Gateway(Kong、APISIX、Envoy)的差异在于:

维度 传统 API Gateway LLM Gateway
协议 REST / gRPC 转发 以 OpenAI 协议为事实标准,做协议归一化
计量 请求数、字节数 Token(prompt / completion)、金额
缓存 Key 精确匹配 语义缓存(embedding 近似)
路由 路径 / Header 模型名、成本、质量、延迟、配额
鉴权 API Key / JWT 加上"虚拟 key → 真实供应商 key"的映射与预算
安全 WAF、限流 Guardrails、PII 脱敏、越狱检测、内容分类
失败处理 5xx 重试 模型级联 fallback、降级到更便宜模型
可观测 QPS / 延迟 增加 token、成本、first‑token 延迟、生成长度分布

本文从"为什么"讲到开源与商业选型,再到核心能力(路由、缓存、Guardrails、计费、可观测),最后给出 LiteLLM 的一套可运行示例与国内企业的落地实践。

二、开源 LLM Gateway 全景

2.1 LiteLLM Proxy

LiteLLM 是目前社区使用最广的开源 LLM Gateway,核心特性:

  • 100+ 模型统一成 OpenAI 协议(OpenAI、Anthropic、Gemini、Bedrock、Azure、Vertex、Mistral、Cohere、DeepSeek、Qwen、Zhipu、Moonshot、Ollama、vLLM、SageMaker......);
  • Python SDK(litellm.completion(...))与独立 Proxy Server(FastAPI)两种形态;
  • 内置 virtual key(虚拟 key)、预算、速率限制、团队/用户模型;
  • 支持 Redis 缓存、语义缓存、Prometheus、Langfuse/Helicone 集成;
  • 路由策略:least‑busy、latency‑based、cost‑based、usage‑based;
  • Fallback 链:主模型失败自动切备模型;
  • Prompt 管理(prompt caching、template);
  • Guardrails 集成(Lakera、Aporia、Presidio、Llama Guard)。

适合中小团队"一条命令起一个企业级网关"。

2.2 OneAPI / NewAPI

OneAPI 与其分叉 NewAPI、FastAPI、VoAPI 是国内社区最流行的 LLM 网关:

  • Go 写成,单二进制,MySQL/SQLite/PostgreSQL 都能跑;
  • 管理端 UI 完善,渠道(channel)管理、用户/令牌/额度/日志一应俱全;
  • 天然支持国产模型:通义、文心、讯飞、智谱、Kimi、豆包、DeepSeek、百川、MiniMax......;
  • 统一对外提供 OpenAI 协议;
  • 在国内做"多供应商 + 计费 + 团队额度"几乎是第一选择;
  • 缺点:路由/Guardrails/语义缓存能力弱,偏"中转 + 计费"。

NewAPI 在 OneAPI 基础上补了很多企业功能:Midjourney、Suno、Rerank、TTS、语音等多模态;以及更灵活的计费模型(按次、按 token、按倍率)。

2.3 Portkey

Portkey 同时提供 SaaS 与开源 Gateway:

  • 轻量 Gateway(Cloudflare Workers / Node 都能跑),路由用 JSON config 描述;
  • 主打 production reliability:fallback、retry、load balance、conditional routing、canary;
  • "Configs as code",便于多环境复用;
  • SaaS 端提供观测、prompt 管理、评估。

适合需要"把路由策略声明式管理"的团队。

2.4 Kong AI Gateway

Kong 在 3.6 之后推出 AI Gateway 一套插件:ai-proxyai-request-transformerai-response-transformerai-prompt-templateai-prompt-guardai-prompt-decoratorai-rate-limiting-advancedai-semantic-cache

  • 把 LLM 能力直接放进已有 Kong 数据平面,与现有 API 治理(OAuth、mTLS、WAF)无缝打通;
  • 适合已经大规模使用 Kong 的企业,不用再引入一套新中间件;
  • 商业版里 ai‑semantic‑cache、ai‑semantic‑prompt‑guard 等更完整。

2.5 Envoy AI Gateway

Envoy AI Gateway 是 CNCF 方向,由 Tetrate 等主导:

  • 基于 Envoy 的 xDS 动态配置能力与 Gateway API 资源模型;
  • 把"LLM 路由"建模成 Kubernetes CRD(AIServiceBackendAIGatewayRouteBackendSecurityPolicy);
  • Token rate‑limit、fallback、model 路由都用 CRD 声明;
  • 适合已经 all‑in K8s + service mesh 的大型组织。

2.6 APISIX AI Plugin

Apache APISIX 同样在插件层增加 ai-proxyai-prompt-guardai-prompt-templateai-ragai-rate-limiting 等,路线与 Kong 类似:已有 APISIX 就原地升级,不再引入新组件。

2.7 Helicone Gateway

Helicone 起步于"LLM observability proxy",只要把 base URL 指向它就能抓日志;后来演化为 Helicone AI Gateway,支持缓存、fallback、rate limit,并延续其强项------开箱即用的观测大盘与 per‑user cost。

2.8 LLMRouter / RouteLLM

这类偏"路由器"而非完整网关:

  • RouteLLM(LMSYS):训练一个便宜的分类器,把 query 路由到强模型或弱模型,以显著降低成本而只损失很少质量;
  • FrugalGPT:级联策略,先用便宜模型,打分不过关再升级到强模型;
  • Not DiamondMartian:商业质量路由器。

它们常常作为一个 Provider 接在 LiteLLM / Portkey 等完整网关的后端。

2.9 开源网关一图速览

2.10 其他值得留意的项目

  • OpenRouter:SaaS 形态的"LLM 路由器 + 聚合支付",本质上也是一个托管 Gateway,开发者友好度极高;
  • TrueFoundry AI Gateway / Bricks:聚焦鉴权与审计;
  • LLMProxy(早期 LiteLLM 定位)、RouterChat:轻量代理;
  • Higress + AI 插件:阿里开源的云原生网关,在国内生态里提供 AI Proxy、Token 限流、内容安全等能力,天然对接阿里通义与百炼。

选型时要注意"Gateway vs. Router vs. Observability proxy"三类定位不同:

类别 代表 核心卖点
完整网关 LiteLLM / OneAPI / Portkey / Kong AI / Envoy AI / APISIX AI / Higress 鉴权、路由、配额、缓存、Guardrails、观测 全套
纯路由器 RouteLLM / Not Diamond / Martian 做"用哪家模型"的决策
观测代理 Helicone / Langfuse proxy / OpenLLMetry 抓 trace、算成本、做评估

实际落地里,常见组合是"完整网关 + 观测代理 + 路由器接后端"。

三、商业网关与云厂商

3.1 全球云

  • Cloudflare AI Gateway:在 Cloudflare 边缘节点提供缓存、rate limit、观测、fallback、Guardrails,配置一条 URL 前缀即可接入任意 OpenAI 兼容接口,边缘缓存尤其省钱;
  • AWS Bedrock:自身就是"AI 网关 + 托管模型集合",通过 IAM 与 VPC 做鉴权与隔离,配合 Bedrock Guardrails 做内容安全、PII、拒答主题;
  • Azure OpenAI:在 Azure API Management(APIM)之上提供 LLM policy(token 限流、semantic cache、prompt shield),可以把自建 OpenAI endpoint 做成企业网关;
  • Google Vertex AI:通过 API Gateway + Model Garden + Model Armor 做多模型与安全层。

3.2 国内云

  • 阿里百炼(DashScope):提供模型调用 + 应用编排 + API Gateway;可直接作为企业统一入口,也能和阿里云 API Gateway/Higress 结合做二次网关化;
  • 火山方舟(Doubao):强调"应用+模型+数据"一体,提供鉴权、配额、审计,并与火山 API Gateway 打通;
  • 百度千帆:类似路线,平台侧已带模型网关能力,支持多租户、多模型路由、审计;
  • 腾讯混元 / 华为盘古:各自平台均有 API Gateway 层。

大部分国内企业的真实选择是:平台 API + OneAPI 私有化,把多家云合在一张内部 OpenAI 协议入口之后,再加一层内部治理(成本、审批、数据分级)。

四、核心能力(一):协议兼容与路由

4.1 OpenAI Chat Completions 成事实标准

网关的第一个工作是协议归一化 。今天几乎所有模型厂商(包括 Anthropic、Gemini、DeepSeek、Qwen、Kimi、GLM、豆包、MiniMax、Mistral、Cohere)都会提供 "OpenAI 兼容" 端点,或由网关在内部把 Anthropic messages、Gemini generateContent 等翻译成 OpenAI chat.completions 格式。

典型的几个字段差异需要网关补齐:

  • system 消息:Anthropic 是独立字段 system,OpenAI 放在 messages[0]
  • 工具调用:Anthropic 用 tool_use / tool_result,OpenAI 用 tool_calls / tool role;
  • 多模态:Gemini 的 parts.inline_data.mime_type
  • Stream 事件:SSE 的 delta.content / delta.tool_calls.arguments 增量结构。

网关通常有一个"请求转换器(request transformer)+ 响应转换器(response transformer)"对,向上游屏蔽差异。

4.2 路由策略

常见策略:

  1. 按模型名直达model=gpt-4o → OpenAI;model=deepseek-v3 → DeepSeek。最简单但不够智能;
  2. 按业务别名 :对外暴露 model=chat-defaultmodel=chat-cheapmodel=chat-reasoning;别名背后的真实模型由网关配置,可以随时替换;
  3. 成本路由:对同类请求优先选最便宜的可用模型;
  4. 延迟路由:实时统计各后端 P95,优先选低延迟;
  5. 质量路由:用 RouteLLM / 分类器选强弱模型;
  6. 配额路由:供应商 A 还有额度就走 A,否则走 B;
  7. 粘性路由:相同 conversation_id 粘在同一后端,便于 prefix cache 命中;
  8. 灰度路由:10% 流量到新模型做 shadow。

LiteLLM / Portkey 等网关大多提供"路由器(router)"抽象,以 weight、tag、cooldown 来组合上述策略。

4.3 Fallback / 熔断 / 重试

真实环境里最有价值的能力:

  • Fallback 链[gpt-4o → gpt-4.1-mini → deepseek-v3 → qwen-max],前者 5xx 或超时就顺次尝试;
  • 熔断(circuit breaker):某后端连续错 N 次进入 cooldown,避免雪崩;
  • 重试:对 429 / 5xx / 超时做指数退避重试;注意要区分"可重试错误"(网络、超时)与"不可重试"(内容策略拒绝);
  • 流式请求的 fallback 很难:一旦开始返回 token 就无法切换,通常只对"首 token 失败"做 fallback;
  • Budget 触发降级 :当本月成本达到阈值,自动从 gpt-4o 降级到 gpt-4o-mini
yaml 复制代码
# LiteLLM router 示例
model_list:
  - model_name: chat-default
    litellm_params:
      model: openai/gpt-4o
      api_key: os.environ/OPENAI_KEY
      rpm: 1000
  - model_name: chat-default
    litellm_params:
      model: deepseek/deepseek-chat
      api_key: os.environ/DEEPSEEK_KEY
      rpm: 2000

router_settings:
  routing_strategy: simple-shuffle
  fallbacks:
    - chat-default: [chat-cheap, chat-local]
  allowed_fails: 3
  cooldown_time: 30
  num_retries: 2
  retry_after: 5

五、核心能力(二):缓存与成本

5.0 缓存分层视图

LLM 请求的缓存不是单一层,而是五层缓存协同工作:

层次 命中粒度 省的是什么 典型实现
L1 精确缓存 请求级(整段 messages 哈希) 一次 LLM 调用 Redis String/Hash
L2 语义缓存 请求级(embedding 近似) 一次 LLM 调用 GPTCache / LiteLLM sem cache
L3 Prefix/Prompt cache 前缀 KV 上游 prompt token 计费 OpenAI/Anthropic/DeepSeek 平台
L4 KV Cache 引擎内 重计算 prefill vLLM / SGLang
L5 结果片段缓存 工具调用 / RAG 中间结果 工具调用与向量检索 业务自建

网关主要负责 L1 / L2,并通过 prompt 结构稳定化让 L3 更易命中;L4 是引擎的事,参考 12:PagedAttention 与 Continuous Batching

5.1 精确缓存

最简单的做法:以 hash(model + messages + temperature + top_p + tools) 作 Redis key。对"同样问题被问很多次"的场景(FAQ、SQL 生成、固定 prompt 抽取)能立刻省 30--80% 成本。

注意点:

  • temperature>0 的请求要谨慎(结果不稳定,缓存会损失多样性);
  • 要把 tool schema、system prompt 一起纳入 key;
  • 结果要存 usage、finish reason,便于后续审计。

5.2 语义缓存(Semantic Cache)

思路:对请求的 messages 做 embedding,在向量库里找相似度 > 阈值的历史结果直接返回。

  • 代表项目:GPTCache、LiteLLM Semantic Cache、Kong ai-semantic-cache
  • 核心组件:embedding 模型(bge‑small / text‑embedding‑3‑small)+ 向量库(Redis Vector、Milvus、pgvector)+ 相似度阈值(通常 0.95 以上才算命中);
  • 风险:语义相近但"差之毫厘谬以千里"的问题(如 "A 能不能买 B" vs "B 能不能买 A"),要结合规则(关键实体必须相同)。

5.3 Prompt 缓存(上游侧)

OpenAI、Anthropic、DeepSeek、Gemini 已普遍支持 Prompt Caching:对长 system prompt / 工具定义做上游缓存,后续请求几乎免费。网关要做的:

  • 保证长 prompt 前缀稳定(把可变内容放后面);
  • 在响应 usage 里读出 cached_tokens,纳入计费折扣;
  • 对上游 prompt cache miss / hit 做监控。

5.4 模型级联(Cascade / FrugalGPT)

python 复制代码
def cascade(query):
    # 1) 便宜模型先答
    ans_small = call("qwen-turbo", query)
    # 2) 置信度评估(可以是自我打分,也可以是规则/分类器)
    if score(ans_small, query) >= THRESHOLD:
        return ans_small
    # 3) 升级到强模型
    return call("gpt-4o", query)

关键是打分:FrugalGPT 论文用一个 regression scorer;实战中可以退而用:

  • logprobs 平均值;
  • 让小模型自己给 confidence: 0-1
  • 用一个很便宜的 judge 模型打分;
  • 针对结构化输出(JSON)用 schema 校验 + 正则判定。

5.5 Prompt 压缩

LLMLingua / LongLLMLingua 用一个小模型删除 prompt 中信息熵低的 token,可在几乎不掉质量的前提下把长上下文压到 1/4--1/10。网关把它作为"前置插件"接上去,对长上下文任务尤其划算。

5.6 组合策略

一张实战里常见的成本降维图:

erlang 复制代码
原始成本
   ↓ Prompt Caching(上游)
   ↓ Prompt 压缩(LLMLingua)
   ↓ 语义缓存(GPTCache / 网关内置)
   ↓ 模型级联(FrugalGPT)
   ↓ 质量路由(RouteLLM)
最终成本(常见压到 20--40%)

六、核心能力(三):Guardrails 与安全

6.1 为什么要在网关做 Guardrails

业务应用层做 Guardrails 很常见,但放在网关有几个好处:

  • 集中更新:新出一个越狱方式,改一处即可;
  • 旁路不可绕过:开发者不能"忘了接";
  • 统一审计:所有拦截事件都在一个地方;
  • 便于合规:一次过审满足所有业务。

6.2 开源 / 商业 Guardrails

6.3 典型 Guardrails 流水线

sql 复制代码
用户输入
 → Presidio(PII 检测 + 脱敏)
 → Prompt Guard(越狱 / 注入检测)
 → 关键词 / 敏感词
 → Llama Guard(有害内容 IN)
 → 业务 Prompt
 → 模型
 → Llama Guard(有害内容 OUT)
 → Guardrails(结构 / 事实 / 词表约束)
 → 响应

6.4 越狱检测

常见越狱模式:

  • "忽略之前所有指令";
  • 角色扮演(DAN、祖母漏洞);
  • Base64 / Unicode homoglyph 编码绕过;
  • Payload 拆分跨轮;
  • 多模态攻击(图中藏 prompt)。

防守组合:Prompt Guard(小模型)+ 关键词 + 语义相似度 + 历史模式库;对高风险工具调用再加一层人类 / 二次模型复核。

6.5 数据不出域与脱敏

  • 域内部署:网关和模型都在 VPC 内;若必须调外部云,走专线 + 加密;
  • 请求脱敏:手机号、身份证号、邮箱、银行卡、公司内部词表替换成占位符,存映射;响应回来再还原;
  • 日志脱敏:网关存日志前再脱一次敏;
  • 分级策略:不同数据密级走不同后端(公开数据可走公有云,内部数据必须走自建)。

6.6 Guardrails 的放置位置

按"早发现越便宜"的原则,Guardrails 尽量前置。但某些检测依赖模型输出,只能放后置。一个常见编排:

python 复制代码
# 伪代码:Gateway Guardrails 流水线
async def handle(req):
    # 1) PII 脱敏(前置,修改 request)
    req, pii_map = presidio_redact(req)

    # 2) 注入 / 越狱(前置,可并行)
    checks = await asyncio.gather(
        prompt_guard_detect(req),
        keyword_filter(req),
        policy_check(req.user),
    )
    if any(c.blocked for c in checks):
        return refusal_response(checks)

    # 3) 输入内容安全(前置,小模型分类)
    if await llama_guard_input(req):
        return refusal_response("unsafe_input")

    # 4) 真实模型调用(此处可启用缓存 / 路由 / fallback)
    resp = await router.call(req)

    # 5) 输出内容安全(后置)
    if await llama_guard_output(resp):
        return refusal_response("unsafe_output")

    # 6) 结构校验(对 JSON/Schema 要求)
    resp = schema_validate_or_repair(resp, req.response_format)

    # 7) 还原 PII(如业务允许)或保持脱敏
    resp = maybe_restore(resp, pii_map)
    return resp

选择 pre/post/stream 三种模式要点:

  • 流式响应下,输出 Guardrails 要逐块扫描,发现不合规立即切断流,而不是等全部生成完;
  • 注入检测放前置即可,但要注意 RAG 场景里"间接注入"------恶意 prompt 藏在检索命中的文档里,需要对拼装后的最终 prompt 再扫一次;
  • 对高代价的 Guardrails(例如大模型 judge),建议采样而不是全量。

七、核心能力(四):计费、配额与多租户

7.1 Token 计量

每次请求结束,网关必须能拿到三类数字:

  • prompt_tokens / completion_tokens / cached_tokens
  • 对应单价(美元 / 人民币 / per 1K tokens);
  • 汇率与账单周期。

难点:

  • 不同供应商返回的 usage 字段并不一致,要统一;
  • 流式响应必须在 stream: true + stream_options.include_usage 下才能拿到;
  • 图像、音频 token 要按 modality 分开计费(OpenAI 已经 vision tokens 分开);
  • Prompt cache hit 的 token 要折扣计入。

7.2 多租户配额

经典分层:

  • 组织(org):整个公司的月度预算;
  • 团队(team):研发、运营、客服;
  • 应用(app / virtual key):单个业务接入;
  • 用户(end user):个人日/时限额。

每一层都应当能配置:

  • RPM(requests per minute)
  • TPM(tokens per minute)
  • 日 / 月预算(美元 / 人民币)
  • 允许的模型白名单 / 黑名单
  • 可访问的时间段

LiteLLM 里一条 virtual key 可以绑定:user、team、models、max_budget、tpm_limit、rpm_limit。

7.3 优先级队列

生产环境还需要"VIP 业务优先":

  • 低优先级请求排队,高优先级直通;
  • 某后端限流时,优先为 P0 保留 quota;
  • 对 batch / 异步任务降低优先级,给交互式请求让路。

Envoy AI Gateway、Kong、APISIX 都支持在 gateway 层做优先级调度;LiteLLM 则通过 priority 字段 + 队列实现。

7.4 计费模型的坑

真实计费里最容易出问题的几件事:

  1. 汇率与价格变动:OpenAI、Anthropic 隔几个月就调价;网关要把价格放到配置文件里,不要硬编码;
  2. Prompt Cache 折扣:OpenAI 的 cached input tokens 价格是常规的 50%,Anthropic 的 cache write/read 价格不同,要分别计量;
  3. 图像 token:OpenAI vision 按分块数量计算(每张按 tile 数量折 token),不是按像素,直接沿用 completion usage 里的数字即可;
  4. 语音 token:GPT‑4o Realtime 的 audio token 单独计价;
  5. 流式 usage :必须显式 stream_options: {"include_usage": true} 才会在最后一个 chunk 里带 usage;
  6. 失败请求:4xx/5xx 不计费,但 Guardrail 拦截后消耗的小模型成本要算入网关自身;
  7. 多活 / 重试:重试成功但前一次已产生部分 prefill 成本(某些供应商按"已生成的 token"计费,即便流被取消),要把这部分当作合理损耗记入监控。

网关通常把每一条请求产生的成本明细写一张宽表(request_id, team, app, user, model, prompt_tokens, completion_tokens, cached_tokens, usd, cny, latency_ms, cache_hit, fallback_from, ...),下游 BI 做任意维度透视。

八、核心能力(五):可观测与审计

8.1 必采指标

  • 请求维度:QPS、错误率(按 code、按 provider)、P50/P95/P99、首 token 延迟(TTFT)、token 生成速度(TPS);
  • Token 维度:prompt / completion / cached 分别统计;
  • 金额维度:按 team / user / model / app 汇总;
  • 质量维度:人工评分、自动打分、用户反馈(thumbs up/down);
  • 安全维度:Guardrail 触发次数、拦截原因分布、越狱检出率。

8.2 观测平台

  • LangSmith:LangChain 自家,Trace + Eval + Dataset 一体;
  • Langfuse:开源,支持自建,GUI 友好,Trace + Prompt 管理 + Eval;
  • Helicone:proxy 式观测,一行 base URL 切换即可;
  • Arize Phoenix / Arize AX:强在"评估 + 漂移检测";
  • Traceloop OpenLLMetry:基于 OpenTelemetry,接任意后端(Jaeger、Tempo、Datadog)。

8.3 审计

合规审计要求:

  • 每一次请求可追溯到"谁(身份)、何时、用了什么模型、输入输出是什么、是否被 guardrail 拦截、花了多少钱";
  • 日志留存 N 年;
  • 对含 PII 的日志要做加密或脱敏后留存;
  • 支持导出与检索。

网关通常把完整日志写到对象存储(OSS / S3)+ 索引到 ES / ClickHouse。

8.4 Trace 的最小字段集

一条合格的 LLM Trace 至少要包含:

json 复制代码
{
  "request_id": "req_abc123",
  "parent_span_id": "span_xxx",
  "timestamp": "2026-04-22T10:00:00Z",
  "team": "team-search",
  "app": "doc-qa",
  "user_id": "u-123",
  "virtual_key_id": "vk-abc",
  "model_requested": "chat-strong",
  "model_actual": "openai/gpt-4o",
  "fallback_chain": ["openai/gpt-4o", "deepseek/deepseek-chat"],
  "cache": { "type": "semantic", "hit": true, "similarity": 0.973 },
  "guardrails": [
    { "name": "pii-presidio", "blocked": false, "entities": ["PHONE"] },
    { "name": "prompt-guard", "blocked": false, "score": 0.02 }
  ],
  "usage": { "prompt_tokens": 812, "completion_tokens": 231, "cached_tokens": 600 },
  "cost": { "usd": 0.0041, "cny": 0.030 },
  "latency": { "ttft_ms": 420, "total_ms": 2380 },
  "finish_reason": "stop",
  "error": null
}

这张 Trace 就是计费、审计、排障、评估 四件事的共同源数据。下一篇 23:LLM 可观测性 会展开讲如何把它串进 OpenTelemetry。

九、A/B、灰度与 Shadow

9.1 场景

  • 新模型上线前对比老模型的质量与成本;
  • Prompt 调整的效果验证;
  • 两家供应商对比。

9.2 网关侧能力

  • 流量分割(split):按 user‑id 哈希 10% 走 B;
  • 影子流量(shadow):请求同时发给 A、B,只把 A 的结果返回给用户,B 的结果存下来对比;
  • 镜像采样(mirror):对线上真实流量按比例复制到 staging 做回归;
  • 结果对比:自动评分(LLM‑as‑judge)+ 延迟 + 成本 + 错误率对比报表。

影子流量要注意:翻倍的成本与"对带副作用的工具调用会重复执行"的坑------带副作用的请求不应 shadow。

9.3 一个 Shadow 实战配置

yaml 复制代码
# Portkey-style config 示例
strategy:
  mode: loadbalance
  targets:
    - provider: openai
      override_params: { model: gpt-4o }
      weight: 1.0
    - provider: anthropic
      override_params: { model: claude-sonnet-4 }
      weight: 0.0        # 不走真实流量
      shadow: true       # 但复制请求
      shadow_sample: 0.1 # 采样 10%
request_timeout: 60

Shadow 数据落入一张对比表:

request_id primary.model primary.usd primary.latency shadow.model shadow.usd shadow.latency judge_score
r1 gpt-4o 0.012 1900 claude-sonnet-4 0.009 1700 0.92/0.95

每周跑一次 judge(LLM‑as‑judge + 人工抽检)即可得到"切到 Claude 能省 25% 成本且质量相当"这样的决策依据。

十、结构化输出与工具调用在网关层的处理

10.1 统一结构化输出

各家结构化输出方案并不一致:

  • OpenAI:response_format={ "type": "json_schema", "json_schema": {...} },支持 strict;
  • Anthropic:prompt 里声明 + 客户端 tool_use 方式;
  • Gemini:response_schema
  • 本地模型:常用 Outlines / XGrammar / lm-format-enforcer 在引擎层约束。

网关可以做两件事:

  • 向上统一 :业务只传 response_format=json_schema,网关转换到各家私有格式;
  • 向下增强:对不支持 strict JSON 的后端,网关在上层做 repair(JSON5 容错解析、字段缺省补齐)。

10.2 工具调用(Function Calling / Tool Use)

网关需要:

  • 协议互转:OpenAI tools/tool_calls ↔ Anthropic tool_use/tool_result ↔ Gemini functionCall
  • 流式事件归一化:tool call 的 delta 在不同厂商差异很大;
  • MCP(Model Context Protocol)桥接:把 MCP Server 暴露的工具注入到任意模型的 tool schema 中,参考 20:工具调用与 MCP
  • 工具权限:限制哪些 virtual key 能调哪些工具(尤其是写类工具)。

10.3 一个协议归一化的实际 case

业务代码统一用 OpenAI Chat Completions:

python 复制代码
client.chat.completions.create(
    model="chat-strong",
    messages=[
        {"role": "system", "content": "你是理财助手"},
        {"role": "user", "content": "把持仓按风险分三类"},
    ],
    tools=[{
        "type": "function",
        "function": {
            "name": "get_holdings",
            "description": "查询用户持仓",
            "parameters": {"type": "object", "properties": {"user_id": {"type": "string"}}, "required": ["user_id"]},
        },
    }],
    response_format={"type": "json_schema", "json_schema": {...}},
    stream=True,
    stream_options={"include_usage": True},
)

当网关把它路由到 Anthropic,需要:

  • tools 翻译成 Anthropic tools 格式(input_schema 字段名一致,整体结构类似但顶层不一样);
  • system 消息从 messages[0] 提到顶层 system
  • response_format 降级为"在 system 里追加 JSON 指令 + tool 强制调用";
  • 把返回的 content_block_delta / tool_use / input_json_delta 事件翻译回 OpenAI SSE 格式;
  • 把最终 message_delta.usage 里的 input_tokens / output_tokens 转成 prompt_tokens / completion_tokens

LiteLLM、Portkey 都内置了这套转换;如果你在做自研网关,要对每个新接入的供应商各写一对"入参/出参/流式事件"适配器,并写大量差异回归用例。

十一、代码示例:LiteLLM Proxy 全景配置

11.1 目录结构

arduino 复制代码
gateway/
  config.yaml
  .env
  prompts/
    summarize.yaml
  docker-compose.yml

11.2 config.yaml

yaml 复制代码
model_list:
  # 外部模型
  - model_name: chat-strong       # 业务别名
    litellm_params:
      model: openai/gpt-4o
      api_key: os.environ/OPENAI_API_KEY
      rpm: 1000
      tpm: 200000
  - model_name: chat-strong
    litellm_params:
      model: anthropic/claude-sonnet-4
      api_key: os.environ/ANTHROPIC_API_KEY
  - model_name: chat-cheap
    litellm_params:
      model: deepseek/deepseek-chat
      api_key: os.environ/DEEPSEEK_API_KEY
  - model_name: chat-cheap
    litellm_params:
      model: openai/gpt-4o-mini
      api_key: os.environ/OPENAI_API_KEY

  # 自建 vLLM
  - model_name: chat-local
    litellm_params:
      model: openai/qwen2.5-72b-instruct
      api_base: http://vllm-qwen.svc:8000/v1
      api_key: none

litellm_settings:
  drop_params: true
  set_verbose: false
  cache: true
  cache_params:
    type: redis
    host: redis
    port: 6379
    ttl: 3600
    # 语义缓存
    supported_call_types: ["acompletion", "completion"]
    mode: "default_on"
    similarity_threshold: 0.97
    embedding_model: "text-embedding-3-small"
  success_callback: ["langfuse", "prometheus"]
  failure_callback: ["langfuse"]
  max_budget: 10000
  budget_duration: 30d

router_settings:
  routing_strategy: usage-based-routing-v2
  fallbacks:
    - chat-strong: [chat-cheap, chat-local]
    - chat-cheap: [chat-local]
  allowed_fails: 3
  cooldown_time: 60
  num_retries: 2
  retry_after: 5
  timeout: 60

guardrails:
  - guardrail_name: pii-presidio
    litellm_params:
      guardrail: presidio
      mode: pre_call
  - guardrail_name: jailbreak-lakera
    litellm_params:
      guardrail: lakera
      mode: during_call
      api_key: os.environ/LAKERA_API_KEY

general_settings:
  master_key: os.environ/LITELLM_MASTER_KEY
  database_url: os.environ/DATABASE_URL
  alerting: ["slack"]
  alert_types: ["budget_alerts", "llm_exceptions", "spend_reports"]

11.3 启动

bash 复制代码
docker run -d --name litellm \
  -p 4000:4000 \
  -v $(pwd)/config.yaml:/app/config.yaml \
  --env-file .env \
  ghcr.io/berriai/litellm:main-stable \
  --config /app/config.yaml --port 4000

11.4 签发 Virtual Key

bash 复制代码
curl -X POST http://localhost:4000/key/generate \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "team_id": "team-search",
    "models": ["chat-strong", "chat-cheap"],
    "max_budget": 200,
    "budget_duration": "30d",
    "rpm_limit": 500,
    "tpm_limit": 100000,
    "metadata": {"app": "doc-qa", "owner": "alice"}
  }'

11.5 客户端调用(OpenAI SDK)

python 复制代码
from openai import OpenAI

client = OpenAI(
    base_url="http://gateway.internal:4000/v1",
    api_key="sk-virtual-xxx",
)

resp = client.chat.completions.create(
    model="chat-strong",
    messages=[
        {"role": "system", "content": "You are a concise assistant."},
        {"role": "user", "content": "解释一下 PagedAttention。"},
    ],
    metadata={"user_id": "u-123", "session_id": "s-abc"},
    extra_body={
        "fallbacks": ["chat-cheap", "chat-local"],
        "cache": {"no-cache": False},
    },
)
print(resp.choices[0].message.content)
print(resp.usage)  # prompt_tokens / completion_tokens / cached_tokens

11.6 一个"成本路由 + 级联"的自定义插件

python 复制代码
# custom_router.py
from litellm import CustomLogger, completion

class CascadeRouter(CustomLogger):
    async def async_pre_call_hook(self, user_api_key_dict, cache, data, call_type):
        # 小模型先跑,分数达标就直接返回;否则放行给强模型
        msg = data["messages"]
        small = await completion(model="chat-cheap", messages=msg, max_tokens=256)
        text = small.choices[0].message.content
        score = self._judge(text, msg[-1]["content"])
        if score >= 0.8:
            data["_short_circuit_response"] = small
            return data
        return data  # 继续走默认路由到 chat-strong

    def _judge(self, answer, question):
        # 示例:规则 + 小 judge model
        if len(answer) < 40:
            return 0.0
        return 0.9

挂载方式(config.yaml):

yaml 复制代码
litellm_settings:
  callbacks: ["custom_router.CascadeRouter"]

十二、国内企业的落地姿势

12.1 "OneAPI 私有化 + 合规"的主流方案

一个典型中型企业的网关架构:

markdown 复制代码
业务应用  ──►  内部 LLM Gateway(OneAPI / NewAPI 私有化)
                     │
        ┌────────────┼────────────────────────────────┐
        │            │                                │
   国内供应商     国外供应商(经合规出口)         自建推理
  (通义/文心/       (OpenAI via Azure /          (vLLM/SGLang
   Kimi/豆包)       Anthropic via Bedrock)        + Qwen/DeepSeek)

OneAPI 负责:

  • 多供应商通道统一到 OpenAI 协议;
  • 团队 / 用户 / 令牌三层额度;
  • 日志与成本账单;
  • 简单的 fallback 与重试。

在它之上,企业通常再包一层"治理层":

  • 审批流程(新应用接入要走审批);
  • 数据分级路由(涉密走自建);
  • 高级 Guardrails(内部敏感词 + 行业词表);
  • 与内部 SSO / 工单 / 飞书对接。

12.2 金融 / 政务:数据不出域

  • 全内网部署:网关 + 模型都在机房,禁止访问外网;
  • 审计留痕:所有调用写到审计库,保留 3--5 年;
  • 双人复核:对敏感输出增加人工复核环节;
  • 模型备案:所用模型在监管平台完成备案(中国《生成式人工智能服务管理暂行办法》);
  • 差分日志:prompt 侧存脱敏版,仅在事件调查时解密。

12.3 互联网应用:成本优先

  • 首选 DeepSeek / Qwen / GLM / Kimi 等国产模型;
  • 语义缓存 + 级联,能把成本压到海外方案的 1/10;
  • 出海业务保留 OpenAI/Anthropic 通道兜底。

十三、架构全景图

![架构全景图转存失败,建议直接上传图片文件]quant67.com/post/llm-in...)

十四、选型建议与落地清单

14.1 选型速查

诉求 推荐
一键起网关、全球多家模型、团队/预算完整 LiteLLM Proxy
国内多供应商计费 + 中转 OneAPI / NewAPI
声明式路由、prompt 资产管理 Portkey
已有 Kong / APISIX / Envoy 原地加 AI 插件
K8s 原生、平台团队运维 Envoy AI Gateway
只要观测,不想改架构 Helicone / Langfuse proxy
降成本优先 LiteLLM + 语义缓存 + RouteLLM + 级联
合规金融 / 政务 OneAPI 私有化 + 自建推理 + 内容安全

14.2 落地 Checklist

  • 确定对外协议:统一为 OpenAI Chat Completions;
  • 定义模型别名:chat-default / chat-strong / chat-cheap / chat-reasoning / chat-local
  • 设计 virtual key 层级:org → team → app → user;
  • 预算与限流:TPM / RPM / 月度金额;
  • Fallback 链 + cooldown;
  • 精确缓存 + 语义缓存 + Prompt Caching 组合;
  • Guardrails:PII + 越狱 + 有害内容 + Schema 校验;
  • Observability:Langfuse/Helicone + Prometheus + 成本日报;
  • A/B 与 Shadow:新模型 / 新 Prompt 强制走对比;
  • 审计:保留策略 + 数据脱敏 + 合规导出;
  • 内网 / 出网策略:分级数据走分级后端;
  • 灾备:网关自身多活 + 配置版本化(GitOps)。

十五、小结

LLM Gateway 的本质不是"加一层代理",而是把多模型时代的工程复杂度------鉴权、计费、限流、缓存、Guardrails、观测、合规------从业务代码里抽出来放到一个可演进的基础设施里。

  • 如果你刚起步:从 LiteLLMOneAPI 起,一天就能上线;
  • 如果你已经有 API Gateway:Kong / APISIX / Envoy 原地加 AI 插件,复用既有治理;
  • 如果你是平台团队:考虑 Envoy AI Gateway 的 CRD 与多租户能力;
  • 无论哪种选择:语义缓存 + 级联 + 路由 + Guardrails + Observability 是五件套,缺一件成本或风险都会在几个月内反噬你。

下一篇我们把视角切到网关之后:一个请求进入模型后究竟发生了什么、如何把 Trace/Metrics/Logs 串成可排障的观测体系------23:LLM 可观测性

参考资料


上一篇21:推理服务化 下一篇23:LLM 可观测性

相关推荐
a8a3021 小时前
Laravel8.x新特性全解析
java·spring boot·后端
白露与泡影2 小时前
Spring Boot 完整流程
java·spring boot·后端
Mr.Rice.Fool2 小时前
rust面试经验1
后端·面试·职场和发展·rust
北风toto3 小时前
Spring Boot / Spring Cloud 配置文件加密详解:使用 jasypt-spring-boot 实现 ENC() 加密
spring boot·后端·spring cloud
代码羊羊3 小时前
Rust 格式化输出完全攻略:从入门到精通
开发语言·后端·rust
Rust研习社3 小时前
Rust + PostgreSQL 极简技术栈应用开发
开发语言·数据库·后端·http·postgresql·rust
geovindu3 小时前
go:Template Method Pattern
开发语言·后端·设计模式·golang·模板方法模式
白晨并不是很能熬夜4 小时前
【RPC】第 4 篇:服务发现 — Zookeeper + 缓存容错
java·后端·程序人生·缓存·zookeeper·rpc·服务发现