Files
hunjing/docs/architecture/memory-and-knowledge.md
T
chenxin 5da1efe921 📝 docs: 统一 PostgreSQL 主库并固化索引命名约定
- 新增 ADR-024:服务端关系主库统一 PostgreSQL,不设 SQLite 档(pgvector 与中文全文无法在 SQLite 承载,双档必然残缺或第二实现);端侧离线缓存不受约束
- AGENTS.md:权威事实源与部署句更新;8.6 固化 pk_/uk_/idx_/fk_ 索引命名约定
- system-architecture、data-architecture、memory-and-knowledge、roadmap WP-01、handoff(决策 29)同步清理 SQLite 引用
2026-09-09 21:14:10 +08:00

11 KiB
Raw Blame History

记忆与知识架构

本文定义 1.0 的记忆所有权、写入、版本、检索和上下文装配边界。字段与稳定枚举以 docs/contracts/ 和后续 OpenAPI 3.1 为准。

1. 边界

  • Message 是不可被记忆覆盖的原始交流记录;编辑产生 Revision。
  • MemoryCandidate 是待判定的提取结果,不参与正式召回。
  • Memory 是稳定标识;MemoryVersion 是不可变内容版本,当前版本仅由 Memory 指针引用。
  • KnowledgeDocument 保存外部资料和世界设定;其切片与索引是可重建投影,不冒充人物经历。
  • Character baseline、用户资料、关系、知识和记忆分别建模;任何记忆策略都不能直接修改 CharacterVersion。
  • 对话压缩、工作上下文和 Provider Prompt Cache 是运行期派生状态,不属于长期记忆。
  • 1.0 不定义可绕过治理的 WorkingMemory 类型;当前分支消息和 Run 临时上下文始终按 Personal Domain/Workspace、Character、Conversation、Branch 与 Run 授权,不能因“临时”跳过隔离。

1.0 的权威记忆是可检查、可纠正的文本或结构化记录。KV cache、隐藏状态和模型权重适配不作为权威记忆,也不进入 1.0 记忆可携格式。

2. 所有权与作用域

每条 Memory 必须属于且只属于一个授权边界:

所有权 必需关联 可选关联 用途
Personal Domain personal_domain_id character_id 用户级或私密角色级记忆
Workspace workspace_id character_id 经成员权限允许的协作记忆

约束:

  • personal_domain_id 与 workspace_id 二选一;在数据库层使用检查约束落实。
  • character_id 只能引用同一所有权边界内的 Character。
  • conversation_id、message_id、content_block_id、run_id 和 tool_call_id 是来源或适用条件,不是授权边界。
  • 角色间共享通过显式授权和独立引用完成,不复制一份失去来源关系的 Memory。
  • 子 Agent 只读父 Run 已批准的召回快照;默认没有创建、批准、纠正或删除长期记忆的能力。
  • 社区 Release、市场交付物和推荐特征不得包含 Personal Domain Memory。Workspace 内容发布前同样经过独立发布审查。

3. 记忆分类

1.0 只定义四类可解释长期记忆;稳定值登记在协议与稳定标识,并在实现前进入 OpenAPI/Schema:

类型 含义 默认写入要求
fact 可核对的人、事、状态或约束 有明确来源;冲突时生成纠正候选
preference 用户或角色明确表达、或系统推断的偏好 显式与推断分开;推断偏好需要置信度
event 带时间范围的经历或事件 保留时间语义和来源
relationship 人物间关系及其变化 高影响,默认人工确认

身份基线、人格设定、权限、秘密、工具定义和知识文档不塞入上述类型。需要新类型时先更新契约和评测,不使用任意 metadata 绕过类型系统。

4. 写入与版本

flowchart LR
  S[Source] --> E[Extract]
  E --> C[Candidate]
  C --> P{Policy}
  P -->|approve| V[MemoryVersion]
  P -->|review| H[Human review]
  H -->|approve| V
  P -->|reject| X[Rejected]
  H -->|reject| X
  V --> A[(Authoritative DB)]
  A --> I[Indexes]
  I --> R[Retrieve]
  R --> M[ContextSnapshot]

