回溯性重构 · dsh-retcon
一句话
它是一份封存格式 + 一把尺子。 核心只有一句:写下判断时,必须写清「什么情况下它是错的」。没写,就不算数。
- 格式跟宿主无关。
格式.md是纯 markdown——笔记本、Obsidian、Word,照抄就能用。 - 检查器零依赖。
check_seal.py,有 Python 就能跑。 - 插件是可选的自动手。 有 DSH 时装上,它帮你生成格式、回访时补记、列未结案;没有 DSH,用手写 + 检查器,生成的文件一模一样。
- 它不存记忆。 不是知识库,不是画像系统,不是 RAG,不做向量、不建索引。
- 它做的全部事情,是让「什么情况下我是错的」这一栏,没法空着过去。
它到底解决什么
AI 是基于上文存在的 —— 但她每次不可能完全读完上文。
上下文有限。不管记忆做得多细,AI 读到的永远是被压过的那部分:摘要、结论、上一次的判断。它不是「读完了全部再回答」,是「读了别人留给它的结论再回答」。
结论一旦被当成事实沿用,AI 就不像人了。
人也不读完自己的全部记忆。人也是拿当下语境重新得出判断 —— 她的判断永远是「进行时」:随时可以推翻。
这就是这套格式唯一在做的事:把 AI 读上文得到的结论,写成一条可被推翻的进行时。
下次读到时,它不是「已知事实」,是「一个待验的假设」—— 第③栏写着怎么推翻它,第④栏写着上次推翻改了什么。
所以它不提高 AI 的记忆量。它让 AI 记忆里的每一个结论,都保持可被推翻的状态。
这就是「像人的地方」的归纳:不是像人一样会忘,是像人一样,判断永远可改。
它服务谁
两个生态位,不是所有人:
| 你是谁 | 为什么需要它 |
|---|---|
| 极限模式的正常用户 | 把 AI 当长期助手深度用,记忆里塞满判断。一旦某个结论过期而你忘了改,它会被一直沿用——而且没人知道它过期了 |
| 有艺术鉴赏需求的用户 | 看画、看片、看图,「这好在哪里」本身就是判断。审美判断最容易被写成一句结论,也最需要可推翻 |
其他人不用。 没有 live 冲突的人、只把 AI 当日用工具的普通用户、团队流程里图省事的人 —— 这套格式对他们只是负担。它不劝人用。
这套东西是怎么来的(先说清楚)
独立研究的产物。 五栏、推翻条件、变更史,都不是从哪个现成插件抄的,是从下面这几条地上长出来的:
- 精神分析:人对自己说的话,从来不是一次就说到位的——它总有一层被压抑、被改写的版本。要理解它,得拿「它本来想说什么」去跟「它说出来的」对。我们把这套读法搬到了 AI 的记忆上。
- 认知心理学:记忆不是存档,是每次现编。编的时候会和别的经验混、会丢、会补。所以「记得准」不该是目标,「记得能被人改」才是。
- 两边一起算:这套东西不是只为了让人好用,也不是只为了让 AI 变强。是让 AI 和人的好处在同一套规则里对齐——AI 写下的判断,人签得了字;人推翻的判断,AI 改得动。单边好处最后都会反过来伤另一边。
撞名说明:发布时发现 GitHub 上已有两个叫 dsh-retro 的仓库(tangzheng202202/dsh-retro、uckkk/dsh-retro),方向不同、各自独立。那是撞名,不是抄,也不是被抄。 本包更名为 dsh-retcon(retcon = retroactive continuity,追溯性连续性)——词是旧的,这套实现是新的。
框架分三层
L0 格式 + 尺子 格式.md + 读取/标准.md + scripts/check_seal.py
纯 markdown,跟宿主无关 —— 你不用装任何东西
L1 宿主的手 index.js(DSH 插件)—— 替你记住格式、执行检查
L2 机器 变更史 / 回访 / 度量 —— 让框架自己跑起来,不靠人的记性
现在 L0 独立了,L1 是插件,L2 里变更史做了、度量还没做。
只想拿 L0、不想装任何东西 → retcon-form(格式包:格式 + 给任何 AI 的提示词 + 检查器,跟 DSH 无关)。 本仓库(
dsh-retcon)是插件版,等于 L0 + 一个自动执行格式的手。
为什么先说 L0:这套东西最值钱的部分(判据、格式、样例、检查器)全在 L0,而 L0 谁都能拿走,不依赖 DSH 活一天。插件只是让「记得住格式」这件事不必靠人。
装(三步,30 秒)
1. 找到 DSH 的插件目录。
别猜。问你的 AI 一句:「你的插件目录在哪?」 —— 它就跑在 DSH 里,它知道。
拿到路径后,把包放进去,目录名叫 dsh-retcon/:
<那个目录>/dsh-retcon/
├── index.js
├── cordis.patch.yml ← 不用改,拷进去就行
└── package.json
不装插件也能用:
格式.md+scripts/check_seal.py是独立的,拷到任何地方都行。
⚠ 目录不存在就自己建(
plugins/就是个普通文件夹)。 ⚠ 如果你是第一次装,别去找"现有的插件"(没有)—— 问 AI,或者看 DSH 启动时的工作目录下的plugins/。
2. 重启 DSH。
3. 验收:问 AI「有没有 seal_write 这个工具」,或者直接让它调一次。
⇒ 没出现 = 目录放错了。 回第 1 步换候选(三个候选在文末「八、装」)。
如果你没装 DSH,用
格式.md+check_seal.py照样能跑通整套流程——插件只是替你记住了格式,不是替你做了判断。 详细说明见文末「八、装」。
四条路,自己挑
这个包给了四样东西。它们可以分开用,也可以一个都不用。
| 你想要 | 拿哪个 | 需要 |
|---|---|---|
| 想让它拦你一下 | 装插件(见第八节) | 有 DSH |
| 不想装任何东西,照格式手写 | 格式.md |
一支笔 |
| 只要一把尺子 | 读取/标准.md + scripts/check_seal.py |
Python |
| 想写出你自己的判据 | 读取/填空.md |
一支笔 |
| 先看真事长什么样 | 读取/样例一.md、读取/样例二_一次真实的批评.md、读取/样例三_一条判断塌了.md |
眼睛 |
⇒ 没有人该被劝着用这个。四个可以一起用,也可以一个都不用。
⇒ 不要因为「作者说好」才用。你自己的事,你自己挑。
一、它不是什么
先把话说清楚,因为它跟市面上所有「记忆插件」反着来:
| 它们在比 | 这个在比 |
|---|---|
| 记得多全、多准 | 记得有没有被推翻的可能 |
| 检索多快 | 每条能不能回到当时的原片 |
| 上下文塞得多满 | 塞不进去的是不是被记下来了 |
它不提高上限,它提高下限。
它不帮你记得更多。它只挡住一件事:把当时的判断,慢慢洗成“我当时就想对了”。
写出来长什么样
记忆就是一个 markdown 文件,落在 封存/ 下,文件名带日期:
20261025_标题.md
├── # 标题
├── > 封存时间 / 来源 / 衍生自(可选)
├── ## 一、我的假设(写完不改)
│ ### 那是什么 ← 要以「我猜/我以为」开头
│ ### 凭什么这么假设 ← 指到具体哪句话/哪一帧
│ ### 我可能错在哪 ← 至少两条
│ ### 怎么推翻我 ← 一件能执行的事(必填,空着就拒)
├── ## 二、原片(指针)
├── ## 三、后来 ← 回访时填
└── ## 四、注释 ← 推翻记录 + 那套东西改了哪一条
⇒ 格式由 seal_write 自动生成,你不用记。 你要填的是内容。
完整示例(一份真封存,它自己只有 4/5 分)见第四节。
二、它拦的那一下
你(或者你的 AI)想记一件事。插件只问一句:
「这条,怎么推翻?」
- 答得出来 → 写进去,第③栏永远空着,等一个「后来」。
- 答不出来 → 拒收。
⇒ 一条你怎么都想不到如何推翻的判断,不是判断,是信念。
信念不是不能有。但它不能混在「判断」里过夜。
三、装完之后你多了三个工具
| 工具 | 干什么 |
|---|---|
seal_write |
封存一条判断:假设 / 证据 / 我可能错在哪 / 怎么推翻我(必填) |
seal_later |
回访:验完了,记「站住了」还是「塌了」,以及为什么 |
seal_list |
列出还没结案的(「后来」空着的) |
另有可选脚本 scripts/cut_ledger.py,管另一半——丢弃:
python scripts/cut_ledger.py cut <路径> --why "为什么觉得它不重要" --pred "切掉后什么该还在"
python scripts/cut_ledger.py list # 没结案的
python scripts/cut_ledger.py back <ID> ok|broke --note "后来怎样了"
python scripts/cut_ledger.py audit
丢 ≠ 删。 删是损毁,丢是一次切断实验:切掉 → 预测什么该还在 → 回来记「塌了 / 没事」。 只有前三栏的注释是流水账;补上「后来」,才是实验记录。
四、读一遍就知道它是怎么被用坏的
插件给的是结构。它给的不是内容。
封存/ 里会长出这种文件:
# 记忆功能那条视频(判断封存)
## 一、我的假设(原文,写完不改)
### 那是什么
这条视频的议题不是「记忆好不好用」,是「记忆该被当成账本还是时间」。
### 凭什么这么假设
1. 2:40 那帧只有两行:时间 ≠ 重要性 / 你难道说忘就忘?
2. 4:25 那帧:B →(?)→ 修改 | 新建,下面一行「反正我现在认为是做不到的啊」
### 我可能错在哪
1. 我把 4:25 的 B 当成「记忆条目」,它也可能是「用户」或「版本 B」
2. 4 个时间点不代表中间是连续的 —— 我可能又在没有刻度的横轴上画曲线
### 怎么推翻我
取全片等间隔 12 帧。若 2:40 与 4:25 之间没有承接,则「一条论证线」塌掉。
## 二、原片(指针)
| 源 | BV11jnm6bENb(7:11) |
| 原片位置 | 封存/原片/20261025_xxx/ |
| 横轴有没有 | ✅ 有时间戳 ⚠ 只有 4 个点,不许画趋势 |
## 三、后来
(空着)
这个文件真正有意思的不是第一节,是第三节。 第一节谁都能写。
第三节空着的时候,它只是一个猜想。填了,才是知识。
五、它不该天天用(以及三个会踩的坑)
先说最大的那个: 回溯性重构是极限处才动的一刀,不是日常习惯。
命中下面一条才封存,其余时候别碰它:
- 赌注大 —— 这个判断错了会连带作废后面一串
- 反直觉 —— 你自己都不太信,但暂时没别的解释
- 已经在用了,却说不清凭什么
- 有人跟你说的相反,而你说不出他对在哪
日常偏好、已确认的事实、随手的选择、情绪 —— 都不要封。
⇒ 一个 封存/ 里有 200 条的人,通常一条都不重要。10 条以内的,才值得看。
完整判定见 读取/标准.md 第七节;封存之间怎么互相衍生,见第八节。
三个坑
① 第一轮你一定会被拒。 因为你会写「这个方案更好」,然后答不出怎么推翻。被拒是设计的一部分,不是 bug。
② 你会想只补一句「多试试就知道」。 那不算推翻条件 —— 它不可执行。「怎么推翻我」必须能指向一次具体的取帧、摘句、跑数。 (v0.1.1 起,这类废话会被直接拒掉。)
③ 你会开始为了能写进去,把话说窄。 这是好事。说窄了才验得了。 但注意别窄成同义反复(「这个可能会成功也可能失败」)。
六、插件和文档,不是二选一
两个都要有,因为它们管的不是同一件事。
- 格式管得住结构:
格式.md是死的,不会因为今天忙就少写一栏——只要你照抄。 - 插件管得住那次写入:它不信你的自觉,它只认那一栏有没有字。
模板可以跳栏,它不能。 你手写的时候,那栏空着就空着了,没人管;装了这个,那次写入直接失败。
但这话有个反面,得说清楚
这套东西,一个 markdown 模板 + 一句「写完记得填推翻条件」,效果能有八九成。 少记三个工具名,少装一个包。
那这个插件多出来的到底是什么? 只有一样:
模板可以跳栏,它不能。 你手写的时候,那栏空着就空着了,没人管;装了这个,那次写入直接失败。
⇒ 所以这张表你自己填:
| 你是什么样 | 该怎么做 |
|---|---|
| 能坚持按模板填 | 手写模板就行,还轻 |
| 三天后模板就空栏 | 装。你需要的是那一下拒 |
它不提高你的能力,它挡的是你自己的滑。
七、填空:问题都给你,答案自己写
判什么、什么值得记、什么算好 —— 这些我没有标准答案。但我知道该问什么问题。
所以 读取/填空.md 里放了七道题。每道题旁边是我们填的(标了「只是我们的,不是标准」),右边留空。
- 你为什么需要它记住?
- 一条记忆要带几样,你才敢信它?
- 你怎么知道自己记错了?
- 什么该丢?丢之前记什么?
- 多久回看一次?
- 你希望它记住你的什么?
- 你打算怎么用「后来」那一栏?
七道题里,我们四道有答案,一道承认是空的(第五题:一条都没回看过),两道只有半截。
⇒ 空着的不是「不给你」,是「我也没有」。
⇒ 而你不填的话,封存/ 里长的就还是我的形状。
⇒ 还有一层:这是刻意的。
如果我们把七道题全填满,你拿到的就是我的答案 —— 一个满的模板,你只会抄,不会想。
留着那个空,不是留白设计,是 —— 那是你能自己补上的地方。**
⇒ 匮乏得挑着用:能让你自己补上的,我们留着;不填你就走不了的地基(这是什么、怎么装),我们填满。
拿到空的模板、不知道往里面填什么 —— 那不是你的问题,是给的人没把题出完。这一版把题补上了。
八、装(细节版)
上面「三条」已经够装了。这里只补两件容易踩的。
插件目录在哪
可能是这三处之一:
| 候选 | 路径 |
|---|---|
| A | 你启动 DSH 的那个目录下的 plugins/ |
| B | ~/.dsh/plugins/ |
| C | DSH 安装目录下的 node_modules/ |
⇒ 不用猜。判据是硬的:装完重启,工具出现 = 目录对了;没出现 = 换下一个。
三个都试过还不行 → 问你的 AI「你的插件目录在哪」,然后照样用这个判据验证它说得对不对(装进去,看工具出不出来)。
⇒ 你没法独立验证 AI 说的路径 —— 但你能验证结果。这个判据不依赖任何人。
目录结构
<插件目录>/
└── dsh-retcon/
├── index.js
├── cordis.patch.yml
└── package.json
第 2 步:重启 DSH。
第 3 步:确认三个工具出现了(问你的 AI「有没有 seal_write 这个工具」,或者直接让它调一次)。
关于 cordis.patch.yml
- insert:
- id: retro # DSH 内部的节点名,随便叫,不影响功能
name: 'dsh-retcon' # ⚠ 必须跟 package.json 的 "name" 完全一致
这两个名字容易混:id 是挂载点的标签(自由),name 是包名(必须对)。index.js 里还有第三个 export const name = 'retro' —— 那是插件自己报给 DSH 的短名,跟 package.json 的 dsh-retcon 差一个前缀,这是 DSH 插件的惯例,不是笔误(对照 dsh-call-guard / call-guard)。
第一次用:一条真调用
装完别干看着,直接写一条:
seal_write({
title: "先试试它拦不拦",
claim: "这个插件装上之后,我的 AI 会开始记「当时凭什么这么判」",
evidence: ["我自己写的这一条,没有外部证据 —— 这就是故意的"],
guess_wrong: ["可能装上就忘了用,三天后 封存/ 还是空的"],
can_refute: "两周后回来 seal_list,若还是只有这一条,说明它没被用起来,这个判断塌了"
})
然后故意留空再写一次:
seal_write({ title: "空推翻条件", claim: "这个方案更好", evidence: ["直觉"], can_refute: "" })
第二次会被拒绝。 那一下拒,就是这个插件的全部。
关于位置(封存/ 会长在哪)
默认 = 你启动 DSH 时的当前目录。换个目录启动,就是另一个 封存/。
想固定在一个地方(比如所有项目共用一个封存库),设环境变量:
# Windows (PowerShell)
$env:SEAL_BASE = "D:\我的封存库"
# macOS / Linux
export SEAL_BASE=~/封存库
scripts/cut_ledger.py 认同一个变量,两边保持一致。
MIT。改、拆、骂都行。
想知道为什么这么做
设计理由(像人 / 荒诞主义 / 辩证法 / 为什么记经历不记偏好)全在 → 读取/为什么.md
它不影响你能不能装。 装、拦、三个坑、四条路,都在上面。
作者
B 站:@深海里的阿深
第一条视频发在那儿 —— 讲的就是这个包那个 4/5 分的事(我拿自己的标准量自己,扣在「假设位」)。
没装 DSH 也能看。 那期不讲代码,讲一个更小的事:你手上那条挺确定的结论,怎么推翻它。
No comments yet. Be the first to write one.