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