多环境 API 怎么管理?dev/test/prod 一套规范
一个 API Key 跑三个环境,是不少团队的真实状态。代码先在本地调通,推到测试环境跑一遍,没问题就上生产------结果测试流量悄悄蹭了生产额度,或者开发调试时的异常请求打进了真实用户数据。这类问题很难靠流程管住,得从基础设施层面做隔离。
本文给出的是一套直接能落地的多环境 API 管理规范,覆盖环境变量分离、接入层虚拟 Key、按环境选模型、日志隔离四个维度。
一、问题到底出在哪
团队用一个 Key 跑所有环境,核心风险有两个:
额度混淆。 测试阶段跑一批调试请求,消耗的是生产预算。API 提供商的账单按 Key 计,看不出哪次调用来自哪个环境。额度超了影响真实用户,调账单还得从代码里翻调用记录。
环境污染。 测试写进去的脏数据进了生产表,或者测试用的模型配置改了生产行为。环境没隔离,功能能跑,但后果不可控。
解决思路很简单:每个环境有独立的 Key、独立的基础设施入口、独立的使用限额。但具体怎么落地,下面逐层说。
二、第一层:环境变量分离
最基础也是最有效的手段。不同环境的配置通过不同的 .env 文件加载,代码本身不感知环境,读取同一个变量名,值由运行时注入。
项目结构这样组织:
bash
.env.example # 模板,含所有变量名,无真实值
.env.development # 开发环境
.env.staging # 测试/预发布环境
.env.production # 生产环境
.env.example 必须提交到仓库,内容类似:
bash
# 基础配置
APP_ENV=development
LOG_LEVEL=debug
# API 配置
OPENAI_API_KEY=sk-XXXXXXXXXXXX
OPENAI_BASE_URL=https://api.openai.com/v1
OPENAI_MODEL=gpt-4o-mini
# 额度上限(单位:美元/月)
MONTHLY_BUDGET=10
开发环境用 gpt-4o-mini 之类的便宜模型,测试用同款小模型,生产才切到主力大模型。变量名统一,值按环境不同。
Python 读取示例(基于 python-dotenv + pydantic-settings):
python
from pydantic_settings import BaseSettings, SettingsConfigDict
from dotenv import load_dotenv
import os
load_dotenv(f".env.{os.getenv('APP_ENV', 'development')}")
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", extra="ignore")
openai_api_key: str
openai_base_url: str = "https://api.openai.com/v1"
openai_model: str = "gpt-4o-mini"
log_level: str = "info"
settings = Settings()
启动命令带上环境标识:
bash
APP_ENV=development uvicorn main:app
APP_ENV=production uvicorn main:app --host 0.0.0.0 --port 8000
这一层做好的标准:代码里没有出现任何环境判断分支,所有配置统一从 Settings(或等价的对象)读取。
三、第二层:接入层虚拟 Key 隔离(LiteLLM)
光靠环境变量分离,只是降低了配置错误的风险。如果团队人数多、项目多,手动管 Key 本身就成了瓶颈。
LiteLLM 是一个开源的统一 API 接入层,核心能力是把所有模型(OpenAI、Anthropic、Azure、Gemini、Ollama 等)统一成一套 OpenAI 兼容的 API。配合它的**虚拟 Key(Virtual Keys)**功能,可以做到:
- 给每个团队/服务生成独立的虚拟 Key
- 每个 Key 绑定自己的可用模型列表、月度额度、请求频率上限
- 所有调用通过接入层路由,后端真实 Key 不暴露在任何项目代码里
- 消费明细按 Key 分开查
部署一个最小可用的 LiteLLM 实例(Docker 方式):
bash
curl -sSL https://docs.litellm.ai/docker-compose.yml | docker compose -f - up -d
或者用 Docker Compose 配持久化数据库:
yaml
services:
litellm:
image: ghcr.io/berriai/litellm:main-latest
ports:
- "4000:4000"
volumes:
- ./litellm_config.yaml:/app/config.yaml
environment:
- DATABASE_URL=postgresql://litellm:password@db:5432/litellm
- LITELLM_MASTER_KEY=sk-your-master-key-here
- OPENAI_API_KEY=${OPENAI_API_KEY}
command: ["--config", "/app/config.yaml", "--port", "4000"]
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: litellm
POSTGRES_PASSWORD: password
POSTGRES_DB: litellm
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
管理后台在 http://localhost:4000/ui,用 LITELLM_MASTER_KEY 登录。
然后按环境生成虚拟 Key:
bash
# 开发/测试 Key --- 低额度,只能用便宜模型
curl -X POST http://localhost:4000/key/generate \
-H "Authorization: Bearer sk-your-master-key-here" \
-H "Content-Type: application/json" \
-d '{
"key_alias": "dev-team",
"models": ["gpt-4o-mini", "gpt-4o"],
"max_budget": 5.0,
"budget_duration": "30d",
"metadata": {"env": "development"}
}'
# 生产 Key --- 更高额度,完整模型列表
curl -X POST http://localhost:4000/key/generate \
-H "Authorization: Bearer sk-your-master-key-here" \
-H "Content-Type: application/json" \
-d '{
"key_alias": "production-service",
"models": ["gpt-4o", "gpt-5"],
"max_budget": 200.0,
"budget_duration": "30d",
"metadata": {"env": "production"}
}'
拿到虚拟 Key 之后,应用层代码改成指向 LiteLLM(统一接入层):
python
from openai import OpenAI
client = OpenAI(
api_key="sk-virtual-key-from-gateway", # 虚拟 Key,不是真实 Provider Key
base_url="http://your-litellm-host:4000"
)
response = client.chat.completions.create(
model="gpt-4o-mini", # 实际走哪个模型,由接入层按配置路由
messages=[{"role": "user", "content": "分析这份数据报告"}]
)
这样每个项目/服务有自己独立的 Key,额度用完接入层直接拒掉,不会影响其他环境的调用。
四、第三层:按环境选模型
接入层隔离了 Key,还需要让不同环境自动走不同的模型。最直接的方式是在调用侧根据环境变量指定模型,但更好的做法是在接入层或配置层做映射,代码不需要关心当前是什么环境。
LiteLLM 的模型别名机制天然支持这一点:
yaml
model_list:
# 开发/测试映射到小模型
- model_name: smart
litellm_params:
model: openai/gpt-4o-mini
api_key: os.environ/OPENAI_API_KEY
# 生产映射到大模型
- model_name: powerful
litellm_params:
model: openai/gpt-4o
api_key: os.environ/OPENAI_API_KEY
# 备用(降级)
- model_name: cheap
litellm_params:
model: openai/gpt-4o-nano
api_key: os.environ/OPENAI_API_KEY
代码里只写 model="smart",接入层根据这个别名查配置文件决定走哪个模型。切换环境只需要改接入层配置,不需要动代码。
如果团队没有自建接入层的条件,也可以在代码层做简单的模型映射:
python
import os
MODEL_MAP = {
"development": "gpt-4o-mini",
"staging": "gpt-4o-mini",
"production": "gpt-4o",
}
current_model = MODEL_MAP.get(os.getenv("APP_ENV", "development"), "gpt-4o-mini")
五、第四层:日志隔离便于排查
环境隔离了,日志也得能分开查。不然测试环境出问题了,去生产日志里翻半天找不到。
LiteLLM 自带消费日志,可以按 Key 查:
bash
# 查某个虚拟 Key 的消费
curl "http://localhost:4000/key/info?key=sk-virtual-key-from-gateway" \
-H "Authorization: Bearer sk-your-master-key-here"
返回包含该 Key 的累计消费、有效期、可用额度。
在自己的应用里,日志结构加上环境标识字段:
python
import structlog
import os
structlog.configure(
wrapper_class=structlog.make_filtering_bound_logger(
{"env": os.getenv("APP_ENV", "unknown")}
)
)
log = structlog.get_logger()
log.info("api_request", model="gpt-4o-mini", env=os.getenv("APP_ENV"))
用 ELK 或 Loki 之类的日志平台时,按 env 字段过滤,生产日志和测试日志就完全分开了。
六、快速排错表
| 现象 | 排查方向 |
|---|---|
| 调用报 401 | 虚拟 Key 不存在或已过期,查 LiteLLM 管理后台 |
| 报 429 额度超限 | 该 Key 的月度额度用尽,查 /key/info |
| 返回结果不符合预期 | 确认当前环境加载的是哪个 Key,对应的是哪个模型 |
| 模型不支持该操作 | 虚拟 Key 的 models 列表是否包含目标模型 |
| 日志查不到记录 | 确认日志里的 env 字段,查对应环境的日志索引 |
| 生产环境用了测试模型 | 检查环境变量 APP_ENV,确认 CI/CD 注入正确 |
| 批量请求被限流 | 查 LiteLLM 的 RPM/TPM 限制,调整 rpm_limit |
七、配置检查清单
上线前逐项确认:
-
.env.development/.env.staging/.env.production三个文件齐全,变量名一致 - 生产环境的
OPENAI_API_KEY已从本地文件迁移到云端密钥管理(AWS Secrets Manager / 阿里云 KMS 等) - LiteLLM 虚拟 Key 已按团队/服务分别生成,不是共用一个 Key
- 每个虚拟 Key 的
max_budget和budget_duration已设置 - 代码中所有 API 调用走
Settings(或等价对象),没有硬编码 Key 或 URL - 日志系统已按
env字段建立索引,上线前验证过滤功能正常 - CI/CD 流水线中,
APP_ENV的注入逻辑已覆盖所有阶段(build / deploy) - 新增模型时,同步更新 LiteLLM 的
model_list,并更新对应虚拟 Key 的models允许列表