issue #134: Knowledge差异化合并升级为同轮LLM融合 #141
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/134-knowledge-llm-merge"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #134
实现内容
ADR-0015 拍板的 Knowledge 合并是"同一次 Delta 压缩 LLM 调用产出的结构化融合 + 差异化保留",
而 origin/main 上
merge_knowledge是一句确定性字符串拼接,且合并逻辑活在存储层、发生在 LLM调用返回之后——这个位置本身就使"同一次调用产出融合结果"无法成立。核心是一次 port 契约反转:
把合并决策从存储层上提到编排层。
被推翻的初始设计
最初考虑给
_EXTRACT_MEMORIES_TOOL.knowledge[]加target_entry_id字段,让 LLM 显式指认合并目标。设计阶段的四路独立对抗校验推翻了这个方向:
零新增字段/新增机制"——这条约束当时是为差异化保留契约本身写的,同样覆盖"要不要为合并
目标识别新开一个字段"这件事。
write_knowledge本就无条件做find_matching_entry查重(ADR-0015"拒绝了"节"写入盲目追加,不查重"),让 LLM 的判断结果失效时退回同一套关键词匹配兜底,等于新机制的"失败路径"
与"不加这个机制"完全等价,用更粗的机制(关键词交集)去否决更精确的判断,方向也反了。
最终形状:不加任何新 LLM schema 字段,合并目标继续 100% 由
find_matching_entry(关键词交集)在编排层决定;LLM 只借助新增的"已知话题记忆"prompt 输入块写出更准的
trigger_keywords(自然复用/扩展旧关键词)与差异化保留的完整
canonical_meaning。具体改动
_compress_one_chat压缩前先get_knowledge读该 chat 全部已有 Knowledge,用_select_relevant_knowledge(复用trigger_injection.match_and_rank,id()回填映射——
TriggerEntry带 list 字段不可哈希、且值相等可能碰撞)预筛喂给 LLM;查重决策对全部已有 Knowledge(不是预筛子集,否则
max_items截断会让查重形同虚设)跑find_matching_entry,命中就merge_knowledge算最终字段值连同target_id传给write_knowledge;本地累积快照随每次写入更新,让同一批多条候选描述同一新话题时互相也能查重命中
KnowledgeCandidate新增target_id: str | None字段——纯 Python 内部字段,不是 LLM 输出,由编排层填入
write_knowledge两份实现(storage.py/sent_log.py)简化为按target_id插入/更新,不再自己查重;
target_id指向的行不存在时退化为插入新行,不静默丢弃候选merge_knowledge保留(未删除),但canonical_meaning逻辑换挡:信任candidate. canonical_meaning已经是差异化保留后的完整融合结果(整体替换,不再拼接),只有候选给出空canonical_meaning时才退回"保留 existing 原样不动"(机械兜底,ADR-0009 纪律)arise_knowledge_merge_context_max_items配置项(默认 5,独立于arise_max_knowledge_per_turn——运行时注入 vs 压缩期预筛两个场景语义不同)_build_prompt新增"已知话题记忆"输入块 + 差异化保留 instruction;抽出共享的_render_transcript辅助函数,避免"预筛看到的原文"和"LLM 实际看到的原文"不同步candidate.canonical_meaning(即将写入存储、以后会被触发注入进prompt 的那份内容)——不判"新增部分",与
persona_drift_guard.py/drift_veto.py既有的"候选描述应该等于通过后会被落库的内容"这条接口契约一致
skill.py::merge_skill按 AC 显式未动;DeltaCompressor输入端仍然只喂纯文本,未触碰ADR-0028 媒体路由边界
测试与验证
快照更新"两条第一次尝试变异后发现原有测试没有真正覆盖到,已各自补一条回归测试,重新变异
验证确认现在能抓住
storage.py那两条经行号偏移核对确认是 issue #133 就已存在的旧噪音
两轴 review
Standards 维度发现并经对抗校验确认三处真实问题(均已修正):
config.py/delta.py两处 docstring 把"合并目标"判断误归给 LLM,与最终裁决矛盾_select_relevant_knowledge里的KnowledgeEntry→TriggerEntry映射与runtime_loop.py已有逻辑重复,已抽成共享的
knowledge.py::to_trigger_entrycompress()新增的current_knowledge参数缺一条对称于既有current_profile模式的单元级 prompt 渲染测试,已补齐
文档
docs/adr/0015-topic-memory-knowledge-and-persona-lore.md已补更新节(docs 分支本地提交,按约定不推送)。design.md/CONTEXT.md"技能自改进复用 Knowledge 查重合并模式"补了一句分道说明
——避免读者误以为技能自改进也跟着升级为 LLM 差异化融合。
🤖 Generated with Claude Code