fix(usage): 统一用户排行榜 Token 统计口径

- 将用户排行榜 Tokens 调整为与仪表盘今日 Token 一致
- 统一 effective input、cache creation fallback、cache read 计算规则
- 补齐 Postgres 聚合、admin 内存构建和内存仓库回退路径
- 增加缓存命中场景的统计口径测试
This commit is contained in:
AAEE86
2026-05-11 22:34:37 +08:00
parent e16a225eb3
commit bfbf7a4663
8 changed files with 133 additions and 54 deletions

View File

@@ -1,3 +1,4 @@
use crate::observability::usage::admin_usage_total_tokens;
use aether_data::repository::auth::StoredAuthApiKeySnapshot;
use aether_data_contracts::repository::{
provider_catalog::StoredProviderCatalogProvider,
@@ -1799,12 +1800,7 @@ pub fn build_user_leaderboard_items(
cost: 0.0,
});
entry.requests = entry.requests.saturating_add(1);
entry.tokens = entry.tokens.saturating_add(
item.input_tokens
.saturating_add(item.output_tokens)
.saturating_add(item.cache_creation_input_tokens)
.saturating_add(item.cache_read_input_tokens),
);
entry.tokens = entry.tokens.saturating_add(admin_usage_total_tokens(item));
entry.cost += item.total_cost_usd;
}
@@ -2202,4 +2198,24 @@ mod tests {
assert_eq!(leaderboard.len(), 1);
assert_eq!(leaderboard[0].name, "alice");
}
#[test]
fn user_leaderboard_tokens_match_dashboard_effective_token_rules() {
let item = StoredRequestUsageAudit {
input_tokens: 100,
output_tokens: 20,
total_tokens: 999,
cache_creation_input_tokens: 0,
cache_creation_ephemeral_5m_input_tokens: 12,
cache_creation_ephemeral_1h_input_tokens: 8,
cache_read_input_tokens: 80,
..sample_usage(Some("legacy-default"))
};
let leaderboard =
build_user_leaderboard_items(&[item], &BTreeMap::new(), false, false, false);
assert_eq!(leaderboard.len(), 1);
assert_eq!(leaderboard[0].tokens, 140);
}
}

View File

@@ -1135,7 +1135,7 @@ pub fn admin_usage_record_json(
}
pub fn admin_usage_total_tokens(item: &StoredRequestUsageAudit) -> u64 {
item.input_tokens
admin_usage_effective_input_tokens(item)
.saturating_add(item.output_tokens)
.saturating_add(admin_usage_cache_creation_tokens(item))
.saturating_add(item.cache_read_input_tokens)
@@ -2292,7 +2292,7 @@ mod tests {
admin_usage_has_fallback, admin_usage_is_failed, admin_usage_is_success,
admin_usage_matches_search, admin_usage_matches_status, admin_usage_matches_username,
admin_usage_record_json, admin_usage_resolve_request_capture_body,
admin_usage_upstream_is_stream, build_admin_usage_detail_payload,
admin_usage_total_tokens, admin_usage_upstream_is_stream, build_admin_usage_detail_payload,
};
use aether_data_contracts::repository::usage::{StoredRequestUsageAudit, UsageBodyField};
@@ -3054,6 +3054,22 @@ mod tests {
assert_eq!(payload["total_tokens"], 50);
}
#[test]
fn admin_usage_total_tokens_uses_effective_input_for_cached_openai_usage() {
let item = StoredRequestUsageAudit {
input_tokens: 100,
output_tokens: 20,
total_tokens: 999,
cache_creation_input_tokens: 0,
cache_creation_ephemeral_5m_input_tokens: 12,
cache_creation_ephemeral_1h_input_tokens: 8,
cache_read_input_tokens: 80,
..sample_usage("completed", Some(200), None)
};
assert_eq!(admin_usage_total_tokens(&item), 140);
}
#[test]
fn detail_payload_exposes_typed_settlement_section() {
let item = StoredRequestUsageAudit {