[Bug]: Unstable offset pagination in get_daily_activity (order by date only) yields non-deterministic, inflated spend totals

在 LiteLLM 中通过 REST API /user/daily/activity 或 /team/daily/activity 查询用户或团队的日常消费数据时,客户端需要分页遍历所有结果并汇总 metrics.spend 。当某天的行数超过单页大小时(例如一个繁忙的租户每天有数千条请求记录),

[Bug]: Unstable offset pagination in get_daily_activity (order by date only) yields non-deterministic, inflated spend totals

[Bug]: Unstable offset pagination in get_daily_activity (order by date only) yields non-deterministic, inflated spend totals

快速结论:该报错通常发生在调用 /team/daily/activity/user/daily/activity 获取分页消费数据时,返回的 spend 合计值随 page_size 变化,甚至相同请求两次结果不同。优先确认 litellm/proxy/management_endpoints/common_daily_activity.pyget_daily_activity 函数的排序字段是否包含 id 作为唯一性 tiebreaker。

问题场景

在 LiteLLM 中通过 REST API /user/daily/activity/team/daily/activity 查询用户或团队的日常消费数据时,客户端需要分页遍历所有结果并汇总 metrics.spend。当某天的行数超过单页大小时(例如一个繁忙的租户每天有数千条请求记录),使用偏移分页(offset pagination)且仅按 date 排序会导致非确定性结果。

报错原文

/team/daily/activity returned non-deterministic results for the same date range:
page_size=1000 run 1: 15,231.91
page_size=1000 run 2: 13,977.13

Correct total (via aggregated endpoint or single large page): 13,977.13

Summed totals vary by page_size:
page_size 50:   13,990.72
page_size 100:  16,393.02
page_size 250:  13,955.38
page_size 500:  13,977.13
page_size 1000: 13,977.13 (but non-deterministic on re-run)
page_size 5000: 13,977.13

原因分析

问题根源在 litellm/proxy/management_endpoints/common_daily_activity.pyget_daily_activity 函数中,数据查询使用了偏移分页,但排序键仅包含 date 字段。由于 date 并非唯一键(同一天内有多行,每行对应不同的 api_key、model 等),偏移分页的排序结果是不确定性的。这会导致不同查询之间的行顺序不一致:一些行被跳过(导致汇总不足),另一些行在多个页面中被重复返回(导致汇总过度)。结果值依赖于 page_size 和查询时间。

环境排查

  • LiteLLM 版本:已验证在 v1.88.1、v1.88.2、v1.89.2 以及 main 分支上均可复现。
  • 数据量:当某天的行数超过单页大小时(例如每天数千行),问题易触发。
  • 依赖:确保 litellm 包和相关数据库(如 PostgreSQL)版本一致。

解决步骤

  1. 打开文件 litellm/proxy/management_endpoints/common_daily_activity.py,定位到 get_daily_activity 函数中的 find_many 调用。
  2. 找到 order 参数,当前为 [{"date": "desc"}]
  3. 添加唯一性 tiebreaker 字段:将 order 修改为 [{"date": "desc"}, {"id": "asc"}],其中 idLiteLLM_DailyUserSpendLiteLLM_DailyTeamSpend 表中的主键(类型为 String @id @default(uuid()))。
  4. 保存文件并重启 LiteLLM 服务。

注意:尽管 PR #30167 中已包含此修复,但实际发布版本中该变更未被合并。如果上述修改不存在,请手动执行。另外,/team/daily/activity/aggregated 端点目前返回 404(缺少汇总端点),该问题作为后续关注事项。

验证方法

对同一数据和相同日期范围执行以下测试:

  • 使用不同的 page_size(如 50、100、500、1000)多次调用 /team/daily/activity,汇总所有页面的 metrics.spend,确认结果稳定且与 /user/daily/activity/aggregated 返回的值一致。
  • 反复执行同一请求(例如 page_size=1000),确认结果不再变化。
  • 检查日志或单元测试(如 test_get_daily_activity_order_has_id_tiebreaker)是否存在。

参考来源

BerriAI/litellm #30164

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

celebrityanime
celebrityanime
文章: 8664

发表回复

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