dsh-plugin-concepts.md 10 KB

理解 DeepSeek Harness:一篇插件机制的科普读物

这是概念篇,讲"为什么这样设计"。代码与命令细节请看同目录的《dsh-plugin-guide.md》(技术参考篇)。

阅读本文不需要编程背景,但读完后你应该能明白:一个插件在 dsh 里是什么、靠什么活下去、如何被别人使用。

一、先搞清楚:Agent Harness 是什么

大语言模型很聪明,但它像一颗泡在营养液里的大脑——没有手,摸不到文件;没有腿,跑不了命令;没有本子,记不住昨天做了什么。

Agent Harness(智能体运行框架)就是给这颗大脑配上的"身体和工位":一个能读文件、执行命令、调用 API、记录对话历史的工作环境。模型负责思考,harness 负责让思考落地。

DeepSeek Harness(简称 dsh)就是 DeepSeek 开源的这样一套"工位"。你在终端或网页里和它对话、让它改代码查资料时,背后支撑这一切的就是它。

二、dsh 最特别的决定:没有"内核"

想象两种商场:

传统商场:有一栋不可动摇的主楼(内核),商户(插件)只能在旁边的铺位营业。你想改造主楼的大堂?对不起,那是开发商的地盘,得动整栋楼的图纸。

dsh 商场:没有主楼。保安室、配电房、广播站、连"商场管理办公室"本身,全都是一间间普通的铺位。每一间都可以退租、可以换成隔壁竞品、可以在隔壁再开一家。

这就是 dsh 的口号——一切皆插件:

  • 对接模型的代码?插件。
  • 工具清单?插件注册出来的。
  • 聊天记录的存储?插件。
  • 甚至"智能体循环"本身(模型思考 → 调工具 → 再思考的那个循环)?也是插件。

为什么这么执着?因为"每一部分都能被换掉"意味着每一部分都能被定制。举例:把"文件系统"插件换成指向远程沙箱的版本,那么所有依赖文件系统的东西——Bash 命令、终端、代码分析——会自动跟着搬进沙箱,一行都不用重写。能力像插头一样换了个插座,电器们毫无感知。

三、那么,"插件"到底是什么?

剥掉所有术语,一个插件就是一份三句话的自我介绍:

export const name = 'hello-plugin'   // 我叫什么
export const inject = ['tools']      // 我需要什么(可以不填)
export function apply(ctx) { ... }   // 入驻后我要做什么

把它想象成入驻商场的租户:

  1. 签合同时报名字(name);
  2. 在合同里写明"我需要水电和网络"(inject)——商场保证这些就位之前,不会让你进场装修;
  3. 进场后开始布置(apply)——挂招牌、摆货架,也就是把你的能力"注册"出去;
  4. 退租时一切自动恢复原样——这一点下一节细讲,它是整个设计的魔法所在。

插件可以简单到一个函数,也可以复杂到一个类。形态不重要,重要的是这份"自我介绍"的契约。

四、两个基石概念:服务与上下文

服务:插在墙上的标准插座

插件之间怎么合作?不是互相抄微信,而是通过服务。

dsh 里每个能力都占一个公开的、有名字的位置——像一个标准的墙面插座:

  • ctx.tools —— 工具登记处
  • ctx.llm —— 模型接线总机
  • ctx.fs —— 文件系统接口
  • ctx.sessions —— 会话档案室

想用工具?你不需要认识"工具部"的任何一个人,只要找到 tools 这个插座。依赖名字,而非依赖具体的人——这是解耦的第一课:插座后面接的是谁,随时可以换。

上下文(ctx):租户的钥匙牌

每个插件入驻时,商场发给它一块钥匙牌(ctx)。用这块牌子能做的一切操作——注册工具、监听事件、占用资源——都被记账。为什么要记账?为了下一节的主角。

五、魔法所在:可逆的副作用

传统插件系统最常见的烂尾方式:插件装了又卸,留下几个再也杀不掉的定时器、几个没人认领的监听器,系统越跑越脏,最后只能重启。

dsh 的解法朴素而彻底:你在钥匙牌(ctx)上做的每一个注册,都会被记账;退租时按账单逐条撤销。

  • 注册了一个工具?卸载时自动注销。
  • 监听了一个事件?自动移除。
  • 起了一个定时器?用 ctx.effect(() => 返回清理函数) 告诉商场怎么关掉它。

带来的直接后果是:插件可以随时加载、随时卸载、随时热替换——改一行配置,旧的退场、新的进场,不留残渣。上一节说"一切皆可替换",而"可逆的副作用"就是让"替换"敢真的发生而不留后患的地基。

六、插件之间怎么说话:事件

插座(服务)解决"找到对方",但很多场景不适合一对一喊话:

  • 我只是想知道发生了什么("有工具刚执行完");
  • 我想拦截一件事("这次文件写入,先问过用户没有?");
  • 很多插件都想加工同一份数据("请求发出去之前,每人加一点自己的料")。

