优化: df-ai/df-storage/df-nodes 底层加固: 上下文/模型/节点/仓储

df-ai:
- context/mod.rs + manager_tests.rs: 上下文管理调整 + 测试同步(48 行)
- openai_compat.rs: OpenAI 兼容层增强(+51)
- presets/models.json: 模型预设 +18

df-storage:
- crud/conversation_repo.rs: 会话仓储(loop_state 相关)
- crud/task_repo.rs: 任务仓储
- crud/mod.rs: 导出调整

df-nodes:
- task_advance_node.rs: 任务推进节点

验收: cargo check -p devflow EXIT 0。
This commit is contained in:
lxy
2026-10-09 22:54:25 +08:00
parent d7e626a813
commit f4ca01f2f2
8 changed files with 296 additions and 36 deletions
+26 -22
View File
@@ -1045,9 +1045,12 @@ fn phase1_append_after_dirty_stays_dirty_until_save() {
// ============================================================
#[test]
fn eviction_inserts_summary_message_at_view_head() {
// 触发淘汰 → 视图头部应有一条 "[早期对话概要]" user 摘要(补偿无声丢弃的早期主题),
fn eviction_inserts_summary_message_at_view_tail() {
// 触发淘汰 → 视图尾部应有一条 "[早期对话概要]" user 摘要(补偿无声丢弃的早期主题),
// 概要 ≤ EVICTION_SUMMARY_MAX_CHARS,保护消息完好,且纯视图(不污染内存全量/不落库)。
// 缓存友好(2026-10):摘要改尾部追加(push)而非头部插入(insert(0))——头部插入位移
// 整条前缀字节,使 DeepSeek 等自动前缀缓存 provider 全部缓存失效(命中率掉到个位数)。
// 尾部追加让稳定前缀(system + 早期 history)逐轮不变,命中率最大化。
let mut mgr = ContextManager::new(cfg(200));
for i in 0..20 {
if i % 2 == 0 {
@@ -1063,46 +1066,47 @@ fn eviction_inserts_summary_message_at_view_head() {
let (msgs, trimmed) = mgr.build_for_request(0);
assert!(trimmed, "超预算应触发裁剪");
// 视图头部 = 补偿摘要(role=user,"[早期对话概要]" 前缀 + 高频主题)
let head = msgs.first().expect("视图不应为空");
// 视图尾部 = 补偿摘要(role=user,"[早期对话概要]" 前缀 + 高频主题)
let tail = msgs.last().expect("视图不应为空");
assert!(
matches!(head.role, MessageRole::User),
"视图头部应为 user 摘要, 实际 {:?}",
head.role
matches!(tail.role, MessageRole::User),
"视图尾部应为 user 摘要, 实际 {:?}",
tail.role
);
assert!(
head.content.starts_with("[早期对话概要] 高频主题: "),
tail.content.starts_with("[早期对话概要] 高频主题: "),
"摘要格式不符, 实际 {}",
head.content
tail.content
);
assert!(
head.content.contains("审批"),
tail.content.contains("审批"),
"摘要应含被淘汰区高频主题词'审批', 实际 {}",
head.content
tail.content
);
assert!(
head.content.chars().count() <= EVICTION_SUMMARY_MAX_CHARS,
tail.content.chars().count() <= EVICTION_SUMMARY_MAX_CHARS,
"摘要应 ≤ {} 字符, 实际 {}",
EVICTION_SUMMARY_MAX_CHARS,
head.content.chars().count()
tail.content.chars().count()
);
// 保护消息完好:末条(i=19 assistant)保留;摘要 user 与首轮真实 user 相邻,由
// sanitize 的 ensure_sequence_legal 合并(摘要在前,换行接原文),故 msgs[1] 为 i=1 的 assistant
// 保护消息完好:末条(i=19 assistant)保留;摘要 user 追加在尾部,与末尾 assistant
// 不同 role 不合并,故 msgs[倒数第2] 仍为 i=19 的 assistant
assert_eq!(
msgs.last().unwrap().content,
msgs[msgs.len() - 2].content,
"第19条回复内容同样较长用于撑爆上下文预算触发视图裁剪逻辑",
"保护区最新消息被误裁"
);
assert!(
matches!(msgs[1].role, MessageRole::Assistant),
"摘要与首轮 user 合并后,第二条应为 assistant, 实际 {:?}",
msgs[1].role
matches!(msgs[msgs.len() - 2].role, MessageRole::Assistant),
"摘要前一条应为 assistant(i=19), 实际 {:?}",
msgs[msgs.len() - 2].role
);
// 首条仍是保留区真实首条 user(摘要不再抢占头部,不位移前缀)
assert!(
msgs[0].content.contains("审批流程与审批门禁需要适配"),
"合并不应丢失被保留的首轮真实 user 文本, 实际 {}",
msgs[0].content
matches!(msgs[0].role, MessageRole::User),
"视图头部应为真实首条 user(摘要已移尾部), 实际 {:?}",
msgs[0].role
);
// 纯视图:摘要不进内存全量,被淘汰原文存储态不变