Files
HomeAgent/docs/zh/memory-restructure-plan.md
JianFeeeee 1d52ba85d5 docs: 术语与架构措辞对齐(coldcontext / stablemem / security+device 模块)
1. 术语统一:
   - doc_query / doc_commit → coldcontext_query / coldcontext_commit
   - 「图记忆 / Graph 层」→「稳定记忆 / Stablemem 层(L3)」
   - 分层命名补上 L1/L2/L3 语义:Context(热) / Cold-context(冷) / Stablemem(持久)
   涉及 README.md、README_EN.md、assets/docs/{zh,en}/{ARCHITECTURE,OVERVIEW}.md

2. 补上本次最大的结构变化(文档里此前完全没有):
   - 安全防火墙作为**独立内核模块**:凭据闸门、工具黑白名单+沙箱、
     敏感词与提示词注入预警、按主体授权与插件命名限式;显式代理而非 monkey patch
   - device 数据面作为**独立内核模块**:工具注册与路由、inputch/outputch、设备登记;
     路由表在 internal/toolroute 以避免 core ↔ kernelboot 成环

3. 历史计划文档(memory-*.md / context-overflow-l4-design / entities-retirement /
   git-branching)加**归档说明**:明确术语已过时、现行口径以 ARCHITECTURE.md 为准。
   刻意不改写历史正文 —— 那是决策记录,改写等于伪造。

剩余旧词只出现在归档文档与 scripts/capability-bench/PLAN.md(评测历史记录)。
2026-10-27 09:58:14 +08:00

10 KiB
Raw Blame History

记忆系统重构计划:块节点统一载体

归档说明(2026-10-27):本文是历史计划,术语已过时 —— doc_query / doc_commit 已改名为 coldcontext_query / coldcontext_commit, 图记忆(Graph)在对外语义上改称 stablemem(稳定记忆)。 现行架构与术语以 assets/docs/zh/ARCHITECTURE.md 为准;本文保留作为决策记录。

状态:已执行完毕(2026-10-04)。本文是当时的执行计划,保留作为决策记录。 日期:2026-10-02(计划) / 2026-10-04(完成)

执行结果摘要(2026-10-04 回填)

步骤 状态 关键提交
① 重写设计文档 ✅ 6a0d6b7 971cd72 7248558
② distill 沉库改块节点 ✅ 4b54c03 1c260e3 0586f6b
③ memory_recall 加块召回路 ✅ 688ad08 40a6acb
④ memory_commit 止血 ⚠️ 部分(见下) 3bafe1c
⑤ 存量迁移 ✅ 09f31e2 e0a234c 5a70452
⑥ scene 挂接 ❌ 取消(见下) —

计划与实际的偏差(都是实测纠正的)

⑥ scene 挂接取消:计划假设 blocks 是新层、scene 挂在它上面。 但 blocks 不是新层而是图节点升级体,scene 无处可挂。

蒸馏路线整体否决(990b824):生产库 429 条实体里 424 条(99%)无主语, 而 Split 的第五道闸门「无主语不写悬空属性」会把 LLM 已拆对的字段全丢弃。 蒸馏命令已改为只对有主语的实体跑(b21410b),实际处理 5 条。

注意力网络路线否决(6a0d6b7 ~ 57eca02):分域后 token F1 0.918 超过门槛,但跨域不可泛化(域外零字段),而通用 Agent 无法分域。

计划里未被采纳的替代方案

  • 「给块补语义描述」→ 实验否定(中性描述反而更差,排名 26 → 96,7248558)
  • 「给 URL 类事实换更强向量」→ 未测,但裸 URL 无文本可供语义匹配(971cd72)

现行架构

memory_blocks        统一节点载体(文本/媒体都进这里)
memory_block_edges   source_kind → target_kind 多态端点,唯一边表
graph_centroid       中心向量(迁移/蒸馏后自动重建)

原句由 blk_src_<sha256> 原句块承载(内容派生、幂等、不带向量), sentences 表的写入点已清零(迁移与蒸馏都不再写)。

