dsh-plugin-immune:讓 Agent 踩過的坑不再踩第二次

前言

給 Agent 寫提示詞的人基本都遇見過這個模式:同一個坑,這個會話踩過、修好了,下一個會話原樣再踩一遍。寫進文檔沒人維護,寫進系統提示詞太長也太泛。dsh-plugin-immune 的思路是把「踩坑現場」直接變成規則——工具調用失敗再成功,插件自動提煉成一條抗體存進 SQLite,下次問到相關文件名或命令時,先把抗體注入上下文。

它由 meat-daemon-404 維護,分類是「記憶」,GitHub 3 stars,npm 包名 dsh-immune-system(當前 0.9.5),License 爲 MIT。同時支持兩個宿主:DSH(DeepSeek Harness)和 ZCode,共用同一份 core/。

這是什麼

一句話:Agent 的失敗—修復經驗自動蒸餾與召回插件。

工作流程是「配對 → 蒸餾 → 抗體 → 注入」:

 工具失敗 ─┐
           ├─► 配對 ─► 蒸餾 ─► 抗體(SQLite + FTS5,按項目隔離)
 工具成功 ─┘                          │
                                      ▼
        下一次會話提問 ─► <immune_memory> 注入模型上下文

與靜態文檔方案相比,差別在於規則來源。不是人去寫「vite 客戶端環境變量要用 loadEnv」,而是 Agent 真踩過一次之後自己提煉出來,下次在相關上下文裏先出現。

安裝

DSH 側最簡方式是走 npm:

dsh plugin --profile <profile> add dsh-immune-system

<profile> 是 ~/.dsh/profiles/ 下實際在用的那一個,桌面端通常是 desktop。裝完需要重啓 DSH,bundle 是啓動時裝配的。

等價方式有兩種,不需要 npm 賬號:

cd dsh-immune-system && npm pack          # → dsh-immune-system-0.9.0.tgz
dsh plugin --profile <profile> add ./dsh-immune-system-0.9.0.tgz
dsh plugin --profile <profile> add github:meat-daemon-404/dsh-plugin-immune

注意 git: 安裝會在安裝時跑 prepare 構建,pnpm 默認會攔截,需要把 pnpm 打印的 key 加進 profile 的 pnpm-workspace.yaml → allowBuilds。作者的建議是除非就要這個形態,否則用前兩種。

裝完用 /immune 自檢,能返回「暫無抗體」就說明掛上了。

包引擎要求 ^22.19.0 || >=24.0.0,README 的徽章上寫的是 node >=22.5。

怎麼用

正常幹活就行,不需要額外操作。踩坑 → 修好 → 下一回合自動提煉。之後問到包含相同文件名或命令的問題時,上下文裏會出現 <immune_memory>…</immune_memory>。

DSH 側的斜槓命令:

命令 作用
/immune 列出所有抗體(--all 含已退役)
/immune-export 把經過驗證的抗體導出成 SKILL.md
/immune-forget <id> 刪除指定抗體
/immune-forget --last 撤銷上一回合剛學的那條
/immune-forget --prune 退役從未命中且超過 14 天的抗體(可恢復,不再注入)
/immune-forget --purge 物理刪除上述抗體(不可恢復)

ZCode 側命令前綴換成 /dsh-immune-system:,另有 /dsh-immune-system:immune-learn(手動教一條規則)和 /dsh-immune-system:immune-ui(啓動本地儀表盤)。

兩者通用的 CLI:

cli.js ui [--port N]                            # 本地儀表盤,默認 7788,端口占用自動順延
cli.js learn <trigger> [symptom] <prescription> # 手動教一條規則
cli.js search <query>                           # 只讀檢索,與儀表盤/MCP 同一條不計數通道
cli.js export-json <path> / import-json <path>  # 庫快照導出/導入
cli.js doctor                                   # 安裝健康自檢:node 版本、FTS5、數據庫、marker、MCP 腳本

doctor 有一項失敗就退出碼非零,可以直接接進 CI。

存儲與同步

抗體庫是 SQLite 單文件,含 FTS5 trigram 索引,中文按 3 字窗口匹配。DSH 默認路徑:

<DSH_HOME>/storages/dsh-immune-system/<sha1(當前目錄)[0..16]>.sqlite

按項目隔離,不同工作區互不串味,也不往項目目錄裏丟文件。顯式指定 IMMUNE_DB_PATH 時最優先。

跨機器同步走 JSON 快照:

node "<plugin>/dist/zcode/src/cli.js" export-json library.json   # 快照
node "<plugin>/dist/zcode/src/cli.js" import-json library.json   # 合併進當前庫

合併語義是保守的:處方作爲身份去重;兩側都認識的規則,命中/失效計數取 max;狀態任一側 active 即 active。把 library.json 提交進倉庫,團隊成員 import-json 一次就能繼承全部教訓。

