能元 Harness:父层调度与子代理执行

我越来越倾向于把父Agent看成一种基础设施,而不是一个更勤奋的员工。它的价值不在于亲手完成所有事情,而在于把一项混杂的长期工作,整理成可以分派、等待、回收和继续推进的任务网络。

现在的大模型已经会使用工具。它能打开文件、运行命令、搜索资料,也能在一次对话里连续工作很久。于是我们很自然地让它从输入走到输出:先想一想,再做一步,再根据结果想下一步。短任务里,这种方式非常顺滑;问题一旦变长,对话就会变成一条越来越拥挤的走廊,需求、代码、日志、临时决定和未完成的事项全部堆在一起。它还会遇到一种更现实的麻烦:同一项工作在不同阶段需要不同的记忆。设计页面的人关心布局,数据分析的人关心单位,测试的人关心边界条件。让同一个上下文承载这些关注点,等于让每个角色不断把别人的材料搬进自己的桌面。

复杂工作真正缺少的,不是一个更大的聊天窗口,而是一个专门管理工作的上层。研究、编程、设计和验证本来就不是同一种劳动。它们有不同的上下文、不同的工具和不同的完成标准,却常常被塞进同一个Agent的连续记忆里。这个Agent当然可以轮流处理它们,但轮流处理和组织它们,是两回事。很多返工并不是某一步做错了,而是下一步根本没有拿到它所需要的前提。页面代理不知道字段会怎样命名,数据代理不知道页面需要怎样的筛选,报告代理又不知道哪些图表已经经过验证。它们各自给出合理结果,组合起来仍然无法交付。

比如,让AI做一个电力系统知识平台。文献子任务要找原文、整理术语和记录出处;数据子任务要定义字段、单位和时间范围;界面子任务要把这些内容变成可操作的页面;测试子任务要确认页面展示的数字没有被转换错。它们之间有先后,也有可以同时推进的部分。如果一个Agent按自己的感觉把这些工作串成一条线,最先发生的往往不是“做不出来”,而是做了很多不能互相接上的东西。

所以我想提出一个有些反直觉的原则:父Agent应当退出具体执行现场。它保留理解目标、拆分任务、安排顺序和选择模型的权力,却把检索、写代码、制图、测试这些动作交给子代理。父层不是空闲下来,而是把注意力从“下一行该怎么写”换成“下一件该由谁来写”。这个原则也给出了一个很具体的权限划分:父层可以创建任务、暂停任务、改变路由、接受结果;子层可以读写自己的工作区、调用工具并生成产物。谁拥有哪一种权限,和谁承担哪一种责任,应该在系统里直接表达出来。

这和简单地启动几个Agent并不一样。几个并列的对话窗口,只是增加了执行者;一个真正的调度层,还要知道哪些工作彼此独立,哪些工作必须等待,哪种模型适合哪类输入,以及一个结果何时足够好,可以释放后面的节点。没有这层关系,所谓并行很容易变成同时制造几份互不兼容的成果。

能元Harness图表达的正是这种上下分离。Input先进入父层Think,父层利用Skills理解任务并生成Task_x;Task_x交给选择器,选择器从Arc、Thunder、Storm等候选模型中挑选执行者;Subagent接收具体work,完成后把结果送回父层Think。父层继续安排,或者在条件已经满足时形成Output。图里最重要的不是模型名字,而是箭头所规定的控制权。Input和Output位于图的两端,中间不是一条必须由同一个模型走完的通道。父层可以把一个任务拆成几条路径,也可以在某条路径返回后只释放其中一部分后续工作。Work回到Think,表示系统还在运行,而不是已经把所有事情交给了一个黑盒。

从这个角度看,父Agent不再是队伍里最忙的那个人,而更像一台有记忆的调度机器。它掌握的是任务之间的连接:谁提供材料,谁消费材料,谁需要复核,谁可以立刻开始。子代理掌握的是局部工作:在给定边界内调用工具,产出文件、数据或判断,并把可检查的结果交回来。

任务拆分:文献、数据与页面并行后汇合联调

父层也不需要把每个子代理的全部过程复制到自己的上下文中。它只需收到足够改变调度决定的信息:任务是否完成,产物在哪里,验证做到了哪一步,下一步需要什么输入。这样一来,父Agent可以同时管理许多工作,却不会因为某一项工作的细节过深而失去全局视野。在实际使用中,这种克制反而会让父Agent更可靠。它不需要为每次代码改动保留全部上下文,也不需要在一份长日志里寻找自己遗漏的决定。它只维护那些会改变调度的事实,执行者则维护那些会改变产物的细节。

