乐于分享
好东西不私藏

DeepSeek Harness 插件实践:手写一个工具插件

DeepSeek Harness 插件实践:手写一个工具插件

上篇聊完 DeepSeek Harness 的「一切皆插件」框架,道理都懂,插件到底怎么写?这篇就动手。我按难度把扩展路线分成三档,从「零代码」到「换掉 Agent 循环」,一步步来。

先记住一个核心心智模型:插件就是一个导出 apply(ctx) 的 TypeScript 模块。框架加载它时调用 apply 并传入 ctx,你在 ctx 上注册能力。而且通过 ctx 注册的一切都是可逆的——插件卸载时自动清理,不用手写 removeListener。

一、三条路线,先选难度

路线
写法
难度
适合
Skill
技能
一个 SKILL.md
最低
给 Agent 预装流程/规范
工具插件
导出 apply 的 TS 模块
给 Agent 加新能力(调 API/算数据)
深度插件
换循环/UI/Provider
改运行时行为、做皮肤/桌宠

二、路线一:Skill,零代码 5 分钟

如果你只想「教 Agent 一套做事规范」,一个 Markdown 文件就够,不用写代码。核心是 YAML frontmatter + 正文:

--- name: csv-helper description: 当用户要求处理或分析 CSV 文件时使用。 ---  # 正文:给模型的具体操作指令 1. 优先用 Python 的 csv 模块,打印前 3 行确认分隔符 2. 空值统一填 "N/A",日期格式化为 YYYY-MM-DD 3. 结果写到 processed/,文件名加时间戳

把文件放到扫描目录即生效(热加载,无需重启),优先级从高到低:

· <项目>/.dsh/skills/ 项目级(只在该项目会话可见)

· ~/.dsh/skills/ 用户级(任何会话都可见)

触发方式有两种:模型自动发现,或手动 /csv-helper 强制注入。

⚠ 第一个坑:frontmatter 会「静默丢弃」。description 里若含「冒号+空格」「括号」「逗号」这类字符,YAML 解析会失败,但 DSH 只记警告、不报错也不进目录,表现就是 /csv-helper 无反应。解决办法:给这类字段加引号。name 必须用 kebab-case,目录只扫一层、别嵌套。

三、路线二:手写一个工具插件

想给 Agent 加「真实能力」(比如调内部 API、做数据转换),就写工具插件。最小形态三件套:name(身份)、inject(依赖的服务)、apply(挂载时执行)。下面是个「文本转大写」工具:

import { defineTool } from "@deepseek-ai/dsh-base"  export const name = "hello-tool" export const inject = ["tools"]  export function apply(ctx) {   ctx.tools.register(defineTool({     name: "uppercase",     description: "将输入文本转为大写。当用户要求转换大小写时使用。",     parameters: { text: { type: "string", required: true } },     async execute(params) {       return { text: params.text.toUpperCase() }     },   })) }

三个要点记住:name 是模型点名调用的名字,要表意;description 决定 Agent 会不会用,写清触发场景;parameters 决定调用时的输入校验。

插件写好后要「装进」组合。两种挂载方式:

方式 A · 本地快试(--patch):写一个 cordis.yml,用绝对路径指过去,带补丁启动:

# cordis.yml - insert:   - id: hello-tool     name: /abs/path/to/my-plugin.ts  # 启动 pnpm dsh web --patch ./cordis.yml

方式 B · 正式安装(推荐):把包加进 web profile,再在 cordis.patch.yml 登记一行:

dsh plugin --profile web add <包名>  # profiles/web/cordis.patch.yml 追加 - insert:   - id: hello-tool     name: 'hello-tool'

四、路线三(进阶):让 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 开源:一切皆插件,黑鲸出笼》