附录 C|委托是能力加工具,不是循环里的条件分支
先别给子代理做一棵权限树
第 08 章拆作用域时说过一句话:父子是血缘数据,不是一棵往下传工具的树;"这里的委托、长期任务续跑机制,也是同一种数据"。现在把委托这条线补上。
第一次做"让 Agent 派活给子 Agent"的人,几乎都会写同一个东西:在循环里加一个"需要委托"的条件分支,子 Agent 直接构造出来,继承父亲的工具集,开一个新的循环跑完,把结果塞回父亲的消息数组。
这条路同时踩中三个坑:循环长出委托分支、子代理的工具集变成父亲工具集的下传、委托深度变成继承深度。这个系统把三件事拆成了三处,循环一个都不碰。
1. 委托是一条能力,而且"多个实现者可以共存"
先给判断:子代理这个能力不是"一个实现",是"多个命名实现者共存的注册表"。这和第 06 章 shell 能力那种"一个上下文一个实现"是不同的形状。
这条能力家族让一个 Agent 把活派给子 Agent,多个命名实现者可以在同一个上下文里共存。角色分布是:一个能力定义(拥有实现者的注册、委派动作、续跑逻辑);两个进程内实现者(一个开全新子会话,一个从父亲的历史分叉出子会话);若干个进程外实现者(对接不同的外部自动化协议或第三方助手);以及面向模型的工具、控制工具、子代理向父代理汇报的通道这几个消费者。
能力定义说得更直白:调用方只用一个服务接口,具体的实现者决定孩子在这个进程内、另一个进程、还是未来某种传输方式上运行。
这就是第 03 章"创建走工厂"在委托上的投影。循环只提供一个创建 Agent 的工厂接口;"在哪个进程运行、怎么分叉、要不要给模型挂委托工具"全是能力这一侧的事。第 03 章已经看过证据:进程内实现者创造孩子时,打的是父 Agent 自己持有的那份接口注册表,不是直接构造一个具体循环实现的实例。
如果没有这层会怎样?每个要委派任务的插件都得直接依赖循环、自己造孩子、自己管回收。不同的委托方式各自实现一套"开孩子"的逻辑,各自一套取消语义。现在它们共享同一份合同,只差一个具体实现者的名字。
2. 血缘是数据,不捐赠可见性
先给判断:父会话标识、委托深度这些是带在身上的事实,用于计数、授权、追溯谱系,唯独不用于"孩子看见哪些工具"。
这条能力自己拥有一套深度词表——运行时可以指定的深度选项、断言最大深度的检查、从一个 Agent 推算它当前委托深度的方法。落盘的委托深度是权威且单调的:运行时的深度选项只能加深,绝不能降低,所以一个被恢复的子代理不会被重新算成顶层。深度信息和分叉时用作种子的边界,都归这条能力自己拥有——循环既不设置也不读取它们。
关键的一刀在这里:"是否继承父亲的对话上下文"这个标记是描述性的,不是可强制执行的。它只说孩子是否看见父亲已经完成的那部分对话历史(分叉方式看得见,全新子会话和进程外一次性方式看不见),不说它是否继承了工具、服务或权威。
第 08 章已经拆过作用域那半:子代理的作用域是全新的扁平作用域,唯一的"继承"通道是把孩子绑到父亲的常驻预设挂载点,而不是父亲自己的那个作用域钥匙。这里补上血缘这半——两者是两套机制:作用域管可见性,血缘管事实和授权,互不串。
如果没有这层区分会怎样?你会用父会话标识去推导"孩子该有哪些工具",用继承深度去算委托深度,权限树和会话树缠在一起。第 08 章的结论在这里有了对称的镜像:扁平两层作用域让"要么全局、要么就是这一个钥匙"成立,血缘数据让"这个孩子是分叉来的还是全新开的"成为日志里的一条事实,而不是一棵树的形状。
3. 权限边界在委派的那一刻固定
先给判断:孩子不是"继承父亲的权限",而是在委派边界被钉死一份权限快照,且审批被强制关成"从不询问"。
两条进程内的委派路径都通过一个共享的辅助逻辑,在委派边界固定孩子的权限范围:先快照父会话此刻显式生效的沙箱覆盖设置,再把孩子的审批策略强制钉成"从不询问"(只要审批能力被挂载)——不管父亲自己当前的策略是什么。所以被委派的孩子只在它继承到的沙箱范围内行动,每一个需要审批的请求(比如想升级自己的沙箱权限)都会被确定性地拒绝,而不是弹出一个根本没人会看的确认框。
孩子的运行时上下文里还会被塞进一条固定的说明文字:你是被委派的子代理,你的权限范围在启动时已经固定,不能从会话内部扩大——需要审批的操作会被自动拒绝;当工作确实需要超出这个范围时,不要重试被拒绝的操作,在回复里说明限制,让委派方去处理。
这和第 10 章"审批默认拒绝"、第 07 章"所有者政策走闸门、不能翻案"是同一句话,打在委派边界上:孩子能做什么,是它自己日志里可以重建的事实(一条明确标记为"来自委托"的沙箱模式和审批策略事件),不是父亲进程内存里的临时状态。
如果没有这层会怎样?一个被委派去"读代码"的子代理,可能弹出一个权限升级的审批框,等一个根本没人会点的按钮,整个委派卡死。或者孩子把父亲的完全放开权限一起继承过去,最小范围的委派也变成了全权代理。边界固定,让"委派"重新变成一个可控、可预期的动作。
4. 编排是模型写的脚本,跑出去的是一群子代理
先给判断:子代理能力提供的是一个子会话,而"编排"(workflow)能力提供的是模型自己写的一份脚本,跑在独立的工作线程里,把活扇出给一群子代理。
这条能力家族跑由模型自己撰写的编排脚本,构建在子代理能力之上,把通用编排工具和一些固定脚本工具暴露给模型。角色分布是:编排能力定义(拥有执行和生命周期事件)、在独立工作线程里真正跑脚本的实现者、把通用编排能力暴露给模型的消费者工具、以及暴露某个固定脚本的专门工具。
工作线程隔离的是主机的事件循环,不是一个安全边界。脚本运行在受限的执行环境里,脚本里"创建一个子代理"这类调用会通过内部通信回到主机进程,再走子代理能力真正扇出去。
第 06 章说"能力必须成套",编排能力是这条纪律用在"任务编排"上的样子:能力定义、真正跑脚本的实现者、面向模型的消费者,三者拆开。换一个脚本运行环境,不换模型看见的编排工具参数格式。
5. 一种固定脚本的持续迭代模式
先给判断:这是编排能力上的一个固定脚本,专门跑"每轮都是全新 Agent"这一种编排模式。它没有在循环内部加任何这种模式的特殊状态。
对应的模型工具跑一个固定的前台编排脚本,把一个不可变的目标交给一串全新的子 Agent 依次处理;没有给循环本身加任何这种特殊模式,同一个会话内部的长期目标机制也保持独立。
调用方式很简单:给出目标和最大轮数上限,等整轮全部跑完。每一轮都开一个全新的孩子,实现者必须支持结构化输出、且明确标记"不继承父亲的对话上下文"。孩子每轮只收到:不可变的目标、当前第几轮和上限、"共享工作区就是权威记忆"这条指令、以及上一轮留下的结构化交接报告。工作区是长期记忆;父亲的对话和之前几轮孩子的会话都不会被塞进去当种子。
这和第 08 章、本节第 2 点的血缘纪律完全一致:每一轮都是全新的孩子,继承关系只存在于"共享工作区 + 一份有边界的交接报告"这条显式通道,不存在于会话树上。完成状态和阻塞原因都是孩子自己上报的,不是外部独立验证的。
如果没有子代理和编排这两条能力,这种迭代模式会变成什么?循环内部会长出一个专门的模式分支,一个"全新孩子循环"直接写死在司机肚子里,换一种编排策略就要改循环。现在它只是一个固定脚本对应的工具,和通用编排工具共用同一套引擎和注册表。
6. 结语:带走一句话
委托是循环外面的能力(一个共享的子代理服务)加工具(委托/编排/固定脚本):血缘是数据、作用域是可见性、权限在委派边界钉死——循环只提供一个创建动作,谁在哪个进程跑、脚本怎么扇出、每轮全新 Agent 怎么迭代,全是旁边可换的插件。