这里的关键对象不是提示词,而是任务单。一个好的任务单至少说明四件事:要交付什么,手里有什么,完成后如何判断,以及完成后谁会使用它。它可以很短,但不能含糊。子代理不必猜测自己在整套工程中的位置,父层也不必靠回忆推断某个文件为什么会出现在工作区里。任务单还可以携带版本号。上游字段发生变化时,父层能知道哪些下游节点使用了旧版本,先暂停它们,再从新的输入重新派发。这样,系统面对变化时只回收受影响的部分,不必把已经独立完成的工作全部抹掉。

选择器处理的也不是“哪个模型最聪明”这种问题。它处理的是匹配:长文本抽取需要耐心和引用意识,代码迁移需要跨文件理解,批量格式转换需要稳定和速度,视觉草图需要对空间关系有更好的判断。Arc、Thunder、Storm只是可被调度的选项,真正的选择要看任务的输入、工具、时间和验收方式。

这使得模型不再像一个固定岗位上的员工,而像一组可以按需接入的能力。父Agent不必对每种能力都亲自熟练,只要能识别任务的性质,并知道用什么信号判断一次派发是否合适。

我把这套架构理解成一条不断回收结果的工作流。它没有要求父Agent从第一步一直思考到最后一步,而是让每一次完成都成为下一次调度的输入。

第一步不是执行,而是把用户的一句话改写成工作对象。父Agent先找出交付物:是一个可运行的页面,一组清洗后的数据,还是一份带出处的结论。接着找出材料和约束,确认哪些内容可以共享,哪些内容只能在特定环境里处理。最后才是拆分:文献检索、术语表和页面草图可以先同时开始,接口实现要等字段确定,联调要等接口和页面都出现。任务展开时,父层还应把“不能做什么”写进去。例如本地资料不能上传,某些文件只能读取不能修改,报告必须使用指定的单位。限制写得越清楚,子代理越少需要在执行中途停下来猜测,选择器也越容易找到符合条件的模型和环境。

这张拆分图和普通待办事项的差别,在于每一个节点都带着“被谁使用”的信息。文献代理交付的不只是几篇摘要,还要交付可被报告代理引用的原文位置;数据代理交付的不只是一个表格,还要交付字段含义和单位;页面代理交付的不只是截图,还要说明它依赖哪些接口。任务之间因此通过交付物相连,而不是通过一串模糊的“继续做下去”相连。如果一个节点的交付物会被多个下游使用,它就应当有更明确的格式。数据字典可以是结构化文件,文献节点可以附带页码和摘录,页面节点可以给出运行地址和截图。结构化交付让父层不必重新阅读全部内容,也让另一个模型能够直接接手。

*Skills在这里扮演的是边界说明书。它告诉父层有哪些可用的操作,也告诉子代理怎样使用这些操作。检索任务携带引文规则,代码任务携带测试规则,界面任务携带交互约束。不同子代理只拿到与自己有关的那部分能力,工作上下文因而保持轻量。

第二步是派发。选择器读取任务单,结合当前可用模型、并发额度和历史表现,给出一条路由。这个路由不必永久固定;同一类任务在不同时间可以交给不同模型。父层把任务单、相关Skills、文件范围和验收方式一起交给子代理,然后从执行现场退开。它不在旁边逐句指挥,而是等待可供判断的状态变化。派发时,父Agent还要决定子代理是否需要看到上游原始材料。很多时候,执行者只需要一份整理后的输入;把整个工程目录和全部聊天记录都交出去,并不会自然地产生更好的结果。上下文越接近任务边界,子代理越容易专注于自己的验收条件。

第三步是让任务自己流动。没有前置条件的节点进入队列,可以同时启动;有前置条件的节点保持等待。文献整理和页面草图完成后,父层不需要重新理解整项工程,只要把两份结果登记到任务账本里。数据字典一旦通过验收,接口节点自动获得启动条件;接口测试通过,联调节点才被释放。顺序来自数据和状态,而不是来自父Agent临时记住的一串步骤。这种流动可以由一个很小的状态机实现:待启动、运行中、等待输入、待验收、已完成。状态机不是为了增加形式,而是为了让父层知道“现在能做什么”。一个处于等待输入的节点不能被误认为失败,一个待验收的节点也不能直接被当成完成。

