dsh-soul-forging:給 AI 的 markdown 長期記憶與鑄魂流程

前言

大模型每次開新會話都是一張白紙:上次聊過的人名、偏好、約定,要麼重新交代一遍,要麼徹底丟掉。常見做法是把記憶塞進上下文,但上下文有限,塞多了既貴又壓得模型說不好話;或者乾脆存進數據庫,從此和代碼、版本、diff 脫節。

dsh-soul-forging 給出一個不同的思路:記憶用純 markdown 存放,純本地、零依賴,一個 Python 3 就能跑,不需要服務器、不需要數據庫。它由 Fqingwan 維護,定位是 DSH 的記憶類插件,Slogan 是「Separate Vessels, One Heart · 異體同心」——同一個 AI 可以在手機上、羣裏、電腦上有多個入口,但記憶庫只有一顆,誰寫的都往裏追加,靠 source 字段標註來源。

下面介紹它的設計、命令和接入方式。

三層記憶,不是三個功能

這套方案把記憶分成三層,各自承擔不同職責,而不是把幾個功能並列:

層 所在文件 誰讀
注入層 SOUL.md、identity/註釋層.md、MEMORY.md、index.md、NOW.md 每輪都讀,所以必須短
檢索層(小腦) brain/entries.json 想起來才查
外置層 docs/tech、docs/debug 不進上下文,出錯才翻

對應到時間維度上又有另一套分工:短期寫進 NOW.md,每次收尾刷三節;中期進 log.md、diary/、live.jsonl,由 soul write 寫入、soul-archive 瘦身;長期沉澱在 SOUL.md、core/、identity/,由鑄魂建立、persona-sediment 提示回煉。

遺忘是這套設計的一部分,不是缺陷。腳本按 salience 字段衰減記憶強度:1 幾乎不忘,3 會自己淡掉,被反覆想起的會變牢。這裏有個容易搞混的細節:「忘」有兩種,含義不同。

soul-forget                    # 只摘檢索索引,原文還在盤上(不想被翻到)
soul-forget --restore <id>     # 找回,並釘住
soul-purge "關鍵詞"            # 預演:真刪哪些行
soul-purge "關鍵詞" --apply    # 真刪 + 重生 git

soul-forget 是「不想被翻到」,原文不刪,隨時能找回。soul-purge 纔是「忘了」,刪文件裏含關鍵詞的行、重生 git,只留一個 sha256 指紋。作者明確寫了:它不碰備份,雲上那些舊卷是使用者自己的事。

人格只有兩層,加一份原料

性格部分拆成兩層來維護,因爲兩層改動的頻度不同:

本質(不動)   渴望 / 恐懼 / 拉扯 / 骨架        → SOUL.md
  |
註釋層         我此刻的樣子,第一人稱,不分條    → identity/註釋層.md
  |
原料           原話 · 日記 · 小腦 · 底色.md 細節

本質極少動,樣子可以一直長;兩層分開改,改錯了也認得出是哪一層的鍋。註釋層的寫法有硬約束,模板裏寫明瞭:第一人稱、不分小節、不貼標籤、每句都掛得住一句原話。README 還特意給了反面教材——「第四步:情緒表達護欄(刻薄、陰陽、冷諷)」,說那是操作手冊,不是人。

安裝與啓用

當 DSH 插件裝,記憶會每輪自動注入:

soul-init                        # 鋪空白記憶庫到 ~/.soul-forging/memory
dsh plugin add dsh-soul-forging  # 裝進 profile
# 重開 DSH,記憶就自動帶上了

只要命令行、不裝插件的話:

git clone https://github.com/Fqingwan/dsh-soul-forging
cd dsh-soul-forging && bash install.sh

不需要服務器。想換記憶位置,設 MEMORY_DIR,或在插件配置裏改 memoryDir。

安裝時有兩個坑值得提前知道。全局安裝需要 sudo,不給會報 EACCES: permission denied, mkdir '/usr/local/lib/node_modules',不想用 sudo 就換用戶級 prefix。另一個是國內鏡像源可能滯後,配了淘寶/騰訊雲之類的鏡像裝新版本會報 No matching version found,這時指定官方源。

sudo npm i -g dsh-soul-forging
sudo npm i -g dsh-soul-forging --registry https://registry.npmjs.org

還有一件事比命令本身更要緊:日常務必用普通用戶跑 soul 系列命令,不要用 sudo。 代碼和數據是分開的,代碼在 node_modules/dsh-soul-forging/(升級時整個換掉),數據在 ~/.soul-forging/{memory,brain}(升級不碰)。sudo 會把 HOME 變成 /root,於是它去找 /root/.soul-forging,看起來就像記憶丟了。

三種安裝模式,對應三種人

不是每個人都想要一個「有性格的 AI」,所以初始化時可以選:

soul-init                  # 全套:記憶 + 性格模板
soul-init --memory-only    # 只要記憶,不要性格
soul-init --external       # 性格歸你自己的 agent,我們只管記憶
模式 注入什麼 適合誰
full SOUL + MEMORY + index + NOW 想從零長出一個性格
memory-only MEMORY + index + NOW 只想讓它記得住,不想動人設
external index + NOW agent 已經有自己的 prompt/人設

