# 织忆五步实施计划 > 创建时间:2026-05-30 > 状态:E1/E2/E3/E4/E5 全部完成 ✅ > 禁止:偷懒、随意更改变动设计语言 --- ## 总览 | 阶段 | 内容 | 优先级 | 预计工期 | 状态 | |------|------|--------|---------|------| | **E1** | 图谱导航激活 | 🔴 高 | 1-2 天 | ✅ 完成 | | **E2** | 多 agent 命名空间激活 | 🔴 高 | 1 天 | ✅ 完成 | | **E3** | 增量 embedding | 🟡 中 | 1 天 | ✅ 完成 | | **E4** | 图谱推理 | 🟡 中 | 2-3 天 | ✅ 完成 | | **E5** | 产品 UI | 🔵 低 | 长期 | ⏳ | --- ## E1:图谱导航激活 ### 目标 改造 `/recall` 链路,向量搜索后接图谱 BFS 扩展,让搜索结果融合结构化知识。 ### 现状 - 图谱数据:1269 节点 / 31248 边(`graph/stats` 确认) - `navigate.go` BFS 导航代码已写好,但 `/recall` 没调用 - `/recall` 当前纯语义搜索,不走图谱 ### 实施步骤 #### E1.1 确认 navigate.go 接口 - 找到 `navigate.go` 的函数签名和参数 - 确认 BFS 扩展是 1 跳还是 2 跳 - 确认输出格式(节点列表还是边列表) #### E1.2 改造 recall 链路 修改 `internal/api/routes/recall.go`: ``` 语义搜索 → 向量 top-K → 图谱 BFS 扩展(navigate 1跳邻居)→ 合并去重 → bge-reranker 重排 → 返回最终结果 ``` #### E1.3 测试验证 ```bash # 验证图谱有数据 curl http://localhost:7821/api/v1/graph/stats # 验证 recall 走图谱(找有图谱关联的记忆) curl "http://localhost:7821/api/v1/recall?query=织忆图谱导航&top_k=5" # 对比:图谱激活前 vs 激活后的召回结果差异 # 激活后应该出现更多 1 跳邻居相关结果 ``` ### 验收标准 - `graph/stats` node_count > 1000(已有,确认不变) - recall 结果中包含图谱扩展内容(通过日志或响应标记确认) - 延迟 < 500ms(可接受范围) --- ## E2:多 agent 命名空间激活 ### 目标 Hermes 和 OpenClaw 使用独立 namespace,数据物理隔离,互不串味。 ### 现状(2026-05-31 验证) - ✅ Hermes:`agent_id="hermes-a06"` → `namespace="hermes-main"`(Go `deriveNamespace` 自动推导) - ✅ OpenClaw:`agent_id="openclaw"`,`namespace="openclaw-main"`(zhiyi client 显式传递) - ✅ Rust sidecar:`search()` / `scan_all()` 均有 `only_if("namespace = '{}'", ns)` namespace 过滤 - ✅ 验证:同一 query 在 hermes-main 和 default-main 返回不同 ID 的记忆,隔离生效 - ℹ️ 历史数据(`agent_id=default`)在 `default-main`,与 hermes-main/openclaw-main 物理隔离 ### 实施步骤 #### E2.1 确认当前 namespace 配置(已验证) - Hermes 插件:`agent_id="hermes-a06"` 硬编码于 `ZhiYiClient.commit/recall`(`~/.hermes/plugins/zhiyi/__init__.py`) - OpenClaw 插件:`agent_id="openclaw"`, `namespace="openclaw-main"` 硬编码于 `ZhiYiClient`(`/persistent/.../memory-zhiyi/src/client.ts`) #### E2.2 验收(2026-05-31 通过) ```bash # Hermes recall → hermes-main curl -X POST http://localhost:7821/api/v1/recall \ -H "X-API-Key: zhiyi-dev-key-2026" \ -d '{"query":"牧尘 小唯","top_k":3,"namespace":"hermes-main"}' # → 返回 hermes-main 专属记忆 # OpenClaw recall → openclaw-main curl -X POST http://localhost:7821/api/v1/recall \ -H "X-API-Key: zhiyi-dev-key-2026" \ -d '{"query":"牧尘 小唯","top_k":3,"namespace":"openclaw-main"}' # → 返回 openclaw-main 专属记忆 ``` ### 验收标准 - [x] `namespace=hermes-main` 查询不到 `namespace=openclaw-main` 的记忆 - [x] `namespace=openclaw-main` 查询不到 `namespace=hermes-main` 的记忆 - [x] Rust sidecar 在 commit/recall 时正确使用 namespace 过滤 --- ## E3:增量 embedding ### 目标 commit 时同步调用 vLLM embedding,不等 Rust sidecar batch,延迟从分钟级降到毫秒级。 ### 现状(2026-05-31 验证) - ✅ **已实现**:Go `core.go:79` 在 `Commit()` 中调用 `a.Embedder.EncodeSingle(req.Content)` - ✅ **BGE HTTP**:连接 `localhost:8000/v1/embeddings`,17ms/条,L2 归一化 - ✅ **IPC 传输**:Go 将 vector + 文本一起发往 Rust `lancedb_insert`,Rust 直接存储(不重编码) - ✅ **验证**:commit 后立即 recall 测试记忆排第一(score=0.843),无需等待 batch - ℹ️ embedder.go 有 `MOLIFANG_API_KEY` fallback(当前未启用,环境无此 key) ### 实施步骤 #### E3.1 确认当前 embedding 流程(已验证) - Go `core.go:79` → `a.Embedder.EncodeSingle(req.Content)` → BGE HTTP 8000 → 1024-dim vector - Go `core.go:123` → `Vector: vector` 写入 `models.MemoryRecord` - Go `core.go:129` → `a.LanceDB.InsertMemory(mem)` → IPC `lancedb_insert` 发送到 Rust - Rust `lancedb_ops.rs:160-163` → 从 JSON 读取 vector,直接写入 LanceDB FixedSizeListArray #### E3.2 验证结果(2026-05-31) ```bash # commit 后立即 recall curl -X POST http://localhost:7821/api/v1/commit \ -H "X-API-Key: zhiyi-dev-key-2026" \ -d '{"content":"E3增量embedding测试:验证commit时同步生成vector","namespace":"default-main"}' # → memory_id: mem_1780211630617301197 curl -X POST http://localhost:7821/api/v1/recall \ -H "X-API-Key: zhiyi-dev-key-2026" \ -d '{"query":"E3增量embedding测试","top_k":3,"namespace":"default-main"}' # → mem_1780211630617301197 排第一,score=0.843 ✅ ``` ### 验收标准 - [x] commit 响应包含 memory_id(写入成功) - [x] commit 后立即 recall 能搜到(无需等待 Rust sidecar batch) - [x] recall 得分 > 0.8(证明向量有效,非零向量) --- ## E4:图谱推理 ### 目标 图谱真正参与推理:矛盾检测、跨 agent 共享、遗忘决策参考图谱结构。 ### 现状 - 图谱存了 1269 节点/31248 边,只搜不用(2026-05-31 修复了 fmt.Printf debug) - E4.1: Commit 路径已接入 ConflictDetector,检测率依赖 dedup 搜索覆盖 - E4.2: Recall 结果 < 3 时自动补充 shared namespace - E4.3: Forgetter.ShouldForget 支持 graphDegree 可变参数 ### 实施步骤 #### E4.1 矛盾检测(✅ 已实现,2026-05-31) **实现位置**: - `governance/governance.go`: `IsContradiction()` + `DetectContradiction()` 方法(导出供 routes 包调用) - `routes/core.go:API`: 添加 `ConflictDetector` 字段,构造函数签名更新 - `server.go`: ConflictDetector 提到 NewAPI 之前创建(避免作用域错误) **Commit 流程**: ``` Commit() → dedup 搜索 top-5 相似记忆 → 3a: exact match → merge → 3b: near-dup (cos ≥ 0.98) → merge → 3c: 对其余相似记忆运行 DetectContradiction() → 有矛盾 → {"status":"ok","conflicts":["矛盾内容"]} ``` **限制**:依赖 dedup 搜索结果的覆盖率。语义相反的陈述在向量空间中未必是 top-5 最近邻。2026-05-31 修复了 `IsContradiction` 中文感知问题(原用 `strings.Fields` 对中文无效,改用 `unicode.Han` 字符级切分 + `containsNegCN` 否定词检测)。 #### E4.2 跨 agent 知识共享(✅ 已实现,2026-05-31) **实现位置**:`routes/core.go:Recall()` — `pipeline.Recall()` 结果 < 3 时,补充 shared namespace 搜索 **流程**: ``` Pipeline.Recall(query, ns, limit) → len < 3 && ns != "shared" → EncodeSingle(query) → LanceDB.Search("memories", vec, 5, "shared") → 去重已出现在 own ns 的记忆 → 追加到 results,Score 降权 0.5 ``` #### E4.3 遗忘决策参考图谱(✅ 已实现,2026-05-31) **实现位置**:`governance/governance.go:ShouldForget()` **逻辑**(向后兼容,不传 graphDegree 则行为不变): ```go // 节点度 > 5 时,每超 1 度 + 0.03 保留分 if len(graphDegree) > 0 && graphDegree[0] > 5 { score += float64(graphDegree[0]-5) * 0.03 } ``` **调用方待接入**:`routes/admin.go:71`、`server.go:904` — 需要在遗忘循环中查 GraphStore.GetEntityDegree() 注入 graphDegree 参数。 ### 验收标准 - [x] E4.1: Commit 响应包含 `conflicts` 字段(如有矛盾)— ✅ 逻辑已接入 - [x] E4.2: Recall < 3 结果时自动补充 shared — ✅ 已实现 - [x] E4.3: ShouldForget 签名支持 graphDegree — ✅ 已实现,调用方待接 --- ## E5:产品 UI > 规划版本:v1.0 | 2026-06-02 > 目标:给织忆构建三层可视化入口(Obsidian 插件 / 增强 CLI / Web UI),覆盖日常快速查询和图谱深度探索两种场景。 --- ### E5.1:Obsidian 插件(优先级最高) **为什么先做 Obsidian** - 牧尘的笔记和记忆本来就在 Obsidian 里,界面切换成本最低 - 插件形式天然接入 vault 工作流,不需要另外打开窗口 - 图谱可以直接嵌入笔记界面,实体关系和笔记内容联动 **目标功能** - [ ] E5.1.1 插件骨架:`manifest.json` + `main.ts` + `styles.css`,Obsidian 加载并注册 `ZhiYiPlugin` - [ ] E5.1.2 记忆侧边栏面板:展示最近记忆列表,支持按 namespace 过滤,支持分页 - [ ] E5.1.3 实体图谱视图:基于 D3.js force-directed graph,从 `/api/v1/graph/entity/{entity}/neighbors` 获取数据,节点颜色区分 category,hover 显示关系标签 - [ ] E5.1.4 记忆搜索模态框:输入查询词调用 `/api/v1/search/recall`,显示 top-20 结果,点击跳转到记忆详情 - [ ] E5.1.5 实体详情视图:选中图谱节点后,从 `/api/v1/memories/by-entity/{entity}` 获取关联记忆列表 - [ ] E5.1.6 蒸馏状态面板:展示 `/api/v1/distill/status` 和 `/api/v1/distill/quota`,队列为非空时高亮提醒 **技术方案** - 开发目录:`~/projects/memoryweave/plugins/obsidian/` - 插件通过 `fetch()` 调用 Go API(端口 7821),Go 服务需添加 CORS 头(`Access-Control-Allow-Origin: app://obsidian.md`) - 图谱渲染:D3.js v7 从 CDN 加载(`https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js`),不用本地打包 - 构建:esbuild 打包 `main.ts` → `main.js`(`npx esbuild main.ts --bundle --outfile=main.js`) - Obsidian 开启「第三方插件」后,插件文件夹挂载到 `~/.obsidian/plugins/zhiyi-memory/` **CORS 适配(Go 服务改动)** ```go // api/middleware/cors.go — 新增 func CORS() gin.HandlerFunc { return func(c *gin.Context) { c.Header("Access-Control-Allow-Origin", "app://obsidian.md") c.Header("Access-Control-Allow-Methods", "GET, POST, OPTIONS") c.Header("Access-Control-Allow-Headers", "X-API-Key, Content-Type") if c.Request.Method == "OPTIONS" { c.AbortWithStatus(204) return } c.Next() } } // server.go — 注册 middleware server.Use(apiMiddleware.CORS()) ``` **文件结构** ``` plugins/obsidian/ ├── manifest.json # Obsidian 插件清单 ├── styles.css # 插件样式 ├── main.ts # 插件入口,注册侧栏、图谱视图、搜索模态框 ├── src/ │ ├── api.ts # 调用 Go API(fetch 封装,baseURL = http://localhost:7821) │ ├── MemoryView.ts # 记忆侧边栏面板 │ ├── GraphView.ts # D3 图谱渲染 │ └── SearchModal.ts # 搜索弹窗 ├── esbuild.config.mjs # 构建配置 └── README.md ``` **验收标准** - [ ] Obsidian 加载插件后,左侧出现「织忆」侧边栏 - [ ] 侧边栏显示最近 20 条记忆(namespace=default),点击展开内容 - [ ] 图谱视图能渲染至少 3 层邻居节点,节点可拖拽 - [ ] 搜索模态框输入关键词返回结果(<500ms) - [ ] 蒸馏队列非空时侧边栏顶部出现红色提示 --- ### E5.2:增强 CLI(第二优先级) **目标功能** - [ ] E5.2.1 `zhiyi tree` 命令:树形展示 namespace 下记忆结构,按 category 分组,每条记忆显示前 60 字符摘要 - [ ] E5.2.2 `zhiyi graph` 命令:ASCII art 渲染 ego-network 图谱(中心节点 + 一跳邻居 + 关系标签) - [ ] E5.2.3 `zhiyi recall ` 命令:语义搜索,返回 top-10 结果,显示 relevance score 和摘要 - [ ] E5.2.4 `zhiyi stats` 命令:显示记忆总数、namespace 分布、今日新增、蒸馏队列状态 - [ ] E5.2.5 `zhiyi entity ` 命令:查询实体详情(出现次数、关联实体列表、记忆片段) **技术方案** - CLI 命令入口:`~/projects/memoryweave/go/cmd/zhiyi-cli/` - 使用 `cobra` 或原生 `flag` 解析子命令 - 图谱 ASCII 渲染:用 Unicode box-drawing 字符(`┌─┬┐│├┼┤└┴┘`),中心节点用 `◉`,邻居用 `○` - 调用现有 Go API 端点,不直接操作存储 **文件结构** ``` go/cmd/zhiyi-cli/ ├── main.go ├── cmd/ │ ├── root.go │ ├── tree.go │ ├── graph.go │ ├── recall.go │ ├── stats.go │ └── entity.go └── output/ ├── ascii_graph.go # ASCII 图谱渲染 └── formatter.go # 格式化输出 ``` **验收标准** - [ ] `zhiyi tree` 输出格式正确(树形、分组、摘要) - [ ] `zhiyi graph ` 渲染 ASCII 图谱,实体数 ≥ 5 时换行正确 - [ ] `zhiyi recall` 输出 relevance score 排序正确 - [ ] `zhiyi stats` 显示记忆数、namespace 分布、蒸馏配额(used/limit) --- ### E5.3:Web UI(第三优先级) **目标功能** - [x] E5.3.1 React 项目骨架:Vite + React + TypeScript,路由 `/memories` `/graph` `/search` `/distill` - [x] E5.3.2 记忆列表页:分页表格(每页 20 条),列:id / content_preview / category / created_at / namespace,支持点击展开完整内容 - [x] E5.3.3 图谱探索页:全屏 D3.js force-directed graph,支持缩放/拖拽/筛选(category / namespace),点击节点弹出详情 drawer - [x] E5.3.4 语义搜索页:输入框 + 实时结果(debounce 300ms),显示 relevance 和摘要,高亮匹配片段 - [x] E5.3.5 蒸馏监控页:进度条显示 daily used / limit,队列列表(episode_id / category / content_preview) - [x] E5.3.6 响应式布局,支持 1280px+ 宽屏 **技术方案** - 项目目录:`~/projects/memoryweave/web-ui/` - 技术栈:Vite + React 18 + TypeScript + TailwindCSS + D3.js v7 - API 层:Axios 调用 Go API,响应式状态用 React Query 管理缓存 - 图谱:与 E5.1 共用 `/api/v1/graph/navigate` 和邻居接口,数据结构一致 - 部署:Go 服务新增静态文件中间件(`/static/*` → `web-ui/dist/`),`make build-web` 构建后自动同步 **文件结构** ``` web-ui/ ├── index.html ├── package.json ├── vite.config.ts ├── tailwind.config.js ├── src/ │ ├── main.tsx │ ├── App.tsx │ ├── api/ │ │ └── zhiyi.ts # API 客户端封装 │ ├── pages/ │ │ ├── MemoriesPage.tsx │ │ ├── GraphPage.tsx │ │ ├── SearchPage.tsx │ │ └── DistillPage.tsx │ └── components/ │ ├── GraphCanvas.tsx # D3 图谱组件 │ ├── MemoryTable.tsx │ └── DistillStatus.tsx └── dist/ # 构建输出,由 Go 静态中间件托管 ``` **Go 服务静态文件中间件** ```go // api/middleware/static.go — 新增 func StaticFile(root string) gin.HandlerFunc { fs := http.FileServer(http.Dir(root)) return func(c *gin.Context) { if _, err := os.Stat(filepath.Join(root, c.Request.URL.Path)); err == nil { fs.ServeHTTP(c.Writer, c.Request) c.Abort() } else { c.Next() } } } // server.go — 注册 if opt.Mode == "dev" { server.Use(apiMiddleware.StaticFile("../web-ui/dist")) } ``` **验收标准** - [ ] Web UI 能加载并显示记忆列表(分页正常) - [ ] 图谱页渲染实体节点 ≥ 10 个,缩放拖拽流畅 - [ ] 搜索页输入关键词后 1 秒内显示结果,高亮匹配文字 - [ ] 蒸馏监控页显示正确的 used/limit 进度条 - [ ] 各页面在 1920×1080 和 1366×768 下布局正常 --- ### E5 总体依赖关系 ``` E5.1 (Obsidian 插件) └── Go API 需添加 CORS 中间件 └── 构建系统需新增 esbuild 步骤 E5.2 (增强 CLI) └── 复用 E5.1 的 CORS 无关紧要 └── 直接调用 Go API(无需其他依赖) E5.3 (Web UI) └── 复用 E5.1 的 CORS 中间件 └── Go 服务新增静态文件中间件 └── 需要独立的 Vite 构建流程 ``` ### 实施顺序 **第一波(E5.1 Obsidian 插件)** 1. 添加 Go CORS 中间件,构建部署 2. 创建 `plugins/obsidian/` 目录结构 3. 实现 `ZhiYiPlugin` 骨架,注册侧边栏 4. 实现 MemoryView(记忆列表) 5. 实现 GraphView(D3 图谱) 6. 实现 SearchModal(搜索) 7. 本地测试:Obsidian 加载插件,验证全部功能 8. 提交,WORKLOG 同步 **第二波(E5.2 增强 CLI)** 1. 创建 `go/cmd/zhiyi-cli/` 项目结构 2. 实现 tree / graph / recall / stats / entity 命令 3. 本地测试所有子命令 4. 提交,WORKLOG 同步 **第三波(E5.3 Web UI)** 1. 初始化 Vite + React + TypeScript 项目 2. 实现 MemoriesPage 3. 实现 GraphPage(基于 E5.1 相同的 D3 数据源) 4. 实现 SearchPage 5. 实现 DistillPage 6. Go 服务添加静态文件中间件 7. `make build-web` 集成到 Makefile 8. 完整测试,提交 ### 附录:外部调研(GitHub 开源参考) | 方向 | 参考项目 | 关键技术 | |------|---------|---------| | Obsidian 插件 | `obsidianmd/obsidian-sample-plugin` | manifest.json, Plugin class, CustomView | | 图谱可视化 | `react-force-graph` (底层 D3) | force-directed layout, zoom/pan | | Web UI 图谱 | `vis-network` / `react-vis` | alternative to raw D3 | | CLI 图谱 | `dogmap`(Mastodon ASCII 工具) | box-drawing 字符布局 | --- --- ## 阶段推进规则 1. **必须按顺序完成**:E1 → E2 → E3 → E4 → E5 2. **每个阶段必须测试验证后才能进入下一阶段** 3. **禁止跳过测试验证步骤** 4. **禁止偷懒:实施步骤必须逐条执行** 5. **禁止随意更改变动设计语言**:阶段目标和验收标准锁定 6. **如有阻塞,记录到 BLOCKED 章节,继续下一个阶段** --- ## BLOCKED(阻塞记录) | 时间 | 阶段 | 阻塞原因 | 尝试方案 | |------|------|---------|---------| | - | - | 无阻塞 | - | --- ## 进度追踪 | 阶段 | 开始时间 | 完成时间 | 状态 | |------|---------|---------|------| | E1 图谱导航激活 | 2026-05-30 | 2026-05-30 | ✅ | | E2 多 agent 命名空间 | 2026-05-30 | 2026-05-30 | ✅ | | E3 增量 embedding | 2026-05-30 | 2026-05-30 | ✅ | | E4 图谱推理 | 2026-05-31 | 2026-05-31 | ✅ E4.1/E4.2/E4.3 已实现,E4.3 调用方已接入(extractTopEntityDegree) | E5 产品 UI | 2026-06-02 | - | 🔨 | E5.1 ✅ E5.2 待启动 | --- *最后更新:2026-06-02(E5 规划完成)*