前言¶
给 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)补齐。
安装前建议做两件事:
- 读一遍源码。插件声明的权限是「读取工具调用结果与斜杠命令输入;在本机写 SQLite 抗体库;仅在显式配置
IMMUNE_LLM_BASE_URL与IMMUNE_LLM_MODEL时才向该端点发起请求;不读取其它插件的配置,不执行任意命令」。这是 README 里的声明,实际行为仍应以源码为准。 - 确认许可证。仓库为 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