← 返回研究索引
Agent 系统2026-08-14更新 2026-08-14

DeepSeek Harness 插件化架构与工程评估

说明 Cordis 如何装配插件,插件如何通信,服务提供方如何选择,以及插件开发、测试和发布如何进行。

deepseekagent-harnessarchitectureevaluationcordis

DeepSeek Harness 把模型、工具、会话和执行循环都做成可组合插件。它的架构值得研究,但公开证据目前只支持受限试点,不支持组织级默认采用。

调研冻结在 2026 年 8 月 14 日。目标代码为提交 47f943859bef60e4160492346772ded9b24f765a,该提交与调研日的远端 HEAD 一致。本文只评价 Harness 架构、工程流程和公开评测,不评价 DeepSeek 模型能力。

一、DeepSeek Harness 的插件化架构

1.1 Cordis 插件运行时

DeepSeek Harness 的命令名是 dsh。它是一套 Agent 运行外壳:接收请求,调用模型,执行工具,保存会话,并向 Web、ACP 和 SDK 暴露入口。

dsh 主要使用 TypeScript 编写,运行在 Node.js ESM 环境。TypeScript 让插件作者共享类型,但运行时真正加载的是 JavaScript 模块。插件通常导出 apply(ctx, config),或导出一个 Service 子类。根 package.json Cordis 插件教程

概念 作用
Profile 选择一种产品形态,例如 Web 或 headless
Bundle 提供一组可复用的默认插件
patch 增加、替换、禁用或删除配置行
Context 插件访问 Service、Event 和子插件的入口
Loader 按有效配置加载插件模块
Fiber 一次插件挂载的运行实例
Service 插件向其他插件提供的具名能力
effect 与 Fiber 同生共死的注册、监听器或资源
Agent loop 在模型、工具和最终回答之间推进一次任务
SessionEvent 记录用户消息、模型消息和工具结果等事实

Cordis 负责前八项。它把配置变成一组可管理的插件实例,检查服务依赖,并在配置或依赖变化时卸载、重建相关实例。Agent loop 负责每次请求的执行。两者不在同一层。

1.2 插件运行时的启动流程

配置先生成插件运行时

启动时,dsh 按顺序合并 Bundle、Profile patch、Harness home patch 和命令行 --patch。最终配置由带稳定 id 的配置行组成。后层命中同一 id 时,会替换该行的完整 config,不会做字段级深合并。CLI 组合参考

Loader 为每一行创建 Fiber。Fiber 指一次插件挂载的运行实例,与线程和用户请求无关。它保存配置、父 Context、依赖、状态、effect 和清理逻辑。

Fiber 常见状态为 PENDING → LOADING → ACTIVE → UNLOADING。插件声明 inject = ['tools', 'shell'] 后,缺少任一 Service 都会停在 PENDING。服务出现后才执行 apply;服务被替换或消失时,Cordis 会卸载依赖它的 Fiber,再按新依赖重建。YAML 中的先后顺序不决定启动顺序,Service 是否可用才决定。Cordis 服务教程

inject 只声明硬依赖。插件在某项能力缺失时仍可工作,就不应把它放进 inject,而应在使用处调用 ctx.get('serviceName')。未挂载 provider 时它返回 undefined,Fiber 仍可保持 ACTIVE。硬依赖的 provider 被替换时,消费方会重载;可选依赖是否响应变化,则由插件自己的监听和调用方式决定。

插件通过 ctx.on() 注册监听器、通过 ctx.tools.register() 注册工具,或通过 ctx.effect() 管理连接和定时器。这些操作都会返回或绑定清理逻辑。Fiber 卸载时,Cordis 自动撤销它们。插件树表达的正是这种所有权和生命周期关系。

1.3 Agent 请求的执行流程

请求在模型和工具之间循环

一次请求发生在插件全部就绪之后:

  1. Web、ACP 或 SDK 把输入交给 Agent inbox。
  2. Agent loop 读取会话历史、系统提示和可用工具。
  3. 模型直接回答,或发出结构化工具调用。
  4. Tools Runtime 校验参数、执行策略和工具。
  5. 工具结果回到 Agent loop,模型继续生成。
  6. Agent loop 提交最终消息。

