02 · 三个工具,就是全部编排
上一篇结尾说,主 Agent 的派人干活能力来自三个普通工具。这篇把它们摊开看。先换一个任务。上一篇那个加手机号登录是你大致知道该怎么做的活儿,这次换一个你不知道的:支付回调偶尔重复扣款,线上一天两三次,你查一下为什么,能修就修。停下来想一想:你现在能画出一张任务图吗?画不出来。因为该修什么完全取决于是什么原因——可能是回调根本没做幂等,可能做了但幂等键选错了,可能幂等状态存在进程内存里而线上是多实例,也可能是订单状态机允许了一个非法的重复流转。这四种情况要写的代码毫无共同之处。这就是这篇要讲的事:图不能事前规划,只能一边看一边长。三个工具就是让它长出来的全部装置。工具一:spawnSubagent先看它的完整定义。注意这是一个标准的 ReAct 工具,和readFile的结构没有任何区别:// workflowTools.ts{name:spawnSubagent,description:Create a subagent to complete a task.,inputSchema:{type:object,properties:{task:{type:string,minLength:1},role:{type:string,enum:[explorer,reviewer,planner,executor]},dependsOn:{type:array,items:{type:string,minLength:1}},toolHints:{type:array,items:{type:string,minLength:1}},timeoutMs:{type:integer,minimum:1},},required:[task],},isConcurrencySafe:()true,invoke({input}){constconfigparseCreateSubagentInput(input);returnJSON.stringify({subagentId:orchestrator.createSubagent(config,availableTools)});},}几个细节值得停一下:只有task是必填的。主 Agent 最少只需要说干什么,角色默认是explorer(最安全的只读角色)。invoke是同步的,而且立刻返回。它不等子智能体跑完——只是登记一个节点,拿到subagentId就回来了。这个设计是派人和等结果必须分成两个工具的原因:如果spawnSubagent阻塞到结束,就没法先派三个再一起等,并行也就没了。isConcurrencySafe: () true。还记得上个系列讲的并发分批吗?这个标记让主 Agent 可以在一次模型回合里同时派出多个子智能体。三个spawnSubagent调用会被归进同一个并行批次。工具二:waitForSubagents{name:waitForSubagents,description:Wait for subagents to finish and return their results.,inputSchema:{type:object,properties:{subagentIds:{type:array,items:{type:string,minLength:1}}},required:[subagentIds],},isConcurrencySafe:()true,asyncinvoke({input}){constsubagentIdsparseStringArray(input,subagentIds);constresultsawaitorchestrator.waitForSubagents(subagentIds);returnJSON.stringify({results:Object.fromEntries(results)asRecordstring,SubagentResult});},}这个是async的,会真的等。等的实现很朴素:// workflowOrchestrator.tsasyncwaitForSubagents(ids){constrequestedids.map((id){constentryentries.get(id);if(!entry)thrownewError(Subagent${id}not found);return[id,entry.result]asconst;});constresultsawaitPromise.all(requested.map(async([id,result])[id,awaitresult]asconst));returnnewMap(results);}每个子智能体在登记时就挂了一个 Promise,waitForSubagents就是Promise.all它们。注意这里没有轮询、没有超时参数——超时是子智能体自己的事(第 05 篇会讲),等的这一方只管等。工具三:cancelSubagentinvoke({input}){constsubagentIdparseStringProperty(input,subagentId);if(!orchestrator.cancelSubagent(subagentId)){thrownewError(Subagent${subagentId}was not found or is already finished);}returnJSON.stringify({subagentId,cancelled:true});}值得注意的是取消失败会抛错。主 Agent 如果想撤回一个已经跑完的子智能体,会收到一条明确的Tool error,而不是静默的成功。这让模型能知道自己的世界模型过期了。任务图是长出来的,不是规划出来的这是整个架构最容易误解的地方。很多人想象的多智能体是这样:模型先输出一张完整的任务图(JSON 格式的 DAG),然后引擎照着图执行。LoopAgent 不是这样。它没有先给我一张图这一步。图是主 Agent 在自己的 ReAct 循环里,一次一个节点长出来的。回到开头那个重复扣款的任务:主 Agent step 1: spawnSubagent(task找支付回调入口,看有没有幂等校验) → 图: {A} 主 Agent step 1: spawnSubagent(task查订单状态机允许哪些重复流转) → 图: {A, B} (同一回合,并行) 主 Agent step 2: waitForSubagents([A, B]) → 阻塞,等结果 主 Agent step 3: 看到 A 的结论,才知道该派谁 spawnSubagent(task???, roleexecutor) → 图: {A, B, C} 主 Agent step 4: waitForSubagents([C])第 3 步那个???是这篇的全部重点。它填什么,取决于 A 说了什么:A 的结论C 实际会是什么回调里完全没有幂等校验在入口加幂等键,用out_trade_no做唯一索引有幂等校验,但键用的是自增 id换成业务唯一键,补一条 migration有幂等,但状态存在进程内存的 Map 里挪到 Redis,顺带要处理线上多实例的滚动发布幂等没问题,是状态机允许了重复流转根本不碰回调,改OrderState的迁移表四种结论对应四个完全不同的 C。没有任何一张事前画好的图能覆盖这四种分支——除非你把四个分支全画进去,然后运行时丢掉三个,那不叫规划,那叫穷举。这是 ReAct 的本质优势:它能根据观察结果调整计划。✶ 动态成图 vs 预先规划预先规划的好处是可以做全局优化(比如提前算出最优并行度)。动态成图的好处是能对现实做出反应。在代码任务里,你几乎永远不知道下一步该干什么,直到你真的看了代码——所以动态成图几乎总是对的选择。代价是:你无法在开始时告诉用户这个任务要跑 7 步。每插一个节点,就验一遍图既然图是一个节点一个节点长的,那就有个风险:主 Agent 可能声明出一个循环依赖(A 等 B,B 等 A),或者依赖一个不存在的节点。createSubagent在真正登记之前,先做一次校验:// workflowOrchestrator.tscreateSubagent(config,availableTools){if(entries.sizelimits.maxSubagentsPerRun){thrownewError(Max subagents per run (${limits.maxSubagentsPerRun}) exceeded);}constidsubagent-${nextId};constdependencies[...(config.dependsOn??[])];constnextGraphnewMap(graph);// ← 先拷一份nextGraph.set(id,newSet(dependencies));// ← 在副本上试插constvalidationvalidateDAG(nextGraph,limits);if(!validation.valid)thrownewError(validation.error);// ← 不合法就抛真图未被污染// ...校验通过后才 graph.set(id, ...) 和 entries.set(id, entry)}注意const nextGraph new Map(graph)这一句。校验跑在副本上,不在真图上。所以一个非法的spawnSubagent调用抛错之后,真实的图和之前完全一样——不会留下一个半登记的坏节点。这个先在副本上试,通过了再落地的模式,是保证状态机不会进入中间态的标准做法。校验器做三件事// workflow/dagValidator.tsexportfunctionvalidateDAG(graph:ReadonlyMapstring,ReadonlySetstring,limits:PickWorkflowLimits,maxNestingDepth,):DAGValidationResult{for(constdependenciesofgraph.values()){for(constdependencyIdofdependencies){if(!graph.has(dependencyId))return{valid:false,error:Unknown dependency:${dependencyId}};}}if(detectCycle(graph)){return{valid:false,error:Circular dependency detected in subagent graph};}constdepthcalculateDAGDepth(graph);if(depthlimits.maxNestingDepth){return{valid:false,error:Subagent nesting depth (${depth}) exceeds limit (${limits.maxNestingDepth}),};}return{valid:true};}悬空依赖、环、深度超限。前两个好理解,第三个有个容易误读的地方,值得单独说。maxNestingDepth限制的不是嵌套默认值是 3:// workflowOrchestrator.tsconstDEFAULT_LIMITS:WorkflowLimits{maxSubagentsPerRun:50,maxNestingDepth:3,maxConcurrentSubagents:10,subagentTimeoutMs:60_000,maxSubagentTimeoutMs:300_000,};看名字,你会以为它限制的是子智能体能不能再派子智能体,最多派几层。不是。看深度是怎么算的:// workflow/dagValidator.tsexportfunctioncalculateDAGDepth(graph:ReadonlyMapstring,ReadonlySetstring):number{constdepthsnewMapstring,number();constdepthOf(id:string):number{constcacheddepths.get(id);if(cached!undefined)returncached;constdepthMath.max(0,...Array.from(graph.get(id)??[],depthOf))1;depths.set(id,depth);returndepth;};returnMath.max(0,...[...graph.keys()].map(depthOf));}它算的是依赖链的长度。测试里写得很清楚:// test/workflow/dagValidator.test.tsconstgraphnewMapstring,Setstring([[root,newSet()],[build,newSet([root])],[test,newSet([build])],]);expect(validateDAG(graph,{maxNestingDepth:3})).toEqual({valid:true});expect(validateDAG(graph,{maxNestingDepth:2})).toEqual({valid:false,error:Subagent nesting depth (3) exceeds limit (2),});root → build → test三个平级的子智能体,串成一条依赖链,深度就是 3。它们全都是主 Agent 的直接下属,没有任何嵌套。那真正的嵌套呢?在这套实现里根本不可能发生。因为四个角色的工具白名单里,没有任何一个包含spawnSubagent——子智能体拿不到派人的工具。层级恒定是两层:主 Agent 子智能体。✶ 一个名字带来的误解maxNestingDepth这个名字描述的是设计者当初的意图(限制递归深度),但代码实际实现的是依赖链长度限制。两者在子智能体不能派子智能体的前提下,恰好都是有意义的约束,所以这个偏差一直没暴露成 bug。读代码时遇到名字和行为不一致,信行为,不信名字——这也是为什么上面每个结论我都贴了测试断言。接线:workflow 工具是可选的最后看这三个工具怎么装到主 Agent 上:// model/providerRegistry.tsif(deps.enableWorkflowToolsfalse)returncreateParentRunner(parentTools,deps.requiredToolNames,REACT_SYSTEM_PROMPT);return{async*run(request){consteventscreateAsyncQueueHostToWebviewMessage();constorchestratorcreateWorkflowOrchestrator({/* ... */});constunsubscribeorchestrator.onEvent((event)events.push(toHostMessage(event,request.runId)));constworkflowToolscreateWorkflowTools({orchestrator,availableTools:parentTools,});consttools[...parentTools,...workflowTools];// ← 就是数组拼接// ...},};enableWorkflowTools false时直接返回普通的单智能体 runner,一行编排代码都不执行。开启时,也只是[...parentTools, ...workflowTools]——把三个工具拼进数组。多智能体在这里是一个纯增量能力。这也解释了为什么它能不动 ReAct 循环就接上:对循环来说,工具箱里多三个工具,和多三个文件读写工具,没有任何区别。全景:四层,一个写入口把前面所有零件拼起来看:策略层 · workflow/编排层 · workflowOrchestrator.ts工具层 · workflowTools.tstool_calltool_calltool_call① 在 Map 副本上试插② 合法才放行③ 落地③ 落地④resolveRole selectTools建节点时就定死工具每个 entry 持有一个读快照做决策点名 ready 节点finally · 释放槽位resolveResult()结论回到上下文模型在 ReAct 循环里决定下一个节点是什么spawnSubagent同步,立刻返回 idwaitForSubagentsasync,真的等cancelSubagent失败会抛错createSubagent()graphid → 依赖集合拓扑,只增不改entriesid → 运行时状态含一个待 resolve 的 Promiseschedule()无状态,每次现算start()settle()幂等dagValidator环 / 未知依赖 / 深度roleRegistry角色 → 工具白名单subagentContext状态机 深冻结快照这张图里有两件事值得单独指出来。图只有一个写入口。所有对graph的修改都必须经过createSubagent,而它进门第一件事就是在副本上跑校验。没有任何旁路能往图里插节点——包括子智能体自己,因为上一节说过,四个角色的工具白名单里都没有spawnSubagent。图的形状只由主 Agent 决定。schedule()被两处调用,构成了整个引擎的时钟。一条是图变大了(createSubagent末尾),一条是有节点跑完了(start()的finally)。除此之外没有轮询、没有定时器推动执行。图的可执行状态只会因为这两件事变化,所以只需要在这两个时刻重新点名。图长出来了,节点登记好了。但谁决定哪个节点先跑?下一篇讲调度器。关于 LoopAgent本文代码来自 LoopAgent。涉及的文件:src/extension/agent/workflowTools.ts — 三个工具的定义src/extension/agent/workflowOrchestrator.ts — 编排器主体src/extension/agent/workflow/dagValidator.ts — 图校验src/extension/model/providerRegistry.ts — 接线欢迎点个 star ⭐项目地址:https://github.com/oi12344/loopagent-vscode 上一篇:01 · 一个 Agent 不够用的那一刻 下一篇:03 · 谁能跑,谁得等

