![[Bug]: register_model() persists synthesized zero costs on re-registration, silently disabling all budget enforcement](https://www.chat-gpts.plus/wp-content/uploads/2026/06/30198-bba40006.jpg)
[Bug]: register_model() persists synthesized zero costs on re-registration, silently disabling all budget enforcement
快速结论:该问题出现在 LiteLLM Proxy 部署过程中。当模型通过 Admin UI 配置(无自定义定价)并在同一进程内被重新注册时,register_model() 会将 get_model_info() 合成的 input_cost_per_token / output_cost_per_token 零值持久化到 litellm.model_cost 字典中,导致所有预算检查(每标签、每密钥、每团队、每用户、每组织)被静默跳过。优先检查是否在同一个进程中进行了多次模型注册操作,以及 litellm.model_cost 中对应条目的成本键是否被错误写入为 0。
问题场景
用户在生产环境中运行 LiteLLM Proxy(基于数据库的代理)。触发场景:通过 Admin UI 创建模型(未设置自定义定价),之后在同一个进程内模型被第二次注册(例如路由器重建、数据库配置同步、使用 /model/update 接口更新模型、或在 Admin UI 中编辑模型)。此问题在 litellm 1.85.0 到当前主分支版本中均存在。
报错原文
Tag, key, team, user and org budgets are all skipped for that model group.
Billing and /model/info still resolve prices by model name, so spend keeps being charged correctly and everything looks healthy; only enforcement is off.
A pod restart fixes it until the next re-registration, so the symptom flickers and is hard to attribute.
原因分析
根本原因是 get_model_info() 在查找模型成本信息时,若 input_cost_per_token / output_cost_per_token 缺失,默认将其填充为 0(表示“价格未知”,与“免费”共享相同表示)。而 register_model() 函数在重新注册模型时,会将该合成后的条目(包含零成本值)写回到 litellm.model_cost 字典中。具体代码路径如下(位于 litellm/utils.py 的 register_model() 函数中):
try:
existing_model = cast(dict, get_model_info(model=key)) # synthesizes costs = 0
model_cost_key = existing_model["key"]
except Exception:
existing_model = {}
model_cost_key = key
updated_dictionary = _update_dictionary(existing_model, value)
litellm.model_cost.setdefault(model_cost_key, {}).update(updated_dictionary) # zeros persisted
第一次注册时,get_model_info(uuid) 会抛出异常(条目尚不存在),因此条目保持为干净的稀疏标记。第二次注册时,该函数找到了稀疏条目,填写了缺失的成本值(0),并将合并结果写回。条目从“无成本键”变为“成本键显式设置为 0”。这导致 _is_cost_explicitly_configured() 函数(来自 PR #24949)误认为成本已显式配置,进而使 _is_model_cost_zero() 返回 True,最终 common_checks 跳过了所有预算检查。
环境排查
- 确认 LiteLLM 版本:1.85.0 及更高版本(包括 1.88.1)均受影响。
- 确认数据库后端:问题出现在 DB-backed Proxy 场景中。
- 确认模型配置方式:模型通过 Admin UI 创建,且未设置自定义定价(custom pricing)。
- 确认触发操作:是否在同一个进程内进行了第二次模型注册(如 Router 重建、config sync、model update、UI 编辑)。
解决步骤
- 临时规避:重启 Pod。这能清除
litellm.model_cost中的错误写入,直到下一次模型注册触发。 - 根本修复:应用 Issue #30201 中提出的补丁。该补丁将
register_model()中的写入逻辑改为:仅当某个字段在原始条目和调用者提供的value中均缺失时,才执行 pop 操作(即不写入)。这既允许显式零值(BYOK、免费模型覆盖)正常通过,又能防止合成零值被持久化。 - 确认补丁覆盖范围:补丁应对以下五种场景进行测试:双 Router 复现、稀疏条目(只含 ID)、显式零值条目、实际定价条目、首次注册。
验证方法
应用修复后,运行以下复现代码,检查 litellm.model_cost["fixed-uuid-123"] 在第二次注册后是否仍然仅包含 id 和 db_model 字段(无 input_cost_per_token/output_cost_per_token):
import litellm
from litellm import Router
from litellm.proxy.auth.auth_checks import _is_model_cost_zero
ml = [{"model_name": "gpt-4o-mini",
"litellm_params": {"model": "gpt-4o-mini", "custom_llm_provider": "openai", "api_key": "k"},
"model_info": {"id": "fixed-uuid-123", "db_model": True}}]
Router(model_list=ml)
print(litellm.model_cost["fixed-uuid-123"])
r2 = Router(model_list=ml)
print(litellm.model_cost["fixed-uuid-123"])
gi = r2.get_model_group_info(model_group="gpt-4o-mini")
print(gi.input_cost_per_token, gi.output_cost_per_token)
print(_is_model_cost_zero("gpt-4o-mini", r2))
预期输出:第二次注册后,model_cost["fixed-uuid-123"] 不应包含 input_cost_per_token: 0 / output_cost_per_token: 0,_is_model_cost_zero 返回 False。
参考来源
BerriAI/litellm #30198(原始 Issue)
BerriAI/litellm #30201(修复补丁)



