Skip to content

feat(service): 优化Claude缓存创建token处理逻辑 - #6355

Open
kocor01 wants to merge 2 commits into
QuantumNous:mainfrom
kocor01:main
Open

feat(service): 优化Claude缓存创建token处理逻辑#6355
kocor01 wants to merge 2 commits into
QuantumNous:mainfrom
kocor01:main

Conversation

@kocor01

@kocor01 kocor01 commented Jul 20, 2026

Copy link
Copy Markdown

⚠️ 提交说明 / PR Notice

Important

  • 请提供人工撰写的简洁摘要,避免直接粘贴未经整理的 AI 输出。

📝 变更描述 / Description

现象
Tiered billing(动态计费)模式下,使用 Claude 上游返回的 billing_usage 时,cache_creation_input_tokens(缓存写入 Token)在上游返回了总量但未拆分 5m/1h 的情况下,被完全漏计,值为0。总费用未包含缓存写入 Token 的费用。

问题根源
上游数据特征: Claude API 返回了 cache_creation_input_tokens: n(总量),但 cache_creation 子对象为 null,没有 ephemeral_5m_input_tokens / ephemeral_1h_input_tokens 拆分字段。

两处级联 Bug:

① service/billing_usage.go — 数据映射层

cacheCreation5m := claudeUsage.GetCacheCreation5mTokens() // 0(CacheCreation==nil)
if cacheCreation5m == 0 {
cacheCreation5m = claudeUsage.ClaudeCacheCreation5mTokens // 0(也被设为0)
}
// cacheCreation5m = 0,总量 n 丢掉了
GetCacheCreation5mTokens() 返回 0(CacheCreation 为 nil),回退到 ClaudeCacheCreation5mTokens 也是 0(因为 relay 代码同样从 GetCacheCreation5mTokens() 赋值),导致 cacheCreation5m = 0,没有继续兜底到 CacheCreationInputTokens 总量。

② service/tiered_settle.go — 计费参数构建层

cc5m := float64(usage.PromptTokensDetails.CacheCreationTokensTotal()) // = n ✅
if usage.UsageSemantic == "anthropic" {
cc5m = float64(usage.ClaudeCacheCreation5mTokens) // = 0 🔴
}
cc5m 先通过 CacheCreationTokensTotal() 正确初始化为 n,然后被 ClaudeCacheCreation5mTokens(0)无条件覆盖,导致表达式计算时 cc=0。

解决方案
修复 ① — 数据映射层添加兜底(service/billing_usage.go)

当拆分字段和旧字段均为 0 时,兜底到 CacheCreationInputTokens 总量:

if cacheCreation5m == 0 && claudeUsage.CacheCreationInputTokens > 0 {
cacheCreation5m = claudeUsage.CacheCreationInputTokens
}
if cacheCreation1h == 0 && claudeUsage.CacheCreationInputTokens > 0 && cacheCreation5m == 0 {
cacheCreation1h = claudeUsage.CacheCreationInputTokens
}
1h 的兜底加 cacheCreation5m == 0 条件,防止总量被两边重复使用。

修复 ② — 计费参数层加防御检查(service/tiered_settle.go)

只当有真实拆分值时才覆盖,否则保留 CacheCreationTokensTotal() 的初始值:

if usage.ClaudeCacheCreation1hTokens > 0 {
cc1h = float64(usage.ClaudeCacheCreation1hTokens)
}
if usage.ClaudeCacheCreation5mTokens > 0 {
cc5m = float64(usage.ClaudeCacheCreation5mTokens)
}

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix) - 请关联对应 Issue,避免将设计取舍、理解偏差或预期不一致直接归类为 bug
  • ✨ 新功能 (New feature) - 重大特性建议先通过 Issue 沟通
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 IssuesPRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

已在生产环境验证。
修复前:
image

修复后:
image

Summary by CodeRabbit

Summary by CodeRabbit

  • Bug Fixes
    • Improved billing accuracy for Anthropic cache-creation token usage by adding an extra fallback when duration-specific cache-token counts are unavailable.
    • Refined tiered billing calculations to avoid zero-value cache-creation token fields from impacting the derived pricing parameters.

- 在billing_usage.go中添加对CacheCreationInputTokens的fallback处理,
  当原有缓存token为0时使用新的输入token字段

- 在tiered_settle.go中添加对Claude缓存创建token的非零值检查,
  避免无效的零值参与计算
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f0eb9a90-2d1d-476e-8326-558b90e59a84

📥 Commits

Reviewing files that changed from the base of the PR and between 4e715fd and 6cd0d77.

📒 Files selected for processing (1)
  • service/billing_usage.go

Walkthrough

Claude cache-creation token extraction now has an additional fallback, and tiered settlement only initializes corresponding cache fields for positive values.

Changes

Claude cache billing

Layer / File(s) Summary
Recover Claude cache-creation usage
service/billing_usage.go
usageFromClaudeBillingUsage falls back to CacheCreationInputTokens when both 1h and 5m cache-creation values are zero.
Conditionally build settlement parameters
service/tiered_settle.go
BuildTieredTokenParams assigns cc1h and cc5m only when their source values are positive.

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

Possibly related issues

Possibly related PRs

Suggested reviewers: calcium-ion

Poem

I’m a rabbit with tokens to spare,
Cache crumbs now travel with care.
One hour, five minutes,
The counts fit their limits,
And billing hops smoothly from there.

🚥 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 标题准确概括了此次对Claude缓存创建token处理逻辑的优化,和变更内容一致。
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.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@service/billing_usage.go`:
- Around line 132-141: The Claude cache fallback logic must preserve the
original presence of the 5m and 1h split values before populating fallbacks.
Update the surrounding Claude usage handling to record those original
zero/nonzero states, then use them when assigning CacheCreationInputTokens so
both originally absent splits receive the intended 1h fallback without
misattributing it to 5m. Add coverage for both split values initially being
zero.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 02c5f75e-33b6-4cd7-bf65-5e2c836ed6fe

📥 Commits

Reviewing files that changed from the base of the PR and between e0d5156 and 4e715fd.

📒 Files selected for processing (2)
  • service/billing_usage.go
  • service/tiered_settle.go

Comment thread service/billing_usage.go Outdated
移除重复的条件判断逻辑,将CacheCreationInputTokens的回退赋值集中在5分钟缓存处理中,
并添加注释说明Claude标准缓存TL为5分钟。简化了代码结构,避免了不必要的条件检查。
@Calcium-Ion
Calcium-Ion force-pushed the main branch 2 times, most recently from 51fdfc5 to 2b6f1df Compare August 30, 2026 15:03
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