DeepSeek Harness 产品级 Subagent 后台任务:用通用 Job 运行时承载 Codex / Claude Code 一次性委派
【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness
本指南以 DeepSeek Harness 仓库内的 Agent Note(2026-08-12-product-subagent-one-shot-background-tasks.md)为核心骨架,讲解产品级 Subagent(Codex 与 Claude Code)如何在"一个原生进程、一条最终答案"的一次性(one-shot)模型下,通过run_in_background参数接入通用后台 Job 运行时。读完本文,你将掌握该调度决策的完整生命周期、各组件(Provider、dsh-tool-subagent、dsh-jobs-local、dsh-tool-jobs)的责任划分、如何通过 Profile 与 Agent Preset 在组合层开启后台能力,以及对应验证方式与边界约束。
背景与问题:独立委派为何只能被前台阻塞
DeepSeek Harness 中,Codex 与 Claude Code 这两个产品提供方(provider)的运行模型是"一次性"的:一次委托只运行一个自包含任务,并返回一条最终答案。与此同时,dsh-tool-subagent这一面向模型的委派工具,早已能把任意 one-shot Provider 适配到通用的后台 Job 运行时上。
问题出在产品工具行的出厂配置上:随产品发布的工具行默认带上了disabled字段,把后台这条路由关掉了。于是,即使一次委派与 Agent 的下一步动作完全无关、完全可以并行,Agent 也只能在前台干等产品答案返回——独立任务被强制串行化、占住了调用现场。
决策总览:一行参数复用三层既有能力
本决策的目标是:暴露后台执行能力,但不引入任何新的产品会话、产品专属 Job 状态、第二个取消所有者或第二套结果协议。一次 Provider 运行仍然只负责一个原生进程/查询和一条最终答案;Job id、收集、取消、所有者清理与完成通知,全部继续由既有 Job 注册表负责。
实现上,这一决策把三层已经存在的能力拼装起来:
- 产品 Provider 层(
dsh-subagent-codex、dsh-subagent-claude-code):拥有原生协议、答案选择、本地取消与进程树静默(quiescence); - 通用 one-shot 后台适配器:负责后台注册与结算——启动同一个
SubagentRun(见 Subagent 能力缝),用 Job 所有的取消信号覆盖 Provider 启动与执行全程,等待run.result与run.dispose(),把终态结果与可选的安全诊断映射进 Job; - 通用 Job 运行时(
dsh-jobs-local作为 Job Provider,dsh-tool-jobs作为面向模型的消费端):job_output、job_list、job_kill与既有的完成通知负责把 Job 状态暴露给父 Agent。
关键点在于:本调度决策不新增任何 Provider 配置、服务接口、事件、线上字段、持久化格式或产品标识。前台与后台的差异,仅仅在于"由哪个既有消费者去等待同一次 one-shot 运行"。
前台与后台:run_in_background的精确语义
产品工具行的后台能力由 Agent Preset 配置中的backgroundMode: one-shot声明。出厂时,standard、code、cordis三个 Agent Preset 都把对应产品工具行配置为dormant(休眠)状态;组合方把该行的disabled字段移除后,既有的可选参数run_in_background才会出现在暴露给 Agent 的工具 schema 中。
该参数取值决定调度方式:
run_in_background | 行为 |
|---|---|
省略 或false | 前台等待:工具调用阻塞,直到 Provider 启动、run.result返回;completed返回最终文本,其他终态原因映射为错误结果(可携带安全诊断),返回前必定dispose运行 |
true | 后台运行:先做同步的 Job preflight 与注册,然后立即返回一个父 Agent 所有的 Job id;不等待 Provider 启动,也不等待完成 |
后台调用在注册前还会做两道防线:校验父 Agent 身份,并拒绝已经收到中止信号的执行请求(详见 通用后台 Subagent 决策)。
生命周期与所有者清理
原文档给出的生命周期如下:
product tool call -> omitted / false: tool call waits -> final answer or error -> run disposal -> true: Job preflight + owner cleanup -> starter begins provider startup under Job-owned signal -> Job record/id published and returned (startup remains pending) -> provider result + run disposal -> Job settlement + notice -> job_output reads / job_kill cancels -> parent disposal: Job owner cleanup cancels -> run disposal -> process exit几条值得注意的语义:
- 后台任务进程本地、父级所有:它不会在父 Agent 销毁后存活,不暴露中间产品活动,也不会让产品会话变得可续接(resumable);
- 取消信号跨启动期与执行期:
cancel(reason?)中止任务拥有的控制器,同一个信号既覆盖"Provider 尚未启动完成"的挂起期,也覆盖已发布运行剩余的收尾工作; - 终态映射:
completed返回最终文本;被取消的归为killed;其他停止原因归为failed并携带 Provider 诊断(若存在);启动、结果、dispose 任一环节失败都变成失败结果,而不是拒绝任务的 promise; readOutput缺席:运行期间job_output只返回状态;结算后幂等地返回最终输出。中间的子 Agent 活动留在子会话中,不流入父会话日志。
责任分配表
| 事实或资源 | 所有者 | 产品工具责任 | 可观察结果 |
|---|---|---|---|
| 产品 Provider 安装与注册 | 显式 Profile | 安装可选 Provider 包,在 host 平面挂载必需的具名实例 | Provider 名字可用,但不必把包塞进每个生产dsh安装 |
| 产品选择与暴露 | Agent Preset | 把一个固定工具名绑定到一个固定 Provider | 启用一行只暴露该产品工具 |
| 前台/后台选择 | dsh-tool-subagent | 在one-shot策略下解析run_in_background | 省略即前台;显式true返回 Job id |
| Job id、状态、输出、取消、通知 | ctx.jobs与dsh-tool-jobs | 注册并呈现既有的 one-shot 运行 | 通用 Job 工具为精确的父 Agent 收集或停止该运行 |
| 原生结果、可选诊断、进程静默 | 产品 Provider 与dsh-subprocess | 产出一条最终结果并释放一个进程树 | Job 结算与前台返回消费同一条结果,且都等待 dispose |
多实例扩展:命名实例与唯一工具名
在 命名实例决策 的支持下,Codex 或 Claude Code 可以各挂载多个Provider 实例。每个额外的 host Provider 行拥有各自的providerName;每个被暴露的 Preset 工具行通过provider绑定那个确切的名字,同时保留唯一的toolName。前台/后台的调度选择不会限制实例数量——也就是说,组合方可以为不同工作区、不同权限画像配置多套产品 Provider,每一套都可以独立地选择前台或后台运行。
组合(Composition):生产基座、Profile 选装与预置工具行
生产基座零负担
生产版dsh的基座把两个可选产品 Provider 排除在依赖闭包之外。选择加入的 Profile 负责:安装所需包(dsh-subagent-codex或dsh-subagent-claude-code),并在 host 平面挂载必需的 Provider 实例。每个完整 Preset 都保持两个产品工具行处于disabled状态,同时把通用 Job 控制工具(job_output、job_list、job_kill)纳入自己的 Agent 作用域,而共享的 Job 注册表归 base host 所有。
启用流程:用户复制一份 Preset,在 Profile 的 Provider 已就绪之后,从对应产品行移除disabled即可。组合过程中不会启动任何产品进程。
独立自定义组合的最低要求
一个要启用 one-shot 后台执行的独立自定义组合,必须同时提供:
- 产品 Provider(
dsh-subagent-codex/dsh-subagent-claude-code); - 完整的通用 Job 能力:
dsh-jobs-local作为 Job Provider,dsh-tool-jobs作为模型可调用的消费端。
基于dsh-base的 Profile 已经自带 Job 能力,只需在启用 Preset 工具行前追加可选产品 Provider。反过来,没有 Job 运行时的产品工具仍然可以前台执行,但显式的后台请求会在既有的 Job preflight 处失败,而不是发布一个无法收集的 id——这保证了"拿不到 id 就一定不会有孤儿运行"。
ACP 产品组合
ACP 产品组合使用相同的固定产品行与通用 Job 控制。其无密钥(keyless)schema 快照会为每个启用的产品工具暴露description、prompt与可选的run_in_background,而无需真正调用 Codex、Claude Code 或任何外部模型。
验证:四类测试锚定行为
原文档的验证策略覆盖四个层面:
- Web 组合测试:从仓库 examples 依赖锚点显式挂载两个可选 Provider,然后启动四种用户预置变体——"两者都不用、仅 Codex、仅 Claude Code、两者都用"——逐一检查每个启用的产品工具是否同时暴露
run_in_background与job_output、job_list、job_kill; - 两个包自带的 Loader 组合:在空
PATH下运行,检查同样的 schema 与控制工具,证明显式加载 Provider不会启动任何产品进程; - ACP 无密钥快照:钉住组装后的显式产品 schema;
- 既有
dsh-tool-subagent与 Job 测试套件:钉住前台默认值、Job 注册、最终输出收集、共享诊断呈现、取消、完成通知、所有者销毁与 Provider 销毁等行为。
此外,两个真实产品 Provider 套件独立证明:原生权限失败会先进入同一条共享结果,之后才轮到前台或后台任一调度路径消费它——这保证了两条路径对失败呈现完全一致。
备选方案回顾:为什么是"前台默认 + 后台显式"
| 备选方案 | 被否原因 |
|---|---|
| 产品工具仅限前台 | schema 最小,但即使通用 one-shot Job 适配器已具备所需生命周期,Agent 仍无法调度独立的产品工作 |
| 产品委派默认后台 | one-shot Job 需要事后收集,不同于拥有持久会话 id 与结算投递的可续接子会话;前台保持兼容默认,后台保持显式选择 |
| 用 Codex / Claude Code 原生会话状态充当后台所有者 | 会在通用 Job 注册表之外制造 Provider 专属的 id、状态、取消与恢复语义;Provider 保持一次性结果生产者、原生 id 保持私有 |
| 增加产品专属 output / wait / kill 工具 | 重复通用 Job 协议,为每个 Provider 教一套不同的收集流程;既有job_*工具已覆盖所需操作 |
| 同时引入可续接的产品会话 | 恢复、追问、进度与持久化产品会话需要新的产品契约与生命周期所有权;本决策只暴露已实现的 one-shot 后台路由 |
影响与边界
收益:当 Codex 或 Claude Code 处理一项独立的一次性任务时,Agent 可以继续做其他有用工作,随后通过与其他后台生产者完全相同的 Job 控制工具收集最终答案或取消它。前台与 one-shot 后台消费者在失败结果携带安全诊断时呈现完全相同的 Provider 诊断。
不变的契约:每一次产品委派仍然启动全新的原生进程或查询、只产出最终助手文本作为唯一助手负载,并以 Provider 销毁和整树退出收尾;失败结果可额外携带安全诊断。后台调用只是额外暴露通用 Job id、状态、完成通知与收集/取消结果。
硬边界:后台 Job 是进程本地的、父 Agent 所有的——不随父销毁存活、不暴露中间产品活动、不可续接。生产安装除非 Profile 显式安装,否则不为任一产品集成付费;任何暴露run_in_background的组合都必须同时保留通用 Job Provider 与控制工具。
源码索引
- 面向模型的委派工具:
packages/subagent/tool-subagent/package.json(peer 依赖含dsh-jobs、dsh-subagent、dsh-tools等,验证其位于委派与 Job 的交汇处) - Codex one-shot Provider:
packages/subagent/subagent-codex/package.json(依赖@openai/codex,自带cordis.patch.yml组合补丁) - Claude Code one-shot Provider:
packages/subagent/subagent-claude-code/package.json(依赖@anthropic-ai/claude-agent-sdk与 MCP SDK) - Job 运行时与消费工具:
packages/jobs/jobs-local/package.json、packages/jobs/tool-jobs/package.json - 相关决策记录:通用后台 Subagent 适配器、Subagent 能力缝、产品 Provider 后端、非交互权限、命名实例
【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考