摘要

DeepSeek‑Harness(命令行工具dsh)作为开源Agent运行时框架,打破了传统Agent工具的扩展边界,将可替换组件下沉至运行时内核层面。不同于多数Agent框架仅对外开放MCP工具接入、生命周期Hook两类扩展点,dsh基于Cordis插件架构,把模型适配器、工具注册表、会话日志、Agent主循环等核心运行单元全部改造为可插拔组件。本文基于@deepseek‑ai/dsh 0.1.0‑rc.7版本做工程拆解,梳理Agent Harness常见的三类扩展路径,对比不同方案的能力上限,解析dsh运行时配置树、依赖拆分、插件生命周期与卸载回收机制,同时分析插件化架构带来的工程成本与适用边界。在多模型、多Agent服务混合部署场景下,Treerouter这类API网关能够简化多后端服务的接入管理。本文也是dsh系列第一篇,后续会依次拆解插件挂载、Profile组装、主循环事件切面、会话日志、Provider替换、架构取舍等专题。

1. dsh基础认知:一切皆插件的Agent运行时

dsh基于Node.js环境运行,安装完成后执行npx @deepseek‑ai/dsh web即可拉起Web交互界面,默认服务地址为http://127.0.0.1:3080,支持MCP协议完成模型路由、文件访问、工具调用等能力。项目核心设计理念为everything is a plugin,底层依赖Cordis插件框架,相关范式也有配套学术论文阐述。

从表层看,dsh和市面上其他开源Agent Harness同样支持插件、支持扩展,但底层实现存在本质差异。市面上绝大多数Agent框架的扩展能力停留在外部接口层;dsh则把扩展边界推进到运行时内部,允许开发者修改主循环、工具注册表、会话持久化等内核模块。当前版本属于开发者预览版,官方提示后续版本会存在不兼容变更,做生产落地需要关注版本迭代。

2. Agent Harness的三类主流扩展路径

业界Agent Harness框架,一般提供三类扩展方式,三者的可干预深度存在明确层级差异:

2.1 外部工具接入(MCP协议)

MCP是最具代表性的外部接入方案,Claude Code、Codex都支持这套范式。搜索、数据库、浏览器、内部业务系统,都可以通过协议对接至Agent运行时。 这种模式下,扩展新增的仅仅是模型可调用工具集。由Harness本身管控工具的生命周期:何时把工具Schema注入上下文、何时发起调用、调用结束后如何处理返回结果。开发者无法修改Harness内部调度逻辑,只能新增外部能力。

2.2 生命周期Hook钩子

Claude Code提供PreToolUsePostToolUseSessionStartStop等固定时机钩子,其余Harness框架也存在同类设计。开发者可以在这些节点插入日志采集、权限校验、安全拦截等逻辑。 但Hook能介入的范围完全由框架预先定义。没有开放的内部环节,开发者无法干预,想要修改未暴露的流程,只能修改框架源码。

2.3 Plugin插件打包分发

开发者可以把自定义命令、子Agent、MCP Server、Hook逻辑封装成完整插件包,分发给其他用户直接安装使用。 插件解决了扩展能力打包分发的问题,但多数框架的插件体系依旧无法触碰内核组件。当MCP、Hook能力到达上限,想要修改工具注册表、上下文组装逻辑、Agent主循环,仍然需要修改源码。

扩展能力层级对比

扩展能力 MCP外部工具 生命周期Hook 普通插件 dsh运行时插件
外部工具接入
固定时机拦截
提示词/指令文件修改 部分支持 部分支持
工具注册表替换
上下文装配逻辑 部分支持
Agent主循环控制
模型适配器替换
会话日志持久化

传统框架的扩展边界到插件为止。工具注册表、上下文装配、Agent循环、模型适配器、会话日志都被封闭在框架内部。框架封闭内核有现实考量:主循环与状态机逻辑复杂,对内封闭有利于统一做异常处理、问题排查、安全策略和兼容性维护;开放越多内部接口,框架要维护的接口、生命周期约束就越多。

而dsh做出不一样选择:把上述运行时组件全部插件化,允许通过配置自由组合替换。不同插件挂载在同一棵运行时树上,各自拥有独立生命周期,框架不再做强固化约束。

3. dsh运行时配置树与依赖拆解

3.1 查看最终合并配置

执行命令:

npx @deepseek‑ai/dsh --profile web --dump‑config

‑‑dump‑config会打印Profile、Bundle、Patch合并之后的完整运行配置,不需要启动Web服务。输出结果可以看到dsh‑llmdsh‑sessiondsh‑toolsdsh‑agent‑loop等插件项。Web Profile会在基础dsh‑base之上追加Web服务、静态资源相关配置。Profile、Bundle、Patch三者如何叠加生成最终配置,会在系列第三篇详细展开。

3.2 npm依赖包拆解

