多个 API Key 怎么管理和限流
一个 Key 跑全部业务,迟早会撞上额度和对账两堵墙。这篇讲怎么按业务线拆分 Key、用网关层做配额与限流、踩住 429 和超时的重试边界,并给出可直接落地的目录结构与代码。
线上跑的模型调用一旦从"一个脚本"变成"几条业务线共用",第一个出问题的往往不是模型选型,而是 Key 管理。一个 Key 打天下,出了事查不出是谁在刷、月底对不上账、某条业务突然暴涨把别人额度吃干。
这篇按"拆 Key → 分配额 → 限流 → 重试 → 对账"的顺序讲清楚。所有计费口径都来自站内文档,不引用任何外部官方价。
先说结论
- Key 的拆分维度选「业务线 + 环境」,不要按人拆。人一离职,Key 就成孤儿。
- 配额优先做在网关层(自己的服务里),不要指望上游帮你兜底限流。
- 只对 429 和 5xx 重试,400/401/404 重试纯属浪费额度。
- 每个 Key 的用量必须能落到日志里,否则对账时只能靠猜。
- Key 一定要能"一键吊销",所以每个 Key 只做一件事,吊销时影响面才可控。
为什么不能一个 Key 跑全部
先说清楚一个 Key 打天下会烂在哪:
- 无法定位来源。所有请求都是同一个 Key,日志里全是同一串
sk-,出了异常调用不知道是谁。 - 无法独立吊销。一个业务泄露 Key,必须全站换 Key,所有服务同时停摆。
- 无法独立配额。前端客服机器人把额度打满,后端的批处理任务直接 429。
- 无法对账。月底看到一笔总消耗,拆不回到具体业务或具体客户。
这四条里,实际最疼的是第二条和第四条。定位来源可以靠日志补,但"要不要吊销"是个二元决策——Key 只能整体吊销,没法吊销一半。
拆分维度:业务线 × 环境
最省事的拆法是二维:
| 维度 | 取值示例 | 拆的原因 |
|---|---|---|
| 业务线 | 客服机器人、内容生成、代码助手、内部批处理 | 用量互相隔离,出问题影响面小 |
| 环境 | prod、staging、dev | staging 跑测试数据,不该花 prod 的钱 |
命名建议统一成 <业务线>-<环境>,比如 support-prod、content-dev。不要用 key1、key2,三个月后没人知道 key2 是谁的。
按人拆 Key 是常见错误:人离职要回收、转岗要重建、一人参与三个项目又要拆三个 Key。按业务线拆,人只是调用方,不是管理单元。
注册与建 Key 的入口在控制台,具体步骤见 快速上手,新建令牌后是 sk- 开头,切换 base_url 到 https://api.zaimod.com/v1 即可用,不用改代码结构。
配额怎么分
配额的本质是"给每个业务线划一条花钱上限"。有两种做法:
- 硬上限:超过阈值直接拒绝请求。安全,但可能误伤正常流量。
- 软上限:超过阈值只告警不拦截。灵活,但依赖人看告警。
生产环境建议硬上限给到「日均用量 × 3」,软告警给到「日均用量 × 1.5」。这样正常波动不会触发拦截,真出事故时最多烧三天的量。
配额计算要用站内的计费公式,不要凭感觉。计费文档写得很明确:
分组倍率是 default ×1.0,Claude官转、OpenAI官转、Gemini优质三组 ×1.5。也就是说同一个请求走不同分组,费用差 50%。分配配额时必须把倍率算进去,否则同一份预算在 ×1.5 分组里只够三分之二。
网关层限流的实现
限流放在自己服务里,用令牌桶按 Key 隔离。下面是可直接用的最小实现:
import time
from collections import defaultdict
class TokenBucket:
def __init__(self, rate_per_min: float, burst: int):
self.rate = rate_per_min / 60.0 # 每秒补充
self.burst = burst # 桶容量
self.state = {} # key_name -> (tokens, last_ts)
def allow(self, name: str, cost: float = 1.0) -> bool:
now = time.monotonic()
tokens, last = self.state.get(name, (self.burst, now))
tokens = min(self.burst, tokens + (now - last) * self.rate)
if tokens < cost:
self.state[name] = (tokens, now)
return False
self.state[name] = (tokens - cost, now)
return True
# 每个业务线独立限流,单位:请求/分钟
buckets = {
"support-prod": TokenBucket(rate_per_min=300, burst=60),
"content-prod": TokenBucket(rate_per_min=60, burst=20),
"batch-prod": TokenBucket(rate_per_min=120, burst=40),
}
def pick(name: str) -> bool:
return buckets[name].allow(name)
几点注意:按「Key 名」而不是「请求 ID」做 key,桶才是按业务线隔离的;burst 等于允许的瞬时突发,设成 rate_per_min 意味着一分钟能打完全部额度;流式请求耗时很长,占用的并发槽要单独计数。
超时和重试的边界
这是最容易白烧钱的地方。站内错误码文档已经把规则说清楚了,直接照做即可:
| 状态码 | 含义 | 要不要重试 |
|---|---|---|
| 400 | 请求体不合法 | 不重试,改参数 |
| 401 | Key 无效或已吊销 | 不重试,查 Key |
| 403 | 令牌无权使用该模型 | 不重试,查分组权限 |
| 404 | 模型名不存在 | 不重试,查模型名拼写 |
| 429 | 触发限流 | 重试,指数退避 |
| 500 / 502 / 503 | 上游异常 | 重试 2–3 次 |
| 超时 | 长时间无响应 | 流式 + 更短 max_tokens |
关键在两条:400/401/404 重试没有意义,只会多打几次日志;超时不要原样重试,套一个更小的 max_tokens 或改流式,否则大概率超第二次。
429 用指数退避 + 抖动:
import random, time
def backoff(n: int) -> float:
base = min(2 ** n, 30)
return base * (0.5 + random.random() * 0.5)
错误响应的结构是固定的,方便统一拦截:
{"error": {"message": "该令牌无权使用模型 xxx", "type": "forbidden"}}
把 type 字段直接映射到告警级别:forbidden 和 invalid_api_key 是高优,rate_limit_exceeded 只需计数。详细的排查路径在 报错排查 和 429 限流处理 里。
用量怎么落到日志
只要 Key 是按业务线拆的,用量就能直接按 Key 聚合。日志里至少留这几个字段:
key_name:业务线标识model:模型名prompt_tokens/completion_tokens:用量group:分组,决定倍率latency_ms:耗时status:状态码
有了这几列,月末对账就是一句 GROUP BY。反过来,如果日志只有 sk- 前缀,你拿到账单也只能对总数。
需要注意 tokenizer 会有轻微差异,站内文档给的容差是 ±5%。做预算告警时把阈值按 5% 放宽,避免每条告警都是误报。
常见问题
Q:一个 Key 能同时调 OpenAI、Claude、Gemini 的模型吗?
可以。OpenAI 兼容协议走 https://api.zaimod.com/v1,一个 Key 覆盖所有兼容模型。只有调 Anthropic 原生端点时需要把 base_url 改成 https://api.zaimod.com,Key 不变。两套协议的差异见 Claude API 和 OpenAI API 有什么区别。
Q:staging 环境该不该单独建 Key?
该建。不仅是为了钱,更是因为 staging 的调试流量会污染 prod 的用量统计和告警阈值。一个 staging 的压测脚本能把 prod 的日均曲线拉成尖刺,之后所有告警都不准了。
Q:给客户分发 Key,还是我这边代理?
如果客户是你的终端用户,不要直接分发你的 Key。中间加一层自己的服务,用内部 Key 调模型,对外只暴露你的接口。这样客户方无法看到 sk-,也没法拿你的额度去跑别的东西。Key 泄露后的处理流程见 Key 泄露应急。
Q:限流阈值该设多少?
拿历史日志的 P95 值乘 2 起步,跑一周再调。不要从 0 开始猜,猜出来的阈值要么太松没作用,要么太紧天天误杀。
Q:多个 Key 换来换去,代码里怎么写才不脏?
用一个配置表把 key_name → (api_key, base_url) 映射出来,业务代码只传 key_name,不直接持有 sk-。这样换 Key 只改配置,不动代码。
延伸阅读
- 计费规则与错误码——费用公式、分组倍率、状态码语义
- 快速上手——建 Key、换 base_url、常用参数
- 50 美元预算怎么配模型——小预算下的模型组合
- 免费创建 API Key——新账号自带测试额度,可以先拆三个 Key 跑起来验证限流