状态:讨论稿,供后续增量删改
对齐依据:TSD/祖龙 (ZULONG) 机器人系统技术规格说明书 (TSD)1.7.txt
范围:MemoryGraph、DualIndexSummaryStore、RAGManager、InteractionStore、TaskGraph、Web 端记忆图谱展示
当前运行态已采用分片 Hybrid 记忆图谱:
- 图谱权威属性:
data/memory_graph_hybrid/*/properties,LMDB 存储节点与边属性。 - 拓扑缓存:当前实现存在
topology.graphml,用于快速 BFS、邻居发现和 Web 展开。 - 分片索引:
shard_index.json,记录分片统计。 - 会话事件账本:
data/interaction/interaction_store.sqlite3。 - 任务图谱备份:
data/graph_backups/*.json、data/completed_tasks/*.json。
已观察到的问题:
- LMDB 中真实节点数量远多于
topology.graphml,说明拓扑缓存可能滞后。 - Web 首屏若只读根节点,会被误解为“只有根节点,没有子节点”。
- Web 会话与
task_graph_id绑定不足时,任务图谱虽已落盘,但刷新后无法稳定恢复。 - 后期记忆规模极大、分片极多时,Web 端若全量重建 MemoryGraph,会带来明显卡顿。
根据更新后的 TSD 第 21 章,长期大规模运行态应升级为“骨肉分离 + LMDB/mmap + 自定义骨架”的年级记忆方案:
- 骨架:常驻或 mmap 的紧凑二进制拓扑,用于 BFS、邻居展开、注意力路径。
- 肉:LMDB payload/properties,按需 mmap 冷加载节点/边详情。
- 向量:摘要向量/详情向量使用 mmap/FAISS 侧车。
- 分片:按时间或容量分片,冷分片按需打开。
- GraphML/JSON:仅用于调试、导出、人类可读 manifest,不作为大规模运行态主索引。
- 保持 MemoryGraph 的图结构与 RAG 摘要索引协同工作。
- 利用现有 RAG 库能力,对图记忆生成“向量摘要 + 图记忆地址”。
- 检索时采用冷热并行:
- 热数据:遍历活跃/近期图节点,做语义 + 关键词检索。
- 冷数据:走摘要向量、详情向量、FAISS/RAG 检索。
- Web 端只做索引级首屏与按需展开,禁止全量扫描全部分片。
- 任务图谱恢复优先走结构化索引,不依赖全文日志或正则。
LMDB properties是记忆图谱真实数据权威。- 大规模运行态以二进制/内存拓扑骨架作为 BFS 主路径;
topology.graphml仅作为调试/导出快照,不是运行态主索引。 SummaryStore/RAG是冷数据导航层,不替代 MemoryGraph。InteractionStore是 Web 会话恢复与审计账本,不承载完整长期语义记忆。- Web 展示走分页、按需展开、懒加载,不返回全量图。
- 后台维护可以修复和重建索引,前台请求不得同步等待重建。
- 存储层升级不得改变任务编排、工具调用、前端交互、图谱可视化的外部协议和数据契约。
职责:
- 存储会话、轮次、任务、工具、审批、代码锚点等图节点。
- 存储 HIERARCHY、TEMPORAL、REFERENCE、SEMANTIC、ASSOCIATION 等边。
- 支持 BFS 扩散、赫布增强、注意力路径、按需展开。
数据形态:
- 骨架层:节点 ID、节点类型、边、边权重,紧凑二进制或内存结构,负责 BFS。
- 属性层:label、content、metadata、importance、temperature、activation、backend_ref,LMDB/mmap 按需读取。
- 全局索引层:
node_id/session_id/task_graph_id -> shard_id/address,LMDB 独立索引库。 - 导出层:GraphML/JSON 仅作调试、备份、人工检查,不参与高频读写路径。
推荐目录:
data/memory_graph_hybrid/
manifest.json # 人工可读:分片列表、版本、统计、校验时间
global_index/
index.lmdb # node_id/session_id/task_graph_id 等全局定位索引
active_topology/
skeleton.bin # 热/活跃骨架,启动加载或 mmap
shards/
shard_2026_05/
topology.bin # 本分片紧凑拓扑骨架
properties.lmdb # 节点/边属性,mmap 按需冷加载
local_index.lmdb # 本分片局部索引
topology.graphml # 可选,仅调试/导出
职责:
- 对 MemoryGraph 中冷却后的会话、任务、经验生成摘要。
- 保存摘要向量、详情向量和关键词索引。
- 每条摘要必须回写图记忆地址,例如:
node_idsession_node_idround_node_idtask_graph_idshard_idfull_path
推荐摘要对象:
- 会话摘要:一个 session 下多个 round 的主题摘要。
- 任务摘要:TaskGraph 根节点及关键子任务摘要。
- 工具执行摘要:工具调用、审批、结果、失败原因。
- 经验摘要:可复用的错误修复、项目规则、用户偏好。
职责:
- 保存 Web 会话列表、消息账本、
conversation_id、session_node_id、task_graph_id。 - 支撑 Web 刷新后的快速恢复。
- 作为 MemoryGraph 写入失败时的短期回填来源。
InteractionStore 不应成为长期语义检索主库。
热数据范围:
- 当前 session 根节点及 3 跳 BFS 邻域。
- 最近活跃 session / round。
- 当前活跃 TaskGraph。
temperature=hot或最近访问节点。- InteractionStore 最近 N 条事件。
检索方式:
- 图 BFS:从
session_node_id、当前 round、active task 开始扩散。 - 关键词检索:label、content、metadata.goal、metadata.user_text、metadata.bot_text。
- 轻量语义检索:对热节点摘要或 content 做向量相似度。
- 会话优先加权:
session_id匹配应高于全局相似节点。
热路径目标:
- 不跨全部分片扫描。
- 响应时间保持在几十毫秒级。
- 召回当前上下文和近期任务状态。
冷数据范围:
- Warm/Cold 记忆节点。
- 历史会话摘要。
- 历史 TaskGraph 摘要。
- 经验库与 RAG 库。
检索方式:
DualIndexSummaryStore:SQLite 条件过滤 + FAISS 摘要向量。- 详情向量:摘要命中后再加载对应详情。
- 经验库混合检索:向量 0.7 + BM25 0.3。
- 图地址回跳:根据摘要命中的
node_id/shard_id/full_path回到 MemoryGraph,加载邻域。
冷路径目标:
- 不加载完整历史图。
- 先找摘要,再按图地址取局部“肉”。
- 只把高置信结果注入 L1-B 上下文包。
用户输入后,系统先对输入内容进行记忆检索。冷记忆流程建议采用“摘要先行、图地址回跳、工具式增量回忆”:
用户输入
→ L1-B / Memory Retriever 对输入做检索
→ 记忆 RAG 命中摘要
→ 将摘要文本 + 图记忆地址拼接进 LLM 上下文
→ LLM 判断是否需要了解详情
→ LLM 调用记忆工具,以摘要对应的图记忆 ID 作为 BFS 种子
→ MemoryGraph 做一次增量关联扩散
→ 返回局部详细记忆内容
→ LLM 基于增量回忆继续推理
首次注入 LLM 上下文的冷记忆不应是完整历史正文,而应是轻量导航信息:
[冷记忆摘要]
- summary_id: summary_20260527_xxx
- graph_memory_id: dialogue:session_xxx/round_xxx
- shard_id: 2026_05
- full_path: dialogue:session_xxx/round_xxx
- summary: 曾讨论过 Web 端任务图谱刷新后无法恢复,原因是 conversation 未绑定 task_graph_id。
- relevance: 0.86
- recall_hint: 如需详情,可调用 recall_memory,以 graph_memory_id 为 seed 做 BFS 扩散。
LLM 若需要细节,不直接要求系统全量加载历史,而是调用记忆工具:
recall_memory({
"seed_node_id": "dialogue:session_xxx/round_xxx",
"max_depth": 2,
"limit": 20,
"include_content": true
})
工具返回的内容应是局部增量,而不是整库回放:
- 种子节点正文或摘要。
- 直接父子节点。
- 时间相邻 round。
- 关联 TaskGraph 节点。
- 关联工具/审批/结果节点。
- 高权重 SEMANTIC / ASSOCIATION 邻居。
这样冷记忆检索分为两步:
- 摘要召回:低成本把可能相关的历史放入 LLM 注意力范围。
- 增量回忆:只有当 LLM 明确需要细节时,才以图记忆 ID 为种子做 BFS 局部扩散。
建议统一融合分:
score =
0.35 * semantic_score
+ 0.20 * keyword_score
+ 0.20 * graph_proximity_score
+ 0.15 * recency_score
+ 0.10 * importance_score
+ session/task bonus
热路径优先保证上下文连续性,冷路径优先保证历史相关性。若热路径已有高置信结果,冷路径可以异步补充,不阻塞首字输出。
当前 shard_index.json 只记录粗统计。大规模运行态采用 LMDB 独立全局索引库,JSON 退化为人工可读 manifest。
最低索引字段:
session_id -> shard_idconversation_id -> session_node_idtask_graph_id -> shard_idtask_graph_id -> backup_pathnode_id -> shard_idroot_nodesrecent_sessionsactive_nodeshot_nodesupdated_at
索引更新时机:
- 新增节点时更新
node_id -> shard_id。 - 新建 Web 会话时更新
conversation_id -> session_node_id。 - 创建或复用 TaskGraph 时更新
task_graph_id相关索引。 - 会话活跃时更新
recent_sessions。 - 节点温度变化时更新
hot_nodes或摘要状态。
高频路径必须只读 LMDB 全局索引,不扫描所有分片:
- Web 展开节点。
- RAG 摘要命中后回跳图记忆地址。
- TaskGraph 刷新恢复。
read_memory_node/discover_related等工具调用。- MemoryGraph 快照生成中的 active path / execution view 定位。
只返回:
- 最近会话列表。
- 根级 session/task 节点。
- 活跃节点 ID。
- 当前任务图谱摘要。
- 统计信息。
禁止首屏返回所有节点和所有边。
用户展开节点时:
node_id通过索引定位shard_id。- 从
topology.bin/ active skeleton 读取一层 children。 - 从 LMDB 批量加载 children 属性。
- 返回分页结果。
默认限制:
- 单次最多 50-100 个节点。
- 默认深度 1。
- 更深层由用户继续展开。
搜索流程:
- 热路径:当前 session / active task / hot nodes。
- 冷路径:摘要向量 + 详情向量 + 经验库。
- 命中摘要后,先把摘要 + 图记忆地址注入上下文。
- 如 LLM 需要详情,再调用记忆工具,以图记忆 ID 为种子做 BFS 增量回忆。
Web 搜索不应直接遍历全部分片。
启动时比较:
topology.bin/ active skeleton 节点/边数量。- LMDB properties 节点/边数量。
- LMDB global_index 统计。
manifest.json统计。
若差异超过阈值,标记该分片为 topology_stale=true。
后台异步执行:
LMDB properties
→ rebuild_topology_from_properties()
→ save topology.bin / active skeleton
→ 可选导出 topology.graphml
→ 更新 global_index.lmdb
→ 更新 manifest.json
→ 广播索引修复完成事件
前台请求处理策略:
- 若拓扑可用,继续用二进制/内存骨架。
- 若拓扑陈旧但 LMDB 可用,对指定节点可走 LMDB 索引兜底。
- 禁止 Web 请求同步重建完整拓扑。
TaskGraph 恢复优先级:
- 当前内存活跃 TaskGraph。
InteractionStore.conversation.task_graph_id。task_graph_id -> backup_path索引。- MemoryGraph 中 task 节点地址。
- BFS 兜底恢复。
必须保证:
- 创建 TaskGraph 后写入 InteractionStore。
- 复用 TaskGraph 后刷新 conversation 的
task_graph_id。 - TaskGraph 根节点写入 MemoryGraph,并与 session/round 建立
REFERENCE边。 - 任务完成后生成摘要,写入 SummaryStore/RAG,并保留图地址。
存储升级只允许替换 MemoryGraph 的内部存储实现,不允许破坏任务编排、工具调用、前端交互和图谱可视化的外部契约。
必须保持:
- TaskGraph 仍由
zulong/l2/task_graph.py负责运行态编排和to_frontend_dict()序列化。 - TaskGraph 备份仍写入
data/graph_backups/*.json,完成归档仍写入data/completed_tasks/*.json。 TaskGraphAdapter继续把 TaskGraph 投射到 MemoryGraph。task_graph_id仍通过 InteractionStore 和 MemoryGraph metadata 绑定 Web conversation。- Dialogue 与 TaskGraph 的主边继续使用
REFERENCE。
禁止:
- 因存储升级改变 TaskGraph 节点 ID、状态值、
h_edges/d_edges语义。 - 因 MemoryGraph 分片改造阻塞 FC 循环或 TaskGraph 自动保存。
- 把 TaskGraph 恢复改成必须全图扫描。
必须保持 TSD v2.7 工具袋与工具预判链路:
用户输入
→ L1-B 工具预判 + 上下文/记忆打包
→ L2 单次决策
→ 只有真实 tool_call 出现才进入工具循环
记忆工具接口必须稳定:
recall_memoryread_memory_nodesave_memory_notediscover_related
存储升级后,这些工具只改变内部查询路径:
global_index.lmdb 定位分片
→ topology.bin / skeleton 做 BFS
→ properties.lmdb 加载详情
→ 返回原有工具结果结构
禁止:
- 改变工具名、参数名、风险等级语义。
- 让 LLM 看到底层分片实现细节。
- 因索引修复或拓扑重建阻塞工具调用。
必须保持现有 WebSocket / unified protocol 消息类型:
tool:predictiontask:plantask:summaryapproval:requiredattention:updategraph:memory:diffMEMORY_GRAPH_UPDATETASK_GRAPH_UPDATEINTERACTION_EVENT
必须保持 InteractionPayload 的 7 类 kind:
planactionobservationapprovalprogresssummaryuser_interject
存储升级只影响 MEMORY_GRAPH_UPDATE 的数据来源,不影响消息名、字段语义和前端卡片渲染逻辑。
必须保持 MemoryGraph 前端接口:
to_frontend_dict(depth=...)get_node_children_for_frontend(node_id)get_active_node_ids()compute_activations(seed_node_ids, max_depth=3, decay=0.5)
/api/memory-graph/snapshot 与 MEMORY_GRAPH_UPDATE 必须继续返回:
nodesedgesstatsactive_node_idsthought_view
根据更新后的 TSD §23.8.5,快照还必须显式携带 execution_view,用于展示工具调用、工具结果和审批事件:
{
"execution_view": {
"nodes": [],
"edges": [],
"execution_node_ids": [],
"stats": {
"total_execution_nodes": 0,
"tool_call": 0,
"tool_result": 0,
"approval": 0
}
}
}首屏可以继续是根节点折叠视图,但不得隐藏执行事件节点的验收入口。大规模图谱必须采用渐进式加载、分页和渲染降级。
更新后的 TSD 要求任务执行事件采用独立 NodeType:
TOOL_CALLTOOL_RESULTAPPROVAL
存储升级必须支持这些节点类型,且同时兼容枚举模式和字符串模式查询。
图边规则必须保持:
| source | target | edge | 含义 |
|---|---|---|---|
| session | round | HIERARCHY |
会话包含轮次 |
| round | TOOL_CALL / TOOL_RESULT / APPROVAL |
HIERARCHY |
轮次包含工具/审批事件 |
| round | task_graph/task_node | REFERENCE |
对话轮引用任务图 |
| task_node | TOOL_CALL |
DEPENDENCY 或 REFERENCE |
任务节点触发工具 |
TOOL_CALL |
TOOL_RESULT |
CAUSAL |
工具调用与结果配对 |
APPROVAL(request) |
APPROVAL(decision) |
CAUSAL |
审批请求与决策配对 |
TOOL_RESULT |
file/code_symbol | REFERENCE |
工具结果影响文件/代码 |
TOOL_CALL |
next TOOL_CALL |
TEMPORAL |
同一任务内的工具链顺序 |
三层闭环必须保持:
InteractionStore 原始事件
→ MemoryGraph 结构化语义节点和边
→ ExperienceStore 可复用经验
一次 Web 用户消息建议写入顺序:
Web user message
→ InteractionStore.append_event
→ MemoryGraph: session/round/message nodes
→ 热路径索引更新
→ L1-B 上下文检索
→ L2/FC 执行
→ TaskGraph 更新与备份
→ assistant/tool/status events 写入 InteractionStore
→ MemoryGraph 补充 tool/approval/task summary 节点
→ SummaryStore/RAG 异步摘要和向量化
→ ExperienceStore 可复用经验提炼
建议后台任务:
- 拓扑一致性校验与修复。
- Hot/Warm/Cold 状态迁移。
- 冷数据摘要生成。
- 摘要向量索引保存。
- 低价值节点审查与遗忘。
- 分片索引压缩与校验,包括
global_index.lmdb与分片 properties/topology 的一致性校验。 - InteractionStore 到 MemoryGraph 的回填。
这些任务不得阻塞 Web 聊天主链。
global_index.lmdb 是高频点查路径,但新增节点、更新会话、绑定 TaskGraph 时也会产生索引写入。LMDB 同一环境同一时刻只能有一个写事务,因此不能让业务热路径对每个节点都同步开启独立写事务。
推荐采用写缓冲 + 批量提交:
业务写入 MemoryGraph
→ IndexUpdateQueue 追加索引变更
→ 后台 writer 单线程批量提交 LMDB transaction
→ 提交成功后更新内存 hot index
写入策略:
- 单 writer 协程/线程串行写
global_index.lmdb。 - 按数量或时间批量提交,例如
100-500条或50-200ms一批。 - 对强一致路径提供
flush_index_updates(),仅在任务完成、会话切换、关闭前调用。 - Web 展开和工具读取优先查内存 hot index,再查 LMDB。
- 若 LMDB 索引尚未提交,允许通过当前进程的 pending index buffer 命中最新节点。
一致性要求:
- MemoryGraph 节点写入成功后,索引更新至少进入队列。
- 队列持久化可采用轻量 WAL,防止进程崩溃后索引丢失。
- 启动时若发现 WAL 未清空,先 replay,再开放 Web 请求。
- 索引写失败不得阻断 L2 回复,但必须标记
index_degraded=true并触发后台修复。
topology.bin 需要服务 BFS、邻居展开和注意力路径,目标是 mmap 友好、可增量更新、读路径尽量零拷贝。
推荐第一阶段采用自定义数组结构,而不是直接引入 Cap'n Proto / FlatBuffers 作为主拓扑:
- BFS 需要连续数组和邻接表,CSR/CSC 结构比通用对象序列化更合适。
- Cap'n Proto / FlatBuffers 适合稳定对象读取,但动态图增量更新仍需要额外索引和重写策略。
- 自定义结构更贴合 TSD 第 21 章的“自定义骨架 + LMDB/mmap”方向。
建议格式:
Header
magic/version/schema_version
node_count/edge_count
node_table_offset
edge_table_offset
out_index_offset
in_index_offset
string_table_offset
NodeTable[]
node_int_id
node_type
shard_local_id
flags
label_ref/hash
EdgeTable[]
src_int_id
dst_int_id
edge_type
weight
flags
OutIndex[] / InIndex[]
node_int_id -> edge range
StringTable / IdMap
compact int id <-> node_id
增量更新策略:
- 热写入先追加到 delta log:
topology_delta.log。 - 读路径合并
base topology.bin + delta overlay。 - 后台 compactor 定期把 delta 合并回新的
topology.bin.tmp,校验后原子替换。 - 单次业务写入不得全量重写大分片 topology。
当 delta 过大时触发合并:
- delta 边数超过 base 的 5%-10%。
- delta 文件超过阈值,例如 32-128MB。
- 分片从 hot 迁移到 warm/cold 前。
- 系统空闲窗口。
跨分片边不能只散落在各分片本地拓扑中,否则跨冷分片 BFS 会退化为多分片扫描。
推荐新增跨分片边索引:
global_index/
cross_edges.lmdb
索引内容:
src_node_id -> [(dst_node_id, dst_shard_id, edge_type, weight)]dst_node_id -> [(src_node_id, src_shard_id, edge_type, weight)]edge_type -> edge ids可选,用于 SEMANTIC/REFERENCE/CAUSAL 过滤。
存储规则:
- 分片内边写入本地
topology.bin。 - 跨分片边写入
cross_edges.lmdb,并在源/目标分片 local index 中保留轻量引用。 - BFS 默认先走本分片拓扑;到边界节点时查询
cross_edges.lmdb。 - 跨分片 BFS 必须有
max_cross_shards和max_nodes限制。
建议限制:
- 普通 RAG 回跳:最多跨 2 个分片。
- 当前 session/task 恢复:最多跨 3 个分片。
- 全局探索工具:需要显式工具调用并分页返回。
冷分片按需 mmap 打开不能粗暴地直接打开完整 properties.lmdb。lmdb.open() 和大 map size 会有管理开销,分片多时需要分级唤醒。
推荐分级打开:
Level 0: manifest.json / global_index.lmdb 常驻
Level 1: local_index.lmdb 小索引按需打开
Level 2: topology.bin mmap 打开,做局部 BFS
Level 3: properties.lmdb 打开,加载最终 TopK 节点详情
冷分片唤醒流程:
global_index.lmdb定位候选 shard。- 打开或复用
local_index.lmdb,确认节点/摘要存在。 - 需要扩散时 mmap
topology.bin。 - BFS 得到 TopK 节点后,才打开
properties.lmdb加载详情。
缓存策略:
- LRU 管理已打开分片句柄。
- 热分片常驻。
- Warm 分片保留 local index 和 topology,properties 延迟打开。
- Cold 分片默认只保留 manifest/global index 命中能力。
- 后台预热当前 session/task 相关分片。
当摘要量达到百万级,单个 FAISS 内存索引会成为瓶颈。摘要向量需要与 MemoryGraph 分片策略协同。
推荐:
- 热摘要:小型内存 FAISS Flat/HNSW。
- Warm 摘要:按月/主题分段 FAISS。
- Cold 摘要:IVF/PQ 或磁盘索引,按 shard/topical cluster 加载。
检索流程:
query
→ 热摘要索引 topK
→ global summary routing index 粗筛候选分片/主题
→ 并行查询 2-5 个候选分段 FAISS
→ 融合排序
→ 命中摘要携带 graph_memory_id/shard_id
→ 回跳 MemoryGraph
摘要 metadata 必须包含:
summary_idgraph_memory_idshard_idfull_pathtime_rangetopic_clusterstatus= hot/warm/coldsource_node_ids
active_topology/skeleton.bin 是热/活跃骨架,不应无限膨胀成全量拓扑,也不能过小导致频繁冷分片 fallback。
进入 active skeleton 的条件:
- 当前 session 根节点及 3 跳邻域。
- 当前 active TaskGraph。
- 最近 30 分钟热路径命中节点。
- 最近被 RAG 摘要回跳命中的节点及 1-2 跳邻域。
- 高重要度节点:
IMPORTANT、FACT、IDENTITY、MUST_REMEMBER。
剔除条件:
- 超过热窗口且访问次数低。
- 不在当前 session/task 相关邻域。
- 非高重要度节点。
- active skeleton 超过内存预算。
维护策略:
- 使用 LRU + importance 加权淘汰。
- 每次检索只更新激活计数,不同步重写 skeleton。
- 后台定期生成新的 skeleton 快照并原子替换。
- 保留 delta overlay,避免频繁全量重建。
建议预算:
- 桌面端初始预算:50k-200k 节点骨架。
- 嵌入式/低内存端:10k-50k 节点骨架。
- 超出预算时保留当前 session/task、执行事件节点、重要记忆节点。
分片阈值不能只看节点数。TSD 第 21 章给出的长期量级是 skeleton.bin ~15MB、payloads.lmdb ~2GB@10年,并可按年拆成约 200MB/片。结合当前代码的月度分片和 Hybrid LMDB 属性库,运行态采用“节点数 + 物理大小”双阈值。
当前兼容期默认配置:
memory:
hybrid_storage:
global_index_map_size_mb: 256
local_index_map_size_mb: 64
max_nodes_per_shard: 150000
max_shard_property_mb_warning: 150
max_shard_property_mb_split: 200
max_shard_topology_mb_warning: 64
max_shard_topology_delta_mb_compact: 32
max_active_skeleton_nodes: 50000
shard_size_check_interval_nodes: 100触发规则:
- 节点数达到
max_nodes_per_shard * 95%:预警。 - 节点数达到
max_nodes_per_shard * 110%:触发自动分裂。 propertiesLMDB 实际使用量达到150MB:预警。propertiesLMDB 实际使用量达到200MB:触发自动分裂。topology.graphml达到64MB:预警,提示进入topology.bin迁移窗口。
当前代码仍保留 topology.graphml,所以 max_shard_topology_mb_warning 只做风险提示,不把 GraphML 大小作为自动分裂主条件。进入 P3 后,阈值应改为 topology_delta.log 和 topology.bin 的大小。
自动分裂兼容策略:
- 父分片继续保留历史节点。
- 新写入路由到最新
parent_part_N子分片。 - 同一分片内的边继续按源/目标节点共同所在分片写入。
- 跨分片边写入
global_index/index.lmdb中的cross_edges_by_src/cross_edges_by_dst,保证HIERARCHY/REFERENCE在 Web 展开、BFS 和前端快照中不断链。 - 跨分片边数量单独计入
cross_edge_count,不重复计入源/目标分片的本地edge_count。 - 旧版
shard_index.json.cross_edges仅作为迁移兜底,启动时自动写入 LMDB 跨边索引;迁移成功后清空 JSON 中的跨边列表,仅保留legacy_cross_edge_count和迁移时间戳。
这样可以先防止单分片无限膨胀,又不改变 MemoryGraph 外部 API、Web 快照结构、工具 schema 和 TaskGraph 编排逻辑。
目标:
- Web 首屏:只读索引,避免全图扫描。
- 单节点展开:个位数到几十毫秒,取决于 children 数量。
- 热路径检索:几十毫秒级。
- 冷路径检索:百毫秒级以内,允许异步补充。
- 拓扑修复:后台执行,可耗时,不阻塞用户操作。
- 点查定位:通过
global_index.lmdb达到毫秒级或亚毫秒级。 - 冷节点加载:通过 LMDB/mmap 按需读取,目标个位数毫秒内。
风险:
- 如果
node_id -> shard_id缺失,将退化为跨分片扫描。 - 如果二进制骨架或 GraphML 导出长期滞后,BFS 与 Web 展开会漏节点。
- 如果
task_graph_id未绑定 conversation,任务图谱刷新恢复会失败。 - 如果摘要缺少图地址,RAG 命中后无法回跳 MemoryGraph 局部上下文。
- 如果存储升级改变
to_frontend_dict()/get_node_children_for_frontend()输出结构,前端图谱可视化会受损。 - 如果新增节点类型没有兼容枚举和字符串查询,工具执行记忆化会漏掉
TOOL_CALL/TOOL_RESULT/APPROVAL。
- 兼容期启动时检测当前 GraphML 与 LMDB 数量差异。
- 差异明显时后台重建拓扑。
- 修复 Web 会话与
task_graph_id绑定。 - Web 首屏明确返回根节点 +
children_count,避免误判。 - 分片阈值配置化,新增节点数与 LMDB 物理大小双阈值保护。
- 修正自动分裂后的写入路由,避免继续写入已超限父分片。
- 保持 MemoryGraph 外部 API、工具 schema、WebSocket 消息类型不变。
当前已落地 P0 兼容子集:
- 分片加载时会比较
topology.graphml拓扑节点/边数量与 LMDB properties 节点/边数量;GraphML 为空或明显少于 LMDB 时,以 LMDB 为权威自动重建当前分片拓扑缓存。 - 拓扑健康信息写入
shard_index.json.shards[*].topology_health,并统计topology_rebuild_count。 - 已加入节点数 + LMDB properties 物理大小双阈值,超限触发预警或自动分裂。
- 自动分裂后,新写入路由到最新
parent_part_N,避免继续写爆父分片。 - Web 首屏节点序列化携带
children_count,展开接口继续按需返回子节点。 - Web/IDE/MemoryMirror 已补充
task_graph_id绑定与恢复入口,刷新后优先通过索引定位图记忆地址。
兼容期说明:当前重建仍是分片加载时同步修复,适合 P0 避免旧 GraphML 缓存遮住真实 LMDB 数据。P3 后应迁移为后台 compactor 维护 topology.bin / active skeleton。
- 建立
global_index/index.lmdb。 - 建立
node_id -> shard_id,并接入get_node()、has_node()、get_children()、add_edge()等高频路径。 - 基于节点 metadata 建立
conversation_id -> session_node_id、session_id -> node_id、task_graph_id -> task_node_id的轻量二级索引。 - 保留全分片扫描兜底,并在兜底命中后回填
global_index.lmdb。 - Web 展开接口改为索引定位分片。
当前已落地 P1 兼容子集:
global_index/index.lmdb已作为 P1 点查层引入。- 写入新节点时同步维护
node_id -> shard_id。 - 读取节点时优先查 LMDB 全局索引,索引缺失时扫描分片并回填。
get_total_stats()暴露global_index统计,用于观察索引健康度。- 跨分片边已迁入
global_index/index.lmdb的cross_edges_by_src/cross_edges_by_dst,JSONcross_edges仅保留旧数据迁移兜底。 - MemoryGraph 已提供显式恢复接口:
get_session_node_id_for_conversation()、get_task_node_id_for_graph()、get_context_seed_for_conversation()。 - Web 已提供
/api/memory-graph/context-seed和REQUEST_MEMORY_CONTEXT_SEED/GET_MEMORY_CONTEXT_SEED,用于按 conversation/task graph 直接定位图记忆地址。 - IDE BFS 自恢复已优先使用全局索引定位 session seed,MemoryMirror 任务绑定已优先使用全局索引定位 Task 节点。
- 对 session、round、task、experience 生成摘要。
- 摘要写入
DualIndexSummaryStore。 - 摘要 metadata 保存图记忆地址。
- 冷路径命中摘要后回跳 MemoryGraph 邻域。
当前已落地 P2 兼容子集:
recall_memory返回结果追加graph_memory_id、shard_id、full_path、memory_address,不改变原有node_id/type/label/content/score字段。read_memory_node、discover_related、activate_memory_network、list_memory均返回图记忆地址,并兼容 Hybrid/Sharded 后端的字符串节点类型。recall_memory新增可选seed_node_id/graph_memory_id与expand_depth,支持 LLM 以摘要命中的图记忆 ID 作为种子做一次增量回忆。DualIndexSummaryStore的摘要条目新增graph_memory_id、shard_id、full_path、source_node_ids,旧 SQLite 库通过ALTER TABLE自动补列。MemoryGraph.index_summary()/ShardedMemoryGraph.index_summary()已同步写入DualIndexSummaryStore的 SQLite L1 摘要导航层,摘要 ID 采用graph_summary:{graph_memory_id},不会在对话热链路强制触发 embedding。DualIndexSummaryStore.search_graph_summaries()已提供低延迟摘要导航检索入口,命中结果直接携带graph_memory_id/shard_id/full_path,可回跳 MemoryGraph 做 BFS 增量回忆。MemoryGraph.retrieve_context()与ShardedMemoryGraph.retrieve_context()已接入 SQLite 摘要导航检索;即使热路径没有命中,也可以返回source=summary_navigation的冷摘要结果,并携带graph_memory_id/shard_id/full_path/memory_address。- L2/Web/IDE 的记忆上下文注入会显示图记忆 ID,方便 LLM 后续调用
read_memory_node或discover_related以该摘要地址为种子做 BFS 增量回忆。 - 该阶段只追加字段和可选参数,不改变工具名、必填 schema、WebSocket 消息类型、TaskGraph 编排协议和前端图谱 payload 契约。
- 摘要分片化。
- 冷分片按需 mmap。
- 跨分片语义边延迟加载。
- Web 图谱搜索分页与流式返回。
- GraphML 从运行态主拓扑降级为调试/导出。
- 分片拓扑升级为
topology.bin/ active skeleton。
当前已落地 P3 兼容子集:
TopologyIndex已支持topology.bin二进制侧车保存/加载。MemoryGraphHybrid.save()会同时写入topology.bin与topology.graphml;load()默认优先读取topology.bin,失败再回退 GraphML。MemoryGraphHybrid已追加topology_delta.log增量日志;节点/边新增删除先写 delta,加载时回放topology.bin + delta,保存快照时压实并清空 delta。- 分片 usage 统计已增加
topology_bin_bytes/topology_bin_mb与topology_delta_bytes/topology_delta_mb,可观察二进制拓扑和增量日志体积。 - 新增
max_shard_topology_delta_mb_compact配置;当 delta 超过阈值时,ShardedMemoryGraph会启动后台 compactor,把 delta 合并进topology.bin/ GraphML 并清空日志。 - topology compactor 已改为去重队列 + 单后台 worker,并增加短静默窗口调度;失败会记录到 shard index,并最多重试 3 次。
- 新增
active_topology/skeleton.bin兼容骨架;检索命中、焦点更新、BFS 激活会刷新 active 节点与一跳邻接,to_frontend_dict()和 stats 会返回active_skeleton。 - 新增
max_active_skeleton_nodes配置,默认50000;刷新 active skeleton 时按“当前中心/焦点路径优先、激活值、重要度、访问次数、最近访问、任务/会话元数据”打分,超预算时只淘汰非关键候选节点,避免 active skeleton 膨胀成全量拓扑。 - active skeleton 已增加后台防抖刷新队列;检索、焦点更新和 BFS 激活会排队刷新,减少热链路频繁同步写快照。
- 新增分片级
local_index.lmdb侧车索引;新写节点会同步记录轻量节点头,旧分片可通过rebuild_local_index()重建。完整 local index 可在 global index 指向错误或节点缺失时给出确定性未命中,避免无效打开完整冷分片。 - 新增
topology.csrCSR/CSC mmap 读侧车;稳定分片在 delta 压实后可优先用 CSR reader 做邻居查询、边查询和加权 BFS,缺失或陈旧时自动回退 igraph。 - 摘要导航已增加
shard_id/topic/status路由索引与route_graph_summaries()入口,为后续分段 FAISS/IVF/PQ 选择候选向量段。 - 当前
topology.bin仍作为 igraph 拓扑缓存的二进制侧车;topology.csr已承担兼容读路径,但写入和 GraphML 导出仍保留,避免破坏外部契约。 - 当前 active skeleton 仍是 Web/调试/后续迁移用的热骨架快照,还不是 BFS 主路径。
仍未完成:
- 生产级分段 FAISS/IVF/PQ 向量文件仍可在摘要路由索引之上继续增强。
topology.csr当前是读侧车,写入主路径仍由 igraph + delta 承担;完全去 igraph 化可作为后续性能专项。
推荐采用混合摘要,而不是只按 session、round 或任务阶段单一切分。
分层粒度:
- Round 摘要:单轮用户输入、助手回复、关键工具调用。用于精确回忆和冷记忆图地址回跳。
- Session 摘要:一个会话窗口的主题、长期上下文、用户偏好和未完成事项。用于 Web 会话恢复和跨轮上下文召回。
- Task Stage 摘要:TaskGraph 的阶段性目标、已完成节点、失败原因、验证结果。用于复杂任务恢复。
- Experience 摘要:从多次任务中提炼出的可复用经验。用于跨项目/跨会话迁移。
推荐写入关系:
session_summary
→ round_summary[]
→ task_stage_summary[]
→ experience_summary[]
LLM 上下文默认注入 Session/Task Stage 级摘要;当 LLM 需要细节时,再通过摘要中的 graph_memory_id 回跳到 Round 或 Task 节点做 BFS 增量回忆。
理由:
- 只按 round:检索精准,但上下文碎片化严重。
- 只按 session:上下文稳定,但细节损失明显。
- 只按任务阶段:适合任务恢复,但无法覆盖普通聊天和用户偏好。
- 混合粒度最符合 TSD 的 MemoryGraph + SummaryStore + ExperienceStore 三层闭环。
热数据按时间划分,遵循 TSD 与当前代码:
- 当前
ShardedMemoryGraph.retrieve_context()默认hot_window_minutes=30。 - TSD 中 MemoryGraph 节点温度阈值为
hot_max=3600、warm_max=86400。 - 当前 Hybrid 节点温度更新逻辑为:1 小时内 hot,24 小时内 warm,超过后 cold。
推荐策略:
- 检索热窗口默认保持 30 分钟。
- 节点温度继续保持 1 小时 hot、24 小时 warm、之后 cold。
- 访问次数、重要度、当前 session/task 匹配只作为加权,不改变时间分层本身。
Web 默认展示:
根节点 + 最近活跃路径
首屏内容:
- 根级 session/task。
- 最近活跃 session。
- 当前 focus path / active node path。
- 每个根节点的
children_count。
这样既避免全量加载,又能让用户看到“当前记忆正在活跃哪里”。
RAG 命中后回跳 MemoryGraph 的 BFS 深度默认保持现有设置:
compute_activations()默认max_depth=3。TopologyIndex加权 BFS 默认max_depth=3。- 当前跨分片冷路径发现局部实现中有
max_depth=2的性能保护,可继续作为跨分片检索保护。
推荐:
- 单分片或已定位精确
shard_id:默认深度 3。 - 跨分片兜底发现:默认深度 2。
- 工具参数允许 LLM 显式请求更小深度或更小
limit,但不默认扩大。
推荐使用 REFERENCE 作为 Dialogue 与 TaskGraph 的主连接边,不使用 HIERARCHY。
依据:
- TSD 中明确:
HIERARCHY用于父子关系,如session→round、TaskGraph 内部层级;REFERENCE用于跨类型引用,如dialogue↔tasks。 - 当前
DialogueAdapter.add_round()中,当存在task_graph_id时,创建round → task的REFERENCE边。 - 当前
DialogueAdapter.bind_session_to_task()中,会话与任务绑定也使用REFERENCE边。 - 当前
memory_mirror._attach_task_if_present()也使用REFERENCE边连接round → task_node。
推荐结构:
Dialogue Session
└─ HIERARCHY → Dialogue Round
└─ REFERENCE → TaskGraph Root
TaskGraph Root
└─ HIERARCHY / DEPENDENCY → Task Nodes
原因:
- Dialogue 和 TaskGraph 是不同类型的语义对象,不是父子包含关系。
- 使用
REFERENCE可以保留跨类型引用语义,避免把 TaskGraph 错误挂成会话子树。 - BFS 仍可通过
REFERENCE跨到任务图谱,不影响上下文召回。
推荐采用:
LMDB 全局索引库 + LMDB 分片属性库 + topology.bin/active skeleton。
JSON 仅保存低频元信息和人工可读 manifest。
GraphML 仅作为可选调试/导出格式。
建议结构:
data/memory_graph_hybrid/
manifest.json # 人工可读分片 manifest:分片列表、统计、版本、校验时间
global_index/
index.lmdb # mmap / B+树 / 低延时查询
active_topology/
skeleton.bin # 热/活跃骨架,BFS 主路径
shards/
shard_2026_05/
topology.bin # 本分片紧凑拓扑
properties.lmdb # 节点/边属性,mmap 按需读取
local_index.lmdb # 本分片局部索引
topology.graphml # 可选,仅调试/导出
LMDB 全局索引库保存:
node_id -> shard_idsession_id -> shard_idconversation_id -> session_node_idtask_graph_id -> shard_idtask_graph_id -> backup_pathroot_node_id -> shard_idactive_node_id -> shard_idhot_node_id -> shard_id
JSON manifest 保存:
- 分片列表。
- 分片创建时间。
- 粗略节点/边数量。
- 索引版本。
- 最近一次一致性校验时间。
topology.bin / active skeleton 保存:
- 节点 ID 紧凑映射。
- 节点类型轻量标签。
- 出入边邻接表。
- 边类型和边权。
- BFS 所需的最小字段。
properties.lmdb 保存:
- label/content/summary。
- metadata。
- importance/temperature/activation。
- backend_ref/full_path。
- 工具调用、审批、任务执行节点详情。
不推荐只用 JSON:
- 分片和节点数量极大后,JSON 需要整体读写。
- 并发写入和崩溃恢复弱。
- 查询
node_id -> shard_id会退化成内存加载大字典。
不推荐 SQLite 作为主索引:
- SQLite 适合 InteractionStore 这种关系账本和审计查询。
- 对高频点查可以胜任,但与当前 Hybrid 的 LMDB mmap 设计不完全一致。
- 在“磁盘虚拟内存 + 最低加载延时”目标下,LMDB 更贴合 TSD 的骨肉分离方案。
推荐 LMDB 的原因:
- TSD 年级记忆方案明确偏向 mmap/LMDB。
- LMDB B+ 树点查适合
node_id -> shard_id。 - mmap 按需加载,冷读也能保持低延时。
- 读取无锁,适合 Web 展开和检索并发。
- 崩溃安全和事务语义强于 JSON。
GraphML 的定位:
- 保留为导出、诊断、可视化调试格式。
- 不作为超大规模运行态主拓扑。
- 不参与高频 BFS、节点展开、RAG 回跳和 TaskGraph 恢复。