DeepSeek Harness:Subagent、Job、Goal 都叫任务,为什么不能混成一个对象

Subagent、Job、Goal 都叫任务,为什么不能混成一个对象

"让另一个 Agent 查资料""把命令放到后台跑""继续做,直到目标完成",在人看来都像是在创建任务。

如果系统也用一个通用 Task 对象承载它们,接口起初会很整齐:都有 id、status、result、cancel。等到恢复、权限和失败处理真正接入,问题才会暴露:谁拥有对话历史,谁只保存执行状态,谁可以继续下一轮,取消后保留什么,完成又到底代表什么?

DeepSeek Harness 没把这三件事压成一个抽象。固定源码分别提供 Subagent、Job 和 Goal:

  • Subagent 把工作委派给一个子 Agent,核心资产是子 Session、Agent 能力和父子关系;
  • Job 托管一段后台工作的身份、状态、输出、等待与终止,生产者可以是 Bash,也可以是 Subagent;
  • Goal 把同一 Session 的目标、阶段、修订和已启动轮次持久化,让 continuation policy 决定是否继续下一轮。

三者能够组合,却不能互相替代。本文只回答一个工程问题:遇到一段"以后还要继续、观察或停止"的工作时,应该选 Subagent、Job 还是 Goal?

先看对象,而不是先看"异步"

最容易误导设计的词是"异步任务"。异步只描述调用者是否等待,不说明被管理的对象是什么。

可以先问三个问题:

  1. 是否需要另一个 Agent 拥有自己的模型回合、工具范围或对话上下文?
  2. 是否需要把一段执行暴露为可列出、读取、等待、终止的后台生命周期?
  3. 是否需要当前 Agent 在同一个 Session 中围绕一个目标继续多轮,并保留目标阶段和轮次预算?

答案分别指向 Subagent、Job 和 Goal。

选择 管理对象 稳定身份 主要状态 典型完成含义
Subagent 子 Agent / 子 Session child session 或 provider run 对话、Activation、父子关系、输出 一次委派结束,或子 Activation 结算
Job 任意后台生产者 <kind>-N JobId running / stopping / completed / killed / failed 生产者释放资源并提交终态
Goal 当前 Session 的目标 GoalId + revision active / paused / blocked / complete 目标被显式标记完成

这张表的关键不在字段数量,而在"完成"的语义完全不同。Subagent 完成一次工作,不等于上层目标完成;Job 结束,只能证明这段生产者生命周期结算;Goal complete 则是对目标状态的显式判断,不是某个进程自然退出。

Subagent:需要的是另一个 Agent,而不是一条后台记录

固定 Subagent 文档开头就限定了它的角色:这是一个可选 capability seam,用来把工作委派给 child agent,不属于核心 Agent Loop。

这里至少有两种不同生命周期。

One-shot Subagent 是一次前台委派。消费者拿到 SubagentRun,等待一个结果,最后 dispose。它没有 steering,也不能 resume。即使本地 Provider 创建了普通子 Session,这个 Run 仍是一份一次性结果合同,而不是通用后台任务句柄。

Continuable Subagent 则是一份持久子 Session,可以经历多个 process-local Activation。它的后续消息进入子 Agent 自己唯一的 FIFO inbox;没有活跃 Activation 时可以从持久 Session cold resume。固定文档特别强调:continuable path 不创建 Task,也没有中间的 result-bearing wrapper。

这决定了 Subagent 的选用条件:

  • 需要独立模型回合或不同 Provider;
  • 需要给子 Agent 单独限制工具、persona、输出 Schema 或委派深度;
  • 需要父子 Session、子孙枚举、继续发消息或显式报告;
  • 需要区分 spawn、fork、ACP、Codex、Claude Code 等不同子 Agent transport。

它不自动回答后台控制问题。One-shot Run 的结果由消费者直接等待;continuable child 的消息、打断、报告和结算由 continuation manager 管理。若产品还要向模型或 UI 暴露统一的后台 list/read/wait/kill,那是 Job 的职责。

Job:管理后台执行,不决定执行者是不是 Agent

固定 Jobs 文档把 Job 定义为 long-running producer 与 ctx.jobs 之间的共享 Runtime。它不要求生产者是 Agent。

JobKindMap 的固定条目已经给出两个例子:bashsubagent。这正好说明 Job 是外层生命周期,不是 Subagent 的别名。

生产者向 Registry 提交 JobStart:kind、label、可选 owner、输出上限以及同步 run()run() 返回三个关键钩子:

  • cancel():请求生产者停止;
  • done:生产者释放资源后给出 completed、killed 或 failed;
  • 可选 readOutput():消费增量输出。

Registry 自己负责 JobId、权限、状态、等待者、监听器和 first-wins settlement。Owner Session 用于访问控制;owner 或 service dispose 时会请求取消并等待合规生产者释放资源。固定本地 Provider 还对每个 owner 的 running + stopping Job 做并发准入。

