博客 · 指南
你的第一个插件,端到端:DeepSeek Harness 翻译工具
2026 年 8 月 27 日 · dshbase · 动手指南
如果「一切皆插件」对你还停留在抽象层面,这篇把它落地:我们从零构建一个完整的 dsh 插件包——一个翻译工具,让 Agent 能把文本翻译成目标语言。一路覆盖包骨架、defineTool、通过能力接缝调用 LLM、注册与生命周期、行为测试。步骤与官方 cookbook(adding-a-package.md、adding-a-tool.md)一致。
第一步:包骨架
工具生活在 monorepo 里自己的包中。package.json 的要点:
{
"name": "@deepseek-ai/dsh-tool-translate",
"version": "0.0.0",
"private": true,
"type": "module",
"exports": { ".": "./src/index.ts", "./invariant": "./src/invariant.ts", "./package.json": "./package.json" },
"peerDependencies": { "@deepseek-ai/cordis": "workspace:*" }
} 三件事先记牢:private: true 表示这个包留在仓库里、不发布到 npm;type: module 让它只能走 ESM;而 @deepseek-ai/cordis 既是 peer 也是 dev 依赖。工具包依赖的是服务定义(dsh-tools、dsh-llm),而不是某个具体的 Provider——这层间接性,正是工具不与具体模型厂商绑死的关键。
第二步:实现插件
import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'
export const name = 'tool-translate'
export const inject = ['tools', 'llm'] as const
export function apply(ctx: Context) {
ctx.tools.register(defineTool({
name: 'translate',
description: 'Translate text to a specified language.',
parameters: {
text: { type: 'string', description: 'The text to translate', required: true },
targetLanguage: { type: 'string', description: 'Target language', required: true }
}
// 工具实现里通过 ctx.llm 调用语言模型(能力接缝)
}))
} 插件入口是三个导出:name、inject、apply(ctx)。inject 列表就是一句「我要什么」——运行时保证在 apply 执行前,tools 和 llm 服务定义都已经就绪。这就是能力接缝:你的工具只声明需要什么能力、拿到对应的接口,从不 import 某个具体的模型 Provider。
第三步:注册与能力接缝
因为工具只声明服务定义,它天然可移植——同一个工具,只要换掉被加载的服务实现,就能从 DeepSeek 的适配器切到另一个提供方。apply() 在加载时把工具注册进 tools 服务;加载/卸载的生命周期由 Cordis 托管,所以摘下插件时它的注册会被干净地清理掉,而不是留下一堆悬空状态。
第四步:写测试
补两块让它更稳:一个行为测试(translate.spec.ts),用代表性输入断言工具的行为,对应上面示意图里的「行为测试」;一个运行时不变式模块(invariant.ts,经 ./invariant 导出),保存插件运行期间必须始终成立的那些断言——在一个高度组合的系统里,靠「不变式」而不是「乐观路径」兜底,才不容易整片塌掉。
第五步:接进系统
最后把它注册进 monorepo:在聚合 tsconfig 的 references 里加上它的路径,在 cordis.patch.yml bundle 里加一行让运行时知道要加载它,并在聚合 package.json 里加上依赖。
安装者该带走什么
一个工具插件其实是个很小的、可重复的形状:包骨架 + defineTool + 声明的 inject + 测试 + 一两行注册。看懂一个,之后发新工具照抄这个形状即可;又因为工具依赖的是服务定义而非厂商,换什么模型进来,同一个插件都能原样跑。「一切皆插件」至此变成可操作的现实:你自己的能力,就是 Harness 能加载、能检查、能干净卸载的又一个模块。