fix(llm): 官方 OpenAI gpt-5 系列不下发 temperature,修复验证 400(#857) (#888)
* fix(llm): omit temperature for OpenAI gpt-5 family (fixes #857) OpenAI 官方 gpt-5 系列在 Chat Completions 只接受默认 temperature=1, 传 0.3(内置默认)会被 400 拒绝,导致验证/润色全部失败。 官方渠道的 gpt-5* 不再下发 temperature,由服务端用默认值; gpt-4 等其余模型保持原行为。custom 预设显式温度不受影响。 * fix(android): skip set_ignore_cursor_events on Android capsule path Android 胶囊走原生 overlay,tauri::WebviewWindow 无 set_ignore_cursor_events(桌面专用),导致 Android cargo check 编译失败(E0599)。cfg 门控跳过,触摸交互由系统处理。
This commit is contained in:
1 parent
73e65a4077
commit
26cd012433
1 file changed
+77
-1
@@ -578,7 +578,14 @@ impl OpenAICompatibleLLMProvider {
|
||||
"messages": messages,
|
||||
});
|
||||
if let Some(temperature) = self.config.temperature {
|
||||
body["temperature"] = json!(temperature);
|
||||
// OpenAI 官方 gpt-5 系列在 Chat Completions 只接受默认 temperature=1,
|
||||
// 传 0.3 会被 400 拒绝(issue #857)。官方渠道的 gpt-5* 不下发该字段,
|
||||
// 让服务端用默认值;其余模型保持原行为。
|
||||
if !(self.config.provider_id.trim() == "openai"
|
||||
&& openai_model_is_gpt5_family(&self.config.model))
|
||||
{
|
||||
body["temperature"] = json!(temperature);
|
||||
}
|
||||
}
|
||||
apply_openai_compatible_thinking_control(&mut body, &self.config);
|
||||
body
|
||||
@@ -1695,6 +1702,18 @@ fn openai_compatible_thinking_control_for_base_url(base_url: &str) -> Option<Thi
|
||||
None
|
||||
}
|
||||
|
||||
/// OpenAI 官方 gpt-5 系列(gpt-5 / gpt-5-mini / gpt-5-nano / gpt-5.5 等)在
|
||||
/// Chat Completions 中只接受默认 temperature=1,传其它值会返回 400(issue #857)。
|
||||
/// 模型名归一化规则与 `openai_chat_reasoning_effort` 保持一致。
|
||||
fn openai_model_is_gpt5_family(model: &str) -> bool {
|
||||
model
|
||||
.trim()
|
||||
.strip_prefix("openai/")
|
||||
.unwrap_or_else(|| model.trim())
|
||||
.to_ascii_lowercase()
|
||||
.starts_with("gpt-5")
|
||||
}
|
||||
|
||||
fn openai_chat_reasoning_effort(model: &str, thinking_enabled: bool) -> Option<&'static str> {
|
||||
let normalized = model
|
||||
.trim()
|
||||
@@ -2594,6 +2613,63 @@ mod tests {
|
||||
assert_eq!(body["temperature"], json!(DEFAULT_TEMPERATURE));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chat_body_omits_temperature_for_openai_gpt5_family() {
|
||||
for model in ["gpt-5", "gpt-5-mini", "gpt-5-nano", "gpt-5.5", "openai/gpt-5"] {
|
||||
let provider = OpenAICompatibleLLMProvider::new(OpenAICompatibleConfig::new(
|
||||
"openai",
|
||||
"OpenAI",
|
||||
"https://api.openai.com/v1",
|
||||
"k",
|
||||
model,
|
||||
));
|
||||
|
||||
let body = provider.chat_body(false, vec![json!({ "role": "user", "content": "hi" })]);
|
||||
|
||||
assert!(
|
||||
body.get("temperature").is_none(),
|
||||
"{model} must not receive temperature (issue #857)"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chat_body_keeps_default_temperature_for_openai_non_gpt5_models() {
|
||||
for model in ["gpt-4o", "gpt-4o-mini", "gpt-4.1"] {
|
||||
let provider = OpenAICompatibleLLMProvider::new(OpenAICompatibleConfig::new(
|
||||
"openai",
|
||||
"OpenAI",
|
||||
"https://api.openai.com/v1",
|
||||
"k",
|
||||
model,
|
||||
));
|
||||
|
||||
let body = provider.chat_body(false, vec![json!({ "role": "user", "content": "hi" })]);
|
||||
|
||||
assert_eq!(body["temperature"], json!(DEFAULT_TEMPERATURE));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chat_body_keeps_custom_temperature_for_gpt5_on_custom_provider() {
|
||||
// custom 预设由用户显式配温度(issue #857 的绕过路径:custom + temperature=1),
|
||||
// 不该被内置渠道的 gpt-5 特判误伤。
|
||||
let provider = OpenAICompatibleLLMProvider::new(
|
||||
OpenAICompatibleConfig::new(
|
||||
"custom",
|
||||
"Custom",
|
||||
"https://api.openai.com/v1",
|
||||
"k",
|
||||
"gpt-5",
|
||||
)
|
||||
.with_temperature(Some(1.0)),
|
||||
);
|
||||
|
||||
let body = provider.chat_body(false, vec![json!({ "role": "user", "content": "hi" })]);
|
||||
|
||||
assert_eq!(body["temperature"], json!(1.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn provider_temperature_policy_makes_custom_opt_in() {
|
||||
assert_eq!(
|
||||
|
||||
Reference in new issue
Block a user