因此,以下需求优先选择 Job:

  • 命令、下载、索引、构建或一次 Subagent 委派需要在后台运行;
  • 调用者要先拿到 id,之后再 list、read、wait 或 kill;
  • 产品需要统一的后台状态和完成通知;
  • 生产者资源释放与业务工作结束必须区分;
  • 不同生产者需要共享一套 owner 权限和并发上限。

Job 不拥有 Agent 的对话语义,也不保存"为什么做这件事"。detailoutput 是 producer-specific 结果,不是目标状态。Job completed 更不能推出目标达成:一次搜索 Job 成功返回,可能只是证明没有找到答案。

Goal:管理"为什么继续",不是管理后台进程

Goal 的对象不是子 Agent,也不是某段后台执行,而是同一 Session 的人类目标。

固定 Goal 文档把持久 phase 与 process-local activation 分开:

  • durable phase 回答目标发生了什么:active、paused、blocked、complete;
  • process-local activation 回答 continuation consumer 此刻能否启动下一轮。

每次目标变更写入 goal/change Session Event。Goal 使用 GoalId + revision 做 compare-and-set;每次持久变更递增 revision。只有被 continuation consumer 接纳并带有当前 Goal revision 的 user-message round 才增加 roundsStarted,回放会拒绝轮次缺口、旧 revision、停止状态和预算越界。

这说明 Goal 解决的是:

  • 多轮工作如何仍然绑定同一个目标;
  • 暂停、阻塞、恢复和完成如何成为可回放事实;
  • 谁在旧 revision 上修改目标,怎样被拒绝;
  • 自动继续最多允许多少轮;
  • 进程重启后,目标 phase 与本地 continuation authority 怎样分开恢复。

Goal 不创建工作线程,不运行命令,也不天然委派子 Agent。它只是给同一 Agent 的后续轮次提供目标域和持久状态。若达成目标需要并行调研,Goal policy 可以触发 Subagent 或 Job;但那些执行对象仍有各自身份和终态。

三者怎样组合,而不是互相吞掉

一个实际流程可以同时出现三者:

text 复制代码
Goal:完成一份可发布的技术调研
  ├─ Job bash-1:后台运行仓库测试
  ├─ Job subagent-2:包装一次可读取/等待的委派
  │    └─ Subagent:拥有自己的模型回合与工具范围
  └─ 当前 Session 下一轮:根据结果继续、阻塞或完成 Goal

这不是层级越多越先进,而是三份状态各自回答一个问题:

  • Subagent:谁在独立思考和执行?
  • Job:这段后台工作现在处于什么生命周期?
  • Goal:当前 Session 为什么还要继续,目标是否已经完成?

组合时最重要的是不要偷换状态:

  1. Subagent 返回 completed,只能说明这次委派结束;父 Goal 仍应检查结果是否满足验收。
  2. Job killed 只说明 Registry 接受了终止并最终得到 killed;若生产者取消实现不合规,不能假设外部副作用已经停止。
  3. Goal blocked 不应自动 kill 所有 Job。阻塞可能是在等待人工输入,后台只读收集仍可继续;是否取消必须由策略明确决定。
  4. Goal complete 也不等于所有子资源已释放。资源结算仍应等待 Job done 或 Subagent Activation disposal。

取消是三种不同动作

把三者混成 Task,最先出错的通常是 cancel。

Subagent one-shot 的 caller signal 同时覆盖启动前与发布后剩余 turn work;消费者 dispose Run 以取消残余并达到 quiescence。Continuable Subagent 的 follow-up 在 inbox 接受后便脱离 caller signal;interrupt() 只取消当前 turn,并保留未领取 inbox 和已发布 descendants,之后可以再次唤醒。

Job kill 调用 producer 的同步、幂等 cancel,然后状态进入 stopping,最终由 done 给出终态。等待操作自己的 signal 只取消等待,不取消 Job。

Goal pause/block/complete 改变的是目标 phase 并解除自动 continuation。它们不是进程信号。disarm() 甚至只移除 process-local continuation authority,不改变持久 phase 或 revision。

所以 API 不应提供一个含糊的 task.cancel() 然后由调用者猜测它意味着:取消当前模型 Turn、终止后台生产者、丢弃排队消息,还是暂停长期目标。

持久化也不是同一种"可恢复"

Subagent、Job、Goal 都可能出现在"恢复"讨论中,但固定合同并不相同。

  • Continuable Subagent 的 durable child Session 和 descriptor 可以支持 cold resume;process-local Activation 会重建。
  • Goal 的 snapshot、revision、phase 与 roundsStarted 由 owning Session log 中的 goal/change 和被接纳的消息事件折叠出来。
  • 固定 LocalJobRegistry 是 process-local Provider。Jobs 文档保证 Registry 生命周期、owner cleanup 与 settlement,不等于跨进程 durable queue。

