重构: 后端编排拆解与DRY债收敛及命名纠偏

阶段1拆解: stream 系外移 stream_relay.rs,mod.rs 3048→2607,loop_body 502→83
技能收尾: regenerate/edit 回溯补技能,新增 read_skill 工具,项目级技能扫描
DRY: emit 双写 46 处收敛 event_bus 正典,KV 引号归一收口,LOCK-SLOW 33 处单行化
警示骨架 4→1 与压缩兜底 2→1,噪音目录档位收敛,truncate 同名陷阱消除
工具元数据落 ToolMeta 八维,7 张 match 表改查 registry,parity 测试锁等价
命名: is_noise_entry/teardown_round/probe_missed_terminal_event 等 6 项纠偏
This commit is contained in:
lxy
2026-10-01 19:35:19 +08:00
parent 3861e13b32
commit 75c5e23523
40 changed files with 2988 additions and 1964 deletions
+8 -19
View File
@@ -19,8 +19,9 @@ use df_storage::models::{AiProviderRecord, KnowledgeRecord};
use df_types::types::new_id;
use crate::state::{AppState, ExtractTrigger, LlmConcurrency};
use crate::state::{AppState, ExtractTrigger, LlmConcurrency, log_slow_lock};
use crate::commands::ai::audit::truncate_chars;
use crate::commands::err_str;
use super::{AiSession};
@@ -560,8 +561,8 @@ pub(crate) async fn build_knowledge_context(
for r in &results {
let kind = r.kind.clone();
let title = r.title.clone();
// 截断 content 防膨胀(注入侧最多 500 字符)
let snippet: String = r.content.chars().take(500).collect();
// 截断 content 防膨胀(注入侧最多 500 字符;走 audit 正典,截断时尾部补 … 提示有省略)
let snippet: String = truncate_chars(&r.content, 500);
out.push_str(&format!("- [{}] {}: {} (复用 {} 次)\n", kind, title, snippet, r.reuse_count));
}
out
@@ -588,10 +589,7 @@ pub(crate) async fn build_knowledge_context_for_conv(
.iter()
.rev()
.find(|m| matches!(m.role, MessageRole::User) && m.is_active());
let __hold = __lock_t.elapsed();
if __hold > std::time::Duration::from_millis(30) {
eprintln!("[LOCK-SLOW] build_knowledge_context_for_conv 持锁 {:?} (含 lock 等待)", __hold);
}
log_slow_lock(__lock_t, "build_knowledge_context_for_conv:582");
match found {
Some(m) => (m.content.clone(), m.id.clone()),
None => (String::new(), None),
@@ -688,10 +686,7 @@ pub(crate) async fn maybe_spawn_extraction(
}
};
if blocked {
let __hold = __lock_t.elapsed();
if __hold > std::time::Duration::from_millis(30) {
eprintln!("[LOCK-SLOW] maybe_spawn_extraction 持锁 {:?} (含 lock 等待)", __hold);
}
log_slow_lock(__lock_t, "maybe_spawn_extraction:692");
tracing::debug!(
conv_id = %conv_id,
"[knowledge] 跳过自动提炼:提炼中或距上次提炼新增用户消息不足 {} 条(如需立即重提炼用手动按钮)",
@@ -701,10 +696,7 @@ pub(crate) async fn maybe_spawn_extraction(
}
// 守卫 2:消息数。conv_read 未建返 0(< min_messages 自然跳过,语义=空对话不注入知识)。
if msg_count < config.min_messages as usize {
let __hold = __lock_t.elapsed();
if __hold > std::time::Duration::from_millis(30) {
eprintln!("[LOCK-SLOW] maybe_spawn_extraction 持锁 {:?} (含 lock 等待)", __hold);
}
log_slow_lock(__lock_t, "maybe_spawn_extraction:705");
return Ok(());
}
// 原子预置位(TOCTOU 核心):释放锁前先占提炼槽位,杜绝并发窗口内重复 spawn。
@@ -713,10 +705,7 @@ pub(crate) async fn maybe_spawn_extraction(
.lock()
.expect("提炼水位互斥锁中毒")
.insert(conv_id.to_string(), ExtractWatermark::InFlight);
let __hold = __lock_t.elapsed();
if __hold > std::time::Duration::from_millis(30) {
eprintln!("[LOCK-SLOW] maybe_spawn_extraction 持锁 {:?} (含 lock 等待)", __hold);
}
log_slow_lock(__lock_t, "maybe_spawn_extraction:717");
}
let session_arc = session_arc.clone();