From 908db04b67f6927e8c8885c58bee567b3f3073d5 Mon Sep 17 00:00:00 2001 From: john Date: Wed, 2 Sep 2026 10:04:44 +0800 Subject: [PATCH] Document Experience schema and JKRiver read-only references. Map Mi-Memory Structure/Expansion into h5_experience V1 fields and record JKRiver Sleep design lessons under AGPL constraints, plus post-fix MemFuseBench numbers. Co-authored-by: Cursor --- docs/architecture/experience-schema-v1.md | 201 +++++++++++++++++++ docs/architecture/jkriver-sleep-reference.md | 164 +++++++++++++++ docs/architecture/memfuse-bench-baseline.md | 16 +- 3 files changed, 380 insertions(+), 1 deletion(-) create mode 100644 docs/architecture/experience-schema-v1.md create mode 100644 docs/architecture/jkriver-sleep-reference.md diff --git a/docs/architecture/experience-schema-v1.md b/docs/architecture/experience-schema-v1.md new file mode 100644 index 0000000..2a82a36 --- /dev/null +++ b/docs/architecture/experience-schema-v1.md @@ -0,0 +1,201 @@ +# Experience Schema V1(Mi-Memory Structure / Expansion 映射) + +日期: 2026-09-02 + +状态: 设计草案。依据 Mi-Memory 论文(arXiv:2607.18975)**Structure + Expansion** 段与 Memind 现有 `h5_experience` / Agent Memory 定位。**不含 Evolution / Deployment 实现**——那些需等 MemFuseBench 基线与 `memory-v2-product-events` 指标就绪后再做。 + +## 0. 定位 + +Mi-Memory 把 Memory 分成四层角色(Structure / Expansion / Evolution / Deployment),用统一 **Audit Contract** 连接。Memind 上一轮架构判断里,**Personal Memory**(`h5_user_memory_items`)与 **Agent Memory**(`h5_experience`)生命周期不同;Experience Schema V1 只服务后者。 + +| Mi-Memory 概念 | Memind 落点 | V1 范围 | +|---|---|---| +| MemStack L0 Facts | `h5_user_memory_items` | 已有,不在本文 | +| MemStack L1 Summaries | `conversation-memory` / episodic | 已有,不在本文 | +| MemStack L2 Profile | `user-memory-profile` | 已有,不在本文 | +| **MemStack Skills / 可复用行为** | **`h5_experience` 扩展** | **本文** | +| MemSense / MemFuse 来源标注 | Experience 的 `evidence_json` | **本文** | +| D²ACCI / E²MEND Gate | `memory-v2-product-events` + 未来 gate 表 | 后置 | +| LiteMem 部署变体 | 不在 V1 | 后置 | + +论文核心句(§3.1):**memory item ≠ evidence ≠ strategy**。存对了 memory 不够——检索、过滤、打包仍可能丢 evidence。Experience V1 因此必须同时存 **结构化 memory item** 和 **可追溯 evidence 链**,而不是一行 `title + body` 摘要。 + +## 1. 动机:现有 `h5_experience` 缺什么 + +当前 schema(`schema.sql`): + +```sql +h5_experience ( + id, scope, kind, title, body, tags_json, + source_session_id, source_user_id, use_count, + embedding, created_at, updated_at +) +``` + +写入点(`mindspace-agent-runner.mjs`)只填 `kind: 'task_outcome'` + `title` + `body` 一行摘要。`reflect()` 在 `experience-service.mjs` 仍为 `not_implemented`。 + +这无法支撑用户描述的 SSE 场景: + +``` +problem: SSE connection instability +environment: goosed + Docker + PG +hypothesis: connection lifecycle issue +action: modified server.rs +result: success +confidence: 0.86 +``` + +也无法对接 Mi-Memory 的 **Typed Evidence Payload**(source id / time / device / confidence / provenance)。 + +## 2. V1 字段定义 + +### 2.1 表级:`h5_experience` 扩展列 + +在现有列上**加列**,不新建表。保持 `record()` / `search()` 契约向后兼容:旧行新列为 NULL,读路径用 fallback。 + +| 列 | 类型 | 必填 | 来源 / 含义 | +|---|---|---|---| +| `problem` | `VARCHAR(512)` | 否 | 触发本次执行的问题陈述(Mi-Memory: 诊断起点) | +| `environment_json` | `JSON` | 否 | 运行环境:`{ runtime, components[], version?, region? }` | +| `hypothesis` | `VARCHAR(512)` | 否 | 执行前的假设(**可空**;见 JKRiver 反面经验) | +| `action_json` | `JSON` | 否 | `{ executor, steps[], artifacts[], diff_ref? }` | +| `result` | `ENUM('success','partial','failure','unknown')` | 否 | 终态 | +| `confidence` | `DECIMAL(4,3)` | 否 | 0–1,写入时对 result 的确信度 | +| `evidence_json` | `JSON` | 否 | **Mi-Memory Typed Evidence**(见 §2.2) | +| `parent_experience_id` | `CHAR(36)` NULL | 否 | 同类问题复发时的链接 | +| `supersedes_id` | `CHAR(36)` NULL | 否 | 新经验取代旧经验 | +| `status` | `ENUM('active','archived','deleted')` | 是 | 默认 `active` | + +保留现有 `title` / `body`:`title` = 短标题(列表 / 注入),`body` = 人类可读摘要(LLM 注入块)。结构化字段供检索、reflect、skill 晋升,不替代 `body`。 + +### 2.2 `evidence_json`:Mi-Memory Typed Evidence 最小契约 + +对应论文 Table 3 **Typed evidence payload**(source id, time, device, confidence, provenance)。 + +```json +{ + "sources": [ + { + "source_id": "run:abc123", + "source_type": "agent_run", + "actor": "goose", + "device": null, + "timestamp_ms": 1756780800000, + "modality": "tool_result", + "snippet_ref": "event:tool_sse_error_1", + "confidence": 0.86 + } + ], + "provenance": { + "run_id": "abc123", + "session_id": "sess-xyz", + "user_id": "user-1", + "causal_event_ids": ["evt-1", "evt-2"] + }, + "checklist": [ + { "point": "SSE error in goosed logs", "source_ids": ["evt-1"] } + ] +} +``` + +与 MemFuseBench 对齐:`checklist` + `source_ids` 可直接对接 `memory-v2-memfuse-bench.mjs` 的 `checklistCoverage` 指标,作为 Experience 召回质量的离线代理。 + +**V1 不存原始 Event Stream**——只存引用(`run_id` / `causal_event_ids`)。原始事件留在 `h5_agent_run_events`;Experience 是 **derived memory item**,不是 Event Kernel 本身。 + +### 2.3 `kind` 枚举扩展 + +| `kind` | Mi-Memory 对应 | 用途 | +|---|---|---| +| `lesson` | L0 fact / 教训 | 默认,兼容现有 | +| `task_outcome` | L1 summary | 现有 mindspace-agent-runner | +| `execution_pattern` | procedural hook | 可复用执行模式 | +| `skill_candidate` | Skill 候选 | `reflect()` 晋升前 | + +V1 写入仍用 `task_outcome`;`reflect()` 实现后再产出 `skill_candidate`。 + +### 2.4 `environment_json` 示例 + +```json +{ + "runtime": "goosed", + "components": ["docker", "postgres-session", "portal-proxy"], + "versions": { "goosed": "1.4.1", "portal": "61eebb44" }, + "region": "103-canary" +} +``` + +## 3. 写入契约(Expansion 段) + +执行器**不直接写 Experience 表**。对齐 Event Kernel 方向(论文 §5 + Memind 架构共识): + +``` +Goose / OpenHands / Aider / Browser + │ + ▼ + h5_agent_run_events (已有) + │ + ▼ + Experience Extractor (V1 新增:agent-run 完成钩子) + │ + ▼ + h5_experience +``` + +V1 Extractor 触发点(按优先级): + +1. `agent-run-gateway.mjs` — run 终态 `completed` / `failed` +2. `mindspace-agent-runner.mjs` — 已有 `recordExperience()`,扩字段 +3. OpenHands / Aider — 仅当 `tool-gateway` 返回结构化 outcome 时 + +Extractor 必填:`problem`(从 user_message + run 摘要)、`result`、`evidence_json.provenance.run_id`。其余可 best-effort。 + +## 4. 读取契约(Structure 段) + +`experience-service.search()` V1 不改签名;排序层后续可叠加: + +1. 关键词(现有) +2. `environment_json` 组件匹配(如 query 含 "goose" / "sse") +3. `problem` 向量相似度(接 pgvector 后) + +注入格式(`retrieveExperience()`)V1 扩展为: + +``` +# 相关经验(供参考,来自历史任务) +- [2026-09] SSE 连接不稳定 (success, conf=0.86) + 环境: goosed + Docker + PG + 处理: 修改 server.rs 连接生命周期 + 摘要: ... +``` + +## 5. 与 Personal Memory 的边界 + +| 维度 | Personal (`h5_user_memory_items`) | Agent (`h5_experience`) | +|---|---|---| +| 关于 | 这个人是谁 | 怎么做事 | +| 典型字段 | preference, goal, relationship | problem, action, result | +| 生命周期 | JKRiver 式 consolidation(**仅参考,不移植代码**) | 执行 → reflect → skill | +| Mi-Memory 段 | Structure + Expansion(用户态) | Structure(Skills)+ Expansion(tool/run evidence) | + +**禁止**把 `hypothesis` 做成一级必填字段。JKRiver `008_drop_hypotheses.sql` 记录:独立 hypotheses 表建后废弃,改由 `user_profile.layer ∈ {suspected, confirmed}` + `supersedes` 表达。Experience 里 `hypothesis` 保持可空;不确定时用 `confidence < 0.5` + `result: 'unknown'`。 + +## 6. V1 实施顺序 + +1. **Migration**:`h5_experience` 加列(上表),默认值 NULL +2. **Extractor**:扩 `recordExperience()` + agent-run 完成路径 +3. **`reflect()` 最小实现**:把 N 条 `task_outcome` 聚合为 1 条 `execution_pattern`(规则版,无 LLM) +4. **指标**:复用 `memory-v2-product-events` 增 `experience_saved` / `experience_recalled` +5. **MemFuseBench 对照**:Experience 召回不参与 MemFuse(语料不同),但 `checklistCoverage` 格式保持一致以便将来统一 audit + +## 7. 明确不做(V1) + +- E²MEND 自动策略搜索 +- Gate / Rollback 表(Evolution 段) +- LiteMem 文件-native 部署 +- 把 Experience 写进 goosed 会话内 +- JKRiver Sleep Pipeline 代码移植(AGPL-3.0,见 `jkriver-sleep-reference.md`) + +## 8. 参考 + +- Mi-Memory 论文: https://arxiv.org/abs/2607.18975 +- MemFuseBench 基线: `docs/architecture/memfuse-bench-baseline.md` +- 现有实现: `experience-service.mjs`, `schema.sql` `h5_experience` diff --git a/docs/architecture/jkriver-sleep-reference.md b/docs/architecture/jkriver-sleep-reference.md new file mode 100644 index 0000000..58f97c6 --- /dev/null +++ b/docs/architecture/jkriver-sleep-reference.md @@ -0,0 +1,164 @@ +# JKRiver Sleep Pipeline 只读参考 + +日期: 2026-09-02 + +状态: **架构级参考文档**。JKRiver(Riverse)源码位于 `~/Project/jkriver`,**AGPL-3.0 / 商业双授权**,禁止将其实现移植进 Memind 商业 SaaS。本文只记录可安全采用的**设计决策**与**反面教训**,供 `memory-v2-lifecycle.mjs` 未来填槽时对照。 + +## 0. 授权边界(必读) + +JKRiver `LICENSE` 为 **Dual License**: + +- 开源:AGPL-3.0(网络服务需开源修改版) +- 商业:需联系 mailwangjk@gmail.com + +Memind 103 生产为商业 SaaS → **不得复制** `agent/sleep/*.py` 或 `agent/storage/*.py` 的实现。允许: + +- 读源码理解事务边界、幂等策略、数据模型取舍 +- 在 Memind 内**独立设计**语义等价的 JS 逻辑 +- 引用公开概念(Sleep Consolidation、supersede、evidence linking) + +禁止: + +- 逐行翻译 Python → JavaScript +- 嵌入 JKRiver 代码片段 +- 在未取得商业授权前声称「基于 JKRiver 移植」 + +Mi-Memory(MIT)无此限制;JKRiver 有。 + +## 1. 忽略清单(与 Memind 重叠) + +JKRiver 下列模块**不建议**研究或集成——Memind 已有等价或更完整实现: + +| JKRiver 模块 | 原因 | +|---|---| +| Agent / Web Chat / Telegram | 重叠 `wechat-mp`, Portal chat | +| Skills / Task Agent | 重叠 `skills-registry`, `chat-skills` | +| MCP 集成 | 重叠 Goose MCP extension | +| Proactive messaging | 重叠 `schedule-reminder-worker`, `notification-dispatcher` | +| Finance / Health 领域 storage | 领域耦合,与 `h5_user_memory_items` 模型不兼容 | + +## 2. 值得读的核心:`agent/sleep/`(2324 行) + +### 2.1 14 步流水线(`orchestration.py`) + +``` +load_initial → extract_sessions → analyze_behavior → classify_and_integrate +→ cross_verify → resolve_disputes → extract_edges → expire_facts +→ maturity_decay → user_model → trajectory → consolidate → snapshot → finalize +``` + +与 Memind 此前画的 Sleep 图相比,JKRiver **多五步**: + +| 步骤 | 作用 | Memind 对应空槽 | +|---|---|---| +| `cross_verify` | 交叉验证新 fact | 无 | +| `resolve_disputes` | 争议 fact 仲裁(`disputes.py` 231 行) | 无 | +| `user_model` | 用户模型更新 | `user-memory-profile` 部分覆盖 | +| `trajectory` | 长期轨迹 / key_anchors | 无 | +| `consolidate` + `snapshot` | 预编译快照 | `memory-v2-lifecycle.compact()` 占位 | + +Memind V1 只需关注后四个 maintenance 步映射到 lifecycle: + +| JKRiver 步骤 | `memory-v2-lifecycle.mjs` | 现状 | +|---|---|---| +| `expire_facts` | `expire()` | flag 关,逻辑有 | +| `maturity_decay` | decay(无独立函数) | **未实现** | +| `promote`(classify 隐含) | `promote()` | candidate→item INSERT IGNORE | +| `consolidate` | `compact()` | `mode: 'candidate-only'` | +| `reflect`(trajectory 隐含) | `reflect()` | `mode: 'observation-only'` | + +### 2.2 事务与幂等(**可安全采用的设计**) + +`orchestration.py` 核心模式: + +```python +with transaction(): + _run_sleep_pipeline_inner(...) + +# finalize 步才 mark_processed() +# 崩溃 → 整批回滚 → 下次重跑(at-least-once) +# embedding / clustering 在事务外,失败只 warning +``` + +Memind 现状:`expire` / `compact` / `promote` / `reflect` **各自独立调用**,无共同事务边界,无 processed 水位。 + +**可独立采用的设计决策**(不是代码): + +1. Consolidation 批次必须在单 DB 事务内 +2. `mark_processed` / 水位标记必须在流水线**最后一步** +3. 非关键后处理(embedding、聚类)放在事务外 +4. `LLMPipelineError` 单独处理:LLM 不可用则 abort 整批,不部分提交 + +### 2.3 Maturity Decay 语义(`_maturity.py`,17 行) + +```python +_MATURITY_TIERS = [(730, 10, 730), (365, 6, 365), (90, 3, 180)] +# if new_decay > current_decay: update (只增不减) +``` + +这是 **保留期延长**,不是置信度衰减: + +- 跨度 ≥730 天且 evidence ≥10 → `decay_days` 延到 730 +- 命中 `key_anchors` 时门槛 ×0.6 + +与 Memind `experience-service.mjs` 的 **30 天半衰期指数衰减**相反。若 Personal Memory 填 decay 槽,必须先做语义选择,不能混用。 + +### 2.4 Fact 模型(与 Memind 差距) + +JKRiver fact:`category`, `subject`, `value`, `start_time`, `supersedes`, `superseded_by`, `decay_days`, `evidence[]` + +Memind `h5_user_memory_items`:`label`, `memory_text`, `confidence`, `status`, `evidence_message_id` + +这是**换模型**,不是加字段。JKRiver consolidation 算法 tied to 前者,不能直映射。 + +## 3. 反面教训:`008_drop_hypotheses.sql` + +```sql +-- hypotheses 表一直是 0 行,无生产读写 +-- 被 user_profile (layer 'suspected'/'confirmed' + supersedes) 完全取代 +DROP TABLE IF EXISTS hypotheses CASCADE; +``` + +对 Memind 的含义: + +1. **不要把 `hypothesis` 做成独立表或必填字段**(Experience schema 已采纳:`hypothesis` 可空) +2. 未验证的推断应表达为 `layer=suspected` + `supersedes` 链,而不是平行 hypotheses 存储 +3. 建表前先证明有读写路径,否则 0 行表最终被删 + +## 4. Memind 填槽优先级(JKRiver 启发,自行实现) + +在 `memory-v2-lifecycle` flag 打开 + MemFuseBench 基线稳定后: + +| 优先级 | 函数 | JKRiver 启发 | 自行实现要点 | +|---|---|---|---| +| P0 | 事务边界 + 水位 | `orchestration.transaction()` | MySQL 事务包裹 promote+expire | +| P1 | `promote()` supersede | `classify_and_integrate` | candidate 冲突时 supersede 而非 INSERT IGNORE | +| P2 | `expire()` + verify | `expire_facts` + verify strategy | 过期写 verify 候选,不静默删 | +| P3 | decay 延长 | `maturity_decay` | 按 evidence 计数延长 retention,非指数衰减 | +| P4 | `compact()` | `consolidate` + `snapshot` | 保守:只报告 eligible,不覆盖源 | +| P5 | `reflect()` | `trajectory` + disputes | 需 Experience 结构化数据先就绪 | + +## 5. 何时启动 JKRiver 填槽 + +三门(与 `memfuse-bench-baseline.md` 一致): + +1. `h5_memory_v2_candidates` 有真实流量 +2. lifecycle `rolloutMode` 至少 `canary` +3. MemFuseBench / recall benchmark 有**可对比的**前后基线 + +当前(2026-09-02):仅第 3 项部分满足(MemFuseBench 已可跑)。lifecycle 仍 `off` → **不启动填槽实现**。 + +## 6. 本地材料 + +```bash +# 已 clone,不在 Memind 仓库内 +~/Project/jkriver +~/Project/mi-memory # MIT,含 MemFuseBench 数据集 +``` + +关键路径: + +- `agent/sleep/orchestration.py` — 流水线入口 +- `agent/sleep/steps_maintain.py` — expire / maturity +- `agent/sleep/disputes.py` — 争议解决 +- `migrations/008_drop_hypotheses.sql` — 反面教训 diff --git a/docs/architecture/memfuse-bench-baseline.md b/docs/architecture/memfuse-bench-baseline.md index c4a6008..7b17faf 100644 --- a/docs/architecture/memfuse-bench-baseline.md +++ b/docs/architecture/memfuse-bench-baseline.md @@ -25,6 +25,19 @@ 按维度看,`multi_source_conflict_arbitration` 明显最好(候选 71.5% / 召回 39.4%),`cross_device_information_fusion` 最差(26.5% / 6.1%)。 +### keyword 路径修复后(commit `2c0d903e`,k=20) + +只改 `fetchKeywordCandidates`:去掉 `ORDER BY updated_at DESC`,扩大 fetch cap 后按 `lexicalQueryCoverage` 排序;keyword 行携带 lexical 分。`rankHybridCandidates` 未改。 + +| 指标 | 修复前 | 修复后 | Δ | +|---|---|---|---| +| candidateRecall | 36.6% | **72.8%** | +36.2pp | +| recall@k | 13.5% | 13.3% | ≈0 | +| hitAny@k | 41.7% | **43.1%** | +1.4pp | +| checklistCoverage | 16.8% | 16.4% | ≈0 | + +候选池扩大后 rankingLoss 相对值上升(59.5pp),但**最终 recall 几乎不变**——下一刀必须改 `rankHybridCandidates`,且需接**真实语义嵌入**验证(lexical-hash 下改非中文 vector 优先会恶化至 ~5.7% recall)。 + ## 1. 两个已定位的机制 ### 机制一:`lexicalQueryCoverage` 是主排序键,但判别力接近随机 @@ -129,4 +142,5 @@ npm run verify:memory-v2-memfuse-bench - `memory-v2-memfuse-bench.test.mjs` — 内联 fixture,19 个用例,不依赖外部数据集 - `scripts/run-memory-v2-memfuse-bench.mjs` — CLI - `memory-v2-pgvector.mjs` — 被测的生产排序路径(`rankHybridCandidates` / `fetchKeywordCandidates` / `extractKeywordTerms`) -- `memory-v2-recall-benchmark.mjs` — 既有的 4 例中文手写基线,与本文互补 +- `docs/architecture/jkriver-sleep-reference.md` — JKRiver 只读参考(AGPL 边界) +- `docs/architecture/experience-schema-v1.md` — Mi-Memory Structure/Expansion 映射