Reframe digest as the abstract memory layer (details stay in the daily/
resource material; digest holds principles, patterns, precedents reachable
via derived_from provenance edges). Replaces the old digester with a
2-phase ReAct workflow + a daily-tick wrapper:
- Phase 1 (Dreamer extract): clusters material into orthogonal memory
sub-units; each sub-unit maps 1:1 to a digest node (no inner atom
enumeration). Biases toward fewer / richer sub-units.
- Phase 2 (Dreamer integrate per sub-unit): cross-bucket recall +
exactly one write decision (CREATE / UPDATE / SKIP); UPDATE shapes
surfaced explicitly (corroborate / refine / correct).
- CronDreamer: scans <daily_dir>/<today>.md + <daily_dir>/<today>/**
+ <resource_dir>/<today>/** and runs dream_one per file.
Write tools are proper subclasses of the canonical file_io WriteStep /
EditStep with only path-shape + bucket + E-1 edge-conservation rules
layered on top:
- DigestWriteStep(WriteStep): path = <digest_dir>/<bucket>/<slug>.md,
must-not-exist, schema mirrors `write` (path / name / description /
content) so frontmatter lands automatically.
- DigestEditStep(EditStep): body-only find-and-replace + must-exist +
E-1 conservation preflight (refuses if any outbound wikilink would
be dropped).
Configuration:
- Bucket vocabulary structured in code (tuple[{name, description}]);
prompt renders the heuristic block at runtime via {buckets}.
- digest_dir / daily_dir / resource_dir come from app config (not tool
params); prompts use {digest_dir} placeholder.
- BaseStep walks class MRO when loading prompts, so subclasses inherit
parent yaml without duplication.
Tooling: agentscope register_tool_function schemas now wrap in the
proper {"type":"function","function":{...}} envelope. OpenAIAsLLM
routes base_url through client_kwargs so non-default endpoints work.
Smoke: tests4/smoke/{_dreamer_fixture.py,test_dreamer_inproc.py,
test_dreamer_cli.sh} drive the end-to-end pipeline.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
13 KiB
auto-link 设计(背景实体识别 + wikilink 写回)
本文档记录 reme4 中 auto-link 的设计讨论 —— 在已写入节点之间发现隐含关系,把这些关系作为
[[...]]wikilink 写回 body,形成可见、可编辑的图结构增强。配套阅读:
structure.md§1.2(三层数据视角)/ §4(retrieve 三种问法)auto_memory_design.md:auto-link 可反向扫 daily event,补实体 wikilink(daily → digest)auto_dream_design.md:wikilink 模型(§3 边语法 / §4 演化 / §4.4 边守恒 E-1 / E-2 / E-3);auto-link 借这套基础设施auto_maintain_design.md:CAS 写入协议(§5);auto-link L1 写回与 dream / maintain split 三方共用同一套 CAS三层对应:reme 服务整体三层 —— auto-memory / auto-dream / auto-link(本文档)。auto-link 是图关系的后置增强 —— 在已落地的 vault 上做实体识别 + wikilink 写回,补足 content link(写记忆时由 LLM 直接产生的
[[...]])在长 tail 隐含关系上的盲区。核心立场:auto-link 写回 body,不只是产报告。生成的 wikilink 是可见、可编辑的(写在 Markdown 文件里),agent / 人可后续 curate。auto-link 不引入新材料,纯 additive 插入 wikilink,天然满足 E-1 守恒;复用 dream 的 CAS 写入协议,不引入新基础设施。
0. 问题陈述
content link(auto_dream_design.md dream / split 写入时由 LLM inline 产生的 [[...]])解决了"写记忆时显式的关系"。但有一类关系不会在 inline 写入时自然涌现,需要后台扫描已写入的 vault 才能识别:
- 历史 body 的实体未链接 —— dream update 时 LLM 关注新材料融入,可能忽略已有 body 中某个未链接的实体(例如 body 提到 "JWT" 但没写
[[digest/auth/jwt-overview.md]]) - 跨节点 / 跨桶的隐含关联 —— 节点 A 提到 "rate limit",但
digest/api/rate-limit.md是后来才被 split 创建 → A 写入时没机会建立这条边 - 同主题未连 / 同概念重复 —— dream 漏判去重把同概念建成两个节点;或两个主题相关但 0 链接的节点彼此不知晓
auto-link 承担这部分:后台扫描已写入节点 → 实体识别 / 候选挖掘 → wikilink 写回 body。
1. 已对齐决策
1.1 与 content link 的边界
| 维度 | content link(在 dream) | auto-link(本文档) |
|---|---|---|
| 何时产生 | 写记忆 inline:dream update / M split prompt | 后台扫描:离线 / 周期 / 触发后异步 |
| 由谁产生 | LLM 在 dream 写入流中顺手写出 | LLM 在 auto-link 扫描流中识别后写出 |
| 输入 | 新材料 + 召回候选节点 | 已写入 body + 全 vault 索引 |
| 改 body | 是(重写整段 body) | 是(纯 additive 插入 wikilink,不改文字) |
| 守恒 | E-1 强守恒(out ⊇ old) | E-1 天然满足(纯增) |
| 用途 | 写入即关系明示 | 弥补 inline 漏判,挖掘长 tail 关系 |
1.2 写回模型:纯 additive,复用 dream CAS
auto-link 写回是纯 additive 操作 —— 在已有 body 文字中找到实体 mention,替换为 wikilink 形态:
Before: "JWT 轮换的核心是密钥派生 ..."
After: "[[digest/auth/jwt-rotation.md|JWT 轮换]]的核心是[[digest/auth/jwt-key-derivation.md|密钥派生]] ..."
| 维度 | 决策 |
|---|---|
| alias 必须保留原文 | [[path.md|<原文>]] 形态;原文一字不改 —— 守住"不改写其它节点正文" (auto_dream_design.md §4.3 F-2) 的精神 |
| predicate 默认为空 | auto-link 默认产生无谓词 wikilink;升 typed link 走 L3(详 §1.3) |
| 不引入 anchor | 与 dream 一致(auto_dream_design.md §3);target 永远是节点路径 |
| CAS 写入 | 完全复用 auto_maintain_design.md §5 的 read-stamp + CAS-write 协议(冲突重做 ≤ 3 次) |
| E-1 守恒 | 纯 additive:new outbound = old outbound ∪ {new wikilinks};new ⊇ old 天然满足,守恒校验默认通过 |
| rollback | 若 auto-link 误插入(例如 entity mention 是同名歧义),走标准 edit 或 retarget 撤销;auto-link 不维护"我插过哪些"audit log(留给 SDK 决定) |
为什么是 additive 而不是重写:
- additive = 0 文字风险(原文不变,只在原 mention 周围加
[[ | ]]包装) - 重写 = 触发完整 E-1 守恒校验 + LLM 重写整段语义守恒 prompt + 多次 LLM 调用 = 跟 dream update 重复
- additive 失败可见:产生坏 wikilink 时,人/agent 直接编辑 body 修就行
1.3 候选挖掘类型(L1-L4)
| # | 类型 | 描述 | 写回形态 |
|---|---|---|---|
| L1 | 实体识别(主路径) | 扫 body,识别已是 digest 节点的实体名(模糊匹配 + 语义召回);未被 wikilink 化的 mention → 加 [[path.md|<mention>]] |
additive wikilink 插入 |
| L2 | 同主题未连(旧 D7) | 两个 digest 节点谈相关主题但 0 wikilink → 候选 add link;LLM 判后在 body 末尾追加一句引用 | additive(在合适位置 / 节末追加 参见 [[other.md|other]]) |
| L3 | 隐含 predicate 推导 | 已有 [[A]] 但 LLM 可推断关系类型(is_a / causes / extends / ...)→ 升级为 typed link |
改 [[A]] → is_a:: [[A]](predicate 升降级走显式 audit,详 §2.1) |
| L4 | 重复语义检测(旧 D8) | 两个节点描述同一概念但被独立 create(dream 漏判去重)→ 候选 merge | 不写回;产报告 + 提示人/agent 触发 dream update 路径手工合并 |
L1 是主路径 —— 它是 auto-link 最核心、最频繁、最高 ROI 的操作:每个 digest 节点写完后,后台扫一遍 body,找未链接的已知实体,additive 加 wikilink。
L2-L3 是辅助 —— 周期扫,产候选,LLM 终判,写回部分(L2 节末追加 / L3 升 predicate)。
L4 不写回 —— 节点合并是结构改动,影响 E-1 守恒边界 + inbound 链路 + provenance 链路,不适合自动写;auto-link 只产报告,人/agent 决定走 dream update 路径解决。
1.4 触发节奏
| 模式 | 何时 | 适用 |
|---|---|---|
| inline post-write(默认) | 每次 dream update / M split 写完 body → enqueue auto-link L1 job(异步,FIFO,CAS 保护) | L1 实体识别;反应即时,与 D3 写后检测同节奏 |
| 周期 batch(可选) | cron(daily / weekly)扫全 vault | L2 / L3 候选挖掘;成本可控 |
| 手动触发 | SDK / 人显式调用 | 全量重扫 / 修复 |
L1 inline 的必要性:新 split 出的 child 节点立即被既有 body 引用(用 wikilink 而非纯 mention)的关键 = 写入即扫描;不 inline 会让"刚创建的 child 节点"在很长时间内只有 split parent 一个 inbound,中心性失真。
已排除:
- inline 时同步 auto-link(阻塞 dream return)—— 时延不可接受;auto-link 始终异步
- 所有 L* 都 inline —— L2-L3 候选挖掘 RTL 跨节点,成本高,只适合 batch
- 全 cron 唯一触发 —— L1 滞后过久,新节点孤岛
1.5 中心性算法(retrieve 加权依赖)
retrieve 时节点权重 = base × intent 调节 × 中心性增益(详 auto_dream_design.md §5)。中心性需要 auto-link 这一层提供 —— content link 给底子,auto-link 补 long tail,二者合起来才是完整的图。
| 选项 | 优点 | 缺点 |
|---|---|---|
| 简单入度 | 实现最简;split parent 入度天然高;auto-link L1 加边后入度即时反映 | 不区分"权威节点"vs"被随手提的节点";高入度 ≠ 高权威 |
| PageRank | 经典;权威性传递 | 实现复杂 + 增量更新成本(每次写边重算成本高,需 incremental algorithm) |
| eigenvector centrality | 与 PageRank 相近 | 同上 |
首版决策:简单入度(file_graph 已有 inbound 链表,O(1) 查);auto-link L1 加边后入度立刻更新,split parent 自然涌现高入度。dogfooding 后视 retrieve 质量演进。
中心性是 retrieve 时查询时计算,不预存:
- file_graph 已建反向索引(inbound),计算
len(inbound(node))是 O(1) - 不预存避免"加边后中心性陈旧"问题
- PageRank 演进时可加增量计算 + 周期 refresh
2. 待对齐边界点
2.1 L3 predicate 升降级的 audit
L3 把 [[A]] 升级为 is_a:: [[A]] 时,改了 edge identity —— (target, None) 变成 (target, "is_a"),在 E-1 守恒视角下 = 删一条边 + 加一条边:
old outbound: {(A, None)}
new outbound: {(A, "is_a")}
diff: missing = {(A, None)}; added = {(A, "is_a")}
不打 audit 走默认会被守恒校验拦下(missing != ∅ → 重试 / 拒写)。
决策方向:
- L3 写入必须打 audit flag(消费层意图:升级 predicate,允许 drop + add 同时发生)
- audit flag 由 reme4 step 暴露(
maintainer_step(action="predicate_upgrade", from=..., to=...)),不放在普通 write 路径 - 普通 dream / auto-link L1 写入永远不带 audit flag,守恒校验照常严格
详细 audit flag 接口形态留到 SDK 阶段。
2.2 多歧义实体识别
L1 扫 body 找 "JWT" 这个 mention,vault 中有 digest/auth/jwt-overview.md 和 digest/payment/jwt-payment-flow.md 两个 candidate:
候选方案:
- LLM 上下文判 —— 把 body 周围段落给 LLM,选最相关 target
- 跳过模糊 case —— L1 只处理 unambiguous mention,歧义 case 留人/agent
- 全部链 ——
[[overview]][[payment-flow]],后续人 curate
首版:LLM 上下文判(每个候选 candidate 提供 description / 周围若干节点 summary,LLM 选择 top-1 或 drop);成本可接受(扫描已是离线 batch)。
2.3 auto-link 写回与 dream / split 的并发
auto-link 写 body 走 §1.2 CAS,但有特殊情况:
- 同节点同时被 dream update 与 auto-link L1 写入 → CAS 协议自动序列化 (
auto_maintain_design.md§5):后到者重做 - auto-link L1 写完后立刻被 dream update 覆盖(dream 重写 body) → 看 dream prompt 是否守住 auto-link 加的 wikilink(E-1 强守恒 → 守住)
- auto-link L1 与 D3 派发的 split job 同节点并发 → split 先到 / 后到都不影响最终拓扑(split 把 body 拆成 parent + children,auto-link 加的 wikilink 跟着对应内容段自然分配到 parent / child)
结论:CAS + E-1 + E-2 守恒已覆盖所有并发场景,auto-link 不需要新协调机制。
2.4 跨 vault / 跨进程
M0 单 reme 实例 + 单 vault,auto-link 走内进程 enqueue;多实例 / 跨进程留 M1+(同 auto_maintain_design.md §5)。
2.5 实体识别 vs 现成 NER 库
L1 实体识别可选:
- LLM 直接扫(贵但灵活,与 digest 节点同构)
- 现成 NER 库(spaCy 等)预筛 + LLM 终判(快但 entity 类型与 digest 节点形态可能不匹配)
- 纯字符串匹配(已知节点名字 + 简单变体)+ LLM 终判 ambiguity
倾向:从纯字符串匹配 + LLM 终判 ambiguity 起步(实现最简,效果可能已经够好);视 dogfooding 决定是否引入 NER 库。
3. 与其它层的协作
| 上下游 | 关系 |
|---|---|
| ← auto-dream | dream 写完一个节点 → 通过 inline post-write enqueue auto-link L1(§1.4);auto-link 用 dream 的 CAS 协议 |
| ← auto-memory | auto-link 可反向扫 daily event,把实体识别成 [[digest/...]](daily → digest);auto-memory 写入端不主动调 auto-link,触发同 dream 路径 |
| → digest body | 主要写入对象 —— L1 additive 加 wikilink / L2 节末追加引用 / L3 升 predicate(走 audit) |
| → daily body | auto-link 扫 daily event 时同样可加 [[digest/...]](I-2 daily 单作者需协调:auto-link 应在 event 关闭后才动该 event,不与 active event 并发改;实现细节留 step 层处理) |
| → resource body | I-3 immutable;auto-link 不写 resource(reading-only) |
| → L4 候选 report | L4 重复语义检测产报告,落 audit/<date>/auto_link_l4.md(具体路径 / 形态留 step 层) |
4. 与 auto-dream 模型的引用关系
本文档复用 dream 定义的底层模型,所有具体规则在 auto_dream_design.md 中:
| 引用 | 来源 |
|---|---|
wikilink 基础语法([[path.md|alias]] / predicate) |
auto_dream_design.md §3 |
| 节点 / 边模型 | auto_dream_design.md §4 / §2 / §3 |
| F-invariants(F-1..F-11) | auto_dream_design.md §4.3 |
| 边守恒 E-1 / E-2 / E-3 | auto_dream_design.md §4.4 |
| 路径即 ID / rename | auto_dream_design.md §2 |
| CAS 写入协议 | auto_maintain_design.md §5 |
| anchor 不引入 | auto_dream_design.md §3 |
| SearchStep 召回 | auto_dream_design.md §4.2 |
5. 下一步
- L1 实体识别 step 实现 —— 字符串匹配 + 语义召回 + LLM ambiguity 终判 + additive wikilink 写回(§1.2 / §1.3)
- inline post-write trigger 接入 —— dream update / M split CAS 写入成功后 enqueue auto-link L1 job(§1.4)
- L2 / L3 周期 batch 框架 —— cron(daily / weekly)+ 候选挖掘 prompt + 写回路径(§1.3)
- L3 audit flag 接口 ——
maintainer_step提供predicate_upgrade操作,带 audit context 走特殊守恒规则(§2.1) - 中心性 retrieve 增益 —— file_graph inbound count → retrieve 加权乘子(§1.5)
- L4 报告框架 —— 重复语义检测产报告,提供 SDK / 人介入入口(§1.3 / §3)
实现进入 reme4/steps/jobs/ 与 reme4/file_graph/ 时,本文档与 auto_dream_design.md 共同作为契约依据。