相关新闻

基于SpringBoot的农家乐服务系统(源码+lw+部署文档+讲解等)

基于SpringBoot的农家乐服务系统(源码+lw+部署文档+讲解等)

联系博主 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 …

2026/8/22 17:06:52 阅读更多 →
基于SpringBoot的农产品销售系统的设计与实现(源码+lw+部署文档+讲解等)

基于SpringBoot的农产品销售系统的设计与实现(源码+lw+部署文档+讲解等)

联系博主 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 …

2026/8/22 17:06:52 阅读更多 →
基于SpringBoot的农产品销售系统(源码+lw+部署文档+讲解等)

基于SpringBoot的农产品销售系统(源码+lw+部署文档+讲解等)

联系博主 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 …

2026/8/22 17:06:52 阅读更多 →

最新新闻

MathorCup大数据赛题解析:需求预测与库存优化一体化建模实战

MathorCup大数据赛题解析:需求预测与库存优化一体化建模实战

1. 项目背景与赛题核心剖析2023年第四届MathorCup高校数学建模挑战赛的大数据竞赛B题,是一个典型的、将商业智能与运筹学深度结合的实战案例。它没有停留在单纯的数据分析或模型构建层面,而是直指企业运营中最核心、也最棘手的两个问题:需求预…

2026/8/22 19:41:49 阅读更多 →
Git与GitHub零基础入门:从版本控制到团队协作实战指南

