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"不得合并推导为统一分布式任务系统。
相关推荐
这张生成的图像能检测吗1 小时前
图像处理 / 底层视觉论文解析汇总目录
图像处理·人工智能
探路者继续奋斗1 小时前
AI资产科普
人工智能
云边云科技_云网融合1 小时前
连锁门店如何用AI降本增效?云边云科技 “AI +零售”沙龙探门店智能运营新范式
人工智能·科技·零售
倔强的石头1062 小时前
【机器学习】损失函数全解_从MSE到交叉熵
人工智能·机器学习
AINative软件工程2 小时前
LLM 应用的 Warm-Up 工程实践:冷启动延迟从 12 秒砍到 800ms 的 5 个工程手段
后端·llm·ai编程
研华科技Advantech2 小时前
Windows Server IoT 2025深度技术解析:功能、安全与AI性能突破
人工智能·物联网·安全
pingao1413782 小时前
金属翻斗式雨量筒 承雨口径200mm 高精度雨量监测仪
大数据·人工智能·科技
珐恩AI-人工智能2 小时前
大模型隐性权重衰减机制剖析:详解GEO长效维稳如何避免优质
大数据·人工智能·深度学习·机器学习·geo优化