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);
|
||||
|
||||
Some(conv)
|
||||
Some(Arc::new(conv))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -387,7 +387,7 @@ async fn listen_loop(
|
||||
account_id: &str,
|
||||
database: &Option<Arc<Database>>,
|
||||
file_state: &state::StateManager,
|
||||
conversation: Option<Conversation>,
|
||||
conversation: Option<Arc<Conversation>>,
|
||||
approval_manager: Option<Arc<ApprovalManager>>,
|
||||
current_user_id: Arc<tokio::sync::Mutex<String>>,
|
||||
) {
|
||||
@@ -465,32 +465,37 @@ async fn listen_loop(
|
||||
// 更新当前用户(审批流程需要)
|
||||
*current_user_id.lock().await = from.to_string();
|
||||
|
||||
// LLM 回复
|
||||
// LLM 回复(异步执行,避免审批阻塞主循环)
|
||||
if enable_llm {
|
||||
if let Some(conv) = &conversation {
|
||||
let reply_result = if conv.spec().tools.is_some() {
|
||||
generate_reply_with_tools(conv, text.to_string(), database).await
|
||||
} else {
|
||||
generate_reply(conv, text.to_string(), database).await
|
||||
};
|
||||
let conv = conv.clone();
|
||||
let client = client.clone();
|
||||
let database = database.clone();
|
||||
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 {
|
||||
Ok(reply) => {
|
||||
match client.send_text(from, &reply, ctx_token).await {
|
||||
tokio::spawn(async move {
|
||||
let reply_result = if conv.spec().tools.is_some() {
|
||||
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) => {
|
||||
info!("LLM 回复成功 msg_id={}", sent_id);
|
||||
if let Some(db) = database {
|
||||
let _ = db::models::insert_chat_record(
|
||||
db.pool(), "outbound", from, account_id,
|
||||
&reply, "llm", ctx_token, &sent_id,
|
||||
db.pool(), "outbound", &from_owned, &aid,
|
||||
&reply, "llm", ctx_owned.as_deref(), &sent_id,
|
||||
).await;
|
||||
}
|
||||
}
|
||||
Err(e) => error!("发送 LLM 回复失败: {}", e),
|
||||
}
|
||||
}
|
||||
Err(e) => error!("生成 LLM 回复失败: {}", e),
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user