- 移动 session-dedup-knowledge-map OpenSpec 到 archive 目录 - 提交 ISS-001 遗留的 devflow 档案文件 - 更新 ISS-002 状态为已修复 - 新增 mvp/architecture/action-memory-relevance.md 设计文档 - 更新 mvp/README.md 文档导航 - 更新 devflow/index.md OpenSpec 链接指向 archive
4.1 KiB
4.1 KiB
Functional Spec: session-dedup-knowledge-map
REQ-01:工具层去重(Part A)
触发:LookupKnowledgeTool.lookupKnowledge(query) 被调用
行为:
- 从
SessionContextHolder.getSessionId()获取当前 sessionId;若为 null(非会话上下文)跳过去重逻辑,正常检索 - L0+L1 检索完成后,将结果中已在
RetrievedDocTracker中标记的 filePath 过滤掉 - 若过滤后 L0 结果为空、L1 结果也为空(全部已召回),返回
LookupResult.found=false,并在结果中附带提示文本:"以下文档已在本会话中检索过:[列表],无需重复召回" - 未被过滤的文档正常返回后,将其 filePath 写入
RetrievedDocTracker SessionContextHolder.clear()调用时,RetrievedDocTracker.clearSession(sessionId)同步清理
验收:
- 同一 session 内同一文档第二次命中时,返回去重提示而非完整文档内容
- 不同 session 之间互不影响
- sessionId 为 null 时不影响正常检索流程
REQ-02:文档级 LLM 字段生成(Part B - 文档级)
触发:DocumentManagementService.uploadDocument() 完成 frontmatter 解析后
行为:
- 若文档 frontmatter 中已包含
covers和whenToRetrieve,跳过 LLM 生成(作者手动填写优先) - 否则,调用 LLM,输入为文档 title + summary + 正文前 1000 字符
- Prompt 要求 LLM 返回 JSON:
{"covers": [...], "whenToRetrieve": "..."} - 解析结果,回填到
Frontmatter对象 - 序列化存入
api_document.metadata;同步更新KnowledgeEntry写入 L0 索引 - LLM 调用失败时,
covers置为空列表,whenToRetrieve置为 summary(降级),不阻断上传流程
验收:
- 上传后
api_document.metadata中包含covers和whenToRetrieve字段 - frontmatter 已有这两个字段时不覆盖
- LLM 调用异常时文档仍上传成功,字段降级填充
REQ-03:域级聚合与存储(Part B - 域级)
触发:文档上传成功后;文档删除后;loadIndex() 时发现某域在 knowledge_domain 表无记录
行为:
KnowledgeDomainService.onDocumentChange(category)读取该 category 下所有KnowledgeEntry的 title + covers + whenToRetrieve- 调用 LLM,生成域级
when_to_retrieve(要求 LLM 识别域内文档边界,输出含区分语义的路由描述) - 写入
knowledge_domain表(upsert by domain_id),同时更新document_count - LLM 调用失败时,
domain.when_to_retrieve保留上次 DB 记录;若无历史记录则置为空字符串
验收:
- 上传文档后,对应 category 的
knowledge_domain记录被更新 - 删除文档后,对应 category 的
document_count减少,when_to_retrieve重新生成 loadIndex()时无 DB 记录的域自动触发生成
REQ-04:knowledge map 注入 Planner(Part B - 注入)
触发:ChatService.buildChatPlannerAgent() 调用时
行为:
- 调用
KnowledgeDomainService.buildKnowledgeMap()生成 YAML 文本 - YAML 结构:域列表,每个域包含 domain_id、description、when_to_retrieve、documents(title + covers)
- 若 knowledge_domain 表为空(无任何域记录),跳过注入,不修改 prompt
- 注入位置:Planner system prompt 末尾,独立区块
Planner prompt 附加规则:
- 制定步骤时,先查看
available_knowledge_domains,按when_to_retrieve判断是否需要检索该域 - 每个域最多指示 Executor 检索一次;已检索过的域不再安排检索步骤
验收:
- Planner prompt 包含
available_knowledge_domains区块 - 无域记录时 prompt 不包含该区块(不注入空结构)
- knowledge map 文本长度 < 1000 字符(6 个文档场景下)
REQ-05:Frontmatter 字段扩展
行为:
Frontmatter.java新增List<String> covers和String whenToRetrieveKnowledgeEntry.java新增同名字段FrontmatterParser.java解析covers(YAML 数组)和when_to_retrieve(YAML 字符串)
验收:
- 现有文档(无新字段)上传/解析不报错,字段为 null 或空列表
- 含新字段的文档正确解析