SessionEvent 在这条链路旁边记录事实。它保存用户消息、step、模型消息、工具调用、工具结果和最终回答,用于历史、恢复、fork 和 UI 投影;工具结果仍由 Agent loop 送回模型。会话持久化

1.4 插件树、依赖图与调用链

插件树、依赖图和调用链分别描述不同关系:

关系 回答的问题 示例
插件树 谁挂载谁,谁随谁卸载 Loader 挂载 tool-bash Fiber
依赖图 谁必须等待哪项能力 tool-bash 等待 tools 和 shell
调用链 一次请求经过哪些活跃组件 Agent loop → LLM → Tools Runtime → shell → LLM

1.5 插件规模与关系

在当前提交中,仓库包含 219 个 DSH package,其中 170 个可以由 cordis.yml 直接加载。其余 15 个是不能单独挂载的抽象 Service 定义包,34 个是供其他包导入的普通库包。因此,219 是仓库包数量,170 是可加载插件数量。

口径 数量 含义
DSH package 219 排除 7 个测试 fixture 后的仓库包
可加载 Cordis 插件 170 105 个有配置,65 个无配置
Web 根配置行 129 Base Bundle 78 行,加上 Web Bundle 新增的 51 行
ACTIVE Fiber 动态值 由操作系统、disabled、Profile、patch、Agent Preset 和运行时挂载共同决定

129 不是 Web Profile 启动后的 ACTIVE Fiber 数量。它只是用户 patch 生效前的根配置行数;条件分支、禁用项、Realm 和运行时动态挂载都会继续改变实际插件树。

插件关系需要按四种口径分别观察:

关系 当前规模 回答的问题
Package 依赖 1,089 条边 哪个 package 在代码层依赖哪个 package
Service 协作 56 项 Service、213 条角色关系 谁定义、谁提供、谁使用一项能力
运行时硬依赖 101 个插件、198 条 inject 关系 哪项 Service 缺失会让插件无法激活
Event 协作 56 个事件名 谁发布事件、谁监听,以及使用哪种分发语义

正文以 Service 关系作为主图,因为它最能回答“插件怎样接入已有能力”。箭头含义固定为:Definition 声明接口,Provider 注册实现,Consumer 依赖并调用 Service。

三条 Service 能力边界展示定义、提供与使用关系

这张图只呈现三条代表性的 Service 能力边界;移动端可横向滑动查看。

完整关系可以继续查阅仓库自动生成的 Plugin Catalog、Module Graph、Capability Seams和 Event Producer/Consumer。这些清单来自代码扫描,比手工维护一张总图更适合作为完整索引。

二、插件协作的三类接口

插件通过三类接口协作

Cordis 提供 Service 和 Event。dsh 在此基础上增加 Tool。三类接口解决的问题不同。

接口 调用者 接收者 适合的关系
Service 另一个插件 唯一服务提供方 需要返回值的直接调用
Event 发布事件的插件 零到多个监听器 通知、策略和中间件
Tool 模型 Tools Runtime 和工具插件 模型发起的结构化动作

2.1 Service 接口

定义包声明服务名和方法,provider 实现它,consumer 通过 ctx.<name> 调用。consumer 依赖服务名,不依赖具体 provider 包。一个 Context 内重复注册同名 Service 会直接报错,避免两个实现静默争用。

2.2 Event 接口

发布者只知道事件名、参数和分发语义,不知道谁在监听。监听器通过 ctx.on() 注册;它属于 effect,插件卸载时自动注销。

模式 执行方式 适用场景
emit 同步通知所有监听器 无返回值广播
parallel 并发执行并等待全部结果 相互独立的异步任务
serial 依次执行,首个有效结果结束 异步查询或策略裁决
bail serial 的同步形式 同步查询或短路
waterfall 监听器包装、修改或短路下一层 请求改写、guard 和中间件

waterfall 的关键是 next()。监听器调用 next() 才会继续后续链路;不调用就会短路。选择错误的模式会改变执行顺序和失败语义,所以 Event 契约不只有参数类型,还必须说明分发模式。

2.3 Tool 接口

插件用 defineTool 注册名称、描述、输入 Schema、输出 Schema 和 handler。模型只看到公开 Schema。调用进入 Tools Runtime 后,依次经过 tools/pre-execute、审批与 guard、tools/execute、handler、tools/post-execute 和结果固化。Tools Runtime

