DSH plugin 服务隔离怎么做?DeepSeek Harness 的 inject 与 isolate
DSH plugin 的「服务」是插件挂载在 ctx 上向其他插件公开的命名能力,inject 声明插件需要哪些服务,而 cordis.yml 的 isolate 让不同插件组各持一份实例(来源)。 本文面向 DSH插件 / DeepSeek插件 作者,讲清必需依赖与可选依赖的写法、必需服务消失与恢复的运行期行为,以及 isolate 多实例隔离与类型声明合并;Cordis 概念入门见 Cordis 入门,inject 与 ctx.get 的分工写法见 插件规范,这里只讲依赖的运行期行为与隔离。
DSH plugin 的必需依赖与可选依赖
在 Harness 中 tools、llm、agents 都是服务,它们是挂载在 ctx 上的命名能力(ctx.tools / ctx.llm / ctx.agents),任何插件都可以提供服务供其他插件使用(来源)。 消费服务有两种写法,差别在插件何时才加载:
- 必需依赖 — 导出
export const inject = ['tools']。框架保证apply执行时inject声明的服务已全部就绪;服务还没准备好,插件会等着,不会执行。 - 可选依赖 — 省略
inject,在调用点用ctx.get()查询,并配合可选链兜底:
// Required: the plugin does not load while the service is absent.
export const inject = ['tools']
// Optional: omit inject and query with ctx.get() at the use site.
export function apply(ctx: Context) {
const metrics = ctx.get('metrics')
metrics?.record('plugin_loaded', 1)
}
提供服务用 @deepseek-ai/cordis 的 Service 基类:继承它、在构造函数里 super(ctx, 'metrics') 指定服务名,服务自身也可以静态声明 static inject = ['llm'] 依赖别的服务;加载后消费方通过 ctx.metrics 访问。让类型也对则用 TypeScript 声明合并:
declare module '@deepseek-ai/cordis' {
interface Context {
metrics: MetricsService
}
}
DSH plugin 服务消失与恢复的运行期行为
如果应用运行期间某项必需服务消失(例如其提供方卸载),依赖它的插件会自动 dispose 释放资源;当服务重新出现时,插件会自动重新加载(来源)。 这条行为的意义是:防止插件调用一个已经不存在的服务。
换句话说,把服务声明为必需依赖不只是「先等它就绪」的启动期约束,还是一条运行期的可用性契约——服务的可用性变化会自动传导到依赖方的加载状态。这也解释了为什么选择必需还是可选,取决于你的插件能否容忍服务缺席:能容忍就 ctx.get() 可选,不能容忍就让 inject 让框架替你管理生命周期。
DSH plugin 的 cordis.yml isolate 多实例隔离
cordis.yml 支持服务隔离——同一个服务可以有多个实例,不同插件组看到不同实例(来源)。 典型写法是给两个 group: true 的插件组各自 isolate 一份同名服务:
- id: group-a
name: '@deepseek-ai/cordis-plugin-group'
group: true
isolate:
shell: true
config:
- name: '@deepseek-ai/dsh-bash-local'
config:
timeoutMs: 5000
- name: './src/plugin-a.ts'
- id: group-b
name: '@deepseek-ai/cordis-plugin-group'
group: true
isolate:
shell: true
config:
- name: '@deepseek-ai/dsh-bash-local'
config:
timeoutMs: 60000
- name: './src/plugin-b.ts'
plugin-a 和 plugin-b 各自看到自己组内的 Bash 实例,互不影响——group-a 的 timeoutMs: 5000 与 group-b 的 timeoutMs: 60000 不会互相覆盖。这正是「同一个能力接口、多份隔离实现」的落点,和 能力 Seam 的分层思路配套使用。
最后一条查清单的纪律:Harness 内置服务的服务名、公开方法与源码位置由仓库自动生成到各服务的子系统页面(如 core 子系统页)。开发插件时应以这些生成区块和服务的 TypeScript 接口为准,不要维护另一份静态清单,否则会与生成接口脱节。
写完自检三项:这个依赖能否容忍服务缺席(决定用 inject 还是 ctx.get());是否为服务名做了类型声明合并;隔离场景下是否把同名服务放进了对应插件组的 isolate。想找隔离场景下常配的插件(如本地 shell、模型适配器),可在 DSH Plugin Hub 检索;扩展点归属判据见 功能→机制映射。
常见问题
DSH plugin 里声明 export const inject = ['tools'] 就是必需依赖:框架保证 apply 执行时 inject 声明的服务已全部就绪,服务没准备好时插件会等待而不执行。可选依赖则省略 inject,在调用点用 ctx.get('metrics') 查询并配合可选链,例如 const metrics = ctx.get('metrics'); metrics?.record('plugin_loaded', 1),这样服务缺席也不会阻塞插件加载。
DSH plugin 依赖的必需服务在应用运行期消失时(例如其提供方卸载),依赖它的插件会自动 dispose 释放资源;当该服务重新出现时,插件会自动重新加载。这条行为是为了防止插件调用一个已经不存在的服务,因此把服务声明为必需依赖等于让框架替你管理插件的可用性生命周期。
DSH plugin 用 @deepseek-ai/cordis 的 Service 基类提供服务:继承 Service,在构造函数里 super(ctx, 'metrics') 指定服务名,并可静态声明 static inject = ['llm'] 表示该服务自身也依赖别的服务;加载后消费方通过 ctx.metrics 访问。再用 TypeScript 声明合并 declare module '@deepseek-ai/cordis' 给 Context 加上 metrics: MetricsService,让 ctx.metrics 有正确类型。
DSH plugin 的 cordis.yml 用 isolate 做服务隔离:同一个服务可以有多个实例,不同插件组看到不同实例。典型写法是给两个 group: true 的 cordis-plugin-group 分别配 isolate: shell: true,并在 config 里各带一份 @deepseek-ai/dsh-bash-local(timeoutMs 可不同);这样 plugin-a 与 plugin-b 各自看到自己组内的 Bash 实例,互不影响。
DSH plugin 开发时应以 Harness 仓库自动生成的服务名、公开方法与源码位置为准:这些信息会生成到各服务的子系统页面(如 core 子系统页),配合服务的 TypeScript 接口使用。官方明确要求不要另行维护一份静态服务清单,否则会与生成的接口脱节。
相关术语
- Service(服务)
- Service 是插件向其他插件公开的命名能力,挂载在 ctx 上,例如 ctx.tools、ctx.llm、ctx.agents;任何插件都可以通过继承 @deepseek-ai/cordis 的 Service 基类提供服务,并在构造函数中用 super(ctx, 'name') 声明服务名。— https://deepseek-harness.github.io/deepseek-harness/develop/framework/service
- inject(依赖声明)
- inject 是插件声明所需服务的导出常量,例如 export const inject = ['tools'];框架保证 apply 执行时这些服务已全部就绪,任一未就绪则插件等待而不执行,因此 inject 声明的是必需依赖。— https://deepseek-harness.github.io/deepseek-harness/develop/framework/service
- ctx.get()(可选依赖查询)
- ctx.get() 是在调用点查询可选依赖的方式:省略 inject、在需要处 ctx.get('metrics') 并配合可选链处理缺席,使插件即使没有该服务也能正常加载与运行。— https://deepseek-harness.github.io/deepseek-harness/develop/framework/service
- 服务隔离(isolate)
- 服务隔离是 cordis.yml 的一项配置:通过插件组的 isolate 字段(如 isolate: shell: true),同一个服务在不同插件组中各持一份实例,组内插件只看到本组实例,组间互不影响。— https://deepseek-harness.github.io/deepseek-harness/develop/framework/service
来源
- DeepSeek Harness 官方文档 - 服务与依赖· deepseek-ai
- DeepSeek Harness 官方文档 - 架构总览· deepseek-ai