Git与GitHub零基础入门:从版本控制到团队协作实战指南

这次我们来看 Git 和 GitHub 的零基础入门。对于刚接触编程或协作开发的新手来说,Git 的命令行和 GitHub 的复杂界面常常是第一个“劝退点”。但事实上,掌握它们的基础操作并不难,核心在于理解几个关键概念和一套固定的工作流程。这篇文章的目…

2026/8/22 19:41:49 阅读更多 →
专科生AI时代求职:8大工具与差异化策略

专科生AI时代求职:8大工具与差异化策略

1. 专科生如何应对AI时代的挑战作为一名专科院校的学生,面对AI技术的快速发展,确实会感到不小的压力。但我要告诉你的是,AI不是洪水猛兽,而是可以为我们所用的工具。关键在于如何正确认识AI,并找到适合自己的应对策略。…

2026/8/22 19:41:49 阅读更多 →
资源感知知识蒸馏在多智能体强化学习中的实践与优化

资源感知知识蒸馏在多智能体强化学习中的实践与优化

1. 项目概述:当多智能体强化学习遇上“瘦身”难题在工业自动化、机器人集群协同、甚至是游戏AI的研发前线,多智能体强化学习(MARL)正从一个前沿研究课题,迅速演变为解决复杂协同决策问题的核心工具。然而,一…