4.1 来源

Candidate 至少记录:

  • 所有权边界、目标 Character(如有)和候选类型;
  • 精确来源引用,包括 Message/Block、KnowledgeDocument chunk 或 ToolCall 的 ID 与版本;
  • extractor、prompt、parser 和 policy 版本;
  • 候选正文、结构化时间、置信度、敏感度和创建时间;
  • 来源内容 hash 与候选 fingerprint,用于幂等和去重。

自动提取由 Message 完成后的 Outbox/Job 异步触发,不延长消息与 Run 的原子创建事务。重复消费相同来源与 extractor 版本必须返回同一候选或明确的去重结果。

ToolResult、网页、文件和模型输出都只是观察。它们可以产生 Candidate,但未经来源校验与 Policy 判定不能直接成为事实。

4.2 审批

  • 用户显式创建可直接进入批准流程,但仍执行 Schema、所有权、敏感度和冲突检查。
  • 敏感资料、第三方个人信息、关系结论、高影响推断和隐式偏好默认需要人工确认。
  • 低风险自动候选只有在策略明确允许的白名单内容上才能自动批准,并必须附带撤销窗(写入后一段时间内一键撤销且不留检索痕迹);策略版本必须进入审计。白名单外内容一律进入人工审核。
  • Candidate 的批准或拒绝是幂等命令;批准时在一个事务写 Memory/MemoryVersion、AuditEvent 和 OutboxEvent。
  • Candidate 不使用 memory_status;其生命周期与正式 Memory 分开定义。

4.3 纠正与并发

  • 创建、纠正、取代和恢复均创建新的 MemoryVersion,不原地覆盖历史内容。
  • PATCH Memory 必须携带 If-Match;并发版本不匹配返回 412 precondition_failed。
  • 用户纠正优先绑定上一次召回的 Memory ID/Version ID,避免仅凭自然语言重新搜索后误改同名记忆。
  • 纠正后的旧版本保留谱系但不再参与召回;恢复旧内容也创建新版本。
  • 删除立即阻止读取与召回,清除所有版本中的原文及派生索引,只保留不含原文的最小墓碑和审计元数据。

4.4 归真作用域

记忆候选与手动入忆必须携带并保留来源界域 canonical_scope(见 ADR-020):

  • 真界(reality):按既有候选、审批与敏感度规则进入角色正式经历记忆。
  • 境界(world):归真只形成该世界的知识候选(境忆),进入 KnowledgeDocument 与世界实体体系,不进入角色真界经历记忆,也不影响现实关系数据。
  • 幻境(simulation):不自动形成长期记忆候选;用户可将启发、观点或假设手动入忆,强制标注性质(事实/观点/启发/假设),且仍走敏感度与确认规则——幻境不得成为绕过敏感审批的通道。

界域来源不可事后静默更改;跨界引用只提供来源,不改变目标记忆的作用域。

5. 衰减、有效期与整理

  • valid_from/expires_at 表达事实有效期;过期版本在召回资格过滤阶段排除,但仍可按授权查看历史。
  • 衰减只影响排序或生成归档候选,不静默改写、删除或降低用户已确认事实的真实性。
  • 用户可固定重要记忆;固定状态仍不能绕过删除、撤权或有效期。
  • 去重、合并、冲突检测和归档由异步 Job 执行,任务带租约与幂等键;失败不影响权威版本和在线对话。
  • 自动整理结果仍是 Candidate 或新版本提案,不能绕过审批策略。

具体衰减函数和阈值必须通过评测确定,不在架构层虚构固定数值。

6. 检索管线

检索严格按以下顺序执行:

  1. 根据 actor、Personal Domain/Workspace 和 Character 在数据库查询层限定可见集合;
  2. 过滤非 active、已过期、已撤权、已删除和被取代版本;
  3. 并行生成全文、语义和结构化关系候选;
  4. 按 Memory ID/Version ID 合并去重并重排;
  5. 应用敏感度、用途、数据驻留和 Run 权限策略;
  6. 按 token/条目/延迟预算选择进入上下文的结果;
  7. 将召回证据固化到 ContextSnapshot,供用户解释和受保护诊断。

