DeepSeek Harness:一个插件从配置行到运行实例,中间隔着四层

简介: 插件出现在配置里、代码被解析到、服务就绪、实例挂载成功是四件不同的事。拆解 DeepSeek Harness 的 profile 分层、依赖注入、Context 作用域和 Fiber 清理,给出每一层的排查动作。

在 DeepSeek Harness 里,"我装了插件"这句话至少盖住了四件事:配置里有这一行、代码能被解析到、它需要的服务已经就绪、实例真的挂上了。混成一句话讲,排查时就从一个错误现场变成四个。

这篇文章把这四层拆开,每层给出它实际管什么、不管什么,以及一个可以立刻执行的检查动作。

一、为什么插件不是"装上就完了"

DeepSeek Harness 的产品每一部分都是插件——模型适配器、工具注册表、Session 日志、Agent 循环——运行中的 dsh 不是一套写死的组件,而是启动时组合出来的插件树。

这个设计带来一个直接后果:配置里出现一个条目,和这个条目对应的工作真的在跑,是两个不同的检查点。

你以为的状态 实际可能停在 对应证据
装上了 配置行存在,但被后续层替换掉了 --dump-config 的生效输出
装上了 配置生效,但依赖服务没就绪 条目 pending、缺失服务名
装上了 依赖就绪,但插件体本身抛错 启动诊断里的原始错误
装上了 挂载成功,但方法行为不对 一次代表性操作的返回值

下面四节对应这四个卡点。

Profile 的组合包层叠成插件树,服务与副作用具有生命周期

二、第一层:profile 是叠出来的,不是写出来的

Profile 是保存在 Harness home 里的具名组合。它列出组合包、存放为该 profile 安装的树外插件,并保存自己的 cordis.patch.yml。Bundle 则通过 package.json 里的 dsh.profile 声明 profile 的组合包列表、通过 dsh.bundle 指定自己的 patch。

关键在于顺序:这些层不是简单相加,而是按顺序应用到同一个条目列表。

Bundle patch        ← 组合包贡献的配置
Profile patch       ← 当前 profile 的用户改动
Home patch          ← 各 profile 共享的机器本地层
--patch 覆盖层      ← 命令行参数按顺序追加
──────────────────
运行时插件树        ← 被挂载的插件及其活动服务

最容易踩的坑:patch 按 id 定位条目,然后替换整行的 config,不做深合并。

所以下面这种事是真实会发生的:某个 bundle 给的配置里有 timeout: 30 和 retries: 3,你在 profile patch 里只想改 retries,写了个 retries: 5——结果 timeout 没了,因为整行 config 被换掉了。

编辑 patch 之前,先看完整的生效结果:

dsh --profile web --dump-config

顺带一个容易误解的点:dsh-base 是随附 web、headless、sdk、acp 四个 profile 的共享第一层,各应用 bundle 在上面加不同宿主。但 sdk-minimal 是文档写明的例外——它单个 bundle 自带显式 SDK 树,不套 dsh-base。不要因为同属一个框架,就假设各 profile 能力一致。

HMR 也是这样。YAML 控制配置监视:base 启用,Headless / SDK / ACP 禁用,sdk-minimal 不含这项;profile patch 可以覆盖默认值。所以"我改了配置它怎么没热重载",答案通常不在编辑器里,而在你实际启动的那个 profile 的组合里。

三、第二层:inject 表达的是等待,不是安装

服务通过稳定上下文键暴露,比如 ctx.tools、ctx.llm、ctx.sessions。消费者靠键拿能力,而不是 import 某个具体实现。

插件用 inject 声明它需要什么:

import type {
    Context } from '@deepseek-ai/cordis'

export const inject = ['greeter']

export function apply(ctx: Context) {
   
  console.log(ctx.greeter.greet('world'))
}

Cordis 会等 greeter 就绪后再激活这个插件。这解决了"启动顺序"问题——顺序由依赖关系表达,不用作者去预测所有插件的全局启动序列。

但这句话的反面必须一起记住:

  • inject 不会安装提供方。 声明依赖不等于依赖会被满足。
  • 安装消费者不会自动安装提供方。 你得到的是一个一直 pending 的条目。
  • 同一个键在每个作用域里不一定解析到同一个实现。 见下一节。

提供方那边要写三样东西,它们是三件事不是一件:

import {
    Service, type Context } from '@deepseek-ai/cordis'

