构建一个 DSH 插件,更接近于写一个小型库,而不是给一个封闭应用写扩展。你需要一个包、一个入口点,以及一份 dshTarget 声明。本指南会依次走完这三件事,然后演示如何在真实会话中测试结果。
插件到底是什么
插件就是一个导出 apply(ctx) 函数的包。harness 在启动时用一个上下文对象调用它,你注册的一切都经由这个对象完成:工具、命令、界面区域、事件处理器。当插件被卸载时,运行时会销毁你注册过的东西。
这种设计意味着你永远不需要伸手去动全局状态。如果你的插件只有靠修改它并不拥有的东西才能工作,那么它在下一个版本上就会坏掉。
第 1 步:创建包
mkdir my-dsh-plugin && cd my-dsh-plugin
npm init -y
npm pkg set type=module
npm pkg set name=dsh-my-plugin
加上生态话题标签,方便日后被目录站点发现,同时在 README 和包元数据里声明你所针对的 harness 版本:
{
"name": "dsh-my-plugin",
"type": "module",
"keywords": ["dsh-plugin", "deepseek-harness"],
"dsh": { "target": "rc.6" }
}
第 2 步:编写 apply(ctx)
从一个最小可用的插件开始:一个模型可以调用的工具。
import type { Context } from '@deepseek-ai/dsh';
export function apply(ctx: Context) {
ctx.tool({
name: 'word_count',
description: 'Count words in a piece of text.',
parameters: {
type: 'object',
properties: { text: { type: 'string', description: 'Text to count' } },
required: ['text'],
},
async execute({ text }: { text: string }) {
const words = text.trim().split(/\s+/).filter(Boolean).length;
return { words };
},
});
}
这段代码里有三点值得注意。description 是写给模型看的,不是写给人看的,因为模型正是靠它来决定要不要调用这个工具。参数 schema 必须写明确,含糊的 schema 会带来糟糕的调用。返回值是结构化数据,而不是格式化好的字符串,因为调用方通常要基于它做推理。
第 3 步:不只注册工具
工具是最常见的接入面,但不是唯一的一个。想清楚你需要哪种接入面,然后通过 ctx 注册:
- 命令,用于你自己从输入框触发的操作。
- 事件,用于响应会话生命周期的变化。
- 界面区域,如果你做的是 UI 而不是能力。
- 能力接缝,当你为别的插件所消费的东西提供实现时,比如一个记忆提供方。
第 4 步:在真实会话里测试
在包含插件源码的目录下,把它装进 web profile:
dsh plugin --profile web add /absolute/path/to/my-dsh-plugin
然后启动 harness,检查两件事:插件是否无报错地加载,以及模型在合适的场合是否真的会调用你的工具。一个存在但从未被选中的工具,通常问题出在描述上,而不是代码上。
第 5 步:诚实地处理失败
插件的失败应该是可读的。如果一次工具调用无法完成,请返回一个明确指出缺了什么的错误,而不是返回空结果。如果你的插件需要配置,就在加载时失败并说明缺少哪个字段,而不是等到三个会话之后第一次使用时才失败。
第 6 步:把契约写下来
发布之前,写清楚你依赖什么:你注册的能力、你需要的权限、你所针对的 harness 版本。这份文档正是一个目录站点准确收录你所需要的信息,也是审阅者信任这个插件所需要的信息。
FAQ
必须用 TypeScript 吗?
不是必须,但上下文对象的类型定义能挡掉人们写第一个插件时的大多数错误。
一个插件可以依赖另一个插件吗?
可以间接依赖,通过能力接缝。插件之间直接私有导入会在升级时坏掉,还会带来加载顺序问题。
不发布到 npm 该怎么测试?
从本地路径安装,如第 4 步所示。harness 会像对待任何其他包一样对待本地目录。
什么时候该抬高 dshTarget?
每当你采用一项新的运行时能力时。声明一个比你实际需要更新的目标版本,只会把使用旧版本的用户挡在门外,而没有任何好处。
下一步
阅读 Cordis 插件生命周期来理解销毁与加载顺序,然后把你的插件发布并提交到目录站点。