幾個值得注意的設計

失敗判定不賭單一事件。 ZCode 的 PostToolUseFailure 只在工具處理器拋異常時觸發,命令非零退出是正常返回;DSH 的 result.isError 只覆蓋基礎設施失敗。所以插件自己按權威度排序判斷:isError → sandbox 拒絕標記(判失敗但不入庫學習)→ kill/timeout → 結構化 value.exitCode(有則權威,0 成功、非 0 失敗)→ 有結構化 value 但無退出狀態(載荷即結論,正文不掃)→ 行尾 [exit code: N] → 窄口徑失敗標記正則。最後兩步刻意讓位給結構化信號,因爲退出 0 的命令在 grep 輸出裏印出 command not found 是常事,不該被記成失敗。

抗體會淘汰。 一條抗體注入後工具仍然失敗就扣分,滿 3 次自動退役並聯合新證據重新蒸餾。扣分帶相關性判斷,失敗內容必須與該抗體觸發詞有共同詞,並排除工具名本身。

泛型坑只學一條。 File has been modified since read 這類症狀與具體文件無關,實測在三個不同文件上各學一條重複規則。core/lessons.ts 的精選模式表把這類症狀歸一成泛型觸發詞和處方,規則隨後在處方級去重。

人類糾偏優先。 常見的真實鏈路是:工具失敗 → Agent 問人 → 人說「這個倉庫用 pnpm」→ 重試成功。那句人話是最好的蒸餾輸入,UserPromptSubmit 會把新回合的人類消息掛到上一回合未閉合的失敗上,蒸餾時作爲處方的最優來源。「繼續」「ok」這類空話會被 isSubstantiveHint 擋掉。

事前檢查默認關閉。 IMMUNE_GUARD 提供確定性檢查,三檔:off(默認)/ warn / deny。三條只在任何環境都錯的規則(強推 main、rm -rf /、git reset --hard)寫在代碼裏,不進數據庫——蒸餾產物是模型輸出,把它編譯成正則去攔截工具調用等於讓未經審閱的字符串獲得停止工作的權力。deny 是唯一有破壞性的模式,所以不是默認值。

注入衛生。 注入內容只來自插件自己提煉的字段,不放原始工具輸出;抗體文本里的尖括號被剝離;有長度上限;明確標註「僅供參考」。一個回合最多注入一次,且只在回合第一步匹配。

蒸餾掛在回合邊界。 drain() 可能向配置的 LLM 端點發 HTTP 請求,DSH 的 tools/post-execute 監聽器被 await 在工具結果路徑上,放進去會讓每次「失敗後成功」的工具調用都卡到 HTTP 返回。所以它掛在 agent/turn-stopping,未清空的隊列由下次 session-start 的 requeueStuckJobs() 兜底。

串行連接而非 ATTACH DATABASE。 SQLite 明確說明 WAL 模式下跨附加庫的事務不原子,而插件每進程短連接、多 hook 併發,所以項目庫與共享庫用兩條獨立連接。代價只是召回變成兩次查詢。

適用場景與注意

適合這種場景:Agent 固定在同一個工作區、同一個技術棧反覆幹活,踩坑後很快又回到類似上下文。項目之間差異大時,按項目隔離的庫正好防串味;跨項目通用的經驗靠共享庫(global.sqlite)補齊。

安裝前建議做兩件事:

  1. 讀一遍源碼。插件聲明的權限是「讀取工具調用結果與斜槓命令輸入;在本機寫 SQLite 抗體庫;僅在顯式配置 IMMUNE_LLM_BASE_URL 與 IMMUNE_LLM_MODEL 時才向該端點發起請求;不讀取其它插件的配置,不執行任意命令」。這是 README 裏的聲明,實際行爲仍應以源碼爲準。
  2. 確認許可證。倉庫爲 MIT License。

本地儀表盤的安全邊界刻意收窄:只綁 127.0.0.1、每次啓動生成隨機 token 且所有 /api 都要帶它、嚴格 CSP、頁面不加載任何外部資源。

需要說明的是,作者在 README 裏明確標註:宿主 web 端原生設置頁裏那個「免疫」tab 的客戶端與路由契約有測試,但沒有在真實 web 應用裏端到端跑通,tab 是否如期出現需要重啓 DSH 後自己確認。

結尾

這個插件的價值在於把「踩坑經驗」從一次性事件變成可持久化、可檢索、可退役的資產,而不是一套需要人維護的靜態文檔。3 stars 意味着它還是個早期項目,接口和默認路徑都可能變。

目錄頁:https://www.skillhub.cn/plugins/meat-daemon-404/dsh-plugin-immune

GitHub:https://github.com/meat-daemon-404/dsh-plugin-immune

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

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

小夜