declare module '@deepseek-ai/cordis' {
   
  interface Context {
   
    greeter: GreeterService
  }
}

export class GreeterService extends Service {
   
  constructor(ctx: Context) {
   
    super(ctx, 'greeter')
  }

  greet(who: string) {
   
    return `Hello, ${
     who}!`
  }
}

export function apply(ctx: Context) {
   
  ctx.plugin(GreeterService)
}
代码 负责什么 删掉它会怎样
super(ctx, 'greeter') 运行时注册这个键 消费者永远等不到服务
declare module 类型扩展 让 TypeScript 认识 ctx.greeter 编译报错,但运行时服务照样在跑
apply 里 ctx.plugin(...) 真的把提供方挂上去 类型能过,运行时没有实例

拼写不一致是"消费者一直挂起"的头号原因。 super 的名字、Context 声明里的名字、消费者 inject 里的名字,三处写错一个,三个看起来都合理的部分就指向了三个键。类型检查通过只说明 TypeScript 认识这个属性,不说明 Cordis 注册了运行时实例。

还有一个生命周期上的现实:必需服务消失时,依赖它的插件会被释放;服务恢复后重新加载。 所以消费者不能长期缓存"服务一定在"的假设,重载时要确保监听器之类的注册被撤销、不会重复。

四、第三层:Context 作用域解决的是三个不同问题

ctx 是个代理,普通属性读取会走服务解析器。所以"这个键在这里解析到谁",取决于你所在的上下文。

Cordis 给了三种派生子上下文的方法,它们经常被混为一谈:

方法 解决的问题 不做什么
ctx.extend(meta) 添加局部元数据,自有属性遮蔽继承属性 不安装独立服务实现
ctx.isolate(name, label?) 让指定服务在子上下文里用另一个标签解析 不隔离其他服务,也不是进程沙箱
ctx.intercept(name, config) 给下方启动的插件带上该服务的拦截配置 不等于用 profile patch 替换整行插件

两个细节值得单拎出来:

isolate 的标签是合并用的。 默认标签是新建的唯一 Symbol,即每次调用天然独立;但如果你两次调用传同一个标签,它们会加入同一个服务作用域。这既是有意共享的手段,也是"我以为隔离了其实没隔离"的来源。

ctx.root 在文档里标的是实验性,ctx.baseUrl 只在运行时提供时才用于解析相对模块标识。这两个属性本身都不保证插件能访问某个服务,也不证明外部模块可信。

五、第四层:清理是逆序的,而且只覆盖登记过的东西

插件实例的副作用靠 ctx.effect() 这类机制登记,它会立即执行主体,并收集主体产生的释放函数。触发时机是调用返回的释放函数,或 Fiber 卸载,以先发生者为准,释放函数按注册的逆序运行,重复调用是空操作。

逆序这个设计对资源依赖是对的:先拿资源、再拿依赖它的订阅,那么后注册的订阅会先清理。

但有三件事必须自己保证,框架替不了:

  1. 只覆盖登记过的。 在 effect 外面创建的资源,框架不知道它存在。
  2. 异步清理要等。 "注册已经不可见"和"资源已经静止"是两回事,判断资源泄漏前先等释放完成。
  3. 重复释放要无害。 成功路径不等于覆盖了失败路径和重复销毁路径。

服务注册那块也有明确的抛出条件:ctx.provide(name, value) 返回一个释放函数,调用它或 Fiber 卸载都会注销服务;如果同一作用域已经有这个名称的提供者,或者该名称已被声明为 accessor,注册会直接抛错。

再往上一层,Agent 维度的注册有它自己的作用域原语(ScopeKey / Scope.ctx / rawDispose / dispose()),和 ctx.isolate 是两个层面的东西——Agent 专属注册表的覆盖层,不会自动变成独立的服务实现。 读取时按插入顺序先出全局命名项、再加入作用域内的遮蔽项,所以一次精确作用域的贡献可以遮蔽全局同名项,但它并没有修改全局项本身。

六、反过来查:六个检查点

出问题时按这个顺序走,基本不会错认现场:

  1. 确认实际启动的是哪个 profile。 组合包列表和 patch 决定装配,别的 profile 有别的树。
  2. 导出实际装配。 dsh --profile web --dump-config,然后找到目标条目,以及到底哪一层贡献或改写了它。
  3. 先看生效值再改 patch。 记住整行 config 会被替换,不深合并;改之前把还要保留的键抄回去。
  4. 区分"等待依赖"和"插件体失败"。 条目 pending 只是现象,往上找提供方是否在同一作用域、有没有启动成功。
  5. 核对三处名字。 super 的键、类型扩展的键、消费者 inject 的键。
  6. 验证一次代表性操作。 挂载成功只回答"它出现了",不回答"它做对了"。

