Files
DevFlow/docs/02-架构设计/专项设计/跨会话召回最小闭环-设计-2026-10-04.md
lxy b994cf2c54 文档: 设计定稿与评估纪律登记
- 无人值守长任务设计定稿,含效率与可观测补遗
- u-relay wire 协议规格与五项评估结论
- 新能力引入评估纪律五项清单
- todo 销账与狗粮短板分析登记
2026-10-04 16:27:32 +08:00

91 lines
6.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 跨会话召回最小闭环 · 设计(2026-10-04)
> ✅ 拍板通过(2026-10-04,3/3 按建议:B1 mention 唯一才启用/B2 软排序/B3 新增 scoped 方法;见 [拍板集](../滚动规范/拍板集-2026-10-04.md))
> 来源:todo.md「P1 跨会话召回最小闭环(项目级记忆+会话结束提炼进知识库,source_project 已有字段未用)」。
> 勘察结论(2026-10-04 现场核实,以源码为准):
> - 会话内自动提炼链已存在:`knowledge_inject.rs` `extract_knowledge_from_conversation`(user/assistant 过滤+`KNOWLEDGE_EXTRACT_WINDOW` 窗口+JSON 提炼+candidate 批量插入)+ `EXTRACT_WATERMARKS` 水位防重 + `conv(cid).knowledge_extracted` 哨兵 + `trigger_extraction_now` 手动强制。
> - `source_project` 字段在**主仓存储层零使用**:仅 `idea_repo.rs` 列定义/INSERT/UPDATE 贯通,`idea_repo.rs:949` 注释自证「source_project/source_ref 等元字段未被使用却仍随每行读出」。检索侧 `search_keywords`(idea_repo.rs:699)无项目过滤。
> - 注入点:`knowledge_inject.rs:622 inject_knowledge_into_prompt`(`search_keywords(keywords, include_candidates, limit)`,无项目维度)。
> - 会话→项目关联:`ai_conversations` 表**无 project_id 列**(V4 仅补 archived、V33 pending_approvals、V44 origin、V45 boundary_json);项目归属当前只能靠会话内 mention/`boundary_json`/`@项目` enrichment 间接推断。
> - candidate→published 机制已通(自动晋升 + knowledge_promote 工具 + V43 存量迁移 854 条),**跨会话可见性**只欠「published 参与检索注入」+「项目维度过滤」两环。
## 1. 目标与非目标
**目标(最小闭环)**:
1. 会话结束(AiCompleted 收敛点)自动触发提炼时,把当前会话**归属项目**写入产出知识的 `source_project`;
2. 知识注入(`inject_knowledge_into_prompt`)按**当前项目优先**:同项目知识加权/前置,跨项目知识仍可召回但不淹没;
3. 形成闭环:会话 A 的踩坑 → candidate → 晋升 published → 会话 B(同项目)注入时优先命中。
**非目标(本期不做)**:
- 不做会话↔项目的强绑定 schema 变更(不加 `ai_conversations.project_id` 列)——归属用**弱推断**(见 §3.1),避免迁移风险;
- 不动 candidate 晋升策略(C3 已拍板项);
- 不做向量检索(embedding 现状 1033 条全 NULL,另线);
- 不做 UI 变更(Knowledge 页项目筛选留后续)。
## 2. 核心取舍:项目归属从哪来
会话本身不存 project_id。归属来源三选,按可靠性排序:
| 来源 | 可靠性 | 实现成本 | 结论 |
|---|---|---|---|
| a. `boundary_json`(V45 无人值守边界)含项目路径 | 高(显式绑定) | 低(已落库) | ✅ 首选:有则用 |
| b. 会话消息中的 `@项目` enrichment / mention 记录 | 中(用户显式引用过) | 中(解析消息) | ✅ 次选:回退 |
| c. `ai_conversations` 加 project_id 列 | 高但侵入 schema | 高(迁移+全链) | ❌ 本期不做 |
**设计决策 D1(建议拍板)**:归属采用 a→b 两级弱推断,都不命中则 `source_project = NULL`(全局知识,不过滤)。这样零 schema 变更,且与「无人值守长任务」边界模型(boundary 已带项目上下文)天然对齐。
**提炼函数签名扩展**(knowledge_inject.rs 内,不新建文件):
```
async fn resolve_source_project(db, conv_id) -> Option<String>
// 1. 读 ai_conversations.boundary_json → 解析 project_path → 反查 projects 表 path 匹配 → id
// 2. 回退:读最近 N 条消息找 "[项目:xxx]" enrichment 标记 → 反查 → id
// 3. 皆无 → None
```
候选插入处(`extract_knowledge_from_conversation` 内 INSERT 前)把 `source_project = resolve_source_project(...)` 赋上。
## 3. 注入侧:项目维度过滤
**设计决策 D2**:注入不做硬过滤(`WHERE source_project = ?` 会把同问题跨项目通用知识挡死),改**软排序**——SQL 层 `search_keywords` 增加可选 `project_id` 参数:
```
ORDER BY (CASE WHEN source_project = ?1 THEN 0 ELSE 1 END), reuse_count DESC, ...
```
- 同项目知识排前(limit 截断时优先保留);
- `source_project IS NULL`(全局知识)视为第二档但优于异项目:`(CASE WHEN source_project = ?1 THEN 0 WHEN source_project IS NULL THEN 1 ELSE 2 END)`;
- `inject_knowledge_into_prompt` 调用前同样走 `resolve_source_project`(此时是当前活跃会话)取 project_id 传入;
- `knowledge_search` 工具(LLM 显式调用)暂不加项目参数——LLM 不知道当前 project_id,靠注入侧自动带。
**接口改动面**:
- `df-storage/crud/idea_repo.rs`:`search_keywords(&keywords, include_candidates, limit)` → 增参 `project_id: Option<&str>`(或新方法 `search_keywords_scoped`,保旧签名给 MCP 等外部调用方,内部转调);
- `knowledge_inject.rs` 两个调用点(:423 检索、:622 注入前置);
- `knowledge.rs` 工具(tools/knowledge.rs)不动。
## 4. 闭环验证与防劣化
| 风险 | 对策 |
|---|---|
| 提炼重复(每会话产相似 candidate 洪水) | 已有水位+哨兵;新增:插入前按 `title` 相似度(`search_keywords` 查同 title 命中即跳过或 `reuse_count+1`)——复用现有检索,零新机制 |
| 弱推断错误归属(张冠李戴) | 只在高置信(boundary 显式路径)时写 source_project;mention 回退可拍板是否启用(D1-b) |
| 注入 token 膨胀 | limit 不变,软排序只改顺序不增量 |
| 存量 967 条 candidate/907 published 无 source_project | 不回填(NULL=全局,行为正确);增量自然带项目 |
**验收**:
1. 新会话提及某项目 → 完成后提炼的 candidate `source_project` 非空且指向该项目;
2. 同项目新会话注入时该知识(晋升后)排在异项目知识前;
3. 无项目会话(source_project=NULL)注入行为与现状逐字一致(回归门);
4. `cargo test -p df-storage -p df-ai` 全绿 + search_keywords 新旧签名编译兼容。
## 5. 拍板点(3 项)
- **拍板1(D1-b)**:mention 回退推断是否启用?建议启用但仅当会话中项目 mention ≥1 次且唯一(多项目 mention 不猜,置 NULL)。
- **拍板2(D2)**:注入软排序 vs 硬过滤?建议软排序(理由见 §3)。
- **拍板3**:`search_keywords` 改签名(breaking,内部 crate)vs 新增 scoped 方法?建议**新方法**(df-mcp 等外部链路零影响)。
## 6. 工作量估算
约 1 天:resolve_source_project(2h)+ search_keywords_scoped + 两调用点接线(3h)+ 去重跳过(1h)+ 单测(2h)。