DeepSeek Harness 子Agent架构设计
DeepSeek Harness 子Agent架构设计
传统 Agent 框架通常把子 Agent 注册成普通 Tool,由模型根据
description自行判断是否调用。DeepSeek Harness(dsh)则把子 Agent 提升为独立的运行时能力,用Service Definition + Service Provider + Consumer构成一条 Capability Seam。模型看到的只是 Consumer 工具,底层 Provider 可以按配置替换,调用入口和prompt都不需要改变。
这套设计要解决的并不是“能不能调用子 Agent”,而是子 Agent 的边界约束、能力声明、委派深度和会话续接如何从隐式约定变成硬性契约。
一、痛点:子 Agent 的边界一直是隐式规则
在一个常见的代码重构场景里,Claude Code 或 Codex 会在执行过程中自主拉起子 Agent。子 Agent 再往下委派,一层一层继续嵌套,等开发者意识到问题时,上下文可能已经穿过了三层委派链路。
此时真正让人不安的不是“模型具备自主能力”,而是几个边界问题没有被确定下来:
- 这个子 Agent 是谁发起的;
- 当前一共嵌套了多少层;
- 它是否还能继续向下委派;
- 它的会话是否可以接续。
传统实现里,这些规则都写在 prompt 或 description 中。可以写“禁止嵌套”,但这只是软约束,模型是否遵守没有确定性保障。
dsh 的做法是把委派规则显式化成协议。它的子 Agent 子系统由三层机制共同形成硬约束:
- 完整的类型定义;
- 能力协商流程;
- 委派深度持久化机制。
边界管控因此从“模型自行解读”,转变为“运行阶段由 Provider 声明并完成契约校验”。
二、骨架:一切皆插件,Agent Loop 也没有特权
2.1 dsh 内核与插件树
dsh 的底层内核来自 Cordis,Cordis 只负责插件的加载、卸载和依赖关系管理,不内置任何 Agent 业务能力。
在这个内核容器之上,一切皆插件:
- 模型适配器是插件;
- 工具注册中心是插件;
- 会话日志组件是插件;
- Agent 主循环本身也只是一个普通插件。
因此核心模块都可以被替换。要切换底层模型,就挂载对应的 adapter 插件;要替换主循环执行逻辑,就新增或替换插件,不需要 fork 源码去修改核心实现。
配置层由 Profile + Bundle 两层组成。一个 Profile 由有序的 Bundle 逐层叠加,最终形成完整的插件树:
dsh-base是基础层,承载模型适配器、工具集、持久化组件、沙箱环境和审批策略;dsh-web-app在基础层之上追加浏览器交互组件;dsh-headless追加一次性执行的 runner 组件。
配置补丁按行 id 定位,并对整行配置内容完成替换。
2.2 能力缝可插拔架构,和传统可插拔 Tool 架构的区别
很多 Agent 框架都支持可插拔工具,但它和 dsh 的能力缝模型并不在同一个抽象层级。
传统可插拔 Tool 架构的插拔发生在工具层。工具包对外输出 ToolSpec,包含名称、描述、入参 Schema 和 handler 执行函数。框架维护全局工具注册表,模型通过 tool_call 触发 handler。
它的边界止步于工具实现。例如本地 tool-bash 的 handler 内部直接调用 child_process.spawn。如果要改成沙箱执行,或对接远程 E2B 服务,只能再写一个全新的 bash-sandbox 工具,并让模型在 prompt 的工具列表里感知并选择两个工具。
能力缝架构的插拔发生在底层能力契约层。模型看到的仍然是一个 tool-bash 工具,但它只是 Consumer,真正执行依赖 ctx.shell。ctx.shell 下面可以挂载 bash-local、bash-sandbox、pwsh-local 等多个 Provider。切换 Provider 只改配置,工具代码和 prompt 都不用动。
两者差异可以用一张表对照:
| 对比维度 | 传统可插拔 Tool 架构 | Capability Seam 能力缝架构 |
|---|---|---|
| 插拔位置 | 工具 ToolSpec 层面 | 底层能力契约 ctx 层面 |
| 模型感知 | 不同实现对应不同工具,模型需要选择 | 模型只看到同一个调用入口,Provider 透明 |
| 依赖关系 | handler 直接绑定底层实现 | Consumer 只依赖抽象 Definition |
| 替换方式 | 增删工具,prompt、工具列表同步变更 | 切换 Provider,工具、prompt 不变 |
| 级联传递 | 工具之间互相独立 | 支持级联替换,下游自动切换执行环境 |
| 多实现共存 | 多个工具条目并行注册 | 同一契约下多个 Provider 按名称注册 |
| 适用范围 | 只面向模型动作调用 | 覆盖 LLM、Shell、文件系统、子 Agent、持久化、审批等运行时能力 |
一句话概括:传统可插拔工具,插拔的是展示给模型的动作;能力缝架构,插拔的是支撑动作运行的底层执行能力。
三、子 Agent 为什么应该属于 Seam
3.1 传统方案:Agent 工具只是 Loop 的一个组成部分
传统框架把子 Agent 调用逻辑硬编码成一个 Agent 工具,和 bash、edit 注册在同一张工具表里。模型每一轮推理都能看到这个工具,自主判断是否调用,并选择 subagent_type。
框架收到 tool call 后,根据类型名称拉起子 Agent,分配全新上下文,等子 Agent 执行结束,把结果作为 tool result 回传给父 Agent,进入下一轮推理。
// 传统做法:Agent 工具注册在工具表,与 bash/edit 平级
tools.add({
name: 'Agent',
desc: '委托子任务,可选 subagent_type',
call: (args) => spawn(args.subagent_type, args.prompt),
});
// 模型发起 tool call,结果作为 tool result 回灌下一轮
这个方案的最大问题是:边界管控全部依赖模型自觉。什么时候拆分任务、嵌套深度上限是多少、子 Agent 能输出什么内容、会话是否支持接续,都靠 description 文本解读。解读出现偏差时,框架没有拦截机制。
嵌套层级失控、上下文信息串扰,根源就在这里。整套流程走标准 Agent Loop 的工具执行链路,从架构归属上属于 Loop 的一部分,而不是独立运行时能力。
3.2 dsh 方案:子 Agent 是一条独立 Seam
dsh 把子 Agent 提升为一等运行时能力,和 bash 保持同一层级:
dsh-shell定义契约;dsh-bash-local、dsh-bash-sandbox提供实现;dsh-tool-bash负责把能力暴露给模型。
子 Agent 同样采用这条 Seam 形态。类型定义不放在核心内核里,而是挂在 ctx.subagents 服务对象上,后端挂载多个 Provider,再通过 tool-subagent 这个 Consumer 把委派能力开放给模型。
dsh 的 bash 和 subagent 都属于 Capability Seam,但有一个关键区别:bash 同一时间只允许一个 executor 生效,而 subagent 支持多个 Provider 按名称共存,全部挂载在 ctx.subagents 映射表下。
这意味着 spawn 子 Agent 并不存在唯一正确实现。可以在同进程内新建 Agent,可以 fork 一份继承父任务已完成 turn 前缀的实例,可以走远程 ACP 协议,甚至可以把 Claude Code、Codex 这类外部产品整体作为后端执行载体。框架的职责只是定义统一委派协议,不替使用者选定实现方案。
dsh 内置 6 种 Provider:
| Provider | 执行机制 | 是否继承父上下文 |
|---|---|---|
spawn-in-process | 同进程新建 Agent | 不能继承 |
fork-in-process | 同进程 fork,继承父已完成 turn 前缀 | 继承 seed 信息 |
acp | Agent Client Protocol 远程 Agent | 不能继承 |
codex | 拉起 codex app-server --stdio | 不复制父对话 |
claude-code | 调用 @anthropic-ai/claude-agent-sdk,persistSession: false | 不复制父对话 |
dsh-sdk | DSH 自研 JSON-RPC SDK | 按 descriptor 配置决定 |
四、四项布尔能力标识:把校验前置到启动阶段
每份 Provider 在启动前必须声明自己支持的能力集合。这些定义来自 packages/subagent/src/types.ts:
interface SubagentCapabilities {
readonly outputSchema: boolean
readonly depthLimit: boolean
readonly toolFilter: boolean
readonly persona: boolean
}
四个字段分别表示:
outputSchema:是否支持结构化输出;depthLimit:是否遵守委派深度上限;toolFilter:是否支持裁剪子 Agent 可用工具集;persona:是否支持分配独立人格。
关键约束不在声明本身,而在校验时机。父 Agent 发起委派时,如果要求子 Agent 具备某项能力,而 Provider 声明的能力集合不包含该项,dsh 不会先接收任务再静默妥协降级,而是在启动阶段直接抛出 SubagentError('UNSUPPORTED_CAPABILITY')。
官方把这条原则命名为 fail loud, no silent degradation:失败要明确抛出,不允许静默降级。
Claude Code 的 Agent 工具依靠 prompt 中的 description 让模型理解子 Agent 能力范围。模型读完描述后如果判定可以承接任务,就会发起委派;但实际子 Agent 不支持结构化输出或工具集不符合预期时,它不会提前拒绝,而是产出不符合预期的自然语言内容。问题排查往往要回溯很久才能定位到能力不匹配这个根因。
dsh 把判断逻辑从模型语义猜测,转变成 Provider 类型声明和运行阶段契约校验。四项布尔标识就是契约,无法满足契约就不能接入委派链路。这才是协议化管控的本质。
五、三家框架在子 Agent 方向上的设计哲学对比
Claude Code、Codex、DeepSeek Harness 在子 Agent 模块上走出了三条不同路线:
| 维度 | Claude Code | Codex | DeepSeek Harness |
|---|---|---|---|
| 子 Agent 模型 | Agent 工具 + subagent_type,单进程,模型自主决定 spawn | app-server stdio 沙箱进程,审批策略驱动 | 命名式 Provider 注册表,多 Provider 共存,前置能力协商 |
| 边界决定权 | 模型,依靠 prompt 与 description | 产品策略 + 审批流程 | Provider 能力声明 + 启动阶段 fail-loud 校验 |
| 隔离机制 | 同进程独立上下文 | 进程隔离 + sandbox 沙箱 | 可选:同进程 spawn/fork、远程 ACP、外部产品进程 |
| 委派深度管控 | 软约束,依靠 prompt 引导 | 产品侧自主管控 | delegationDepth 持久化 + maxDepth 硬拒绝 |
| 可续子 Agent | 不支持 | 不支持,任务属于临时实例 | 支持 continuable + Activation + followup/interrupt/report 冷恢复 |
| 跨产品委派 | 不能委派给 Codex | 不能委派给 Claude Code | 内置 codex、claude-code Provider,支持互相委派 |
这里有三处差异尤其值得关注。
第一,边界由谁决定。Claude Code 把决策权交给模型,灵活性高,但边界是隐式语义规则,容易漂移。Codex 把决策权收归产品层和审批策略,可控性更强,但扩展弹性偏弱。dsh 选择第三条路径:边界由 Provider 预先声明的能力集合决定,在启动阶段由类型系统完成校验,校验通过才允许接入,失败直接拒绝。约束强度从模型解读、产品管控到能力契约校验,逐级硬化。
第二,可续子 Agent 是 dsh 的独有特性。Claude Code 和 Codex 的子 Agent 都是临时实例,单次调用结束后生命周期终结。真实的长周期任务中,子 Agent 经常需要接收追加追问、接续执行。dsh 的 continuable、Activation、cold resume 机制,是当前开源 Agent 框架里相对完整的子会话生命周期方案。它确实带来更高复杂度,但解决的是工程落地中的真实痛点。
第三,跨产品委派更具颠覆性。dsh 内置 codex、claude-code 两个 Provider,把直接竞品封装成可调用的执行后端。使用方可以在同一套调度体系下,按需委派任务到不同产品的 Agent 执行引擎。
六、总结
很多框架把 Agent 扩展能力停留在工具层,新增能力等价于新增一条工具定义。小规模场景下这种模式足够好用,但随着委派链路变深、执行载体变多,维护成本会快速上升。
Capability Seam 的核心价值,是把调用入口和底层实现解耦。模型只需要面向稳定契约发起调用,底层执行载体可以按配置切换,不需要改动 prompt,也不需要修改上层调用代码。
落到子 Agent 场景,它解决的核心痛点有三类:
- 多层委派带来的边界失控;
- Provider 能力不可核验;
- 子会话无法接续。
从架构演进角度看,把 Agent 运行时能力协议化、可插拔化,对构建大规模 Agent 调度体系有直接的参考价值。如果要做多引擎 Agent 编排或跨平台子任务委派,契约前置校验、多 Provider 共存,以及可续子会话设计,都是值得优先沉淀的工程能力。
更多推荐

所有评论(0)