2026/8/22 19:41:49 阅读更多 →
基于LangGraph与Pydantic的多智能体教育游戏生成框架解析

基于LangGraph与Pydantic的多智能体教育游戏生成框架解析

1. 项目缘起:当教育游戏设计遇上多智能体协同最近在探索AI与教育技术结合的落地场景时,我一直在思考一个问题:如何将高质量的教育内容,高效、规模化地转化为真正吸引学生的互动游戏?传统的教育游戏开发,要么…

2026/8/22 19:41:49 阅读更多 →
农业边缘视觉识别:轻量模型+物理先验的实战落地

农业边缘视觉识别:轻量模型+物理先验的实战落地

1. 这道赛题到底在考什么:剥离竞赛外壳,看清图像识别的真实战场“亚太数学建模竞赛A题:水果采摘机器人的图像识别技术”——光看标题,很多人第一反应是“不就是用YOLO跑个检测框?再加个分类模型分个苹果香蕉&#xff1…

2026/8/22 19:40:49 阅读更多 →

日新闻

沉金PCB工艺实战指南:从设计到SMT焊接的可靠性保障

沉金PCB工艺实战指南:从设计到SMT焊接的可靠性保障

在电子硬件开发领域,PCB(印制电路板)的沉金工艺是提升产品可靠性和焊接质量的关键环节。对于需要高密度互连、长期稳定运行或高频信号传输的板卡,如“黍姐仿通行证”这类可能涉及身份识别、数据交互的硬件项目,选择正确…

2026/8/22 0:00:11 阅读更多 →
电气考研电路八月强化四步法:从知识体系到真题实战的闭环攻略

电气考研电路八月强化四步法:从知识体系到真题实战的闭环攻略

这次我们来看一个针对电气考研电路科目的学习规划项目。它不是软件工具,而是一套聚焦于8月份关键节点的备考策略。对于电气工程考研的同学来说,电路分析是专业课的重中之重,也是拉开分差的关键。进入8月,复习进入强化阶段&#xf…

2026/8/22 0:00:11 阅读更多 →
消除AI代码的“AI味”:Claude Code设计优化技能配置与实战指南

消除AI代码的“AI味”:Claude Code设计优化技能配置与实战指南

大家好,我是专注于前端开发与AI工具实践的技术博主。在日常使用 Claude Code 等AI编程助手时,你是否也遇到过这样的困扰:生成的代码功能上没问题,但代码风格、组件设计、交互逻辑总透着一股“AI味”——布局单调、样式简陋、交互生…

2026/8/22 0:00:11 阅读更多 →

周新闻

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

如果你是一名开发者,最近可能已经感受到了AI大模型正在从“玩具”变成“生产力工具”的强烈信号。从代码补全到智能Agent,从本地部署到云端API,我们正处在一个技术栈快速重构的节点。然而,面对层出不穷的模型、框架和工具&#xf…

2026/8/21 3:21:33 阅读更多 →
工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/22 8:09:09 阅读更多 →
【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…

2026/8/21 6:07:56 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/22 18:08:39 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/22 7:31:03 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/22 3:22:48 阅读更多 →