add retry when llm output is null
This commit is contained in:
@@ -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 等推理模型偶发返回空 content(HTTP 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}"));
|
||||
}
|
||||
}
|
||||
};
|
||||
// 先把原始返回落盘,再解析;解析失败(如输出截断)时仍能从仓库里拿到完整原文。
|
||||
|
||||
Reference in New Issue
Block a user