fix: claude token统计问题

This commit is contained in:
shaw
2025-08-17 00:41:16 +08:00
parent 4643e471ee
commit 77f80ef1f4
2 changed files with 55 additions and 39 deletions

View File

@@ -250,19 +250,13 @@ async function handleChatCompletion(req, res, apiKeyData) {
(usage) => { (usage) => {
// 记录使用统计 // 记录使用统计
if (usage && usage.input_tokens !== undefined && usage.output_tokens !== undefined) { if (usage && usage.input_tokens !== undefined && usage.output_tokens !== undefined) {
const inputTokens = usage.input_tokens || 0
const outputTokens = usage.output_tokens || 0
const cacheCreateTokens = usage.cache_creation_input_tokens || 0
const cacheReadTokens = usage.cache_read_input_tokens || 0
const model = usage.model || claudeRequest.model const model = usage.model || claudeRequest.model
// 使用新的 recordUsageWithDetails 方法来支持详细的缓存数据
apiKeyService apiKeyService
.recordUsage( .recordUsageWithDetails(
apiKeyData.id, apiKeyData.id,
inputTokens, usage, // 直接传递整个 usage 对象,包含可能的 cache_creation 详细数据
outputTokens,
cacheCreateTokens,
cacheReadTokens,
model, model,
accountId accountId
) )
@@ -328,13 +322,11 @@ async function handleChatCompletion(req, res, apiKeyData) {
// 记录使用统计 // 记录使用统计
if (claudeData.usage) { if (claudeData.usage) {
const { usage } = claudeData const { usage } = claudeData
// 使用新的 recordUsageWithDetails 方法来支持详细的缓存数据
apiKeyService apiKeyService
.recordUsage( .recordUsageWithDetails(
apiKeyData.id, apiKeyData.id,
usage.input_tokens || 0, usage, // 直接传递整个 usage 对象,包含可能的 cache_creation 详细数据
usage.output_tokens || 0,
usage.cache_creation_input_tokens || 0,
usage.cache_read_input_tokens || 0,
claudeRequest.model, claudeRequest.model,
accountId accountId
) )

View File

@@ -279,16 +279,10 @@ class ClaudeRelayService {
if (responseBody && responseBody.usage) { if (responseBody && responseBody.usage) {
const { usage } = responseBody const { usage } = responseBody
logger.info('📊 === Non-Stream Request Usage Summary ===', { // 打印原始usage数据为JSON字符串
request_model: requestBody.model, logger.info(
response_model: responseBody.model || requestBody.model, `📊 === Non-Stream Request Usage Summary === Model: ${requestBody.model}, Usage: ${JSON.stringify(usage)}`
input_tokens: usage.input_tokens || 0, )
output_tokens: usage.output_tokens || 0,
cache_creation_tokens: usage.cache_creation_input_tokens || 0,
cache_read_tokens: usage.cache_read_input_tokens || 0,
api_key: apiKeyData.name,
account_id: accountId
})
} else { } else {
// 如果没有usage数据使用估算值 // 如果没有usage数据使用估算值
const inputTokens = requestBody.messages const inputTokens = requestBody.messages
@@ -1008,13 +1002,15 @@ class ClaudeRelayService {
// 如果已经收集到了input数据和output数据这是一个完整的usage // 如果已经收集到了input数据和output数据这是一个完整的usage
if (currentUsageData.input_tokens !== undefined) { if (currentUsageData.input_tokens !== undefined) {
logger.info( logger.debug(
'🎯 Complete usage data collected for model:', '🎯 Complete usage data collected for model:',
currentUsageData.model currentUsageData.model,
'- Input:',
currentUsageData.input_tokens,
'Output:',
currentUsageData.output_tokens
) )
// 触发回调记录这个usage // 保存到列表中,但不立即触发回调
usageCallback(currentUsageData)
// 保存到列表中
allUsageData.push({ ...currentUsageData }) allUsageData.push({ ...currentUsageData })
// 重置当前数据,准备接收下一个 // 重置当前数据,准备接收下一个
currentUsageData = {} currentUsageData = {}
@@ -1080,7 +1076,6 @@ class ClaudeRelayService {
if (currentUsageData.output_tokens === undefined) { if (currentUsageData.output_tokens === undefined) {
currentUsageData.output_tokens = 0 // 如果没有output设为0 currentUsageData.output_tokens = 0 // 如果没有output设为0
} }
usageCallback(currentUsageData)
allUsageData.push(currentUsageData) allUsageData.push(currentUsageData)
} }
@@ -1104,16 +1099,45 @@ class ClaudeRelayService {
{} {}
) )
logger.info('📊 === Stream Request Usage Summary ===', { // 打印原始的usage数据为JSON字符串避免嵌套问题
request_body_model: body.model, logger.info(
total_input_tokens: totalUsage.input_tokens, `📊 === Stream Request Usage Summary === Model: ${body.model}, Total Events: ${allUsageData.length}, Usage Data: ${JSON.stringify(allUsageData)}`
total_output_tokens: totalUsage.output_tokens, )
total_cache_creation: totalUsage.cache_creation_input_tokens,
total_cache_read: totalUsage.cache_read_input_tokens, // 一般一个请求只会使用一个模型即使有多个usage事件也应该合并
models_used: [...new Set(totalUsage.models)], // 计算总的usage
usage_events_count: allUsageData.length, const finalUsage = {
detailed_usage: allUsageData input_tokens: totalUsage.input_tokens,
output_tokens: totalUsage.output_tokens,
cache_creation_input_tokens: totalUsage.cache_creation_input_tokens,
cache_read_input_tokens: totalUsage.cache_read_input_tokens,
model: allUsageData[allUsageData.length - 1].model || body.model // 使用最后一个模型或请求模型
}
// 如果有详细的cache_creation数据合并它们
let totalEphemeral5m = 0
let totalEphemeral1h = 0
allUsageData.forEach((usage) => {
if (usage.cache_creation && typeof usage.cache_creation === 'object') {
totalEphemeral5m += usage.cache_creation.ephemeral_5m_input_tokens || 0
totalEphemeral1h += usage.cache_creation.ephemeral_1h_input_tokens || 0
}
}) })
// 如果有详细的缓存数据添加到finalUsage
if (totalEphemeral5m > 0 || totalEphemeral1h > 0) {
finalUsage.cache_creation = {
ephemeral_5m_input_tokens: totalEphemeral5m,
ephemeral_1h_input_tokens: totalEphemeral1h
}
logger.info(
'📊 Detailed cache creation breakdown:',
JSON.stringify(finalUsage.cache_creation)
)
}
// 调用一次usageCallback记录合并后的数据
usageCallback(finalUsage)
} }
// 处理限流状态 // 处理限流状态