详见 production-recall-validation.md(三十三~三十八节)、 recall-capability-tiers.md(能力分层)、 vector-provider-decision.md(provider 决策与缺口)。 背景:本会话前期的记忆系统改动(630d3f4 / 978bada / 69150d2 / 25d35f8)建立在对记忆架构的错误认知上,经用户逐条纠正后全部重审。本计划是重审后的执行路线。 前置事实核查:全部基于代码与真库实测,标注来源。

〇、认知纠错记录(为什么推翻重来)

错误认知(当时的做法) 正确认知(用户纠正 + 代码核实)
分层是 L0 对话/L1 文档/L2 graph/L3 blocks L0=context / L1=doc / L2=graph。blocks 不是新的一层,是图节点从文本升级为带向量的多模态节点
给 entities 加向量字段(graph-vector-design.md) entities 该退场。memory_blocks 已是带 vector+fingerprint 的节点载体(46f833c)
LLM 拆句产物 Commit 成 entities+relations(630d3f4) 拆出的节点放入 block,保留原句;媒体引用是已删除的老设计(mediaref.go 只剩注释)
三元组 = 我发明的 (主语,维度,值) 三元组 =【节点】【关系边】【节点】;三元组设计文档在知识库 assets/knowledge/homeagent_architecture/content.md
provider 是蒸馏的配件 provider 是内核的模型接入接口,内核对 tfidf 等传统算法与向量化 LLM 无感,payload 一致才能动态接入
多模态要"引用"进图 多模态节点由 LLM 多模态能力拆分入库
场景/scene 表忽略不看 scene 是第三种召回:条件型记忆不吃词法/向量相似,按场面前缀匹配直接取回(scene.go:12-38)

沉痛教训:630d3f4 的 16 三元组端到端验证——验证的是拆分质量,不是正确的落库形态。验证通过 ≠ 架构正确。

一、目标形态(一句话)

入库:拆解器(provider 接口,内核无感)把对话/文档/媒体拆成
      memory_blocks 节点(modality/text_content/vector/fingerprint)
      + memory_block_edges 结构边;原句保留为块。
召回:块向量检索为主 + scene 场景召回补条件型记忆;
      entities+LIKE 是存量过渡路径,逐步退场。

二、既有设施盘点(不重复实现)

能力 已有 位置 状态
块节点存储 PutMemoryBlocks / MemoryBlocks internal/memory/block.go:67/144 ✔ 可用
结构边 AddMemoryBlockEdge(端点校验,测试 453/491 行) block.go:199 ✔ 可用
块检索 BlocksForNode(按端点反查) block.go:254 ✔ 可用
向量检索 vector.Store(Insert/SearchScored/Remove) internal/memory/vector/store.go ✔ 可用
provider SPI pkg/embedding(Embed/Info/Close,Fingerprint) pkg/embedding/embedding.go ✔ 可用
VL 权重双模式 qwen3vl(Embed 出向量)+ qwen3vlgen(tied head 生成) 25d35f8 ✔ 已验证
文本拆解 distill.Extractor(schema 约束+闸门,16 三元组/幻觉0) internal/memory/distill 拆分逻辑可复用,沉库去向要改
旧实体迁移先例 MigrateLegacyMediaEntities internal/memory/migrate.go:47 ✔ 方向先例
scene 召回 RecallByScene internal/memory/scene.go:323 ✔ 已有
拆解生成模型 ollama+qwen3:1.7b(schema 6/6 零幻觉) providers/ollama ✔ 端到端验证过

三、分步执行

第 1 步:重写两份设计文档 ✗ 未开始

  • 删 docs/zh/graph-vector-design.md(给 entities 加向量——前提错误)
  • 重写 docs/zh/triple-distill-llm-design.md:拆解产物=块节点;entities 标注退场路径
  • 修正 providers/qwen3vlgen 与 pkg/generation 的定位注释:不是"蒸馏配件",是入库拆解器的模型面
  • 验收:文档里的每张表名/函数名都能 grep 到;无 entities 加向量字段的任何残留表述

