DeepSeek Harness(DSH)插件开发保姆级教程:从 0 到 1 快速写出第一个插件

发布时间:2026/8/30 16:55:15
DeepSeek Harness(DSH)插件开发保姆级教程:从 0 到 1 快速写出第一个插件 DeepSeek HarnessDSH插件开发保姆级教程从 0 到 1 快速写出第一个插件最近 DeepSeek 开源了自己的 Agent Harness ——DeepSeek Harness简称 DSH。如果你用过 Claude Code、OpenClaw、MCP 或者各种 Agent Framework会发现 DSH 一个非常有意思的地方Everything is a Plugin一切皆插件。模型、Tools、Hooks、Session、UI、Sandbox甚至 Agent 本身的很多能力都可以通过插件组合。DSH 官方目前仍处于Developer Preview阶段插件 API 还可能出现不兼容更新所以现在非常适合学习它的插件机制但生产环境最好锁定版本。这篇文章不讲太多晦涩的架构理论直接带你从 0 开始搭建 DSH创建插件项目注册一个 Tool本地运行安装到 DSH调试插件理解apply / ctx / inject理解cordis.patch.yml发布插件最后再给一份可以直接交给 Codex / Claude Code 的插件开发 Prompt如果你本身做过 Node.js / TypeScript基本上十几分钟就可以把第一个插件跑起来。一、DSH 插件到底是什么先看 DSH 官方给出的最核心定义。一个最简单的 DSH 插件本质上就是一个导出了apply()方法的 TypeScript 模块importtype{Context}fromdeepseek-ai/cordisexportconstnamemy-pluginexportfunctionapply(ctx:Context){// 在这里注册插件能力}就这么简单。DSH 加载插件时会调用apply(ctx)然后把一个Context对象交给插件。插件通过ctx获取或者注册各种能力例如ctx.tools ctx.llm ctx.on(...)ctx.effect(...)官方把这种设计建立在Cordis插件框架之上。你可以粗暴地把它理解成DSH │ ├── Cordis │ │ │ ├── Plugin A │ ├── Plugin B │ ├── Plugin C │ └── Plugin D │ └── Agent Runtime插件并不是传统意义上的“往程序里塞一个脚本”。它更像是向 DSH Runtime 动态注册一个能力模块。二、DSH 插件可以做什么目前常见的插件大概可以分成几类。类型作用Tool Plugin给 Agent 增加工具Event / Hook Plugin监听或拦截 Agent 生命周期Service Plugin给其他插件提供服务LLM Plugin接入新的模型 ProviderSession Plugin处理会话、记忆、持久化Workflow Plugin编排多 Agent / 自动任务WebUI Plugin扩展 DSH Web UIPolicy Plugin权限、审批、安全控制例如我们可以开发天气查询 Git 工具 股票数据查询 数据库查询 网页搜索 企业知识库 RAG 飞书机器人 任务通知 定时任务 代码扫描 Agent 协作 日志追踪 审批系统这些都可以变成 DSH Plugin。官方的 Tool Pipeline 甚至允许插件介入tools/pre-execute ↓ guards ↓ tools/execute ↓ tools/post-execute ↓ tools/result所以像权限控制 日志记录 重试 超时 审计 指标监控都可以通过插件完成。三、准备开发环境首先需要 Node.js。DSH 可以直接通过 npm 运行npx deepseek-ai/dsh web启动成功后默认访问http://127.0.0.1:3080官方也支持直接从源码运行gitclone https://github.com/deepseek-ai/deepseek-harness.gitcddeepseek-harnesspnpminstallpnpmrun buildpnpmdsh web如果后面要使用dsh plugin建议提前安装 pnpm。例如npminstall-gpnpm因为目前dsh plugin--profilexxxaddxxx底层实际上会在 Profile 目录中调用 pnpm。四、最快的方式直接使用插件脚手架如果只是想快速写插件我不建议从零手写所有配置。社区目前已经有create-dsh-plugin可以快速生成 DSH Plugin 项目。例如创建 Tool 插件npx create-dsh-pluginlatest dsh-text-stats-ttool如果希望创建之后顺便验证npx create-dsh-pluginlatest dsh-text-stats-ttool--verify目前脚手架主要提供tool events webui等模板。生成后进入目录cddsh-text-stats安装依赖pnpminstall五、看看 DSH 插件项目到底有哪些东西一个典型的 DSH Tool Plugin大致会长这样dsh-text-stats/ ├── src/ │ └── index.ts │ ├── cordis.patch.yml ├── package.json ├── tsconfig.json └── README.md这里真正需要理解的只有三个东西src/index.ts package.json cordis.patch.yml六、第一部分src/index.ts我们来写一个非常简单的工具text_stats功能是让 Agent 可以统计一段文本的字符数、行数和单词数。修改src/index.ts代码如下importtype{Context}fromdeepseek-ai/cordisimport{defineTool}fromdeepseek-ai/dsh-toolsexportconstnametext-stats-toolexportconstinject[tools]exportfunctionapply(ctx:Context){ctx.tools.register(defineTool({name:text_stats,description:Calculate character count, line count and word count for a piece of text.,parameters:{text:{type:string,required:true,description:The text to analyze,},},output:{schema:{type:string,},render:(_args,value)[{type:text,text:value,},],},asyncexecute(args){consttextargs.textconstcharacters[...text].lengthconstlinestext.length0?0:text.split(/\r?\n/).lengthconstwordstext.trim()?text.trim().split(/\s/).length:0returnJSON.stringify({characters,lines,words,})},}),)}到这里我们已经完成了一个真正可以被 Agent 调用的 DSH Tool。官方推荐的 Tool 写法同样是ctx.tools.register(defineTool(...))defineTool()会负责参数定义、类型推导以及 Tool 输出约束。七、理解最重要的四个概念上面的代码看起来很多真正需要掌握的其实只有四个东西。1. nameexportconstnametext-stats-tool表示插件名称2. inject这里非常关键exportconstinject[tools]意思是我的插件依赖tools服务。Cordis 会等ctx.tools准备好之后再执行这个插件。如果以后需要其他能力例如LLM Session Storage Jobs同样需要声明对应依赖。官方文档明确说明inject用来保证依赖服务已经就绪。3. applyexportfunctionapply(ctx:Context)这是插件入口。可以理解成main()但是它不是程序入口而是Plugin Lifecycle EntryDSH 加载插件时调用它。4. ctxctx是整个 DSH 插件体系的核心。例如ctx.tools代表 Tool Registry。于是ctx.tools.register(...)就是往 DSH 的 Tool Registry 注册一个工具。所以整个插件开发逻辑实际上非常清晰DSH ↓ Context ↓ Plugin ↓ Register Capability八、defineTool 是什么我们再拆开defineTool({name,description,parameters,output,execute})这其实非常像 OpenAI Function Calling。例如parameters:{text:{type:string,required:true}}本质就是告诉模型这个 Tool 需要什么参数。而execute(args)是真正执行 Tool 的地方。模型可能产生{text:hello world}然后 DSH 调用execute({text:hello world})最终返回{characters:11,lines:1,words:2}九、构建插件代码写好以后执行pnpmrun build正常情况下会生成dist/或者脚手架配置的其他构建目录。如果这里就报 TypeScript 类型错误先不要急着安装插件。原则是Build 成功 ↓ 再安装 ↓ 再启动 DSH这样排查问题最快。十、cordis.patch.yml 到底有什么用这是很多第一次写 DSH Plugin 的人最容易迷糊的地方。例如-insert:-id:text-statsname:dsh-text-stats它的意思其实就是把dsh-text-stats插入当前 DSH Plugin Tree。可以理解成DSH Plugin Tree dsh-base │ ├── tools ├── llm ├── session │ └── text-statsDSH 的 Profile 本质上就是很多 Bundle Patch 按顺序叠加之后形成的一棵插件树。官方架构文档将运行配置描述为由多个 Bundle Layer 组合而成。十一、package.json 为什么还有 dsh.bundle你会看到类似{dsh:{bundle:{patch:./cordis.patch.yml}}}这句话非常重要。它是在告诉 DSH这个 npm package 不只是普通依赖。 它还是一个 DSH Bundle。它对应的 Bundle Patch 就是cordis.patch.yml如果没有dsh:{bundle:{patch:./cordis.patch.yml}}那么即使dsh pluginadd安装成功这个包也可能只是普通 npm dependency而不会自动变成 DSH 的组合层。官方打包规范也是通过dsh.bundle.patch来声明插件 Bundle。十二、把插件安装到 DSH现在开始真正安装。例如安装到 Web Profilenpx deepseek-ai/dsh plugin\--profileweb\add./dsh-text-stats或者如果你已经有dshCLIdsh plugin--profilewebadd./dsh-text-statsDSH 会把插件安装到Profile中。Profile 可以理解为一套 DSH 运行环境。例如官方内置web headless不同 Profile 可以拥有不同插件组合。十三、安装完不要急着启动先做这个检查推荐执行dsh--profileweb --dump-config然后搜索text-stats如果可以看到类似text-stats dsh-text-stats说明Bundle ↓ Patch ↓ Profile已经成功组合。官方也推荐使用--dump-config查看机器最终实际启动的插件树。十四、启动 DSH启动npx deepseek-ai/dsh web打开http://127.0.0.1:3080然后直接告诉模型请使用 text_stats 工具统计下面这段文本 Hello DeepSeek Harness This is my first DSH plugin.如果一切正常Agent 就会发起类似text_stats(...)的 Tool Call。到这里你的第一个 DSH Plugin 就正式跑通了。十五、不使用脚手架官方是怎么开发插件的如果你想真正理解 DSH也可以直接在官方源码里开发。首先gitclone https://github.com/deepseek-ai/deepseek-harness.gitcddeepseek-harnesspnpminstallpnpmrun build创建mkdir-pscratch-plugin/src然后scratch-plugin/src/my-plugin.ts写importtype{Context}fromdeepseek-ai/cordisexportconstnamehello-pluginexportfunctionapply(){console.log(Hello DSH Plugin)}创建scratch-plugin/cordis.yml加入-insert:-id:helloname:/绝对路径/deepseek-harness/scratch-plugin/src/my-plugin.ts注意本地 Patch 加载插件时官方要求这里使用绝对路径。然后pnpmdsh web--patch./scratch-plugin/cordis.yml就可以临时加载。这种方式非常适合插件开发 快速调试 研究源码 测试 Hook 测试 Service官方第一个插件教程就是采用这种方式。十六、本地开发和正式安装有什么区别可以简单理解开发阶段--patch例如pnpmdsh web--patch./my-plugin/cordis.yml优点修改快 调试快 不用反复安装正式使用使用dsh plugin--profilewebaddxxx插件进入Profile并长期存在。所以我的推荐工作流是写代码 ↓ --patch 调试 ↓ build ↓ plugin add ↓ dump-config ↓ 正式运行十七、DSH Hook 插件怎么写Tool 只是插件的一种。DSH 还可以监听生命周期事件。例如想记录所有 Tool 的执行结果importtype{Context}fromdeepseek-ai/cordisimporttype{}fromdeepseek-ai/dsh-toolsexportconstnametool-loggerexportconstinject[tools]exportfunctionapply(ctx:Context){ctx.on(tools/result,(exec){console.log([tool]${exec.name}finished)})}这样以后 Agent 调用bash read_file write_file text_stats都可以被观察。DSH 官方提供的扩展点还包括tools/pre-execute tools/execute tools/post-execute tools/result例如pre-execute可以做权限判断 危险命令阻止 参数校验 审批而post-execute可以做结果转换 数据脱敏 日志附加十八、插件如何清理资源假设插件里面启动了Timer Socket 数据库连接 Watcher可以使用ctx.effect((){consttimersetInterval((){console.log(running)},5000)return(){clearInterval(timer)}})插件卸载时return function会负责清理资源。而通过ctx注册的 Tool、Event、Timer 等能力Cordis 本身会跟踪生命周期。这是 DSH 插件机制比普通 Node.js 脚本更舒服的地方之一。十九、DSH Plugin、MCP、Skill 到底有什么区别这个地方非常值得理解。很多人会把Plugin MCP Skill混在一起。其实它们不是一个层级。可以粗略理解DSH │ ┌───────┴────────┐ │ │ Plugin Skill │ │ ├── Tool │ ├── Hook │ ├── UI │ ├── Workflow │ ├── Model │ └── MCP Client │ ▼ MCP ServerSkill更像告诉 Agent 怎么完成一类任务核心是Prompt Instructions WorkflowMCP解决的是Agent 如何通过统一协议调用外部能力。例如GitHub Postgres Browser FilesystemPlugin范围最大。Plugin 可以注册 Tool 实现 MCP Client 修改 UI 监听 Hook 实现 Workflow 提供 Service 接入 LLM所以MCP 可以成为 DSH Plugin 的一部分但 Plugin 并不等于 MCP。二十、最推荐的插件开发架构对于稍微复杂一点的插件我不建议所有代码全部放index.ts推荐src/ ├── index.ts │ ├── tools/ │ ├── search.ts │ ├── analyze.ts │ └── report.ts │ ├── services/ │ └──>index.ts只负责Plugin Registration真正业务逻辑放Service Client Utils例如Agent ↓ Tool ↓ Service ↓ API Client ↓ External System这样以后你想增加第二个 Tool 增加 WebUI 增加 Workflow都比较容易。二十一、一个真正实用的 DSH 插件可以长什么样比如我们做一个dsh-stock-research可以提供search_stock get_kline get_financials get_news analyze_stockAgent 使用用户 分析一下某只股票最近走势DSHLLM ↓ search_stock ↓ get_kline ↓ get_financials ↓ get_news ↓ LLM Analyze ↓ Report再比如dsh-devops可以注册query_logs query_metrics restart_service query_k8s query_sentry于是 Agent 就变成了一个DevOps Agent这也是我认为 DSH 插件生态真正有价值的地方。不是简单做几个Hello World Tool而是把真实业务系统封装成 Agent 可以组合调用的能力。二十二、插件开发最容易踩的几个坑坑 1DSH 现在变化比较快目前官方仍然明确标记Developer Preview并提醒可能出现 Breaking Changes所以建议插件项目锁版本不要所有依赖长期使用latest线上插件升级前先进行兼容测试。坑 2忘记 inject例如使用ctx.tools却没有exportconstinject[tools]这是非常典型的问题。坑 3package.json 没有 dsh.bundle如果没有{dsh:{bundle:{patch:./cordis.patch.yml}}}插件可能只是npm dependency而没有真正加入 Profile Bundle Stack。坑 4本地 --patch 使用相对路径官方源码开发教程里name:需要使用插件文件的绝对路径因为插件解析基于 Profile 环境。坑 5装完插件忘记 dump-config建议养成习惯dsh--profileweb --dump-config确认插件真的进入 Plugin Tree再启动。坑 6同一个插件加载两次如果之前已经通过profile/cordis.patch.yml手动insert插件后来又dsh pluginadd把这个插件作为 Bundle 安装就可能出现duplicate loader entry id因为同一个插件被加入了两遍。社区已经有人遇到过这个问题。所以原则是正式 Bundle 安装后 不要再手动 insert 同一插件。二十三、插件怎么发布当插件完成以后可以发布到npm也可以直接维护GitHub Repository正式 Bundle 至少需要包含package.json 入口 JS cordis.patch.yml并声明{dsh:{bundle:{patch:./cordis.patch.yml}}}例如-insert:-id:my-pluginname:my-dsh-plugin用户就可以dsh plugin--profilewebaddmy-dsh-plugin安装。如果维护 GitHub Repo也建议添加dsh-pluginGitHub Topic。官方 README 也推荐通过这个 Topic 提升插件的可发现性。二十四、以后写 DSH 插件我推荐这个开发流程我自己更推荐1. 明确插件能力 ↓ 2. 判断 Tool / Hook / Service / UI ↓ 3. create-dsh-plugin 创建项目 ↓ 4. 写最小 Tool ↓ 5. pnpm build ↓ 6. --patch 本地调试 ↓ 7. 编写单元测试 ↓ 8. plugin add ↓ 9. dump-config ↓ 10. Web / Headless 实测 ↓ 11. pnpm pack ↓ 12. GitHub / npm 发布不要一开始就搞10 个 Tool 5 个 Service 多 Agent 数据库 WebUI最好先让一个能力跑通。然后逐渐增加Tool ↓ Service ↓ Hook ↓ Workflow ↓ WebUI二十五、让 Codex / Claude Code 直接帮你开发 DSH Plugin最后给一个我比较推荐的提示词。以后想开发插件可以直接把下面内容交给 Codex、Claude Code 或其他 Coding Agent。你是一名熟悉 DeepSeek HarnessDSH、Cordis 和 TypeScript 的高级 Agent 插件开发工程师。 请帮我开发一个 DeepSeek Harness Plugin。 插件名称 dsh-xxx 插件目标 【填写插件功能】 技术要求 1. 使用 TypeScript。 2. 遵循 DeepSeek Harness 当前 Plugin 架构。 3. 插件入口使用 apply(ctx: Context)。 4. 正确声明 inject 依赖。 5. Agent Tool 使用 deepseek-ai/dsh-tools defineTool() ctx.tools.register() 6. Tool 必须提供 - name - description - parameters - output.schema - output.render - execute 7. 业务逻辑不要全部堆在 index.ts。 8. 推荐目录 src/ index.ts tools/ services/ clients/ schemas/ utils/ 9. package.json 必须包含 dsh: { bundle: { patch: ./cordis.patch.yml } } 10. 提供正确的 cordis.patch.yml。 11. 插件必须支持 pnpm install pnpm build 12. 给出本地调试方法。 13. 给出安装方式 dsh plugin --profile web add ./plugin 14. 给出 dsh --profile web --dump-config 验证方式。 15. 如果涉及 Timer、Socket、Watcher、数据库连接等资源 必须通过 Cordis 生命周期机制正确释放。 16. Tool 的业务实现与 DSH 注册逻辑分离。 17. 给插件增加 README.md 错误处理 日志 单元测试 .gitignore 18. 不要修改 DeepSeek Harness 源码。 19. 优先使用 DSH 官方公开 Extension Point 不要侵入 Agent Loop 内部实现。 20. 完成以后输出 - 项目目录 - 每个文件作用 - 完整代码 - 安装步骤 - 调试步骤 - 测试步骤 - 发布步骤 - 常见问题 先分析插件应该属于 Tool、Hook、Service、Workflow 还是 WebUI 然后再开始生成代码。这套 Prompt 基本可以直接让 Coding Agent 帮你把 DSH Plugin 的骨架搭出来。总结如果只记住 DSH 插件开发的核心我认为就记住下面这几个东西apply(ctx)代表插件入口inject代表插件依赖ctx.tools.register()代表向 Agent 注册 Toolcordis.patch.yml代表把插件挂载到 DSH Plugin Treedsh.bundle代表把 npm package 声明成可安装的 DSH Bundledsh plugin add代表把插件安装到 Profile整个流程就是TypeScript Plugin ↓ apply ↓ Cordis ↓ DSH Context ↓ Tool / Hook / Service ↓ Bundle ↓ Profile ↓ Agent一旦理解这个模型DSH 插件开发其实并不复杂。真正值得做的是把我们原来已有的Python 服务 Go 服务 数据库 内部 API 爬虫 RAG 搜索系统 数据平台 CI/CD 监控系统逐步封装成Agent 可以理解 Agent 可以调用 Agent 可以组合 Agent 可以编排的 DSH Plugin。这才是Everything is a Plugin真正有意思的地方。