Skip to content

fix(dashboard): 总 TOKEN 数统计补全 Anthropic 缓存 token#6233

Open
ran411285752 wants to merge 1 commit into
QuantumNous:mainfrom
ran411285752:fix/dashboard-cache-token-count
Open

fix(dashboard): 总 TOKEN 数统计补全 Anthropic 缓存 token#6233
ran411285752 wants to merge 1 commit into
QuantumNous:mainfrom
ran411285752:fix/dashboard-cache-token-count

Conversation

@ran411285752

@ran411285752 ran411285752 commented Jul 15, 2026

Copy link
Copy Markdown

📝 变更描述 / Description

数据看板 Models 视图的“总 TOKEN 数”取自 quota_data.token_used,原写入值为 prompt_tokens + completion_tokens

对于走 /v1/messages(Anthropic 语义)的上游(如 DeepSeek、Anthropic 官方),input_tokens 仅表示未命中缓存的 fresh tokencache_read_input_tokens / cache_creation_input_tokens 未被计入,导致看板数字系统性偏低(实测某日看板约 900 万,而上游面板约 1.2 亿,主要差异来自大量命中的上下文缓存)。

本 PR 做最小修复:在 Anthropic 语义下把缓存 token 加回到 token_used,让看板“总 TOKEN 数”反映真实消耗。

为什么这样改生效:

  • service/text_quota.go 新增 logTotalTokensFromSummary,按 UsageSemantic 判断:
    • Anthropic 语义:PromptTokens + CompletionTokens + CacheTokens + CacheCreationTokens
    • OpenAI 语义:PromptTokens + CompletionTokensprompt_tokens 已含缓存,不再重复加,避免双计)
  • 该总值通过 RecordConsumeLogParams.TotalTokens 传给日志层,RecordConsumeLog 写入 quota_data.token_used 时优先使用,未提供时回退原逻辑,保持其它调用路径兼容。
  • 计费逻辑未改动summary.PromptTokens 仍按原语义参与计费,本次只调整看板统计口径。

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix)

🔗 关联任务 / Related Issue

✅ 提交前检查项 / Checklist

📸 运行证明 / Proof of Work

新增测试 TestLogTotalTokensFromSummary 覆盖两种语义与无缓存场景:

=== RUN   TestLogTotalTokensFromSummary
--- PASS: TestLogTotalTokensFromSummary (0.00s)
ok  	github.com/QuantumNous/new-api/service	0.239s

model 包全量通过:

ok  	github.com/QuantumNous/new-api/model	18.354s

说明:service 包中 TestObserveChannelAffinityUsageCacheByRelayFormat_* 2 个测试在本分支与 origin/main 上均失败(既有 flaky/全局计数器污染,与本次改动无关,本 PR 未触碰 channel_affinity 相关代码)。

Summary by CodeRabbit

  • Bug Fixes

    • Improved token usage reporting for quota and consumption logs.
    • Prevented cached tokens from being counted incorrectly under different provider usage semantics.
    • Included relevant cache read and creation tokens where required for accurate totals.
  • Tests

    • Added coverage for token reporting with and without cached token usage.

Why:
- 数据看板 Models 视图的“总 TOKEN 数”来自 quota_data.token_used,其写入值为
  PromptTokens + CompletionTokens。
- DeepSeek / Anthropic 等使用 /v1/messages(Anthropic 语义)的上游,input_tokens 仅表示
  未命中缓存的 fresh token,cache_read_input_tokens / cache_creation_input_tokens 未计入,
  导致看板数字远低于真实消耗(实测 7 月某日看板约 900 万 vs 上游面板 1.2 亿)。
- 相关上游诉求:QuantumNous#5069(数据看板增加缓存 token 统计)、QuantumNous#4395(Anthropic usage 语义)。

What:
- model/log.go:RecordConsumeLogParams 新增 TotalTokens 字段;RecordConsumeLog 在写入
  quota_data.token_used 时优先使用 TotalTokens,未提供时回退 PromptTokens + CompletionTokens,
  保持旧行为兼容(不影响 RecordTaskBillingLog 等其它路径)。
- service/text_quota.go:新增 logTotalTokensFromSummary,按 UsageSemantic 计算带缓存的总 token:
  Anthropic 语义下补回 cache_read + cache_creation,OpenAI 语义下保持 PromptTokens + CompletionTokens
  (PromptTokens 已含缓存,避免重复计算)。PostTextConsumeQuota 将其通过 TotalTokens 传入日志层。