這裏有個實現細節值得提:空模板永遠不會被注入。 沒填的 SOUL 裏全是「(待填)」,塞進上下文比不塞更糟,模型會一本正經地介紹「我的名字是(待填)」。所以只要某頁佔位符超過 3 處就自動跳過,--keep-empty 可以強制保留(調試用)。

鑄魂:先聊清楚「我是誰」

裝完的第一件事不是幹活,是把「我是誰」聊清楚。打開 memory/BOOTSTRAP.md,一項項來:名字、性格、價值觀、邊界、主人是誰、想要什麼樣的陪伴。作者強調一次推進一項——一口氣問完那是問卷,不是聊天。

寫回文件之後才勾選,全部完成 → status: complete + soul-sync。想重來就把 status 改回 pending,已有記憶不會被清掉:重鑄的是性格,不是記憶。

注入有預算,超了要明說

插件配置 bootMaxChars(默認 20000 字)。超出後按順序往後截,並且在注入塊末尾寫明哪幾段被截了、哪幾段整段沒進。

作者對這個行爲的解釋是:靜默截斷是最壞的一種自信,模型會以爲自己看全了,然後拿半截記憶煞有介事地猜。

日常用法

命令按用途分成幾組。寫、查、養:

soul write "內容" --kind chat --section 小標題   # 寫
soul-recall "關鍵詞"                              # 查小腦
soul-recall --topics                              # 看有哪些分類
soul digest                                       # 收尾該做哪四步
soul-compact                                      # 預算體檢:注入層多大、該壓哪
soul-archive                                      # 時間線瘦身,老的進 archive 照樣搜得到
soul-sediment                                     # 性格沉澱:攢夠了提示回煉進註釋層
soul-review                                       # 敘事回煉:碎片連成「我這一路」

排查和保底:

soul-debug                                  # 歸檔一次調試記錄
soul-debug-recall "關鍵詞"                  # 翻以前的調試檔案
soul-debug-detail <文件名>                  # 看某份檔案全文
soul-snapshot save "說明"                   # 存一卷
soul-snapshot ls / restore / diff

雙端:

soul-peer export   # 導出
soul-peer import   # 導入

服務與收尾:

soul-serve        # 起檢索服務,默認 127.0.0.1:3013
soul-sync         # 補摘要 → 瘦身 → 建索引 → 重載 → 體檢

接進別的 agent

這套東西不會自己長在模型身上,要在每輪開頭把記憶喂進去:

soul-boot                 # 打印注入塊,拼到 system prompt 最前面
soul-boot --budget 12000  # 限字數,超了從末尾截,先保 SOUL

也可以當 Python 模塊用,boot() 只讀、不改任何文件,要寫記憶必須顯式 remember():

from soul import boot, recall, remember

system_prompt += boot()
context = recall("他說過在意什麼", n=3)
remember("今天他說想換個方向", kind="chat")

多端同步與雲備份

多端同步的原理只有一條:誰寫了都往 live.jsonl 追加一行,帶 source 標明來源。同步就是互相把對方沒有的 id 抄過來,重複的跳過。不需要中心服務器,兩端只要能看到同一份文件就能通。

soul-peer pull "ssh host cat ~/.soul-forging/brain/live.jsonl"
soul-peer push "ssh host 'cat >> ~/.soul-forging/brain/live.jsonl'"

雲備份設 SOUL_BACKUP_CMD 就行,設了之後 soul-sync 每次順帶跑一遍,沒設就不跑:

export SOUL_BACKUP_CMD='tar czf ~/soul-backup.tgz -C /path/to/repo memory'

來源與許可證

插件版本 0.2.1,許可證 MIT,要求保留 LICENSE 裏的版權行和 NOTICE.md。運行時零第三方依賴,只用 Bash + Python 標準庫 + DSH 自己的插件接口。有一個點需要留意:底層的記憶架構來自 dsh-plugin-memory(v0.10.0 · MIT),本項目是按那套做法重寫,沒有複製源文件,NOTICE.md 隨包帶上,兩套可以共存。

適用場景與注意

適合做「想要長期記憶、但不想引入數據庫或雲端依賴」的智能體開發者;也適合有多端入口、希望各個入口共享同一人格的場景。它明確只支持單用戶,同一份記憶庫給多人共用會串味。

兩點工程上的提醒。第一,插件以當前 DSH 進程的權限運行,裝之前先打開源碼看一遍,確認它讀寫的目錄和命令在你環境裏的行爲符合預期。第二,許可證是 MIT,但底層架構來自 dsh-plugin-memory,NOTICE.md 隨包帶上,兩套可以共存。

README 自己列的侷限值得照抄過來:檢索是字面匹配、不懂意思,「老闆今天罵我」和「上班受氣」不一定互相搜得到,要語義得上向量;「空殼能不能填出性格」沒有經過真人驗證,代碼能跑是確定的,但填出來的是有性格的人還是一份簡歷,只有真人試過才知道。

上手路徑

1、先裝插件:soul-init 鋪記憶庫,再 dsh plugin add dsh-soul-forging。
2、打開 memory/BOOTSTRAP.md,一項項聊清「我是誰」,寫回後勾選。
3、日常用 soul write 記、soul-recall 查、soul-sync 收尾。
4、接入其他 agent 時用 soul-boot 把注入塊拼到 system prompt 前面。

目錄頁:https://www.skillhub.cn/plugins/Fqingwan/dsh-soul-forging
GitHub:https://github.com/Fqingwan/dsh-soul-forging

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