dsh 用事件覆盖这些场景,几种模式各像一种生活场景:

模式 生活类比 特点
emit 小区广播 谁想听谁听,说完就完
bail 举手认领 排队问"谁能处理?",第一个举手的定案
waterfall 流水线 每站加工一下必须传给下一站;不传,货就被扣下(= 拦截)
serial 依次签收 按顺序过手,每步等上一步

其中 waterfall 值得多看一眼,因为"拦截"就是这么实现的:想做一个权限网关?在流水线上占一站,检查到危险操作就不把货传下去(不调用 next()),整个请求到此为止。想做一个观察者?加工完原样传下去即可。一套机制,两种角色。

另一个容易混淆的点:dsh 里有两类"事件"。实时事件(如 agent/*、tools/*)像广播,听过就过了;会话事件(如每轮对话、每次工具调用的记录)像台账,一笔笔记进日志,回放、恢复、摘要全都从这本台账重建。原则一句话:凡是模型看过的东西,必须能从台账里查回来。

七、插件怎么"给模型装上手":工具

模型终究要通过某种方式操作世界,这个界面就是工具。一个工具是一张标准格式的"操作卡":

  • 说明书(description):写给模型看的——这张卡是干嘛的;
  • 申请表(parameters):模型按格式填参数;
  • 执行器(execute):真正干活的部分;
  • 回执(output):干完之后返回什么。

这里藏着 dsh 一个很克制的设计:回执必须是规范的数据,而不是一段话。比如"搜索文件"工具返回的是结构化的匹配列表,而不是一段"我帮你找到了三个文件,它们分别是……"的散文。原因:散文是给人看的,数据是给程序用的;从数据生成散文容易,反过来就要靠猜。人类可读的展示(UI 卡片)是独立的另一层,不混进模型的结果里。

还有两个理念值得一提:

  • 权限不写死在工具里。"这个操作危不危险、要不要先问用户"属于流水线上的策略站(第六节的 waterfall),工具本身只管干活。工具换到别的环境,策略跟着环境走。
  • 说明书自动生效。工具注册后,它的说明书会自动汇入给模型的提示词——模型"天生"就知道自己有哪些卡可用,不需要额外接线。

八、插件怎么组合成一整套系统

单个插件好理解了,那一个跑起来的 dsh 是怎么拼出来的?答案是分层穿搭:

  1. 组合包(bundle)是一袋配好的料:一个 npm 包,里面除了代码还附一张配置单(声明"我包含哪些插件、各带什么参数")。它是最小的分发单位——你写好一个袋子,别人拎走就能用。
  2. profile是一套完整穿搭:按顺序把 dsh-base(基础款:模型对接、工具、存储……)和各个组合包一层层穿上,再套上用户自己的 cordis.patch.yml(个人偏好层)。
  3. --patch overlay是出门前临时加的外套:不改任何文件,命令行上指定一下就生效——本地开发插件时天天穿它。

叠加规则简单粗暴:后穿的覆盖先穿的,而且是整件替换、不做缝缝补补。这带来一个舒服的生态关系:插件作者提供合理的默认值,用户永远可以在自己的层里整行覆盖,谁也不用求谁改代码。

想看自己身上到底穿了什么?一条 --dump-config 命令展开整套配置树,每一层、每一行都清清楚楚。

九、插件怎么到达用户手里:分发与信任

三种主要途径,本质区别在"用户拿到的是成品还是原料":

  • npm 发布 / tarball:成品。作者预先构建好,用户一条命令安装,无需任何额外授权。
  • GitHub 安装:原料。拉下来的是源码,需要在用户机器上现场构建——这意味着用户必须显式授权"允许这个包在安装时执行构建脚本"。

这个授权设计不是流程刁难,而是一次诚实的风险告知:允许构建脚本,等于允许陌生代码在你机器上、且在任何沙箱之外执行。所以官方建议:只授权给看过源码的包,并锁定到具体 commit。信任应该是一个显式的动作,而不是默认发生的事。

十、把整张地图串起来

最后用一段话把所有概念连成线:

模型是大脑,harness 是工位。工位上的一切设备都是插件——它们靠服务(标准插座)找到彼此,靠依赖声明决定开工顺序,靠事件(广播与流水线)协作与拦截,靠可逆的副作用做到即插即拔不留渣。模型通过工具(操作卡)驱动这些设备,操作卡的说明书自动汇入模型的视野。一个个插件打成组合包分发,用户按层叠穿成自己的 profile——于是,一套完全属于你自己的智能体工位就成型了。

如果这张地图让你产生了"我想试试"的念头,接下来:

  1. 动手写第一个插件:上游仓库 docs/user/develop/basic/index.zh.md(半小时教程,一个文件跑起来);
  2. 查阅具体契约:回到本目录的《dsh-plugin-guide.md》,那里有本文每个概念的精确语法和完整约定。