- service/text_quota_test.go:新增 TestLogTotalTokensFromSummary 覆盖两种语义与无缓存场景。

Impact:
- 仅改变 quota_data.token_used 的统计口径,使其包含缓存 token;计费逻辑未改动
  (summary.PromptTokens 仍按原语义参与计费)。
- 不改数据库:复用已有 token_used 列,无需迁移。
- 历史数据无法自动修正,修复后仅影响新写入的数据。
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Consume-log quota accounting now accepts explicit total tokens. Text quota processing calculates totals from prompt, completion, and Claude cache tokens, then passes them through to quota exports with fallback behavior.

Changes

Consume token accounting

Layer / File(s) Summary
Total-token consume-log contract
model/log.go
RecordConsumeLogParams adds TotalTokens, and quota export uses it or falls back to prompt plus completion tokens.
Quota total calculation and validation
service/text_quota.go, service/text_quota_test.go
Text quota logging calculates Claude-aware totals, passes them to consume logs, and tests OpenAI, cached Claude, and uncached Claude scenarios.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested reviewers: calcium-ion, seefs001

Poem

I’m a bunny counting tokens bright,
Cache-aware totals now hop just right.
Prompt and completion join the queue,
Claude’s cache tokens get counted too.
Logs carry totals, neat and true—
Nibble, test, and ship anew!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: fixing total token counting for Anthropic cache tokens in the dashboard.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
service/text_quota_test.go (1)

743-772: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use assert.Equal for non-fatal value checks.

As per coding guidelines, new or substantially rewritten Go backend tests must use testify/assert for non-fatal value checks, reserving testify/require for setup and fatal assertions. Using assert ensures that if one test case fails, the remaining assertions in the function will still execute and report their results.

♻️ Proposed refactor
 func TestLogTotalTokensFromSummary(t *testing.T) {
 	// OpenAI 语义:PromptTokens 已包含缓存,总 token 不应再加缓存部分,避免重复计算。
 	openAISummary := textQuotaSummary{
 		PromptTokens:          1000,
 		CompletionTokens:      200,
 		CacheTokens:           800,
 		CacheCreationTokens:   100,
 		IsClaudeUsageSemantic: false,
 	}
-	require.Equal(t, 1200, logTotalTokensFromSummary(openAISummary))
+	assert.Equal(t, 1200, logTotalTokensFromSummary(openAISummary))
 
 	// Anthropic 语义:PromptTokens 仅表示 fresh token,需要把 cache_read/cache_creation 加回。
 	claudeSummary := textQuotaSummary{
 		PromptTokens:          100,
 		CompletionTokens:      50,
 		CacheTokens:           200,
 		CacheCreationTokens:   30,
 		IsClaudeUsageSemantic: true,
 	}
-	require.Equal(t, 380, logTotalTokensFromSummary(claudeSummary))
+	assert.Equal(t, 380, logTotalTokensFromSummary(claudeSummary))
 
 	// Anthropic 语义但无缓存:结果与 PromptTokens + CompletionTokens 相同。
 	claudeNoCacheSummary := textQuotaSummary{
 		PromptTokens:          100,
 		CompletionTokens:      50,
 		IsClaudeUsageSemantic: true,
 	}
-	require.Equal(t, 150, logTotalTokensFromSummary(claudeNoCacheSummary))
+	assert.Equal(t, 150, logTotalTokensFromSummary(claudeNoCacheSummary))
 }

(Note: Please ensure github.com/stretchr/testify/assert is imported in this file.)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@service/text_quota_test.go` around lines 743 - 772, Update
TestLogTotalTokensFromSummary to use assert.Equal for all three non-fatal
token-value checks, and ensure the testify/assert package is imported. Keep
require reserved for setup or assertions whose failure must stop the test.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@service/text_quota_test.go`:
- Around line 743-772: Update TestLogTotalTokensFromSummary to use assert.Equal
for all three non-fatal token-value checks, and ensure the testify/assert
package is imported. Keep require reserved for setup or assertions whose failure
must stop the test.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f4319ec3-1c75-4bb4-a717-df8dbae01687

📥 Commits

Reviewing files that changed from the base of the PR and between a63364d and db8abb7.

📒 Files selected for processing (3)
  • model/log.go
  • service/text_quota.go
  • service/text_quota_test.go

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant