add retry when llm output is null

This commit is contained in:
2026-06-26 20:38:13 +08:00
parent f994c82d8c
commit 2258013d92
@@ -1439,6 +1439,7 @@ async fn request_llm_game_draft_with_client(
"",
"",
"",
None,
)
.await
}
@@ -1606,6 +1607,7 @@ async fn run_game_creator_agent_loop_at(
&findings_markdown,
&group_briefs_markdown,
&read_optional_text(&root.join(&agenda.relative_path))?,
progress,
)
.await
{
@@ -1788,6 +1790,7 @@ async fn request_generator_game_draft_with_client(
findings_markdown: &str,
group_briefs_markdown: &str,
agenda_markdown: &str,
progress: Option<&AgentProgressEmitter<'_>>,
) -> Result<LlmGameDraft, String> {
let system_prompt = game_creator_system_prompt();
let user_prompt = game_creator_generator_user_prompt(
@@ -1799,21 +1802,43 @@ async fn request_generator_game_draft_with_client(
group_briefs_markdown,
agenda_markdown,
);
let request = LlmTextRequest::new(vec![
LlmMessage::system(system_prompt),
LlmMessage::user(user_prompt.clone()),
])
.with_max_tokens(GAME_CREATOR_LLM_MAX_OUTPUT_TOKENS);
let response = match request_game_creator_llm_text(client, request).await {
Ok(response) => response,
Err(error) => {
// LLM 调用失败(如 “LLM 返回内容为空”)时,把本次输入连同错误一并落盘,便于复现定位。
persist_llm_game_draft_error_input(
system_prompt,
user_prompt.as_str(),
&error.to_string(),
);
return Err(format!("LLM 生成失败:{error}"));
// deepseek-v4-pro 等推理模型偶发返回空 contentHTTP 200、completion_tokens=0
// 参见 DeepSeek-V3 issue #1453)。这类空返回是上游瞬时故障,原样重发通常即可恢复,
// 因此仅对 EmptyResponse 最多重试 3 次(含首次共 4 次请求),其它错误不重试。
const MAX_EMPTY_RETRIES: u32 = 3;
let mut empty_retries = 0u32;
let response = loop {
let request = LlmTextRequest::new(vec![
LlmMessage::system(system_prompt),
LlmMessage::user(user_prompt.clone()),
])
.with_max_tokens(GAME_CREATOR_LLM_MAX_OUTPUT_TOKENS);
match request_game_creator_llm_text(client, request).await {
Ok(response) => break response,
Err(platform_llm::LlmError::EmptyResponse) if empty_retries < MAX_EMPTY_RETRIES => {
empty_retries += 1;
eprintln!(
"llm.chat.generator.empty-response 重试 {empty_retries}/{MAX_EMPTY_RETRIES}(上游返回空 content,原样重发)"
);
// 同步推送到 App 进度面板,便于在界面上看到重试(无需盯命令行)。
emit_agent_progress(
progress,
"llm.generator.empty_retry",
&format!(
"Generator 收到空返回(DeepSeek 偶发),正在自动重试 {empty_retries}/{MAX_EMPTY_RETRIES}"
),
);
continue;
}
Err(error) => {
// 调用失败(含空返回重试耗尽)时,把本次输入连同错误一并落盘,便于复现定位。
persist_llm_game_draft_error_input(
system_prompt,
user_prompt.as_str(),
&error.to_string(),
);
return Err(format!("LLM 生成失败:{error}"));
}
}
};
// 先把原始返回落盘,再解析;解析失败(如输出截断)时仍能从仓库里拿到完整原文。