乐于分享
好东西不私藏

DeepSeek Harness 的插件架构,把"一切皆插件"做到了极致

DeepSeek Harness 的插件架构,把"一切皆插件"做到了极致

大家好,我是苍一,一个干了13年的后端开发,正在探索AI编程,从产品到开发的全生命周期最佳实践,如果您感兴趣,欢迎关注👇,看我如何自我革命。

最近 DeepSeek Harness 很火,教程满天飞。安装的、配插件的、桌面版的,都讲过了。

今天讲点不一样的:它底下的架构。

核心就一句话:一切皆插件

模型适配器是插件。工具注册表是插件。会话日志是插件。连驱动 Agent 运转的主循环本身,也是插件。

这意味着什么?换模型提供方,不用改源码。换沙箱后端,不用重启。甚至把 agent loop 整个换掉,框架一行不动。

这是 DeepSeek Harness(下面简称 DSH)和传统 Agent 框架最本质的区别。别人是"支持插件",它是整个产品就是插件的组合。

项目怎么组装的:三层结构

DSH 不是一个装完就定型的应用。它启动时按顺序叠加配置,最后在内存里形成一套插件组合。

从下往上看三层。

第一层,Cordis 微内核。

Cordis 是一个专门管插件的框架,只干一件事:插件什么时候加载、什么时候卸载、彼此怎么协作。它最早是开发者 Shigma 为聊天机器人框架 Koishi 写的,2022 年独立开源。后来 DeepSeek 把人和代码一起收了,整套并入自家仓库。

DSH 的每一部分都是 Cordis 插件,包括主循环。

第二层,三层组装机制。

• Profile:存在本地的组装方案,记录你要叠哪些组合包,外加自己的配置补丁。

• Bundle:组合包。把一组插件和配置打包,装一个等于装一整套。

• Patch:补丁。按名字定位到某个插件,替换它的配置。

叠加顺序:先装组合包,再打 profile 补丁,再打本地补丁,最后启动命令还能临时加一层。每一层覆盖上一层。

其中 dsh-base 是每个 profile 必装的第一个组合包,装上就有模型适配器、工具、数据持久化、安全策略、遥测这些基础能力。

第三层,四种运行模式。

Standard、Code、Minimal、Creator,本质是同一套插件的不同组装。Standard 功能全,Code 面向编程,Minimal 只留 Shell 和文件编辑两个工具, Creator 给想做实验的人。

切换模式就是换一套插件组合。不写代码。

三层各司其职:Cordis 管单个插件的加载卸载,组装机制管整套组合怎么搭,运行模式管最终跑哪套。

插件系统:五个概念

插件是 DSH 的基本单元。五个核心概念,不用记名字,记住各自解决什么问题就行。

插件有三种写法。 简单功能用函数,要被别人调用的能力用类,都不想用就传个对象。三种地位平等。

Context 是能力仓库。 每个能力有固定名字:ctx.tools 是工具,ctx.llm 是模型,ctx.sessions 是会话。别的插件按名字取用,不关心是谁实现的、跑在哪。随时换实现,取用方不用改。这是"任意替换"的基础。

Service 是可复用的能力。 用类写一个 Service,自动注册,插件卸载时自动注销。

Fiber 是生命周期记录。 一个插件从生到死要走六个阶段:排队等依赖、启动中、正常运行、卸载中、完全消失,中间可能启动失败。这条状态记录就是 Fiber。

inject 是依赖声明。 插件开工前声明需要哪些能力,框架等能力就位才让它启动。顺序由依赖决定,跟代码先后无关。

插件之间不直接调用,全走事件总线。发通知的不用知道谁在听。事件有五种分发方式,其中 waterfall 模式最关键:每个监听者拿到一个"继续往下传"的开关,调用就交给下一个,不调用就直接拦下。DSH 的工具执行流水线就是四段 waterfall 串起来的。

三个机制,让"动态"变可靠

动态加载不难,难的是动态得可靠。三个机制各管一段。

一、Fiber 状态机管生命周期。

插件状态在六个阶段之间转换。依赖没满足就静默排队,不报错。卸载反着走一遍。

"排队等待"最容易被误判成"插件坏了"。插件声明的能力没装上,它就一直排队,什么都不输出。想知道谁在排队,遍历一遍所有插件状态就行。

热重载也走这条状态机:改代码保存,旧实例先卸载到完全消失,新代码再走一遍排队、启动、运行。改配置文件也会触发,loader 按名字比对,只重载变化的部分。

二、inject 持续跟踪依赖。

不是启动时查一次就完。A 依赖 B,A 排队等 B 就位,配置里谁前谁后无所谓。运行中 B 被卸载,A 跟着卸载;B 恢复,A 重新加载。

威力在一个场景里最明显:把默认的 Shell 执行插件换掉,挂上新的提供方,所有用到 Shell 的插件自动重启、用上新的实现。一行代码不用改,整条依赖链自动重排。

三、effect 管清理。

插件启动时开的定时器、注册的监听器,卸载时都得清干净。Cordis 的办法:插件通过框架 API 做的所有注册都是副作用,卸载时框架自动撤销。框架没直接管的资源,包进 ctx.effect(),返回一个清理函数,插件卸载时自动执行。

注册事件监听器、挂载子插件、往工具注册表加工具,这些天生受 effect 管理,不用自己写清理。

三条纪律:Fiber 管生命周期,inject 管依赖,effect 管清理。互不重叠。

实战:工具运行时

上面所有概念,在工具运行时这个核心组件上全部落地。

它本身是个能力类,自动注册进系统。它注册了 6 种事件,4 种 waterfall 拦截型、2 种广播型。它声明依赖"提示词组装"能力,就位了才启动。

它提供注册工具的方法,每注册一个工具拿回一个卸载函数。想动态卸载哪个工具,调那个函数就行。这是"动态"在最细粒度上的样子。

工具执行是一条四段流水线,每段都是 waterfall 拦截点。审批插件可以在执行前直接拦下,工具逻辑根本不跑;结果屏蔽插件可以在执行后把成功结果改写成错误提示,模型看到的是改写后的内容。

同一个工具运行时还能服务多个 Agent。每个 Agent 能看到哪些工具,沿着继承关系算出来:先继承全局工具,再叠加组合包层的,最后过访问限制过滤。一个 Agent 被限制,不影响别的。

一个真实的 harness 服务就长这样:能力类、多事件注册、声明依赖、effect 管注册、分层管工具集。前面所有概念在这里全有对应。

这套架构意味着什么

DSH 的插件架构,是目前开源 Agent 框架里做得最彻底的。不是"支持插件",是产品本身就是插件组合,任意环节运行时可换。

这给个性化 Agent 留了大量空间。不同工具集、不同上下文策略、不同执行流程,都是换一套插件组合的事。模型可换,工具可换,agent loop 可换,前端也可换——Web UI、CLI、API 是不同的前端插件,挂在同一棵插件树上。

后面可以期待的方向:自定义 agent preset、第三方插件生态、场景化的插件组合模板。Harness 目前还是 v0.1 开发者预览版,接口随时会变,但架构方向已经定了。

单看"任意环节运行时可替换"这一条,这套设计值得认真研究。

ima 知识库,有需要的朋友,在公众号菜单中获取。