新增: F-01阶段5模型路由调用点接入
This commit is contained in:
@@ -12,6 +12,13 @@ use df_ai::provider::{ChatMessage, CompletionRequest, LlmProvider};
|
||||
// CR-30-1: 复用 retry::backoff_delay(jitter 1s→2s→4s) + is_status_retryable(Fatal 分类)
|
||||
// 实现流前失败重试退避对齐(决策 F-260616-07 a1),避免重写退避逻辑。
|
||||
use df_ai::retry;
|
||||
// F-01 阶段5: 智能路由 helper + TaskRequirements + 维度枚举。
|
||||
// 调用点构造 TaskRequirements(主对话:needs_tool_use=true,min_intelligence=Standard,
|
||||
// 当前仅 Text 模态;后续多模态接入时检测消息内 Part/Image 追加 Vision),
|
||||
// 经 select_model_id 在 provider.model_configs 池中选最优;池空/无匹配兜底 default_model。
|
||||
use df_ai::router::{
|
||||
select_model_id, IntelligenceTier, Modality, TaskRequirements,
|
||||
};
|
||||
|
||||
use df_storage::db::Database;
|
||||
use df_storage::models::AiProviderRecord;
|
||||
@@ -154,6 +161,19 @@ pub(crate) async fn run_agentic_loop(
|
||||
key_len = key_len,
|
||||
"[ai] 发起 LLM 请求"
|
||||
);
|
||||
|
||||
// F-01 阶段5: 主对话路由 — TaskRequirements(needs_tool_use=true,min_intelligence=Standard)。
|
||||
// 模态当前仅 Text(图像消息类型未实现,后续多模态接入时检测 Part/Image 追加 Vision)。
|
||||
// select_model_id None(池空/无匹配)→ 兜底 default_model,行为与接入前一致。
|
||||
let agentic_req = TaskRequirements {
|
||||
modalities: vec![Modality::Text],
|
||||
needs_tool_use: true,
|
||||
min_intelligence: IntelligenceTier::Standard,
|
||||
max_cost: None,
|
||||
estimated_context: 0,
|
||||
};
|
||||
let resolved_model = select_model_id(&agentic_req, &provider_config.model_configs)
|
||||
.unwrap_or_else(|| provider_config.default_model.clone());
|
||||
let tool_defs = tools_arc.tool_definitions();
|
||||
// 停止信号副本:stream_llm 与每轮迭代共享读取,避免重复加锁
|
||||
// notify 同取一份 Arc 引用(B-260615-14):stream_llm select! 监听 notified() 即时唤醒
|
||||
@@ -265,7 +285,7 @@ pub(crate) async fn run_agentic_loop(
|
||||
// 一致,重建与复用等价。收益:省去每次重试的 lock() + build_for_request(含
|
||||
// all_messages_clone 全量 clone)。
|
||||
let retry_request = CompletionRequest {
|
||||
model: provider_config.default_model.clone(),
|
||||
model: resolved_model.clone(),
|
||||
messages: messages.clone(),
|
||||
temperature: Some(0.7),
|
||||
max_tokens: Some(8192),
|
||||
@@ -387,16 +407,16 @@ pub(crate) async fn run_agentic_loop(
|
||||
}
|
||||
if !full_text.is_empty() {
|
||||
let mut msg = ChatMessage::assistant(&full_text);
|
||||
msg.model = Some(provider_config.default_model.clone());
|
||||
msg.model = Some(resolved_model.clone());
|
||||
session.messages.push(msg);
|
||||
// 追加系统提示消息:响应因网络中断不完整(对齐决策 a1 系统提示机制)
|
||||
let mut notice = ChatMessage::system("⚠ 响应因网络中断不完整,以上为已接收的部分内容。可重新发送以获取完整回复。");
|
||||
notice.model = Some(provider_config.default_model.clone());
|
||||
notice.model = Some(resolved_model.clone());
|
||||
session.messages.push(notice);
|
||||
}
|
||||
}
|
||||
|
||||
save_conversation(&session_arc, &db, &conv_id, Some(&usage), Some(&provider_config.default_model)).await;
|
||||
save_conversation(&session_arc, &db, &conv_id, Some(&usage), Some(&resolved_model)).await;
|
||||
// 标题生成后台化(失败有 extract_title 兜底)
|
||||
spawn_ensure_title(&provider_config, &db, &conv_id, &app_handle, &session_arc, &llm_concurrency);
|
||||
guard.reset().await;
|
||||
@@ -442,11 +462,11 @@ pub(crate) async fn run_agentic_loop(
|
||||
})
|
||||
.collect();
|
||||
let mut msg = ChatMessage::assistant_with_tools(&full_text, ai_tool_calls);
|
||||
msg.model = Some(provider_config.default_model.clone());
|
||||
msg.model = Some(resolved_model.clone());
|
||||
session.messages.push(msg);
|
||||
} else if !full_text.is_empty() {
|
||||
let mut msg = ChatMessage::assistant(&full_text);
|
||||
msg.model = Some(provider_config.default_model.clone());
|
||||
msg.model = Some(resolved_model.clone());
|
||||
session.messages.push(msg);
|
||||
}
|
||||
}
|
||||
@@ -458,7 +478,7 @@ pub(crate) async fn run_agentic_loop(
|
||||
completion_tokens: tokens.completion(),
|
||||
total_tokens: tokens.total(),
|
||||
};
|
||||
save_conversation(&session_arc, &db, &conv_id, Some(&usage), Some(&provider_config.default_model)).await;
|
||||
save_conversation(&session_arc, &db, &conv_id, Some(&usage), Some(&resolved_model)).await;
|
||||
// 标题生成后台化:不阻塞 Completed emit(失败有 extract_title 兜底)
|
||||
spawn_ensure_title(&provider_config, &db, &conv_id, &app_handle, &session_arc, &llm_concurrency);
|
||||
guard.reset().await;
|
||||
@@ -483,7 +503,7 @@ pub(crate) async fn run_agentic_loop(
|
||||
completion_tokens: tokens.completion(),
|
||||
total_tokens: tokens.total(),
|
||||
};
|
||||
save_conversation(&session_arc, &db, &conv_id, Some(&usage), Some(&provider_config.default_model)).await;
|
||||
save_conversation(&session_arc, &db, &conv_id, Some(&usage), Some(&resolved_model)).await;
|
||||
// B-260615-26: 审批等待 return 前 disarm guard——保持 generating=true 留 try_continue 续生成,
|
||||
// 同时 Drop 因 done=true 跳过复位 spawn(避免误复位审批态 generating 致 ai_approve→try_continue 不续)
|
||||
guard.disarm();
|
||||
@@ -512,7 +532,7 @@ pub(crate) async fn run_agentic_loop(
|
||||
completion_tokens: tokens.completion(),
|
||||
total_tokens: tokens.total(),
|
||||
};
|
||||
save_conversation(&session_arc, &db, &conv_id, Some(&usage), Some(&provider_config.default_model)).await;
|
||||
save_conversation(&session_arc, &db, &conv_id, Some(&usage), Some(&resolved_model)).await;
|
||||
// 暂停态保持 generating=true(防其他 send 抢占,仿审批),disarm guard 跳过 Drop 兜底复位
|
||||
guard.disarm();
|
||||
let _ = app_handle.emit("ai-chat-event", AiChatEvent::AiMaxRoundsReached {
|
||||
@@ -540,8 +560,9 @@ pub(crate) async fn run_agentic_loop(
|
||||
let knowledge_config = knowledge_config.clone();
|
||||
let app_handle = app_handle.clone();
|
||||
let llm_concurrency = llm_concurrency.clone();
|
||||
let resolved_model = resolved_model.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
save_conversation(&session_arc, &db, &conv_id, Some(&usage), Some(&provider_config.default_model)).await;
|
||||
save_conversation(&session_arc, &db, &conv_id, Some(&usage), Some(&resolved_model)).await;
|
||||
// 知识提炼:需读已落库的对话消息,故在 save 之后
|
||||
if let Err(e) = maybe_spawn_extraction(&session_arc, &db, &conv_id, &provider_config, &knowledge_config, llm_concurrency.clone()).await {
|
||||
tracing::warn!("知识提炼触发失败(非阻断): {}", e);
|
||||
|
||||
Reference in New Issue
Block a user