上篇聊完 DeepSeek Harness 的「一切皆插件」框架,道理都懂,插件到底怎么写?这篇就动手。我按难度把扩展路线分成三档,从「零代码」到「换掉 Agent 循环」,一步步来。
先记住一个核心心智模型:插件就是一个导出 apply(ctx) 的 TypeScript 模块。框架加载它时调用 apply 并传入 ctx,你在 ctx 上注册能力。而且通过 ctx 注册的一切都是可逆的——插件卸载时自动清理,不用手写 removeListener。

一、三条路线,先选难度
| Skill | |||
| 工具插件 | |||
| 深度插件 |

二、路线一:Skill,零代码 5 分钟
如果你只想「教 Agent 一套做事规范」,一个 Markdown 文件就够,不用写代码。核心是 YAML frontmatter + 正文:
把文件放到扫描目录即生效(热加载,无需重启),优先级从高到低:
· <项目>/.dsh/skills/ 项目级(只在该项目会话可见)
· ~/.dsh/skills/ 用户级(任何会话都可见)
触发方式有两种:模型自动发现,或手动 /csv-helper 强制注入。
⚠ 第一个坑:frontmatter 会「静默丢弃」。description 里若含「冒号+空格」「括号」「逗号」这类字符,YAML 解析会失败,但 DSH 只记警告、不报错也不进目录,表现就是 /csv-helper 无反应。解决办法:给这类字段加引号。name 必须用 kebab-case,目录只扫一层、别嵌套。
三、路线二:手写一个工具插件
想给 Agent 加「真实能力」(比如调内部 API、做数据转换),就写工具插件。最小形态三件套:name(身份)、inject(依赖的服务)、apply(挂载时执行)。下面是个「文本转大写」工具:
三个要点记住:name 是模型点名调用的名字,要表意;description 决定 Agent 会不会用,写清触发场景;parameters 决定调用时的输入校验。
插件写好后要「装进」组合。两种挂载方式:
方式 A · 本地快试(--patch):写一个 cordis.yml,用绝对路径指过去,带补丁启动:
方式 B · 正式安装(推荐):把包加进 web profile,再在 cordis.patch.yml 登记一行:
四、路线三(进阶):让 AI 帮你写,甚至换循环
不想手写?切到「创造模式」,直接跟 AI 提需求,比如「帮我做个右下角桌宠插件,任务完成播『你干嘛~』」。AI 开发完会先让你人工审批再安装,安全性有保障——社区已有人把 Codex 桌宠移植过来开源了。
更硬核的玩法是换掉 Agent 循环本身:默认循环只是 ctx.agents.setFactory() 单槽位上的一个实现。做法是「禁用默认行 + 插入新行」。但自定义循环要守三条持久化契约:每条 assistant 消息必须带 provider+model、必须实现 resume()、每条回复要发 step 帧——否则历史会话打不开、界面不渲染。这块建议等官方 cookbook 稳定再上。
五、插件是怎么「分层」的
DSH 用 Bundle → Profile → Patch → Overlay 把「一切皆插件」落到可管理、可覆盖、可分发的工程实践上。每个 patch 就是一堆「插件行」:id + 包名 + config。上层覆盖下层,所以你能轻松用现成组合,也能深度定制并贡献给社区。
⚠ 第二个坑:Web 插件的 settings 白名单。浏览器侧经 api-proxy 只能读写内置 namespace,第三方 namespace 一律返回 settings-not-exposed。正解:Host 半用 ctx.settings.register('ui-skin', schema) 持有 owner scope(进程内不受白名单限制),浏览器侧走插件自己的 HTTP route(ctx.webServer.register(...))完成读写。另外给活动主题叠 token 时记得按签名去重,否则会触发重入风暴。
六、小结
给 Agent 装能力,先用 Skill(零代码),要真干活再写工具插件,要改运行时才碰深度插件。目前社区内测已冒出数百个插件,涵盖工具、UI、权限钩子;给仓库打 dsh-plugin 话题即可被社区发现。
一句话收尾:它的开源不止是「能跑」,而是把「怎么让模型跑」交到了你手里——从改一行 description,到换掉整个循环,都是你说了算。
仓库:github.com/deepseek-ai/deepseek-harness | 社区话题:dsh-plugin | 上篇:《DeepSeek Harness 开源:一切皆插件,黑鲸出笼》
夜雨聆风