子代理返回的也不应只有一句“做完了”。它需要交回产物、位置、摘要和验证记录。父层据此更新账本:节点从运行变成完成,或从运行变成需要补充。父Agent的思考变成了对状态的读取和下一次派发,而不是对每个细节的亲自重做。如果验证没有通过,父层可以把节点退回原模型,也可以把同一份任务改派给另一个模型。两种做法都比让父Agent临时接管更容易追踪,因为工作仍然留在任务单和执行记录里。

第四步是汇总。最终输出不是把所有子代理的聊天记录拼在一起,而是根据任务图重新组织成用户要的东西。报告代理读取已核验的文献和图表,测试代理给出可以复现的结果,父层负责确认这些产物都已经进入正确的位置。于是Output不是某个模型的一次发挥,而是一串已完成节点的合成。汇总时还可以保留中间成果。用户也许只要最终报告,但父层应知道报告中的每个数字来自哪一张表、哪一张表来自哪个清洗节点。最终文档因此不是一次生成的文字,而是一条可以沿着产物反向检查的链。

这种安排会改变我们对效率的理解。并行的收益不在于子代理数量越多越好,而在于关键路径被缩短了多少。三个没有依赖的节点同时跑,等待时间接近其中最慢的一个;三个共享同一份未确定材料的节点同时跑,只会把返工提前。父Agent真正要优化的是等待关系,而不是屏幕上同时出现多少个运行中的窗口。所以调度器要关注的是关键路径和可复用产物。一次字段整理如果能同时服务接口、图表和报告,它的优先级就高于一个只影响局部展示的小修饰。父Agent在这里做的是资源安排,而不是对每个专业决定发表意见。

模型成本也可以因此按任务分层。简单清洗不必占用最强模型,复杂推理不必交给只追求速度的模型;能自动验收的节点可以快速循环,需要人判断的节点则保留清晰的预览。每次任务完成,系统记录模型、耗时、产物质量和验收结果,下一次选择就有了依据。模型路由因此不是一次性的配置,而是一张随着工作增长而更新的能力地图。随着这些记录累积,选择器甚至可以学到更细的条件:同一模型在短文本和长文本上的差异,在有工具和无工具时的差异,在一次性输出和多轮修改时的差异。模型能力不再是一张静态标签,而变成和任务类型绑定的经验。

这套架构和“多智能体协作”看似接近,重心其实不同。多智能体常常强调角色之间如何讨论、互相评价;这里首先关心的是控制流:谁创建任务,谁占用工作区,谁有资格推进下游,谁把结果写回账本。子代理可以互相不认识,只要它们遵守输入和输出的约定,父层就能把它们接到同一条工作链上。

用户最终看到的也不应是一群模型在后台喧闹,而是一张会变化的进度图。哪些任务正在并行,哪一个节点在等待,哪一份成果已经可预览,哪一个模型被安排在下一步,都可以被解释。父Agent把复杂性留在调度层,用户获得的是更少的等待和更清楚的选择。这也让用户可以在必要时介入正确的位置。用户不需要重新解释全部需求,只要对某个节点的产物做选择,父层就能沿着受影响的下游重新安排。人的判断被放在最有信息量的时刻,而不是被要求在任务开始时写完一篇完美说明。

回到那个电力系统平台:检索代理先把论文和原文位置交给资料节点,数据代理同时整理字段,页面代理先搭出不依赖真实数据的骨架。字段确认后,接口代理开始工作;接口和页面汇合后,联调代理接手;最后,报告代理使用已经登记的证据组织结论。父Agent没有亲手写一段代码,却一直知道工作走到了哪里,以及下一个可被释放的节点是什么。如果用户后来把“研究平台”改成“面向移动端的研究平台”,父层只需重开页面和交互节点,已经核验的文献与数据节点仍然可以复用。任务账本保存的是工作之间的关系,因而修改需求也能变成一次局部重排。

这也是我认为父Agent必须退出执行现场的原因。它一旦亲自接管某个局部任务,就会重新把全局调度和局部细节混在一起;它保持调度身份,任务才有机会被拆开、并行、暂停、回收和继续。Harness的核心不是让一个模型变得无所不能,而是让不同能力可以在一条可追踪的工作流中轮流上场。从工程角度说,这是一种把模型调用变成可组合部件的方式。模型可以更换,子代理可以重启,某个节点可以暂停,但任务的输入输出约定仍然稳定。系统的连续性不再依赖某一个模型始终记得全部故事。

父Agent不负责把每件事做完;它负责让每件事有地方开始,也有结果回来。