Skip to content

fix: subtract cached_tokens from input_tokens in OpenAI→Claude usage conversion - #5850

Open
sunhatSH wants to merge 2 commits into
QuantumNous:mainfrom
sunhatSH:fix/glm-cache-token-mapping
Open

fix: subtract cached_tokens from input_tokens in OpenAI→Claude usage conversion#5850
sunhatSH wants to merge 2 commits into
QuantumNous:mainfrom
sunhatSH:fix/glm-cache-token-mapping

Conversation

@sunhatSH

@sunhatSH sunhatSH commented Jul 2, 2026

Copy link
Copy Markdown

变更描述 / Description

功能概述

修复 OpenAI 兼容上游通过 /v1/messages Anthropic 格式请求时,input_tokens 未扣除缓存部分导致数值虚高的问题。修复覆盖两种场景:

  1. Cache-Write(首次请求,缓存写入):原有分支已处理,保留
  2. Cache-Read(重复请求,纯缓存读取,CacheWriteTokens==0CachedTokens>0):原代码漏掉,本次修复补齐

背景

OpenAI 兼容上游返回的 prompt_tokens 是全量 token 数(包含已缓存的 token),prompt_tokens_details.cached_tokens 标明缓存命中数。Anthropic 协议中 input_tokens 语义是不含缓存的纯输入,缓存单独放在 cache_read_input_tokens

旧代码只在 CacheWriteTokens > 0 时做减法,纯 cache-read 场景(第二次相同请求命中缓存)绕过了条件,导致 input_tokens 包含全量 + cache_read_input_tokens 再次加上缓存 = 双倍统计,可能触发客户端提前自动压缩上下文。

参考:HsMirage 在 #4395 的详细分析。

具体变更

文件service/relayconvert/internal/oai_chat/to_claude_messages_resp.go

buildClaudeUsageFromOpenAIUsage() 函数:条件从仅 CacheWriteTokens > 0 扩展为 CacheWriteTokens > 0 || CachedTokens > 0

// 旧
if oaiUsage.PromptTokensDetails.CacheWriteTokens > 0 {

// 新
if oaiUsage.PromptTokensDetails.CacheWriteTokens > 0 || oaiUsage.PromptTokensDetails.CachedTokens > 0 {

测试

新增 TestBuildClaudeUsageFromOpenAIPureCacheRead 回归用例:

输入 期望
PromptTokens=15305, CachedTokens=15104, CacheWriteTokens=0 InputTokens=201
CompletionTokens=5 CacheReadInputTokens=15104
OutputTokens=5

总上下文 = 201 + 15104 = 15305(不双倍统计)

关联

Fixes #4395

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

buildClaudeUsageFromOpenAIUsage now subtracts cached tokens from OpenAI prompt token totals before assigning Claude InputTokens, while leaving output and cache-creation fields unchanged.

Changes

Token accounting fix

Layer / File(s) Summary
Cached-token subtraction in input token calculation
service/convert.go
Computes inputTokens from PromptTokens, subtracts valid PromptTokensDetails.CachedTokens values, and uses the adjusted result for Claude InputTokens.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Possibly related PRs

  • QuantumNous/new-api#1120: Both PRs adjust OpenAI-to-Claude token accounting in service/convert.go to handle cached tokens in prompt totals.
  • QuantumNous/new-api#2811: Both PRs adjust Claude usage/token fields to account for cached-token counts in Claude usage conversion.
  • QuantumNous/new-api#3438: Both PRs modify the same conversion path in service/convert.go for Claude/OpenAI usage cache handling.

Suggested reviewers: seefs001

Poem

A rabbit counted tokens, hop and flop,
Then trimmed the cached ones off the top.
Now input numbers stay nice and true,
With tidy little totals hopping through. 🐰

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: subtracting cached tokens from input_tokens in usage conversion.
Linked Issues check ✅ Passed The code matches issue #4395 by excluding cached tokens from Claude input_tokens while leaving cache fields intact.
Out of Scope Changes check ✅ Passed The patch stays focused on the usage conversion fix and adds no unrelated changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ 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/convert.go (1)

235-251: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Verbose inline rationale comment.

The 16-line comment block is helpful context but noticeably longer than typical inline comments elsewhere in this file. Consider trimming to the essential rationale (why subtract, and the guard condition) and moving the provider-specific narrative to a commit message or doc if not already covered there.

🤖 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/convert.go` around lines 235 - 251, Shorten the inline rationale
comment in the conversion logic so it keeps only the essential reason for the
cached-token subtraction and the guard condition. Update the comment near the
prompt_tokens/cache_read_input_tokens handling in convert.go to be concise, and
move the provider-specific examples and extended explanation out of the inline
comment if needed.
🤖 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/convert.go`:
- Around line 235-251: Shorten the inline rationale comment in the conversion
logic so it keeps only the essential reason for the cached-token subtraction and
the guard condition. Update the comment near the
prompt_tokens/cache_read_input_tokens handling in convert.go to be concise, and
move the provider-specific examples and extended explanation out of the inline
comment if needed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c088305c-8f85-4f58-9ef3-f1dd111b74ed

📥 Commits

Reviewing files that changed from the base of the PR and between 52858ad and 5836ebe.

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

@sunhatSH

sunhatSH commented Jul 2, 2026

Copy link
Copy Markdown
Author

Friendly ping for review. This fixes #4395 which has multiple users confirming the issue. The change is minimal (4 lines of logic + 4 lines of comment in a single function) and has been verified with GLM, DeepSeek, Qwen, and Claude models.

Previously only CacheWriteTokens > 0 triggered the deduplication of
cached tokens from input_tokens.  Pure cache-read responses (CachedTokens > 0
but CacheWriteTokens == 0) bypassed the guard, causing input_tokens to
double-count cached tokens when summed with cache_read_input_tokens.

Now the condition also covers CachedTokens > 0 (pure cache-read),
matching HsMirage's analysis in QuantumNous#4395.

Fixes QuantumNous#4395
@sunhatSH
sunhatSH force-pushed the fix/glm-cache-token-mapping branch from 39ec3e5 to f212f00 Compare July 13, 2026 12:19
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.

/v1/messages 格式请求 OpenAI Compatible 上游返回的usage

1 participant