因此,固定源码不能支撑"所有后台 Job 重启后自动恢复"这一结论,也不能支撑"子 Agent Session 已 flush 就一定由某个持久化后端保存成功"。Subagent 文档明确写到,最终 flush 的 participation boolean 不能证明任意 persistence backend 已经落盘;失败会记录,但 Activation 仍会释放。

生产系统若要求进程崩溃恢复,还需要额外定义:任务声明是否持久、租约归谁、运行实例如何 fencing、重复启动怎样幂等、外部副作用如何对账、结果如何重放。不能把 Session 可恢复或 Job 有状态枚举直接升级成分布式调度保证。

一张可直接使用的选择矩阵

场景 首选 原因 还可能组合
让另一个模型独立审查代码 Subagent 需要独立 Agent、工具范围与结果 长时间运行时外包一层 Job
后台执行 Bash 并稍后读日志 Job 需要 id、增量输出、wait/kill Goal 记录为什么运行
当前 Agent 持续多轮完成迁移 Goal 需要 objective、revision、phase、轮次预算 每轮可启动 Job/Subagent
可继续对话的研究子 Agent Continuable Subagent 需要 durable child Session、follow-up、cold resume UI 若需统一后台面,可增加 Job 视图但不能替代子 Session
一次性并行检索多个来源 One-shot Subagent 需要多个独立模型执行流与结果 可由 Job Registry 暴露后台控制
下载、转码、索引等非 Agent 工作 Job 生产者不是 Agent,仍需生命周期 目标完成前由 Goal 观察结果
等待用户补充信息后再继续 Goal blocked/paused 停的是 continuation 意图,不是任意进程 策略决定保留或终止相关 Job
跨机器、可租约、可故障转移的任务 三者都不够 固定合同没有证明分布式 durable scheduler 需额外队列、fencing、幂等与恢复层

使用这张表时,优先确定"需要保存什么事实",再决定接口。需要对话历史就不能只存 Job output;需要后台资源状态就不能只存 Goal phase;需要长期目标就不能拿 Subagent 的一次 result 代替。

结论

Subagent、Job、Goal 看起来都在描述"接下来要做的事",但它们拥有的事实不同。

Subagent 拥有子 Agent 身份、Session、Provider 与对话生命周期;Job 拥有后台生产者的 id、状态、输出、等待和终止;Goal 拥有同一 Session 的目标、revision、phase 与 continuation round。

最稳妥的设计不是发明一个无所不包的 Task,而是让三种状态保持正交,再通过显式策略连接:哪一个 Goal 触发了哪一个 Job,哪个 Job 包装了哪次 Subagent 委派,什么证据允许 Goal complete,阻塞或取消时分别处理哪些执行对象。

这样做的收益不是"对象更多",而是每一种完成、取消和恢复都有可以核对的语义。

参考资料

  1. 固定 Commit Subagent Subsystem:github.com/deepseek-ai...
  2. 固定 Commit Background Task Runtime:github.com/deepseek-ai...
  3. 固定 Commit Same-session Goals:github.com/deepseek-ai...
  4. 固定 Commit Subagent Package:github.com/deepseek-ai...
  5. 固定 Commit Jobs Package:github.com/deepseek-ai...
  6. 固定 Commit Goal Package:github.com/deepseek-ai...

证据与推导边界

  • 三个子系统的字段、状态、取消、持久化与权限语义:固定 Commit 官方文档事实;2026-08-18 核对当前 master 三份文档与固定基线逐字一致。
  • 三原语选择矩阵、组合图和验收建议:作者工程分析。
  • 未运行真实模型、跨进程 Job 恢复、跨机器调度、故障转移或生产 E2E。
  • "可持久 Session""event-sourced Goal""process-local Job Registry"不得合并推导为统一分布式任务系统。
相关推荐
朝阳资本论2 分钟前
群核科技:从空间设计龙头到物理AI“卖水人”的升维之战
人工智能
七夜zippoe9 分钟前
为什么 2026 年每个 Java 团队都该懂 AI Agent
java·开发语言·人工智能
举个栗子。11 分钟前
SwarmForge:AI 智能体协同编程框架,让多个 Agent 在隔离工作区并行协作
人工智能·开源·ai编程
AIGC小尼22 分钟前
Windows 本地 AI 漫剧全自动生产线部署完整教程(零基础、全指令、带源码、模型配置、排错方案)
人工智能·windows·ai漫剧
合米AI SOP系统26 分钟前
传统产线如何快速上马落地 AI 防错?合米科技 AI SOP 7天即可上线。
大数据·人工智能·科技
思录Echo27 分钟前
什么决定具身智能的最终走向?多技术路线与落地现实辨析
大数据·人工智能
ShallWeL1 小时前
Orin 上多模型常驻与显存预算
人工智能·嵌入式硬件·nvidia·orin
xiaohaiAIgeo1 小时前
【2026年】AI监控加行为分析守护实验室安全
大数据·人工智能·科普知识
IT_陈寒1 小时前
Python的多线程就是个假把式,我算是体验到了
前端·人工智能·后端