fix: 审批死锁修复 — LLM 调用异步化
listen_loop 核心改动: 新消息到达 → tokio::spawn(generate_reply) → 主循环立即继续 LLM 调用 High 工具 → approval_flow 阻塞 spawn 的 task → 主循环不受影响 → receive_messages() 继续接收 → 用户回复确认码 → handle_reply 触发 oneshot → spawned task 从 approval_flow 恢复 → LLM 生成最终回复 Conversation 用 Arc 包裹以支持跨 task 共享 send_text + 入库移到 spawned task 内部完成
This commit is contained in:
+21
-16
@@ -335,7 +335,7 @@ async fn cmd_listen(
|
|||||||
|
|
||||||
conv.set_tool_executor(executor);
|
conv.set_tool_executor(executor);
|
||||||
|
|
||||||
Some(conv)
|
Some(Arc::new(conv))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@@ -387,7 +387,7 @@ async fn listen_loop(
|
|||||||
account_id: &str,
|
account_id: &str,
|
||||||
database: &Option<Arc<Database>>,
|
database: &Option<Arc<Database>>,
|
||||||
file_state: &state::StateManager,
|
file_state: &state::StateManager,
|
||||||
conversation: Option<Conversation>,
|
conversation: Option<Arc<Conversation>>,
|
||||||
approval_manager: Option<Arc<ApprovalManager>>,
|
approval_manager: Option<Arc<ApprovalManager>>,
|
||||||
current_user_id: Arc<tokio::sync::Mutex<String>>,
|
current_user_id: Arc<tokio::sync::Mutex<String>>,
|
||||||
) {
|
) {
|
||||||
@@ -465,32 +465,37 @@ async fn listen_loop(
|
|||||||
// 更新当前用户(审批流程需要)
|
// 更新当前用户(审批流程需要)
|
||||||
*current_user_id.lock().await = from.to_string();
|
*current_user_id.lock().await = from.to_string();
|
||||||
|
|
||||||
// LLM 回复
|
// LLM 回复(异步执行,避免审批阻塞主循环)
|
||||||
if enable_llm {
|
if enable_llm {
|
||||||
if let Some(conv) = &conversation {
|
if let Some(conv) = &conversation {
|
||||||
let reply_result = if conv.spec().tools.is_some() {
|
let conv = conv.clone();
|
||||||
generate_reply_with_tools(conv, text.to_string(), database).await
|
let client = client.clone();
|
||||||
} else {
|
let database = database.clone();
|
||||||
generate_reply(conv, text.to_string(), database).await
|
let from_owned = from.to_string();
|
||||||
};
|
let text_owned = text.to_string();
|
||||||
|
let ctx_owned = ctx_token.map(String::from);
|
||||||
|
let aid = account_id.to_string();
|
||||||
|
|
||||||
match reply_result {
|
tokio::spawn(async move {
|
||||||
Ok(reply) => {
|
let reply_result = if conv.spec().tools.is_some() {
|
||||||
match client.send_text(from, &reply, ctx_token).await {
|
generate_reply_with_tools(&conv, text_owned, &database).await
|
||||||
|
} else {
|
||||||
|
generate_reply(&conv, text_owned, &database).await
|
||||||
|
};
|
||||||
|
let reply = reply_result.ok().unwrap_or_default();
|
||||||
|
match client.send_text(&from_owned, &reply, ctx_owned.as_deref()).await {
|
||||||
Ok(sent_id) => {
|
Ok(sent_id) => {
|
||||||
info!("LLM 回复成功 msg_id={}", sent_id);
|
info!("LLM 回复成功 msg_id={}", sent_id);
|
||||||
if let Some(db) = database {
|
if let Some(db) = database {
|
||||||
let _ = db::models::insert_chat_record(
|
let _ = db::models::insert_chat_record(
|
||||||
db.pool(), "outbound", from, account_id,
|
db.pool(), "outbound", &from_owned, &aid,
|
||||||
&reply, "llm", ctx_token, &sent_id,
|
&reply, "llm", ctx_owned.as_deref(), &sent_id,
|
||||||
).await;
|
).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => error!("发送 LLM 回复失败: {}", e),
|
Err(e) => error!("发送 LLM 回复失败: {}", e),
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
Err(e) => error!("生成 LLM 回复失败: {}", e),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user