File size: 6,896 Bytes
bbb1195 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | // 模型名称映射
use std::collections::HashMap;
use once_cell::sync::Lazy;
static CLAUDE_TO_GEMINI: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
let mut m = HashMap::new();
// 直接支持的模型
m.insert("claude-opus-4-5-thinking", "claude-opus-4-5-thinking");
m.insert("claude-sonnet-4-5", "claude-sonnet-4-5");
m.insert("claude-sonnet-4-5-thinking", "claude-sonnet-4-5-thinking");
// 别名映射
m.insert("claude-sonnet-4-5-20250929", "claude-sonnet-4-5-thinking");
m.insert("claude-3-5-sonnet-20241022", "claude-sonnet-4-5");
m.insert("claude-3-5-sonnet-20240620", "claude-sonnet-4-5");
m.insert("claude-opus-4", "claude-opus-4-5-thinking");
m.insert("claude-opus-4-5-20251101", "claude-opus-4-5-thinking");
m.insert("claude-haiku-4", "claude-sonnet-4-5");
m.insert("claude-3-haiku-20240307", "claude-sonnet-4-5");
m.insert("claude-haiku-4-5-20251001", "claude-sonnet-4-5");
// OpenAI 协议映射表
m.insert("gpt-4", "gemini-2.5-pro");
m.insert("gpt-4-turbo", "gemini-2.5-pro");
m.insert("gpt-4-turbo-preview", "gemini-2.5-pro");
m.insert("gpt-4-0125-preview", "gemini-2.5-pro");
m.insert("gpt-4-1106-preview", "gemini-2.5-pro");
m.insert("gpt-4-0613", "gemini-2.5-pro");
m.insert("gpt-4o", "gemini-2.5-pro");
m.insert("gpt-4o-2024-05-13", "gemini-2.5-pro");
m.insert("gpt-4o-2024-08-06", "gemini-2.5-pro");
m.insert("gpt-4o-mini", "gemini-2.5-flash");
m.insert("gpt-4o-mini-2024-07-18", "gemini-2.5-flash");
m.insert("gpt-3.5-turbo", "gemini-2.5-flash");
m.insert("gpt-3.5-turbo-16k", "gemini-2.5-flash");
m.insert("gpt-3.5-turbo-0125", "gemini-2.5-flash");
m.insert("gpt-3.5-turbo-1106", "gemini-2.5-flash");
m.insert("gpt-3.5-turbo-0613", "gemini-2.5-flash");
// Gemini 协议映射表
m.insert("gemini-2.5-flash-lite", "gemini-2.5-flash-lite");
m.insert("gemini-2.5-flash-thinking", "gemini-2.5-flash-thinking");
m.insert("gemini-3-pro-low", "gemini-3-pro-low");
m.insert("gemini-3-pro-high", "gemini-3-pro-high");
m.insert("gemini-3-pro-preview", "gemini-3-pro-preview");
m.insert("gemini-2.5-flash", "gemini-2.5-flash");
m.insert("gemini-3-flash", "gemini-3-flash");
m.insert("gemini-3-pro-image", "gemini-3-pro-image");
m
});
pub fn map_claude_model_to_gemini(input: &str) -> String {
// 1. Check exact match in map
if let Some(mapped) = CLAUDE_TO_GEMINI.get(input) {
return mapped.to_string();
}
// 2. Pass-through known prefixes (gemini-, -thinking) to support dynamic suffixes
if input.starts_with("gemini-") || input.contains("thinking") {
return input.to_string();
}
// 3. Fallback to default
"claude-sonnet-4-5".to_string()
}
/// 核心模型路由解析引擎
/// 优先级:Custom Mapping (精确) > Group Mapping (家族) > System Mapping (内置插件)
pub fn resolve_model_route(
original_model: &str,
custom_mapping: &std::collections::HashMap<String, String>,
openai_mapping: &std::collections::HashMap<String, String>,
anthropic_mapping: &std::collections::HashMap<String, String>,
) -> String {
// 1. 检查自定义精确映射 (优先级最高)
if let Some(target) = custom_mapping.get(original_model) {
crate::modules::logger::log_info(&format!("[Router] 使用自定义精确映射: {} -> {}", original_model, target));
return target.clone();
}
let lower_model = original_model.to_lowercase();
// 2. 检查家族分组映射 (OpenAI 系)
// GPT-4 系列 (含 GPT-4 经典, o1, o3 等, 排除 4o/mini/turbo)
if (lower_model.starts_with("gpt-4") && !lower_model.contains("o") && !lower_model.contains("mini") && !lower_model.contains("turbo")) ||
lower_model.starts_with("o1-") || lower_model.starts_with("o3-") || lower_model == "gpt-4" {
if let Some(target) = openai_mapping.get("gpt-4-series") {
crate::modules::logger::log_info(&format!("[Router] 使用 GPT-4 系列映射: {} -> {}", original_model, target));
return target.clone();
}
}
// GPT-4o / 3.5 系列 (均衡与轻量, 含 4o, mini, turbo)
if lower_model.contains("4o") || lower_model.starts_with("gpt-3.5") || (lower_model.contains("mini") && !lower_model.contains("gemini")) || lower_model.contains("turbo") {
if let Some(target) = openai_mapping.get("gpt-4o-series") {
crate::modules::logger::log_info(&format!("[Router] 使用 GPT-4o/3.5 系列映射: {} -> {}", original_model, target));
return target.clone();
}
}
// GPT-5 系列 (gpt-5, gpt-5.1, gpt-5.2 等)
if lower_model.starts_with("gpt-5") {
// 优先使用 gpt-5-series 映射,如果没有则使用 gpt-4-series
if let Some(target) = openai_mapping.get("gpt-5-series") {
crate::modules::logger::log_info(&format!("[Router] 使用 GPT-5 系列映射: {} -> {}", original_model, target));
return target.clone();
}
if let Some(target) = openai_mapping.get("gpt-4-series") {
crate::modules::logger::log_info(&format!("[Router] 使用 GPT-4 系列映射 (GPT-5 fallback): {} -> {}", original_model, target));
return target.clone();
}
}
// 3. 检查家族分组映射 (Anthropic 系)
if lower_model.starts_with("claude-") {
let family_key = if lower_model.contains("4-5") || lower_model.contains("4.5") {
"claude-4.5-series"
} else if lower_model.contains("3-5") || lower_model.contains("3.5") {
"claude-3.5-series"
} else {
"claude-default"
};
if let Some(target) = anthropic_mapping.get(family_key) {
crate::modules::logger::log_warn(&format!("[Router] 使用 Anthropic 系列映射: {} -> {}", original_model, target));
return target.clone();
}
// 兜底兼容旧版精确映射
if let Some(target) = anthropic_mapping.get(original_model) {
return target.clone();
}
}
// 4. 下沉到系统默认映射逻辑
map_claude_model_to_gemini(original_model)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_model_mapping() {
assert_eq!(
map_claude_model_to_gemini("claude-3-5-sonnet-20241022"),
"claude-sonnet-4-5"
);
assert_eq!(
map_claude_model_to_gemini("claude-opus-4"),
"claude-opus-4-5-thinking"
);
// Test gemini pass-through (should not be caught by "mini" rule)
assert_eq!(
map_claude_model_to_gemini("gemini-2.5-flash-mini-test"),
"gemini-2.5-flash-mini-test"
);
assert_eq!(
map_claude_model_to_gemini("unknown-model"),
"claude-sonnet-4-5"
);
}
}
|