feat(llm): 统一思考模式配置,支持显式禁用状态

This commit is contained in:
2026-06-01 17:39:36 +08:00
parent 928ebb61b4
commit 7636d0b5a6
4 changed files with 41 additions and 19 deletions

View File

@@ -46,7 +46,8 @@ struct SystemContent {
struct ThinkingConfig {
#[serde(rename = "type")]
thinking_type: String,
budget_tokens: u32,
#[serde(skip_serializing_if = "Option::is_none")]
budget_tokens: Option<u32>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
@@ -354,7 +355,10 @@ impl AnthropicClient {
top_p: self.top_p,
messages,
system,
thinking: None,
thinking: Some(ThinkingConfig {
thinking_type: "disabled".to_string(),
budget_tokens: None,
}),
stream: false,
};
@@ -409,7 +413,7 @@ impl AnthropicClient {
let thinking = ThinkingConfig {
thinking_type: "enabled".to_string(),
budget_tokens: self.thinking_budget_tokens,
budget_tokens: Some(self.thinking_budget_tokens),
};
// max_tokens must exceed budget_tokens
@@ -596,13 +600,23 @@ mod tests {
fn test_thinking_config_serialization() {
let config = ThinkingConfig {
thinking_type: "enabled".to_string(),
budget_tokens: 2048,
budget_tokens: Some(2048),
};
let json = serde_json::to_string(&config).unwrap();
assert!(json.contains(r#""type":"enabled""#));
assert!(json.contains(r#""budget_tokens":2048"#));
}
#[test]
fn test_thinking_config_disabled_serialization() {
let config = ThinkingConfig {
thinking_type: "disabled".to_string(),
budget_tokens: None,
};
let json = serde_json::to_string(&config).unwrap();
assert_eq!(json, r#"{"type":"disabled"}"#);
}
#[test]
fn test_system_content_serialization() {
let content = SystemContent {

View File

@@ -291,13 +291,13 @@ impl DeepSeekClient {
async fn chat_completion(&self, messages: Vec<Message>) -> Result<String> {
let url = format!("{}/chat/completions", self.base_url);
let thinking = if self.thinking_enabled {
Some(ThinkingConfig {
thinking_type: "enabled".to_string(),
})
} else {
None
};
let thinking = Some(ThinkingConfig {
thinking_type: if self.thinking_enabled {
"enabled".to_string()
} else {
"disabled".to_string()
},
});
// 思考模式下temperature/top_p 等参数不应传递
// 非思考模式下可以正常传递

View File

@@ -273,13 +273,13 @@ impl KimiClient {
async fn chat_completion(&self, messages: Vec<Message>) -> Result<String> {
let url = format!("{}/chat/completions", self.base_url);
let thinking = if self.thinking_enabled {
Some(ThinkingConfig {
thinking_type: "enabled".to_string(),
})
} else {
None
};
let thinking = Some(ThinkingConfig {
thinking_type: if self.thinking_enabled {
"enabled".to_string()
} else {
"disabled".to_string()
},
});
// 对于 kimi-k2.6 等支持思考模式的模型,使用默认 temperature 即可
// 思考模式下不显式指定 temperature

View File

@@ -275,7 +275,11 @@ impl OpenAiClient {
max_tokens: Some(self.max_tokens),
temperature: Some(self.temperature),
top_p: self.top_p,
reasoning_effort: None,
reasoning_effort: if is_reasoning_model(&self.model) {
Some("none".to_string())
} else {
None
},
stream: false,
};
@@ -619,6 +623,10 @@ pub fn is_valid_model(model: &str) -> bool {
OPENAI_MODELS.contains(&model)
}
fn is_reasoning_model(model: &str) -> bool {
model.starts_with("o")
}
#[cfg(test)]
mod tests {
use super::*;