禁止先跨域全量召回再在应用层过滤。向量分数不能替代授权、来源可信度或有效期判定。

公开 Memory Search 只返回调用者有权查看的命中项,并包含命中版本、来源、各检索通道分数、重排结果、召回说明和是否进入上下文。被权限过滤的对象不能以计数、分数或错误细节泄露存在性。

7. 上下文装配

上下文顺序沿用 Agent 运行时:工具定义 → 稳定指令 → 当前分支消息 → 获准记忆与知识 → 动态运行上下文 → 当前输入。

ContextSnapshot 对每个候选记录:

  • Memory ID、Version ID、来源引用和内容 hash;
  • 召回通道、原始分数、重排分数和策略结果;
  • 是否选中、未选原因、估算 token 和最终顺序;
  • 检索器、embedder、reranker、policy 与装配器版本。

ContextSnapshot 不保存隐藏推理。普通 Run API 只返回用户可理解的来源摘要;详细分数、排除原因和版本信息遵守 DiagnosticGrant。

8. 索引与故障语义

  • PostgreSQL 中的 Memory、MemoryVersion 和来源关联是权威事实;全文、pgvector 和图关系是可重建投影。
  • 权威事务通过 Outbox 驱动索引更新。索引延迟时,新版本可暂时降级为关系数据库检索,旧版本不得继续被召回。
  • 删除与撤权事件优先于普通重建任务;消费者按 event ID 幂等。
  • 无法证明索引已清除时,对目标 Memory fail closed,并记录待修复状态,不能继续返回旧结果。
  • 图投影只用于结构化关系检索;没有量化多跳收益前不引入专用图数据库。

9. 插件边界

Memory extractor、deduper、reranker、decay 和 context provider 可以由插件贡献。Core 始终负责:

  • 身份、所有权和授权过滤;
  • Candidate/Version 状态迁移与事务;
  • 敏感度、审批、删除、审计和 Outbox;
  • 插件输入输出 Schema、资源预算和版本快照;
  • 最终 ContextSnapshot 与召回证据。

插件只能提出 Candidate、分数或排序,不能直接写权威 Memory、扩大作用域、读取未授权来源或阻止删除传播。

10. 评测与验收

WP-04 至少留下以下可重复证据:

  • 写入质量:事实、偏好、事件、关系的提取 precision/recall,以及敏感内容错误自动批准率;
  • 召回质量:长对话、多会话、时间推理、冲突纠正和多跳关系的 Recall@K、MRR/nDCG 与最终问答正确率;
  • 安全正确性:跨用户、跨角色、跨 Workspace、跨 Conversation/Branch/Run、已删除、已过期和已撤权内容的召回率必须为 0;Candidate、来源 Prompt Injection 和插件输出不能扩大 scope 或绕过审批;
  • 可追溯性:每个进入上下文的 Memory 都能定位到当前版本和未删除来源;
  • 恢复能力:索引全量重建、重复 Outbox、乱序消费和删除重放后结果一致;
  • 性能成本:写入延迟、检索 p50/p95、候选数、rerank 时延、上下文 token 和单次召回成本。

LoCoMo、LongMemEval 等公开数据集可用于回归,不替代 Hunjing 自有的中文、多角色、分支、敏感审批、删除和越权测试集。阈值在实现前通过基线实验写入发布门,不引用外部项目宣传分数作为验收结果。

11. MemOS 采纳边界

参考基线:MemTensor/MemOS commit 28dfb4e7d3adad1c93fd5574675f913921367d36,Apache-2.0。详细证据见参考项目研究。

采纳:类型化且可检查的记忆、来源追踪、分层检索、快速摄取后异步精炼、后台整理、基于已召回 ID 的纠正、可重复评测。

不采纳:把 MemCube 当作 Hunjing 授权边界、原地更新权威记忆、开放式 metadata 代替契约、运行时隐式建表、把向量/图存储作为事实源、保存或回放隐藏状态/KV cache、在 1.0 用参数记忆修改模型权重。