[Bug]: Responses-API bridge drops the SpendLogs row for non-streaming /v1/chat/completions (standard_logging_object not found)

当 LiteLLM Proxy 上声明为 mode: responses 的模型在非流式 /v1/chat/completions 请求中走 chat→responses 桥接,而底层 provider 又强制 stream=True 时,调用虽然返回 HTTP 200,但 standard_log

快速结论:当 LiteLLM Proxy 上声明为 mode: responses 的模型在非流式 /v1/chat/completions 请求中走 chat→responses 桥接,而底层 provider 又强制 stream=True 时,调用虽然返回 HTTP 200,但 standard_logging_object 未构建、response_cost 为 None,导致 LiteLLM_SpendLogs 不落行。优先排查该模型是否命中 responses 桥接 + 强制流式 provider。

适用环境:LiteLLM Proxy;Issue 确认于安装版 v1.95.0 与 ghcr.io/berriai/litellm-database:v1.100.0;Python 3.13;PostgreSQL + Redis;两副本部署。触发 provider 包括原生 chatgpt/*,以及生产观察到的 AWS Bedrock Claude(bedrock/us.anthropic.claude-opus-4-8、bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0)。CUDA、显卡在 Issue 中无证据。

最快修复方案:升级到包含 #41235 修复的 LiteLLM 版本;该修复让非流式桥接调用不再走流式迭代器,spend 行可正常写入。

注意事项:#41235 的发布版本号在 Issue 中未明确,需按实际 release notes 确认。Bedrock 侧历史上无法证明每一次告警都走同一 iterator/bridge 路径,因此属于强佐证而非唯一根因证明。若暂时无法升级,Issue 中未给出已验证的配置级绕过方案,可优先考虑临时改用流式请求路径来保住计费行,但这会改变调用方行为。

问题场景

在 LiteLLM Proxy 中,把某个模型通过 model_info: mode: responses 声明为 responses 模式,并对该模型发起非流式的 POST /v1/chat/completions 请求。若该模型的 provider 在子调用中强制设置 stream = True(例如原生 chatgpt/*,在 litellm/llms/chatgpt/responses/transformation.py 中无条件设置 request["stream"] = True),则会触发该问题。调用方拿到正确的 200 响应与 usage,但 SpendLogs 中没有对应记录,日志里出现 standard_logging_object not found 的 traceback。Issue 正文给出了隔离虚拟 key 的计数结果:非流式 /v1/chat/completions 在 5 分钟内没有任何 SpendLogs 行;同一 key 的 stream: true 请求有 1 行且 call_type: responses;失败请求(4xx)落的是 error 行。约 7 小时汇总:2394 次成功的非流式 POST /v1/chat/completions 对应约 0 行,而 1336 次 POST /v1/responses 产生约 1561 行 aresponses,且计费错误出现次数与非流式 chat 请求 1:1 对应(2068 次),该 traceback 风暴约占整个代理日志输出的 43%。

报错原文

[Bug]: Responses-API bridge drops the SpendLogs row for non-streaming /v1/chat/completions (standard_logging_object not found)

Cost tracking failed for model=<model>
Debug info - standard_logging_object not found

call_type='responses'  stream=False  model='gpt-5.6-terra'
standard_logging_object=None  response_cost=None

原因分析

按 Issue 正文给出的调用链(行号基于安装的 v1.95.0 包),最可能的原因如下:

  1. litellm/main.py:5404 判断 responses_api_model_info.get("mode") == "responses" 且未 skip,则路由进 chat→responses 桥接。
  2. litellm/completion_extras/litellm_responses_transformation/transformation.py:436,443 中,桥接的嵌套调用共享父级 Logging 对象并把 call_type 改成 responses。
  3. provider 强制 stream = True,因此嵌套的 aresponses()(.../handler.py:343)返回原始流式迭代器,桥接在 .../handler.py:376 通过 _collect_response_from_stream_async 自行把流抽干。
  4. 结果对象是原始迭代器,standard_logging_object 始终没被构建,response_cost 保持 None。
  5. litellm/proxy/hooks/proxy_track_cost_callback.py 中数据库写入位于 if response_cost is not None: 内(约 :222、:240 _update_database_and_spend_counters),条件不满足就完全不会持久化;执行到 :305 抛错,被本地捕获后经 spend_tracking/spend_log_error_logger.py:81 记录。

正文还指出,对 cost callback 加桩后每次请求只产生一次调用,且此处 model 已丢失 provider 前缀(’gpt-5.6-terra’),而正常写入的行会带 chatgpt/gpt-5.6-terra,可用于日志区分。此外对 litellm_core_utils/litellm_logging.py::Logging.async_success_handler 加桩显示该路径上它从未被调用,说明失败回调是经由其他路径分发的(正文未继续深挖)。

评论中补充的可能机制:非流式调用方把已完成的 Responses 迭代器抽干时,success logging 收到的是 ResponseCompletedEvent 包装对象而非内层 response,导致标准日志载荷与 response_cost 缺失,cost callback 无法写 SpendLog、也无法更新 spend 计数器。评论者提供了窄范围本地兼容 backport,思路是保留既有 detached-copy 行为,仅在非流式 success logging 时解包内层 ResponsesAPIResponse,并指出这是对 #40139 方案思路的复现。

环境排查

  • 确认 LiteLLM Proxy 版本:Issue 在 v1.95.0 与 ghcr.io/berriai/litellm-database:v1.100.0 上复现。
  • 确认 Python 版本:生产 Bedrock 环境为 Python 3.13。
  • 确认部署形态:PostgreSQL + Redis,两个 proxy 副本(Bedrock 生产环境)。
  • 确认该模型是否被声明为 model_info: mode: responses,即是否命中 chat→responses 桥接。
  • 确认底层 provider 是否强制 stream = True:已知 chatgpt/*;评论建议一并检查 Gemini responses mode 等其他 provider 是否有同样模式。
  • 确认相关计费开关状态,例如 Bedrock 环境中的 enable_anthropic_prompt_caching: true,以及 pre_call guardrail(如 Headroom)是否成功通过。
  • 在日志中确认 Cost tracking failed for model= 与 standard_logging_object not found 是否与非流式 /v1/chat/completions 请求 1:1 出现。
  • 检查日志中 model 字段是否丢失 provider 前缀,用以判断是否走了失败路径。

解决步骤

  1. 先建立可复现的最小计数基线:使用隔离的虚拟 key,分别发一次非流式 /v1/chat/completions 和一次 stream: true 请求,只统计该 key 在 LiteLLM_SpendLogs 中的行数,确认是否只有流式路径落行。
  2. 确认该模型是否走 responses 桥接(mode: responses),以及对应 provider 是否在子调用中强制 stream = True。
  3. 升级到包含 #41235 的 LiteLLM 版本。Issue 中维护者确认该修复「让非流式桥接调用不再走流式迭代器,因此 spend 行可以落库」,这是已验证的首选处理方式。
  4. 升级版本号需按实际 release notes 确认,#41235 的具体稳定发布版本在 Issue 中未明确说明,不要按推测版本升级。
  5. 若暂时无法升级,可优先尝试改为走流式请求路径(同一模型的 stream: true 在 Issue 中确认可正常计费),但需评估对调用方兼容性的影响。
  6. 评论中提到的 #40139 思路与本地 backport(非流式 success logging 时解包内层 ResponsesAPIResponse)属于窄范围兼容修复,尚未确认为官方最终方案,仅作参考,不建议在生产直接套用未验证补丁。
  7. 若你的环境是 Bedrock 而非 chatgpt/*,注意 Issue 正文明示 Bedrock 历史日志不足以证明每次告警都走同一 iterator/bridge 路径,因此升级后仍需按验收标准逐项核对。

验证方法

按评论中提出的升级验收标准逐项确认:

  • 每一次成功的可计费请求恰好产生一条 SpendLog。
  • 该行 response_cost 非 null。
  • 对应 key / user / team 的计数增量一致。
  • 不再出现 failed_tracking_spend 或 standard_logging_object not found 告警。
  • 日志中失败路径特有的无 provider 前缀 model 字段不再出现于非流式请求。

也可采用评论中提到的周期性对账方式:把 provider 侧 usage 报表与内部 spend 日志定期比对,对偏差超过 1% 的情况告警;或做简单健康检查——发一个已知的非流式请求,等 60 秒后查询该 key + 时间窗口的 LiteLLM_SpendLogs,缺失即告警。

参考来源

BerriAI/litellm #36426

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 27515

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注