DeepSeek Harness 多 Agent 实战:一句话拉起 AI 团队
生命不息,折腾不止。单兵再强也怕活多——今天让 dsh 里的 Agent 学会「组队」,把大任务拆给几个子 Agent 并行干。
前两篇我们把 dsh 从「装上」玩到了「能写插件」。但真正干活的场景里,一个 Agent 从头盯到尾有个致命问题:上下文越滚越长,到最后模型大半注意力都在考古——三十轮之前的对话跟当前这步基本没关系,却一直占着 token。DeepSeek Harness 给出的答案是「多 Agent」:主 Agent 当项目经理,把活拆给几个子 Agent 各干各的,最后收拢结果。
这篇就带你把 dsh 的多 Agent 体系跑起来。先说明一点:dsh 的「多 Agent」不是一个开关,而是一组可组合的工具,搞清楚每把工具的用途,比背命令重要得多。
一、先分清:dsh 的「多 Agent」其实是五套工具
翻 dsh 的文档会发现,「委派」这件事被拆成了五组独立的插件工具,职责泾渭分明:
| 工具 | 干什么 | 一句话理解 |
|---|---|---|
subagent / subagent_fork |
派活 | 创建子 Agent 干活 |
subagent-control |
管理 | send_message / interrupt_agent / list_agents |
jobs |
统一后台 | job_list / job_output / job_kill |
workflow |
编排 | agent() / pipeline() / parallel() |
ralph |
有界迭代 | 一轮轮换新会话,只传交接报告 |
底层支撑它们的是一个叫 subagent seam 的机制:ctx.subagents 注册了六个命名 provider——spawn-in-process(默认,同进程建子 Agent)、fork-in-process(一次性前台)、acp(跨进程/跨机器)、codex、claude-code、dsh-sdk。模型看到的接口永远一样,背后跑的是谁可以随便换。这套东西在 Standard 模式里默认就挂好了,不用额外装。
二、两个「派活」工具:subagent 和 subagent_fork
最常用的是这两个,区别一句话就能记住:
subagent:创建的是可续聊的后台子 Agent(continuable)。它默认在后台跑,有自己的「收件箱」,干完通过report工具把结果推回主 Agent。你中途还能再给它发消息追加要求。subagent_fork:一次性前台。它带着主 Agent 当前的会话历史起步,跑完直接把结果返回来,没有收件箱、不能追加,发出去就完事。
选择规则也很直白,官方社区给了个口诀:
fork when the context IS the task, spawn fresh when the task is separable.
翻译成人话:如果子任务本身就依赖你当前已经聊出来的上下文(「顺着这个思路,换个修法再试」),用 subagent_fork;如果子任务可以独立拆出去(「去把这三十个文件读一遍,告诉我结果」),用 subagent 新建。
三、上手:让主 Agent 同时派三个子 Agent 干活
不用写代码,直接开 Web UI 就能体验。流程如下:
1 | # 1. 启动 dsh(已装好环境的话) |
新建会话,模式选 Standard(子 Agent 和工作流都在这套模式里)。然后给主 Agent 布置一个「要拆解」的任务,比如:
1 | 帮我调研「本地优先的 AI Agent 运行时」这个话题: |
主 Agent 会自己判断:这个任务能拆,于是连续调用 subagent 开出三个后台子 Agent,各自去查各自的方向。子 Agent 干完,用 report 把发现推回来——子 Agent 的 report 有两个投递模式:
wakeup(默认):报告一到,唤醒主 Agent 开一个新回合接着干;quiet:只把结果塞进主 Agent 上下文,不打断它正在做的事。
如果子 Agent 跑偏了,主 Agent 还有三个管理工具兜底:list_agents 看看哪些还活着(状态分 running 干活中 / idle 空闲 / ready 只在存储里可恢复),send_message 给某个子 Agent 补一句要求,interrupt_agent 叫停一个跑偏的家伙。这才是真正的消息传递,不是发出去就撒手不管。
四、用 workflow 写编排脚本:从「手动派活」到「自动流水线」
单个任务手动派活够用,复杂编排就得靠 workflow 工具了。它的思路很硬核:模型写一段 JavaScript,引擎在 worker_threads 里跑。脚本里有三个原语:
1 | // 一个 workflow 脚本(模型生成,执行前先做 meta 校验) |
agent() 建单个子 Agent,pipeline() 让每个条目依次流过所有阶段(条目 A 走到第三阶段时,条目 B 可能还在第一阶段,互不等待),parallel() 则是栅栏——所有任务全部完成才继续下一步。两者的选择也很简单:只有当后面的阶段真的一次性需要前面所有结果(比如全量去重、决定要不要继续)时才用 parallel(),否则用 pipeline() 更快,它耗时等于「最慢的那条链」,而不是「所有阶段之和」。
防失控有三道保险:maxTotalAgents 限制单次运行最多能 agent() 出多少个子 Agent;signal(AbortSignal)可以中途取消;meta 在执行前先校验,引擎绝不靠「跑一下脚本」来提取元信息。
五、Ralph loop:长任务不掉链子的秘诀
还有个大杀器叫 Ralph loop(ralph 工具),专门治「长会话考古病」。它的规则很死:
- 目标不可变(immutable objective):一轮轮跑,目标不许漂移;
- 每轮一个全新子会话:不继承父会话、也不继承上一轮的对话;
- 跨轮只传一份「交接报告」(handoff):
{ status, summary, evidence, nextSteps, blockerText }。
所以 Ralph 每轮都把考古垃圾扔掉,只保留一份有界的结构化交接——上下文永远跟眼前这步的活成正比。适合「写一篇长文」「分阶段重构代码」这种有终点、但一轮干不完的活。它和 workflow 的区别在于:workflow 是通用编排(模型写任意 JS),Ralph 是固定策略(新子会话 + 交接报告),拿不准就先 workflow,要跑长迭代任务再上 Ralph。
六、避坑指南
先确认工具真挂上了。子 Agent、workflow 这些全是插件,挂没挂取决于你的模式和 profile 堆的 bundle。设计编排之前,先跑
dsh --profile web --dump-config看一眼有哪些工具,别对着一个没挂载的工具空想编排。fork 别滥用,会浪费 token。
subagent_fork会把当前会话历史一起塞给子 Agent,如果子任务根本不需要这些上下文,纯属白烧 token。可分离的任务一律用subagent新建。子 Agent 不是拿你的工具副本。子 Agent 有自己独立的 scope,工具可以被裁剪或替换——比如可以配一个「只读、绝不写文件」的审查员。这正是预设(preset)能实现「只读审查者」的机制。
list_agents 有范围参数。默认
scope: 'children'只列直系子 Agent;scope: 'descendants'会按序走完整棵子树,并标注每个节点的父会话和深度。send_message只能发给深度 1 的子 Agent,再深层的只能interrupt_agent。多模型换着来更省钱。多 Agent 场景天然适合「什么活配什么模型」:研究型子 Agent 用 DeepSeek V4,需要强写作的子 Agent 换 Claude——dsh 一个 key 就能把多家模型接上,多模型对接、价格还便宜,折腾阶段尤其划算(中转站配置见前几篇,ai.aklibk.com)。
五套工具串起来,dsh 就从「单兵 Agent」进化成了「能组队、能调度、能交接的项目经理」。下一篇我们换个角度:不再只用一个模型干到底,而是把 settings.yaml 玩明白。
生命不息,折腾不止。下一篇:《DeepSeek Harness 配置调优与模型切换实战》——settings.yaml 深入、多 provider 配置、按场景给不同 Agent 配不同模型,敬请期待。