第 5 步尤其容易跳过:类型检查通过会给人很强的安全感,但它证明的是编译期,不是运行时。

七、边界:这套机制不是安全机制

必须说清楚,因为插件体系读起来很像一套权限模型:

  • 隔离是服务解析层面的。 ctx.isolate 改变的是指定服务在子上下文里解析到哪个标签,文档没有把它描述为进程沙箱或安全保证。
  • 清理不是回滚。 释放函数撤销的是登记过的注册;网络请求、已经写入磁盘的数据,可能比发起它们的注册活得更久。
  • 挂载成功不等于安全。 插件会执行代码、注册副作用。加载前应该看准确版本的代码和依赖,用合适的数据和权限测试。
  • 组合的灵活性不等于兼容性。 名字相似的插件不一定能互换,替换提供方前要读实现、配置和预期服务接口;替换会影响所有解析该键的消费者,只测一个调用方的成功路径是不够的。

相关阅读

术语速查

  • Profile:组合包与 profile 专属变更构成的具名组装。
  • Bundle:配置项及挂载代码的分发形式。
  • Fiber:一次插件应用的运行时实例,承载生命周期与副作用。
  • Effect:立即执行、并提供清理函数的注册。
  • 服务键:从上下文解析能力使用的名称。
  • 隔离标签:isolate 用于选择服务作用域的 Symbol。

本文由 DSH Plugin 社区(dsh-plugin.com)维护者撰写,首发于阿里云开发者社区。

目录
相关文章
|
13天前
|
Linux 开发工具 iOS开发
Codex保姆级教程(下载+安装+登录+使用,含所有版本,2026最新)
Codex是OpenAI推出的开源AI编程智能体,本地运行,可理解整个代码库,支持自然语言指令改代码、执行命令、跑测试、修Bug,兼容Win/macOS/Linux。(239字)
5314 40
|
13天前
|
JavaScript API iOS开发
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(DSH)是DeepSeek于2026年开源的MIT协议AI Agent框架,支持插件化组装模型、工具、沙箱与UI,兼容主流大模型。本文提供免Node.js的桌面端安装包(Win/macOS),含详细图文教程及热门插件推荐。
4721 54
|
7天前
|
Linux 开发工具 iOS开发
2026最新codex下载安装保姆级使用教程(下载+安装+登录+使用,含所有历史版本)
本文详解OpenAI Codex国内快速上手指南:提供Win/macOS/Linux全平台免安装包、npm/Homebrew等多方式安装、账号/API Key双登录、简体中文切换,覆盖下载、安装、汉化、使用及高频避坑(如微软商店失败、npm超时等),10分钟即可跑通。
1882 5
|
14天前
|
iOS开发 Docker MacOS
【2026实测】Docker Desktop下载、安装、汉化、配置教程(附官网安装包)
Docker Desktop 是 Docker 官方推出的桌面容器管理工具,集成引擎、CLI、图形界面与 Kubernetes,支持 Win/macOS/Linux。2026 最新版 4.88.1 强化 ARM 原生运行、镜像加速及资源可视化,附中文汉化与国内镜像配置指南。
2236 7
|
5天前
|
人工智能 安全 API
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(dsh)是DeepSeek AI于2026年开源的轻量级Agent运行框架,基于Cordis内核,践行“一切皆插件”理念。支持Web/桌面双端,开箱即用;内置多模型接入、丰富插件生态(超3.5万),适配编程、办公、创作等场景。(239字)
1193 0
|
8天前
|
云安全 人工智能 安全
|
1天前
|
云安全 人工智能 安全
|
7天前
|
人工智能 并行计算 调度
本地 AI 一键部署工具 LocModel:Windows 端集成画图、视频生成、Agent 的开源模型运行方案
LocModel 是专为 Windows 设计的一站式本地 AI 工具,支持零配置启动、自动硬件检测、GGUF 模型一键加载、文生图/视频生成及 Agent 自动化任务。适配 8G 显存,内置显存分片调度,轻松实现 AI 漫剧批量创作与离线大模型调用。(239 字)