01 — 价格 JSON 文件(model_cost map)生命周期¶
概述¶
litellm.model_cost 是一个进程级全局 dict,存储所有已知模型的价格与能力信息。它在模块导入时同步初始化,之后作为所有计费查询的基础数据源。
初始化时机与代码路径¶
触发点:import litellm 时,Python 解释器顺序执行 __init__.py,在第 440 行完成同步赋值。
# litellm/__init__.py:339-341
model_cost_map_url: str = os.getenv(
"LITELLM_MODEL_COST_MAP_URL",
"https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
)
# litellm/__init__.py:438-440
from litellm.litellm_core_utils.get_model_cost_map import get_model_cost_map
model_cost = get_model_cost_map(url=model_cost_map_url)
进程内共享:同一进程的所有线程和协程引用同一个 dict 对象,任何修改(register_model、热重载)都对全局可见。
远程拉取流程¶
flowchart TD
A[get_model_cost_map URL] --> B{LITELLM_LOCAL_MODEL_COST_MAP=true?}
B -- 是 --> C[load_local_model_cost_map\n读取 backup JSON]
B -- 否 --> D[fetch_remote_model_cost_map\nhttpx.get timeout=5s]
D -- 成功 --> E{validate_model_cost_map}
D -- 失败/超时 --> F[fallback: load_local_model_cost_map]
E -- 校验通过 --> G[使用远程 dict]
E -- 校验失败\n模型数 < 最小值 或 缩减超比例 --> F
F --> H[litellm.model_cost]
G --> H
C --> H
相关文件:litellm/litellm_core_utils/get_model_cost_map.py:154-200
# get_model_cost_map.py:154-169
def get_model_cost_map(url: str) -> dict:
if os.getenv("LITELLM_LOCAL_MODEL_COST_MAP", "").lower() == "true":
return GetModelCostMap.load_local_model_cost_map()
try:
content = GetModelCostMap.fetch_remote_model_cost_map(url)
except Exception as e:
verbose_logger.warning("Failed to fetch remote model cost map ... Falling back to local backup.")
return GetModelCostMap.load_local_model_cost_map()
...
本地 backup 文件¶
| 项目 | 说明 |
|---|---|
| 文件路径 | litellm/model_prices_and_context_window_backup.json |
| 访问方式 | importlib.resources.files("litellm").joinpath("model_prices_and_context_window_backup.json") |
| 生效环境变量 | LITELLM_LOCAL_MODEL_COST_MAP=true |
| 自定义模型写法 | 在此文件中添加 key,格式为 "provider/model_name" |
添加自定义模型的 key 格式规则(查找优先级顺序):
| 优先级 | key 格式 | 示例(model=Vendor2/Claude-4.6-Opus, provider=anthropic) |
|---|---|---|
| 1 | {provider}/{model} |
"anthropic/Vendor2/Claude-4.6-Opus" |
| 2 | {model} |
"Vendor2/Claude-4.6-Opus" |
| 3 | {provider}/{stripped_model} |
同 1(无版本号可剥离) |
| 4 | {stripped_model} |
同 2 |
| 5 | {split_model} |
同 2 |
两种格式均可命中,推荐使用格式 1("anthropic/Vendor2/Claude-4.6-Opus")最明确。
热重载端点¶
端点:POST /reload/model_cost_map
定义:litellm/proxy/proxy_server.py:12075-12147
权限:仅 PROXY_ADMIN
热重载做了什么¶
# proxy_server.py:12075~
@router.post("/reload/model_cost_map")
async def reload_model_cost_map(...):
# 1. 重新拉取(或读 backup)
new_map = get_model_cost_map(url=litellm.model_cost_map_url)
# 2. 整体替换 dict
litellm.model_cost = new_map
# 3. 清空大小写 lookup cache 和 LRU cache
_invalidate_model_cost_lowercase_map()
# 4. 向 DB 写 force_reload=True,通知其他 Pod
await prisma_client.db.litellm_config.upsert(...)
热重载做不到的事¶
sequenceDiagram
participant Admin
participant ProxyServer
participant model_cost as litellm.model_cost
participant Router
Admin->>ProxyServer: POST /reload/model_cost_map
ProxyServer->>model_cost: 整体替换为新 dict
Note over model_cost: ⚠️ 所有 UUID 条目被清除!\n(UUID 不在远程 JSON 中)
Note over Router: Router.model_list 中的 deployment\n仍然存在,但计费查不到 UUID 价格
Note over Router: 等待 30s 轮询 add_deployment\n重新执行 _create_deployment → register_model\n才能恢复 UUID 条目
结论:热重载后约 30 秒内,使用 UUID 路径(custom_pricing=True)的模型会临时找不到自定义价格,回退到 JSON 路径。
litellm.register_model() 的作用¶
调用时机:每次 Router._create_deployment() 执行时,被调用两次。
定义:litellm/utils.py:2782-2820(约)
# router.py:6197-6230
# 第一次:以 UUID 为 key,注册完整自定义价格
for field in CustomPricingLiteLLMParams.model_fields.keys():
if deployment.litellm_params.get(field) is not None:
_model_info[field] = deployment.litellm_params[field]
litellm.register_model(model_cost={model_id: _model_info})
# 第二次:以 "provider/model_name" 为 key,注册不含自定义价格字段的共享信息
_custom_pricing_fields = CustomPricingLiteLLMParams.model_fields.keys()
_shared_model_info = {k: v for k, v in _model_info.items() if k not in _custom_pricing_fields}
litellm.register_model(model_cost={_model_name: _shared_model_info})
影响的数据结构:
- litellm.model_cost dict:写入/更新对应 key
- _model_cost_lowercase_map:大小写不敏感 lookup 缓存,同步失效
- provider 模型集合(litellm.anthropic_models 等):按 litellm_provider 字段追加
多 Pod 场景的热重载同步¶
sequenceDiagram
participant Pod1
participant DB as PostgreSQL litellm_config
participant Pod2
Pod1->>Pod1: POST /reload/model_cost_map
Pod1->>Pod1: litellm.model_cost = new_map
Pod1->>DB: INSERT force_reload=True
Note over Pod2: 每30秒 _check_and_reload_model_cost_map()
Pod2->>DB: 查询 force_reload 标志
DB-->>Pod2: force_reload=True
Pod2->>Pod2: 重载 model_cost
Pod2->>DB: 清零 force_reload 标志
相关代码:proxy_server.py:4388-4389