土法炼钢兴趣小组的算法知识备份

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

文章导航

分类入口
architectureai-infra
标签入口
#llm-gateway#litellm#oneapi#portkey#kong-ai#semantic-cache#routellm#guardrails#fallback#multi-provider

目录

一、为什么需要 LLM Gateway

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

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

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,核心特性:

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

2.2 OneAPI / NewAPI

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

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

2.3 Portkey

Portkey 同时提供 SaaS 与开源 Gateway:

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

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

2.5 Envoy AI Gateway

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

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

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

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

2.9 开源网关一图速览

开源网关一图速览

2.10 其他值得留意的项目

选型时要注意”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 全球云

3.2 国内云

大部分国内企业的真实选择是:平台 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 格式。

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

网关通常有一个”请求转换器(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 / 熔断 / 重试

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

# 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,在向量库里找相似度 > 阈值的历史结果直接返回。

5.3 Prompt 缓存(上游侧)

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

5.4 模型级联(Cascade / FrugalGPT)

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;实战中可以退而用:

5.5 Prompt 压缩

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

5.6 组合策略

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

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

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

6.1 为什么要在网关做 Guardrails

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

6.2 开源 / 商业 Guardrails

6.3 典型 Guardrails 流水线

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

6.4 越狱检测

常见越狱模式:

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

6.5 数据不出域与脱敏

6.6 Guardrails 的放置位置

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

# 伪代码: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 三种模式要点:

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

7.1 Token 计量

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

难点:

7.2 多租户配额

经典分层:

每一层都应当能配置: - RPM(requests per minute) - TPM(tokens per minute) - 日 / 月预算(美元 / 人民币) - 允许的模型白名单 / 黑名单 - 可访问的时间段

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

7.3 优先级队列

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

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 必采指标

8.2 观测平台

8.3 审计

合规审计要求:

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

8.4 Trace 的最小字段集

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

{
  "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 场景

9.2 网关侧能力

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

9.3 一个 Shadow 实战配置

# 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 统一结构化输出

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

网关可以做两件事:

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

网关需要:

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

业务代码统一用 OpenAI Chat Completions:

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,需要:

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

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

11.1 目录结构

gateway/
  config.yaml
  .env
  prompts/
    summarize.yaml
  docker-compose.yml

11.2 config.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 启动

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

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)

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 一个”成本路由 + 级联”的自定义插件

# 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):

litellm_settings:
  callbacks: ["custom_router.CascadeRouter"]

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

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

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

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

OneAPI 负责:

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

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

12.3 互联网应用:成本优先

十三、架构全景图

架构全景图

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

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

十五、小结

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

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

参考资料


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

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。


By .