2026-04-22 · architecture / ai-infra
【大模型基础设施工程】二十四:成本、合规与安全
从卡时、电费到 AI Act 与 Prompt Injection——一份写给基础设施工程师的大模型成本、合规、安全三位一体手册。























上一篇 21:推理服务化 讲了单一模型从 vLLM/SGLang 到 K8s 的上线路径。但真实企业里,一个业务很少只用一个模型、一个供应商:
如果让每个业务自己去调 OpenAI SDK、再各自埋点、各自配置降级与重试,就会出现:
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 的一套可运行示例与国内企业的落地实践。
LiteLLM 是目前社区使用最广的开源 LLM Gateway,核心特性:
litellm.completion(...))与独立
Proxy Server(FastAPI)两种形态;适合中小团队”一条命令起一个企业级网关”。
OneAPI 与其分叉 NewAPI、FastAPI、VoAPI 是国内社区最流行的 LLM 网关:
NewAPI 在 OneAPI 基础上补了很多企业功能:Midjourney、Suno、Rerank、TTS、语音等多模态;以及更灵活的计费模型(按次、按 token、按倍率)。
Portkey 同时提供 SaaS 与开源 Gateway:
适合需要”把路由策略声明式管理”的团队。
Kong 在 3.6 之后推出 AI
Gateway
一套插件:ai-proxy、ai-request-transformer、ai-response-transformer、ai-prompt-template、ai-prompt-guard、ai-prompt-decorator、ai-rate-limiting-advanced、ai-semantic-cache。
Envoy AI Gateway 是 CNCF 方向,由 Tetrate 等主导:
AIServiceBackend、AIGatewayRoute、BackendSecurityPolicy);Apache APISIX 同样在插件层增加
ai-proxy、ai-prompt-guard、ai-prompt-template、ai-rag、ai-rate-limiting
等,路线与 Kong 类似:已有 APISIX
就原地升级,不再引入新组件。
Helicone 起步于”LLM observability proxy”,只要把 base URL 指向它就能抓日志;后来演化为 Helicone AI Gateway,支持缓存、fallback、rate limit,并延续其强项——开箱即用的观测大盘与 per‑user cost。
这类偏”路由器”而非完整网关:
它们常常作为一个 Provider 接在 LiteLLM / Portkey 等完整网关的后端。
选型时要注意”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、算成本、做评估 |
实际落地里,常见组合是”完整网关 + 观测代理 + 路由器接后端”。
大部分国内企业的真实选择是:平台 API + OneAPI 私有化,把多家云合在一张内部 OpenAI 协议入口之后,再加一层内部治理(成本、审批、数据分级)。
网关的第一个工作是协议归一化。今天几乎所有模型厂商(包括
Anthropic、Gemini、DeepSeek、Qwen、Kimi、GLM、豆包、MiniMax、Mistral、Cohere)都会提供
“OpenAI 兼容” 端点,或由网关在内部把 Anthropic
messages、Gemini generateContent
等翻译成 OpenAI chat.completions 格式。
典型的几个字段差异需要网关补齐:
system 消息:Anthropic 是独立字段
system,OpenAI 放在
messages[0];tool_use /
tool_result,OpenAI 用 tool_calls
/ tool role;parts.inline_data.mime_type;delta.content /
delta.tool_calls.arguments 增量结构。网关通常有一个”请求转换器(request transformer)+ 响应转换器(response transformer)“对,向上游屏蔽差异。
常见策略:
model=gpt-4o
→ OpenAI;model=deepseek-v3 →
DeepSeek。最简单但不够智能;model=chat-default、model=chat-cheap、model=chat-reasoning;别名背后的真实模型由网关配置,可以随时替换;LiteLLM / Portkey 等网关大多提供”路由器(router)“抽象,以 weight、tag、cooldown 来组合上述策略。
真实环境里最有价值的能力:
[gpt-4o → gpt-4.1-mini → deepseek-v3 → qwen-max],前者
5xx 或超时就顺次尝试;gpt-4o 降级到 gpt-4o-mini。# 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: 5LLM 请求的缓存不是单一层,而是五层缓存协同工作:
| 层次 | 命中粒度 | 省的是什么 | 典型实现 |
|---|---|---|---|
| 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。
最简单的做法:以
hash(model + messages + temperature + top_p + tools)
作 Redis key。对”同样问题被问很多次”的场景(FAQ、SQL
生成、固定 prompt 抽取)能立刻省 30–80% 成本。
注意点: - 对 temperature>0
的请求要谨慎(结果不稳定,缓存会损失多样性); - 要把 tool
schema、system prompt 一起纳入 key; - 结果要存
usage、finish reason,便于后续审计。
思路:对请求的 messages 做 embedding,在向量库里找相似度 > 阈值的历史结果直接返回。
ai-semantic-cache;OpenAI、Anthropic、DeepSeek、Gemini 已普遍支持 Prompt Caching:对长 system prompt / 工具定义做上游缓存,后续请求几乎免费。网关要做的:
cached_tokens,纳入计费折扣;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;LLMLingua / LongLLMLingua 用一个小模型删除 prompt 中信息熵低的 token,可在几乎不掉质量的前提下把长上下文压到 1/4–1/10。网关把它作为”前置插件”接上去,对长上下文任务尤其划算。
一张实战里常见的成本降维图:
原始成本
↓ Prompt Caching(上游)
↓ Prompt 压缩(LLMLingua)
↓ 语义缓存(GPTCache / 网关内置)
↓ 模型级联(FrugalGPT)
↓ 质量路由(RouteLLM)
最终成本(常见压到 20–40%)
业务应用层做 Guardrails 很常见,但放在网关有几个好处:
用户输入
→ Presidio(PII 检测 + 脱敏)
→ Prompt Guard(越狱 / 注入检测)
→ 关键词 / 敏感词
→ Llama Guard(有害内容 IN)
→ 业务 Prompt
→ 模型
→ Llama Guard(有害内容 OUT)
→ Guardrails(结构 / 事实 / 词表约束)
→ 响应
常见越狱模式:
防守组合:Prompt Guard(小模型)+ 关键词 + 语义相似度 + 历史模式库;对高风险工具调用再加一层人类 / 二次模型复核。
按”早发现越便宜”的原则,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 三种模式要点:
每次请求结束,网关必须能拿到三类数字:
prompt_tokens /
completion_tokens /
cached_tokens;难点:
usage
字段并不一致,要统一;stream: true +
stream_options.include_usage 下才能拿到;经典分层:
每一层都应当能配置: - RPM(requests per minute) - TPM(tokens per minute) - 日 / 月预算(美元 / 人民币) - 允许的模型白名单 / 黑名单 - 可访问的时间段
LiteLLM 里一条 virtual key 可以绑定:user、team、models、max_budget、tpm_limit、rpm_limit。
生产环境还需要”VIP 业务优先”:
Envoy AI Gateway、Kong、APISIX 都支持在 gateway
层做优先级调度;LiteLLM 则通过 priority 字段 +
队列实现。
真实计费里最容易出问题的几件事:
stream_options: {"include_usage": true}
才会在最后一个 chunk 里带 usage;网关通常把每一条请求产生的成本明细写一张宽表(request_id, team, app, user, model, prompt_tokens, completion_tokens, cached_tokens, usd, cny, latency_ms, cache_hit, fallback_from, ...),下游
BI 做任意维度透视。
合规审计要求:
网关通常把完整日志写到对象存储(OSS / S3)+ 索引到 ES / ClickHouse。
一条合格的 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。
影子流量要注意:翻倍的成本与”对带副作用的工具调用会重复执行”的坑——带副作用的请求不应 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: 60Shadow 数据落入一张对比表:
| 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% 成本且质量相当”这样的决策依据。
各家结构化输出方案并不一致:
response_format={ "type": "json_schema", "json_schema": {...} },支持
strict;tool_use
方式;response_schema;网关可以做两件事:
response_format=json_schema,网关转换到各家私有格式;网关需要:
tools/tool_calls ↔︎ Anthropic
tool_use/tool_result ↔︎ Gemini
functionCall;业务代码统一用 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,需要:
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 都内置了这套转换;如果你在做自研网关,要对每个新接入的供应商各写一对”入参/出参/流式事件”适配器,并写大量差异回归用例。
gateway/
config.yaml
.env
prompts/
summarize.yaml
docker-compose.yml
config.yamlmodel_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"]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 4000curl -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"}
}'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# 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"]一个典型中型企业的网关架构:
业务应用 ──► 内部 LLM Gateway(OneAPI / NewAPI 私有化)
│
┌────────────┼────────────────────────────────┐
│ │ │
国内供应商 国外供应商(经合规出口) 自建推理
(通义/文心/ (OpenAI via Azure / (vLLM/SGLang
Kimi/豆包) Anthropic via Bedrock) + Qwen/DeepSeek)
OneAPI 负责:
在它之上,企业通常再包一层”治理层”:
| 诉求 | 推荐 |
|---|---|
| 一键起网关、全球多家模型、团队/预算完整 | LiteLLM Proxy |
| 国内多供应商计费 + 中转 | OneAPI / NewAPI |
| 声明式路由、prompt 资产管理 | Portkey |
| 已有 Kong / APISIX / Envoy | 原地加 AI 插件 |
| K8s 原生、平台团队运维 | Envoy AI Gateway |
| 只要观测,不想改架构 | Helicone / Langfuse proxy |
| 降成本优先 | LiteLLM + 语义缓存 + RouteLLM + 级联 |
| 合规金融 / 政务 | OneAPI 私有化 + 自建推理 + 内容安全 |
LLM Gateway 的本质不是”加一层代理”,而是把多模型时代的工程复杂度——鉴权、计费、限流、缓存、Guardrails、观测、合规——从业务代码里抽出来放到一个可演进的基础设施里。
下一篇我们把视角切到网关之后:一个请求进入模型后究竟发生了什么、如何把 Trace/Metrics/Logs 串成可排障的观测体系——23:LLM 可观测性。
上一篇:21:推理服务化 下一篇:23:LLM 可观测性
把当前热点继续串成多页阅读,而不是停在单篇消费。
2026-04-22 · architecture / ai-infra
从卡时、电费到 AI Act 与 Prompt Injection——一份写给基础设施工程师的大模型成本、合规、安全三位一体手册。
2026-04-22 · architecture / ai-infra
面向工程师的大模型基础设施开篇地图,覆盖 2022 到 2026 的工程分水岭、五层工程栈、训练与推理的工程差异、中国与全球行业版图以及成本曲线。
2026-04-22 · architecture / ai-infra
从 CPU 与 GPU 的架构差异出发,讲清楚 SM、Warp、Tensor Core、HBM、NVLink 的工程含义,并结合 Roofline、FlashAttention 与国产算力栈,给出大模型工程师能直接上手的 GPU 心智模型。
2026-04-22 · architecture / ai-infra
从 nvcc 到 Triton,把 NVIDIA 软件栈的每一层拆给大模型工程师看,顺便谈谈 ROCm、CANN 为什么一直追不上。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。