目录
- 什么时候派、怎么派
- 给分身划好边界
- 干完了,交回什么
- 写在最后
有些活,一个人做太慢:一次要查清三个模块的调用关系,或者把一批文件逐个审一遍。让 AI 一件件做,也是一样的慢。
WES Code 的 AI 可以把这类活拆开,派出几个子 Agent 分头去做。每个子 Agent 是一个临时的分身,在自己的环境里独立干活,干完把结论交回来,主 Agent 再汇总。
什么时候派、怎么派
什么时候会派。派不派,由 AI 自己判断。这个工具的使用说明里写了三种适合派的情况:
- 有个子任务比较复杂,需要单独用一套工具,或者换一种专长来做
- 有几件事互不相干,可以放到后台同时跑
- 已经注册了一个更合适的专用 Agent
简单的事它会自己直接做,不会为了一个小活专门派人。
子 Agent 是独立运行的,看不到主对话的历史。所以派活时,任务说明要写得完整、自成一体,参数说明里也专门提醒了这一点。
派活的几种方式。派一个子 Agent,最基本的是两个参数:prompt写清要它做什么,description写一句不超过 80 个字的简短说明,显示在界面和日志里。在这个基础上,还有几种派法:
| 方式 | 怎么用 |
|---|---|
| 指定专用 Agent | 用subagent_type指定一个注册好的 Agent;不指定,就复制一份当前 Agent 的配置 |
| 放到后台跑 | run_in_background设为 true,立刻拿到一个task_id,主 Agent 接着干别的,之后凭task_id查结果 |
| 一次派一批 | 用tasks一次给多个任务,最多同时跑 3 个,结果一起交回 |
| 换个模型 | 用model给这个子 Agent 单独指定模型 |
专用 Agent 不只是内置的那几个。在 WES Code 的 Agent 编辑器里,你可以自己建一个:名字、描述、系统提示词、用哪个模型、能用哪些技能,甚至头像都能设。建好的 Agent 和预设的一样,登记在引擎的 Agent 注册表里,派活时用subagent_type指名就行。
子 Agent 用哪个模型,按这个顺序定:这次派活单独指定的,优先;其次是专用 Agent 自己配置的;都没有,就用主 Agent 正在用的那个,也就是你在对话里选的模型。
给分身划好边界
分身多了,最要紧的是管住它们能做什么。派活时,可以给每个子 Agent 划三道边界:
read_only:只读。写文件、改文件、打补丁、跑命令统统禁掉,适合分析和审查tools_allow:只给指定的工具,比如只给 read、grep、glob,做一个纯粹的调研员。它只会在主 Agent 已有的工具里收窄,不会多出主 Agent 没有的工具work_scope:只让它在某个子目录里干活,比如src/auth
另外还有一道默认的边界:子 Agent 默认是「叶子」角色,不能再往下派分身,也不能直接弹卡片问你,问题统一由主 Agent 来问。需要它继续往下分派时,可以设成「编排者」角色。指定专用 Agent 时,它的权限还会再按主 Agent 的权限收紧一遍,分身的权限不会超过派它的人。
我把引擎给子 Agent 定权限的那段规则节选出来,喂了 4 种派活方式,看每个分身最后能用什么:
// 给子 Agent 定权限:照 runner.go 里 delegate 的那一段写,只保留角色和这次派活自带的限制funcchildPolicy(task engine.DelegationTask,params engine.RunParams,parentWorkDirstring)engine.RunParams{varroleDeny[]stringswitchtask.Role{caseengine.DelegationRoleOrchestrator:roleDeny=[]string{"ask_user"}default:// leaf — childMustDenyTools = {agent, ask_user}roleDeny=append([]string(nil),childMustDenyTools...)}params.ToolDeny=mergeUnique(params.ToolDeny,roleDeny)iftask.ReadOnly{params.ToolDeny=mergeUnique(params.ToolDeny,[]string{"write","edit","apply_patch","exec",})params.WorkspaceAccess="ro"}iflen(task.ToolsAllow)>0{iflen(params.ToolAllow)==0{params.ToolAllow=task.ToolsAllow}else{params.ToolAllow=intersect(params.ToolAllow,task.ToolsAllow)}}iftask.WorkScope!=""{scopedDir:=filepath.Join(parentWorkDir,task.WorkScope)params.WorkDir=scopedDir params.AllowPaths=[]string{scopedDir}}returnparams}// 4 种派活方式cases:=[]struct{namestringtask engine.DelegationTask}{{"1 默认派一个子 Agent",engine.DelegationTask{}},{"2 派一个编排者",engine.DelegationTask{Role:engine.DelegationRoleOrchestrator}},{"3 只读调研员",engine.DelegationTask{ReadOnly:true,ToolsAllow:[]string{"read","grep","glob"}}},{"4 只管 src/auth",engine.DelegationTask{WorkScope:"src/auth"}},}运行结果:
1 默认派一个子 Agent 禁用:[agent ask_user] 只允许:[] 工作目录:/home/dev/shop 访问:rw(默认) 2 派一个编排者 禁用:[ask_user] 只允许:[] 工作目录:/home/dev/shop 访问:rw(默认) 3 只读调研员 禁用:[agent ask_user write edit apply_patch exec] 只允许:[read grep glob] 工作目录:/home/dev/shop 访问:ro 4 只管 src/auth 禁用:[agent ask_user] 只允许:[] 工作目录:/home/dev/shop/src/auth 访问:rw(默认)「只允许」是空的,表示沿用主 Agent 的全部工具。只读调研员那一行最能说明问题:禁掉了 6 个工具,只剩 read、grep、glob 三个,访问方式也变成了只读。
干完了,交回什么
子 Agent 干完,交回的不只是一段结论。结论后面还附着一份改动报告:改了哪些文件,每个工具用了几次,一共调了多少次工具。上面测试的最后一段,就是这份报告的样子:
[side-effects] Files modified: src/auth/login.go, src/auth/login_test.go Tools used: read:6, edit:3, exec:5 Total tool calls: 14主 Agent 看一眼就知道分身动了哪里。子 Agent 改过的文件,也会同步记到主 Agent 名下,后面要回头核对时不会漏掉。
一次派一批的时候,交回的是一份汇总:每个任务的说明、状态、结果和用了多久,一个都不少。
同时能派多少,也有默认的护栏:
- 同时运行的 Agent 最多 10 个,每个 Agent 最多带 8 个子 Agent
- 分身最多往下派 3 层,不会无限地层层分派下去
- 单个子 Agent 忙着跑工具时最多 20 分钟,两轮之间闲着时最多 5 分钟
写在最后
把活拆给几个分身,难的从来不是「派出去」,而是「管得住」:每个分身能用什么、能碰哪里、做完了改了什么,都要清清楚楚。WES Code 把这些都做进了派活这一步。下次遇到一大批相互独立的活,不妨直接跟 AI 说一句:「分头去做」。
文中的子 Agent 是 WES Code 里的功能,官网是 weisyn.com。你平时会让 AI 一次做一件事,还是让它分头并行,欢迎评论区聊聊。
觉得有用的朋友,欢迎点赞、收藏、关注,后面会继续分享 AI 编程的实战经验。