2.4 接口契约的保障机制

TypeScript 接口只提供编译期检查,运行时会被擦除。交互由四层共同保障:

  1. Definition package 固定名称、方法和类型。
  2. Cordis 检查 Service 唯一性、inject 依赖和生命周期。
  3. Tools Runtime 用 Schema 校验模型输入和输出。
  4. 文档、组合测试和 snapshot 检查类型无法表达的行为语义。

代码里的 interface 也不一定都是“给其他插件的 API”。判断方式如下:

定义位置 主要对象 含义
declare module ... interface Context Service consumer ctx 上存在什么服务
declare module ... interface Events 事件发布者和监听器 事件名、参数和返回值
插件导出的 Config Profile 和部署者 这个插件接受什么配置
defineTool 的 Schema 模型和 Tools Runtime 模型可以传什么、得到什么
普通内部 interface 当前包实现 可能只是内部数据结构

只有前四类可能构成跨插件或外部契约。是否公开还要看它是否从 Definition package 导出,并在 subsystem 文档中出现。

三、Service 的实现与选择

Provider 不是一种独立的 dsh 组件类型,而是插件相对于某项 Service 承担的角色。一个插件可以为一项 Service 提供实现,同时使用另一项 Service。例如,@deepseek-ai/dsh-bash-local 是 shell 的 Provider,也是 subprocess 的 Consumer。

3.1 Service 的定义方、提供方与使用方

官方 shell 链路包含三种角色:Definition(定义方)声明接口,Provider(提供方)实现接口,Consumer(使用方)调用接口。这些名称描述插件与 Service 的关系,不是三种固定的插件类型。

Definition 包 @deepseek-ai/dsh-shell 定义 ctx.shell:

declare module '@deepseek-ai/cordis' {
  interface Context {
    shell: ShellExecutor
  }
}

export abstract class ShellExecutor extends Service {
  constructor(ctx: Context) {
    super(ctx, 'shell')
  }
  abstract resolve(request: ShellExecRequest): ShellExecSpec
  abstract run(spec: ShellExecSpec): Promise<ShellRunResult>
}

Provider 实现这项服务。@deepseek-ai/dsh-bash-sandbox 和 @deepseek-ai/dsh-bash-local 都继承 ShellExecutor,最终都把自己注册为名为 shell 的 Service。

Consumer @deepseek-ai/dsh-tool-bash 不导入具体 provider。它只导入 Definition 包中的类型,并声明服务依赖:

export const inject = ['tools', 'shell', 'systemPrompt', 'shellEnv']

ctx.tools.register(defineTool({
  name: 'bash',
  execute: async (args) => {
    const spec = ctx.shell.resolve(args)
    return ctx.shell.run(spec)
  },
}))

因此,@deepseek-ai/dsh-tool-bash 只知道 ctx.shell 的接口,不知道当前实现来自 dsh-bash-local 还是 dsh-bash-sandbox。

3.2 Profile 对 Service 实现的选择

Profile 不直接把 shell 绑定到某个类名,而是挂载一个会注册 shell 的 Provider 插件。默认基础 Bundle 在非 Windows 环境选择 @deepseek-ai/dsh-bash-sandbox。其关键配置是:

- id: bash-sandbox
  name: '@deepseek-ai/dsh-bash-sandbox'

- id: tool-bash
  name: '@deepseek-ai/dsh-tool-bash'

这条链路可以读成:Profile 挂载 Provider → Provider 注册 ctx.shell → Cordis 激活依赖 shell 的 Consumer → Consumer 调用 ctx.shell。如果 Profile 改为挂载 @deepseek-ai/dsh-bash-local,Consumer 的代码不需要改变。

同一个 Context 只能注册一个同名 Service。若 Profile 在同一作用域同时挂载两个 shell Provider,Cordis 会因重复注册而报错,不会静默选择其中一个。

3.3 实际 Service 实现的确认

用户可以查看实际挂载结果,但目前没有一条命令直接输出完整的 Service → Provider → 配置来源 映射:

  1. dsh --profile web --dump-default-config 查看 Profile 默认配置。
  2. dsh --profile web --patch ./extra.yml --dump-config 查看叠加 patch 后的有效配置和来源注释。
  3. 运行时 plugin inventory 查看模块名、启用状态和 Fiber phase。
  4. 对照 Definition 或 subsystem 文档,确认该模块注册了哪项 Service。