测试版本dsh主包一共有61个直接依赖,其中58个来自@deepseek‑ai/*命名空间;剥离前两层依赖后,可以看到一共103个@deepseek‑ai子包。整个项目做了高度颗粒度拆分:

  1. 插件内核:Cordis核心加载器、插件依赖管理;
  2. 启动与组装:boot入口、base基础配置、web/headless/cli不同形态启动入口;
  3. 模型对接层:llm抽象适配器,同时实现deepseek、pi‑ai两套后端,内置重试、校验逻辑;
  4. 工具注册表:bash、文件读写、web编辑器等工具拆分为独立子包;
  5. 执行与安全策略:文件系统读写、权限审批、沙箱管控,策略与执行实现分离;
  6. 编排与子进程:子Agent、子进程spawn实现,区分进程内、进程外执行模式;
  7. 主循环与会话存储:Agent主循环、会话持久化、SQLite存储、遥测埋点;
  8. 第三方依赖:仅少量底层通用包。

模型层设计了双适配器机制,dsh‑llm‑deepseekdsh‑llm‑pi‑ai互为校验替身。同一套业务逻辑可以对接两套模型实现,方便做回归验证,也实现了Provider的可替换。

会话模块同样做能力拆分:会话存储、查询、投影、遥测、检查点全部拆成独立组件,每一部分职责边界清晰。

3.3 策略与执行分离设计

dsh大量组件采用“策略‑执行分离”思想。以文件系统为例:文件操作执行能力、访问观察策略、权限审批是三套独立插件。Policy组件负责判断本次操作是否合规,实际文件操作交给底层工具组件。权限、审批、执行环境相互解耦,替换某一部分不需要改动整套文件工具逻辑。正是这种拆分,才产生数量众多的小包,运行时依靠配置树重新组装为完整能力。

4. 运行时插件:动态挂载与卸载回收问题

dsh‑tool‑cordis提供面向模型的插件能力。Agent在运行过程中,可以生成插件代码,动态挂载到当前运行树上。插件加载之后,可以注册Tool Schema、事件监听器,持有上下文服务对象。

这里引出关键工程问题:插件能否干净卸载?

完整的插件生命周期流程分为四步:

  1. 模型生成插件对象代码;
  2. 将插件挂载到正在运行的组件树;
  3. 插件执行,注册工具Schema、事件监听,产生一批运行时注册项;
  4. 触发dispose销毁逻辑,回滚全部注册,释放资源。

如果第4步销毁逻辑执行不彻底:工具Schema残留在提示词上下文,事件监听器依旧挂在Agent主循环。下一轮Agent循环依旧会调用已经逻辑上“卸载”的插件,产生各类诡异bug。此时只能依靠重启服务清除残留状态,会话上下文全部丢失。

Cordis框架核心就用于解决该问题:插件注册的资源跟随插件生命周期,卸载时自动执行清理回调,撤销注册项。插件挂载、依赖跟踪、卸载回滚,是本系列第二篇重点内容。

5. 插件化架构带来的成本

高度插件化带来灵活性的同时,也引入几类不可忽视的工程代价。

第一是配置复杂度。Profile、Bundle、Patch多层叠加,通过‑‑dump‑config输出的配置文件很长,很难直观追溯最终配置来源于哪一个模块。Patch补丁修改配置结构之后,依赖该配置的已有Patch也需要同步维护。

第二是生命周期管理成本。插件运行时注册的监听器、服务实例、句柄资源,都需要配套销毁逻辑。如果多个插件之间存在依赖关系,卸载顺序错误就会引发异常。事件派发模式差异,也会带来插件之间的兼容问题。

第三是版本风险。dsh现阶段处于开发者预览,API、配置结构持续变动。基于当前版本做二次开发,后续升级需要跟进适配变更。

6. 架构适用边界

这套架构并不适合所有场景。 如果团队只需要对内交付固定形态Harness,不需要运行时动态修改内核组件,把主循环拆分为大量可替换组件并不会带来收益,反而会增加维护负担。

dsh这套设计更适配两类场景:

  1. 第三方插件生态:外部用户需要在运行时动态新增、替换各类Agent能力;
  2. Agent自修改场景:Agent运行过程中动态生成插件、变更自身可用能力,并且插件卸载之后完整回滚状态。

这两类场景下,仅仅做到插件加载远远不够,卸载之后状态干净回滚是硬性要求。

7. 本篇小结

dsh最大创新不在于支持插件,而在于把扩展边界推进Agent运行时内核。传统Agent Harness大多停留在MCP工具接入、生命周期Hook、插件包分发三层扩展;dsh将模型适配器、工具注册表、Agent主循环、会话存储全部开放为可替换插件。依靠Cordis插件框架实现资源注册、依赖追踪、卸载销毁闭环。

但灵活是有代价的:多层配置叠加、大量细粒度子包、插件生命周期管理、预览版API持续变动,都会提升二次开发的维护成本。选型时需要结合业务场景判断,只有确实需要运行时动态修改内核组件,这套架构的价值才能够充分发挥。后续系列会继续拆解插件挂载机制、Profile组装、主循环事件切面、会话日志、Provider切换与架构取舍。

了解更多:https://treerouter.com