From f56301560ea14cef2b9598652e9400759b484ec1 Mon Sep 17 00:00:00 2001 From: chengqian Date: Mon, 17 Aug 2026 11:52:27 +0800 Subject: [PATCH] =?UTF-8?q?fix(model):=E4=BF=AE=E5=A4=8Dgemini=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E6=80=9D=E8=80=83token=E4=BA=8C=E6=AC=A1=E8=AE=A1?= =?UTF-8?q?=E8=B4=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- relay/channel/openai/gemini_response.go | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/relay/channel/openai/gemini_response.go b/relay/channel/openai/gemini_response.go index e7e5779..64729a1 100644 --- a/relay/channel/openai/gemini_response.go +++ b/relay/channel/openai/gemini_response.go @@ -172,9 +172,19 @@ func handleGeminiInboundStream(ctx context.Context, resp *http.Response, info *c FinishReason: reason, }} if usage.PromptTokens > 0 || usage.CompletionTokens > 0 { + // Gemini 语义:CandidatesTokenCount 不含 thoughts,OpenAI CompletionTokens 已含 reasoning + // 需要扣减 reasoning 避免双计(Gemini 客户端按 total = prompt + candidates + thoughts 汇总) + candidatesTokens := usage.CompletionTokens + if usage.CompletionTokenDetails != nil && usage.CompletionTokenDetails.ReasoningTokens > 0 { + candidatesTokens -= usage.CompletionTokenDetails.ReasoningTokens + if candidatesTokens < 0 { + candidatesTokens = 0 + } + } + finalChunk.UsageMetadata = &dto.GeminiUsageMetadata{ PromptTokenCount: usage.PromptTokens, - CandidatesTokenCount: usage.CompletionTokens, + CandidatesTokenCount: candidatesTokens, TotalTokenCount: usage.TotalTokens, } if usage.PromptTokensDetails != nil { @@ -220,9 +230,19 @@ func openAIToGeminiResponse(openaiResp *dto.ChatCompletionResponse, info *common resp.Candidates = []dto.GeminiCandidate{candidate} + // Gemini 语义:CandidatesTokenCount 不含 thoughts,OpenAI CompletionTokens 已含 reasoning + // 需要扣减 reasoning 避免双计(Gemini 客户端按 total = prompt + candidates + thoughts 汇总) + candidatesTokens := openaiResp.Usage.CompletionTokens + if openaiResp.Usage.CompletionTokenDetails != nil && openaiResp.Usage.CompletionTokenDetails.ReasoningTokens > 0 { + candidatesTokens -= openaiResp.Usage.CompletionTokenDetails.ReasoningTokens + if candidatesTokens < 0 { + candidatesTokens = 0 + } + } + resp.UsageMetadata = &dto.GeminiUsageMetadata{ PromptTokenCount: openaiResp.Usage.PromptTokens, - CandidatesTokenCount: openaiResp.Usage.CompletionTokens, + CandidatesTokenCount: candidatesTokens, TotalTokenCount: openaiResp.Usage.TotalTokens, } if openaiResp.Usage.PromptTokensDetails != nil {