dump-config 解决“配置选择了什么”,inventory 解决“当前启动了什么”。inventory 不保留完整配置来源,也不直接反推 Service provider。这是当前排障能力的明确缺口。Plugin inventory

四、自定义插件的接入流程

4.1 扩展类型与接入点

开发新插件应先确定自己使用哪类扩展接口,再查对应的 Definition 和生成文档,无需遍历所有实现包。

目标 首选接入点
替换一项核心能力 实现对应 Service Definition
监听或改变现有流程 订阅 Event 或 waterfall
增加模型可调用动作 注册 Tool
组合已有能力 编写 Profile 或 patch
接入外部工具服务器 使用 MCP client
从外部控制 Agent 使用 ACP 或 SDK

仓库提供三类索引:cordis-surface 文档列出 Service;event-producer-consumer 列出事件、分发模式、发布者和监听器;tool-catalog 列出模型可见 Tool Schema。高级 Cordis 组合还提供 cordis_inspect_list/query,可从当前仓库和运行时服务存储中查询 Service、Event、Tool 和 Slot。它们比遍历每个插件 README 更适合作为入口,但仍需要阅读目标 Definition 的语义和测试。

4.2 自定义插件开发流程

一个正常的自定义插件流程是:

  1. 选择扩展接口。
    • 直接调用使用 Service。
    • 广播或中间件使用 Event。
    • 模型动作使用 Tool。
  2. 导入 Definition 包,只依赖公开类型和服务名。
  3. 声明运行约束。
    • 硬依赖写入 inject。
    • 插件配置定义运行时 Schema。
    • 监听器、工具和资源注册为 effect。
  4. 用 patch 挂载插件。
    • 用 --dump-config 检查有效配置。
    • 用 inventory 确认 Fiber 已进入 ACTIVE。
  5. 补齐工程测试。
    • 增加单元测试和一次真实组合测试。
    • 影响模型或用户的行为增加 keyless snapshot。
  6. 固定兼容提交,再发布插件包。

动态 cordis_define/run 适合在当前进程里试验,但定义只存在于内存。进程重启后会消失,也不会生成插件包、安装依赖或写入 Profile。正式接入仍要落到插件包、配置和测试。

4.3 外部协议与进程边界

外部边界与进程内插件也应分开理解:Cordis 是进程内组合机制;Web 使用 HTTP 与 WebSocket;ACP 使用基于 stdio 的 newline-delimited JSON-RPC;SDK 使用项目自己的 line JSON-RPC 2.0;MCP 把外部工具注册进 Tools Runtime。MCP 当前主要桥接 Tool,Cordis 插件仍由进程内模块接口管理。ACP SDK 协议 MCP client

五、插件变更与重启机制

5.1 配置变更

Profile 和 Harness home 的 cordis.patch.yml 会被监听。有效配置变化会事务式重算,相关 Fiber 和 effect 随之卸载或重建,通常不需要重启整个 dsh 进程。

5.2 代码变更

代码变更只有在挂载 @deepseek-ai/cordis-plugin-hmr 并覆盖目标路径时才会热替换。Web 客户端插件还需要 pnpm run dev:web 重建前端 bundle。生产环境升级 npm 包时,不能假设 HMR 一定覆盖新文件;除非部署明确启用了完整 watcher 链,否则应重启进程。

HMR 的行为是卸载旧 Fiber、加载新模块,再重建依赖方。前端新模块加载失败时,Fiber 会进入 FAILED,不会自动回滚到旧代码。因此关键插件更新仍需保留固定版本、健康检查和回退方案。组合与 HMR

六、仓库质量保障流程

代码改动先经过仓库质量链

仓库同时约束单包行为、真实组合、跨平台兼容和发布产物。

6.1 代码与文档的同步要求