第 2 步:distill 沉库改块节点(核心) ✗ 未开始

  • distill.Extractor.Split 产出改为块结构(新增 distill.Blocks 类型,保留 Triple 输出做对照期)
  • 原句 → text block(text_content=原句, vector, fingerprint)
  • 字段 → text block(text_content=字段内容, vector, fingerprint)
  • 边:原句 block —contains→ 字段 block
  • 向量来源走 pkg/embedding(默认 provider 由配置决定;无 provider 时 vector 留空+fingerprint 空,不静默编造向量)
  • pipeline.go 的 distillBatch 改调块写入
  • 判据:
    • 拆一条真实记录后,MemoryBlocks/MemoryBlockEdges 能查到原句块+字段块+边
    • 断电安全:PutMemoryBlocks 是事务(block.go 已有端点校验事务先例)
    • 无 provider 时块仍入库(vector=''),检索退化为符号路,不报错不编造
  • 变异自证:把"contains 边"删掉,块查询测试必须红

第 3 步:memory_recall 增加块召回路 ✗ 未开始

  • GraphDB 增加 RecallBlocks(queryVec, topK):走 vector.SearchScored
  • 工具层 memory_recall:块向量召回为主,entities LIKE 为存量兜底,输出统一格式
  • 工具名/参数不变(调用方模型无感知)
  • fingerprint 不匹配时拒绝比较(报"向量空间已变更,需回填"),绝不拿 2048 维查询比 512 维库
  • 判据(真库 + 跨记录探针,用本会话已验证的判据):
    • 跨维度定位 ≥4/5(现状 LIKE 0/5)
    • 端口类数字串不退化(向量弱、符号强——混合必要性)
  • 变异自证:去掉块召回路,跨维度判据必须退化到现状水平

第 4 步:memory_commit 同步止血 ✗ 未开始

  • description 明确要求:拆解后走块形态;禁止 43-50 字符整句实体
  • 工具实现侧加闸门:超长 subject 拒绝并提示(与 distill 闸门同款)
  • 判据:新写入的实体长度分布不再出现 >25 字符主体

第 5 步:存量迁移 ✗ 未开始

  • 沿 MigrateLegacyMediaEntities 方向写 MigrateLegacyTextEntities: 188 实体 → 原句块(带向量)+ 字段块 + contains 边
  • 独立命令入口(参照 homed-kb-migrate),可回滚:导出原库快照→迁移→对比→确认后替换
  • 孤儿实体(49/108 无关系无原句)保持原样,不编造
  • 判据:迁移后跨维度探针 ≥4/5;原库快照可完整回滚

第 6 步:scene 挂接(可选,后置) ✗ 未开始

  • 拆解块带 scene 键(memory_blocks.scene 字段已在 schema 里)
  • 验证 RecallByScene 对块节点生效
  • 前置:第 2-5 步稳定后再做

四、每步通用约束

  1. provider 边界:内核不出现任何 provider 名分支;一切经 pkg/embedding/pkg/generation 接口
  2. 禁止静默错误:fingerprint/维度不匹配必须显式报;无向量必须显式留空
  3. 回填必落盘(document.go:137 陷阱:不落盘则判定条件永远成立、每次启动重算)
  4. 变异自证:每条关键判据写测试后,手动破坏对应实现,测试必须变红
  5. 长任务纪律:导出/回填等内存密集任务绝不与测试并行(本会话三次 OOM 教训)
  6. 验证通过 ≠ 架构正确:每步完成后对照本计划第一节逐条自检

五、暂不做

  • entities 表的物理删除(存量过渡期内仍服务 LIKE 兜底)
  • KV cache(qwen3vlgen 全量前向 O(N²),生成低频,已注释标明)
  • 多模态拆解(第 6 步之后,依赖块路稳定)
  • 切换生产实例 /var/tmp/ha-c 的 provider 配置(需人工确认)