代码按责任分区:packages/*/* 保存官方 Service、provider 和 consumer;apps/* 保存 CLI 与 Web 产品入口;docs/ 和 .agents/notes/ 保存公开契约与设计记录;scripts/ 和 .github/workflows/ 保存生成器、门禁和 CI。修改一项能力时,应从所属 package 开始,再同步它的 README、JSDoc、测试和必要的 Agent Note。仓库布局

6.2 本地验证的三个层级

  1. 验证单包行为。
    • 运行 pnpm run test。
    • 按改动运行 typecheck、lint、doc-sync 和 build。
  2. 验证真实组合。
    • 产品可见插件必须经过 Loader、应用或进程入口。
    • 只手工构造 ctx.plugin 不能替代组合测试。
  3. 验证模型和真实服务边界。
    • 模型、协议或用户行为增加 test:snapshot。
    • 真实 provider 才选择带密钥的 test:e2e。

6.3 Issue 与 PR 的关联规则

内部 PR 的关联采用“作者显式声明、程序自动校验”的方式。PR 作者或编码 Agent 必须在正文中写明关联关系,自动化不会根据代码内容寻找 Issue,也不会替作者创建 Issue。

  1. 解决型关联。
    • 写法:Fixes #123、Closes #123、Resolves #123。
    • 含义:该 PR 用于解决 Issue,会进入解决型关联和状态同步。
  2. 信息型关联。
    • 写法:Related to #123、#123。
    • 含义:只记录关联关系,不表示合并后关闭 Issue。

当非 Draft、非 Bot 的 PR 请求评审或收到 Review 后,issue-policy.yml 会从默认分支检出可信规则并执行 node .github/issue-management/policy.mjs pr。脚本解析同仓引用,排除指向其他 PR 的编号,再校验 Issue 关联、唯一的 kind/*、至少一个 area/* 和 Priority 一致性。PR 模板 Issue policy 规则实现

issue-lifecycle.yml 使用 dsh-issue-management GitHub App 同步解决型 Issue 的 Project 状态。PR 开始开发后可进入 In progress,请求评审后进入 In review,Review 要求修改时退回 In progress。这套组件执行固定 JavaScript 规则,不是负责理解需求和评审代码的 LLM Agent;语义评审、合并和发布授权仍属于维护者。Issue lifecycle 项目配置

项目配置指向 deepseek-harness/deepseek-harness,而公开仓库是 deepseek-ai/deepseek-harness。结合公开仓库当前不接受外部 PR,更合理的解释是这套 Issue/PR 流程主要服务内部仓库。该判断来自配置与公开政策的交叉推断,官方没有公开内部仓库的完整协作说明。

6.4 开发参与者的公开规模

截至 2026 年 8 月 14 日,GitHub Contributors API 返回约 30 个非 Bot 贡献记录。Contributor 记录可能包含匿名作者、同一人的多个提交身份或历史导入,因此不能直接当作员工人数。15 个记录的贡献数不少于 100;前 10 个记录约占全部贡献的 90%,前 5 个约占 73%。这支持“代码主要由约十几名高频贡献者完成”的判断,不支持“100 多人共同开发”的说法。Contributors API

  1. 内测用户。
    • 职责:使用产品并反馈问题。
    • 规模:官方仓库与文档没有公布人数;百人级说法未获官方证据确认。
  2. 开发贡献者。
    • 职责:领取 Issue、修改代码、提交内部 PR。
    • 规模:高频贡献者约为 10~15 个公开记录;包含零星贡献后约为 20~30 个记录。
  3. 维护者。
    • 职责:进行语义评审,决定合并和发布。
    • 规模:GitHub Team、仓库权限和审批名单不公开,无法确认人数。
  4. 自动化账号。
    • 职责:校验元数据、同步状态、执行 CI。
    • 边界:GitHub Actions 和 GitHub App 不等同于开发者或 LLM Agent。

内测规模、代码贡献规模和维护权限规模属于三个不同口径。即使存在百人级内测,测试者也不必拥有仓库写权限;从反馈到内部 Issue 的转化入口没有出现在公开代码中。公开证据只能说明:反馈面可能较宽,持续代码生产集中在十几名贡献者,最终写入和发布权限进一步收窄。

6.5 合并与发布的权限边界

  1. Git hooks 先检查翻译、lint、空白、生成文件和 typecheck。
  2. 开发者或编码 Agent 在 PR 正文中显式关联 Issue,并填写变更、验证和标签。
  3. GitHub Actions 自动校验 Issue 关联、元数据以及 static、逐文件 100% coverage、snapshot、Node 兼容、Python、Wine 和 Windows 等检查。
  4. all checks passed 聚合通过后,改动才具备进入 master 的技术条件。
  5. 维护者完成语义评审并决定是否合并;自动检查通过不能代替这项判断。
  6. 发布先构建和打包全部 DSH 成员,再验证安装产物;tag 和受保护 environment 由有权限的维护者触发。

逐文件 100% coverage 只是一项仓库门槛。行为质量还依赖真实组合测试和 keyless snapshot。真实 API e2e 使用密钥,只在可信事件运行;fork 和 Dependabot 会跳过,避免泄露 secret。开发指南

公开工作流只能证明 CI 已配置。required checks 是否已在 Branch Protection 或 Ruleset 中设为强制、reviewer 数量、merge method 和发布 environment 审批名单均无法从公开仓库文件确认。

本轮按要求没有重新运行 Harness 本地测试。以上内容描述冻结仓库定义的开发流程,不代表本轮测试已经通过。

七、外部插件的发布方式

当前 CONTRIBUTING.md 明确说明项目仍处早期,暂不接受外部 Pull Request。官方建议外部开发者创建独立插件仓库,并使用 GitHub topic dsh-plugin 供用户发现。

现在可以让 Codex 在 fork 或独立仓库中完成插件、测试、文档和补丁,也可以准备一份可供维护者参考的变更记录。创建本地分支和提交需要用户明确授权;推送 fork 或创建 PR 还需要已登录的 GitHub 身份、目标仓库权限和外部写入授权。官方仓库当前不接受外部 PR,具备工具权限也不能绕过这项政策。

如果目标是扩展 dsh,当前可执行路径是:基于公开 Definition 开发独立插件,锁定兼容提交,完成组合测试,发布自己的包和 dsh-plugin 仓库。只有官方重新开放外部 PR 后,主仓贡献链才成立。

八、公开评测与证据边界

8.1 公开 Agent 任务评测

本文把“公开 Agent 评测”限定为同时给出任务或数据集、指标与分母、已测量结果。在冻结范围内,没有发现 SWE-bench、Terminal-Bench、AgentBench 或 GAIA 等 Agent 任务的公开成绩。

BENCHMARK.md 只说明怎样用 Python SDK 启动 minimal agent,并为独立任务设置 workspace 和 session ID。它提供评测接入口,没有给出评测结果。

8.2 工程评测资产

仓库包含工程评测资产:

资产 指标 当前证据
Web 长历史 runner 侧边栏、长对话、轨迹和 soak 的 wall time、p95 等 有脚本,未发现正式结果
reasoning chunk 压力 10 万 chunk;主线程和交互延迟门槛 250 ms 有断言,未发现官方汇总
CI runner benchmark 不同平台和 core 数下的检查耗时 用于 CI 容量,与 Agent 能力评测无关
单元、snapshot、e2e 类型、行为、组合和真实 API 链路 证明工程链路,不证明任务成功率

8.3 评测缺口

缺失的评测至少包括:

  • 固定模型和预算下的任务成功率。
  • 工具调用正确率。
  • 权限拒绝与恢复率。
  • 断点恢复正确率。
  • 长会话质量。
  • 插件组合兼容性。
  • 相同任务上的对照 Harness。

没有这些结果,就不能从高覆盖率推导出 Agent 效果。

九、采用建议

9.1 当前采用判断

阶段 当前判断 条件
架构观察 通过 源码和文档足以解释主要机制
受限试点 有条件通过 固定提交、隔离 workspace、低风险任务、明确权限和回退
组织级采用 不通过 缺少稳定发布、迁移承诺、安全审查和目标任务评测

DeepSeek Harness 当前标注 Developer Preview,会主动发生兼容性变化;会话格式仍为 v0;调研日未见正式 GitHub Release。这些事实不否定架构价值,但会放大插件兼容、会话迁移和运维成本。

9.2 受限试点要求

合理的下一步是选择一个低风险任务做隔离试点:

  1. 固定版本。
  2. 保留 workspace-write + ask。
  3. 逐项确认 shell、文件、Web 和外部服务是否进入审批策略。
  4. 保存有效配置和 plugin inventory。
  5. 把升级、会话导出和插件回退都当作可能失败的步骤。

只有在固定任务集上取得可复现结果,并补齐安全、发布和迁移责任后,才应重新讨论默认采用。

十、调研范围与证据