【从0开发一个 Agent】第十一章:构建 Planner
在前面的章节中我们赋予了 AI 工具调用、长期记忆、RAG 知识库和工程化 Prompt 等强大能力。但当你向它提出“帮我分析上周的销售数据生成一份包含图表的周报并发送给团队”这样的复杂指令时它依然会陷入混乱。它可能会在还没有获取数据时就尝试生成图表或者在发送失败后直接放弃而不是寻找替代方案。这是因为传统的 ReAct 模式思考-行动-观察在处理长链路、多依赖的复杂任务时存在严重的“上下文稀释”和“意图漂移”问题。本章我们将引入 Planner规划器与多 Agent 协作架构让 AI 从“单步执行者”进化为“项目管理者”。1. 为什么复杂任务不能一次完成在单 Agent 模式下模型需要同时承担“拆解任务”、“执行工具”、“整合结果”三重角色。随着任务步骤增加Prompt 中充斥着大量的中间状态和工具返回结果导致模型对最初目标的注意力被严重稀释。更致命的是ReAct 模式是串行的每一步都依赖上一步的输出一旦中间某个工具调用失败或返回非预期结果整个链路就会崩溃且模型缺乏“回溯重规划”的能力。Planner 的核心价值将“规划”与“执行”解耦。Planner 负责将复杂目标拆解为有向无环图DAG明确任务依赖关系Executor 负责按图执行当执行失败时Planner 能够基于当前状态进行局部重规划而不是推倒重来。2. Planner 架构设计从 ReAct 到 REWOO我们摒弃传统的串行 ReAct采用REWOOReason without Observation架构。它通过“一次性生成完整工具链”来减少 Token 消耗并通过“规划-执行-合并”三阶段实现稳定的复杂任务处理。REWOO 三阶段解析Planner规划器接收用户指令一次性生成包含多个相互关联计划的蓝图。每个计划都分配了变量如#E1供后续任务引用。Executor执行器根据 Planner 的蓝图循环执行任务。它不依赖 LLM 的实时推理而是直接调用工具将结果存入变量。Solver合并器将所有计划和执行结果结合起来形成最终解决方案。为什么选择 REWOO 而非 ReActToken 效率ReAct 每一步都需要 LLM 调用长任务会导致 Token 爆炸REWOO 只在规划和合并阶段调用 LLM中间执行阶段零 LLM 开销。稳定性ReAct 的串行依赖容易因单步失败而崩溃REWOO 的变量引用机制和重规划能力使其具备更强的容错性。可观测性REWOO 生成的任务 DAG 是结构化的便于前端可视化展示任务进度也便于后端进行断点续传和状态追踪。3. 核心代码实现3.1 Planner生成结构化任务 DAG我们使用 Zod 定义严格的任务输出格式确保 Planner 生成的计划是可执行的。// src/lib/planner/schema.tsimport{z}fromzod;exportconstTaskSchemaz.object({id:z.string().describe(任务唯一标识),name:z.string().describe(任务名称),description:z.string().describe(任务详细描述),tool:z.string().describe(需要调用的工具名称),params:z.record(z.any()).describe(工具参数可引用上游变量如 #E1),dependencies:z.array(z.string()).describe(依赖的上游任务ID列表),});exportconstPlanSchemaz.object({title:z.string().describe(计划标题),tasks:z.array(TaskSchema).describe(任务列表),});exporttypePlanz.infertypeofPlanSchema;在src/lib/planner/index.ts中实现 Planner// src/lib/planner/index.tsimport{generateObject}fromai;import{openai}from/lib/ai/config;import{PlanSchema}from./schema;exportasyncfunctioncreatePlan(userQuery:string,availableTools:string[]):PromisePlan{const{object}awaitgenerateObject({model:openai(gpt-4o),schema:PlanSchema,system:你是一个任务规划专家。请将用户指令拆解为可执行的任务DAG。 可用工具:${availableTools.join(, )}规则: 1. 任务必须原子化每个任务只调用一个工具。 2. 明确任务依赖关系确保DAG无环。 3. 参数中引用上游结果时使用 #E{taskId} 格式。 4. 如果任务无法完成不要编造返回空任务列表。,prompt:userQuery,});returnobject;}3.2 Executor按图执行与变量管理Executor 负责解析 Planner 生成的 DAG按依赖顺序执行任务并管理变量池。// src/lib/planner/executor.tsimport{Plan,Task}from./schema;import{getTool}from/lib/ai/tools;exportclassExecutor{privatevariablePool:Mapstring,anynewMap();privatetaskResults:Mapstring,anynewMap();asyncexecute(plan:Plan):PromiseMapstring,any{// 拓扑排序确保依赖任务先执行constsortedTasksthis.topologicalSort(plan.tasks);for(consttaskofsortedTasks){try{// 解析参数中的变量引用constresolvedParamsthis.resolveParams(task.params);// 调用工具consttoolgetTool(task.tool);constresultawaittool.execute(resolvedParams);// 存入变量池和结果集this.variablePool.set(#E${task.id},result);this.taskResults.set(task.id,{status:completed,result});}catch(error){this.taskResults.set(task.id,{status:failed,error:error.message});// 失败时触发重规划见下文constreplannedawaitthis.replan(plan,task.id,error);if(replanned){returnthis.execute(replanned);}thrownewError(Task${task.id}failed and replanning failed:${error.message});}}returnthis.taskResults;}privateresolveParams(params:Recordstring,any):Recordstring,any{constresolved:Recordstring,any{};for(const[key,value]ofObject.entries(params)){if(typeofvaluestringvalue.startsWith(#E)){resolved[key]this.variablePool.get(value);}else{resolved[key]value;}}returnresolved;}privatetopologicalSort(tasks:Task[]):Task[]{// 实现 Kahn 算法进行拓扑排序// ...returntasks;}privateasyncreplan(plan:Plan,failedTaskId:string,error:any):PromisePlan|null{// 调用 Replanner基于当前状态生成新计划// ...returnnull;}}3.3 Solver整合结果与生成最终响应// src/lib/planner/solver.tsimport{generateText}fromai;import{openai}from/lib/ai/config;exportasyncfunctionsolve(plan:Plan,results:Mapstring,any):Promisestring{constresultSummaryArray.from(results.entries()).map(([id,data])任务${id}:${JSON.stringify(data)}).join(\n);const{text}awaitgenerateText({model:openai(gpt-4o),system:你是一个结果整合专家。请基于以下任务执行结果生成最终的用户响应。 如果任务失败请向用户解释原因并提供替代方案。,prompt:计划:${JSON.stringify(plan)}\n执行结果:\n${resultSummary},});returntext;}3.4 在 API Route 中集成 Planner// src/app/api/chat/route.tsimport{createPlan}from/lib/planner;import{Executor}from/lib/planner/executor;import{solve}from/lib/planner/solver;import{getAvailableTools}from/lib/ai/tools;exportasyncfunctionPOST(req:Request){const{messages}awaitreq.json();constuserQuerymessages[messages.length-1].content;// 1. 判断是否需要规划简单问题直接回答constneedPlanningawaitcheckIfPlanningNeeded(userQuery);if(!needPlanning){returnstreamText({model:openai(gpt-4o),messages}).toDataStreamResponse();}// 2. 生成计划constavailableToolsgetAvailableTools();constplanawaitcreatePlan(userQuery,availableTools);// 3. 执行计划constexecutornewExecutor();constresultsawaitexecutor.execute(plan);// 4. 整合结果constfinalResponseawaitsolve(plan,results);returnnewResponse(JSON.stringify({content:finalResponse}),{headers:{Content-Type:application/json},});}4. 测试验证验证清单复杂任务拆解输入“分析上周销售数据并生成周报”验证 Planner 是否生成了包含“查询数据”、“生成图表”、“撰写报告”等步骤的 DAG。依赖关系正确性验证“生成图表”任务是否正确依赖“查询数据”任务的结果。失败重规划故意让“查询数据”工具返回错误验证 Executor 是否触发 Replanner 并生成替代方案如“使用缓存数据”或“询问用户是否重试”。变量引用解析验证下游任务是否正确接收了上游任务的结果如 #E1 被正确替换为实际数据。5. 常见问题与踩坑分析问题 1Planner 生成的任务 DAG 存在循环依赖原因模型对任务依赖关系的理解出现偏差生成了 A→B→A 的环。解决在 Executor 的拓扑排序阶段增加环检测。如果发现环直接返回错误并触发 Replanner而不是尝试执行。问题 2变量引用解析失败导致工具调用参数错误原因Planner 生成的变量名格式不规范或 Executor 的解析逻辑未覆盖所有引用场景。解决在 Planner 的 Prompt 中明确变量命名规范如 #E{taskId}并在 Executor 中使用正则表达式进行严格匹配和解析。问题 3Replanner 陷入无限重规划循环原因Replanner 生成的新计划依然包含失败的任务且没有改变执行策略。解决在 Replanner 中记录历史失败任务强制要求新计划必须避开已失败的任务或工具或引入“最大重规划次数”限制。本章总结我们剖析了 ReAct 模式在处理复杂任务时的局限性并引入了 REWOO 架构。实现了 Planner、Executor、Solver 三阶段协作机制支持任务 DAG 生成、按图执行和结果整合。构建了变量池和拓扑排序机制确保任务依赖关系正确执行。实现了失败重规划能力增强了 Agent 的容错性和鲁棒性。至此我们的 AI Agent 已经具备了拆解复杂任务、按图执行和失败重规划的能力真正实现了从“单步执行者”到“项目管理者”的跨越。但企业级应用不仅是单个 Agent 就能满足的。从下一章开始我们将实现多 Agent让你的 Agent 复杂任务能一次完成。

相关新闻

大学生HTML期末大作业——HTML+CSS+JavaScript音乐网站

大学生HTML期末大作业——HTML+CSS+JavaScript音乐网站

HTMLCSSJS【音乐网站】网页设计期末课程大作业 web前端开发技术 web课程设计 网页规划与设计💥 文章目录一、🏁 网站题目二、🚩 网站描述三、🎌 网站介绍四、🏴 网站效果五、🏳️ 网站代码六、&#x1f3f3…

2026/10/15 17:37:43 阅读更多 →
开源RPA工具OpenRPA终极指南:免费企业级自动化零基础入门

开源RPA工具OpenRPA终极指南:免费企业级自动化零基础入门

开源RPA工具OpenRPA终极指南:免费企业级自动化零基础入门 【免费下载链接】openrpa Free Open Source Enterprise Grade RPA 项目地址: https://gitcode.com/gh_mirrors/op/openrpa 想要实现业务流程自动化却担心高昂的软件费用?OpenRPA作为一款完…

2026/10/17 5:53:26 阅读更多 →
2026 年 GEO 优化服务商怎么选?先看技术路线和国内AI平台的适配度

2026 年 GEO 优化服务商怎么选?先看技术路线和国内AI平台的适配度

一、AI搜索普及,GEO成为企业数字营销刚需中国信通院《2026生成式搜索产业白皮书》数据显示,2026年国内GEO服务市场规模预计突破286亿元,全年增速达125%;企业级GEO服务渗透率达到48.2%,消费、制造、教育培训、B2B服务等…

2026/10/16 1:43:46 阅读更多 →

最新新闻

机器人与AI交汇:具身智能的技术脉络与工程落地指南

机器人与AI交汇:具身智能的技术脉络与工程落地指南

机器人搞了七十年的“身体”,AI搞了七十年的“脑子”,到了这两年,两条线突然开始往一起凑。搞机器人的发现光有精度不够,得让系统学会“看情况”;搞AI的发现光有模型不行,模型得有个身体去接触真实世界&…

2026/10/17 9:24:36 阅读更多 →
云原生架构实践:容器、镜像与Kubernetes核心机制精读笔记

云原生架构实践:容器、镜像与Kubernetes核心机制精读笔记

1. 先说结论:为什么这两章值得反复读拿到《阿里云云原生架构实践》这本书的时候,我原以为第二章和第三章还是那种"概念铺陈"式的章节,翻几页就能过去。但实际读下来发现,这两章恰恰是整本书最容易"一看就懂、一用就…

2026/10/17 9:24:36 阅读更多 →
从声浪到产线:AI落地、端侧智能与具身智能的产业真问题

从声浪到产线:AI落地、端侧智能与具身智能的产业真问题

过去这一年,我钻进会场的次数比往年多了不少。讲台上,嘉宾们几乎都用“前沿科技”四个字开场,恨不得把所有热词都装进一页PPT;但台下真正被反复追问、被围住加微信的,永远是那些能把技术换算成成本、良率、交付周期的人…

2026/10/17 9:24:36 阅读更多 →
PL/0编译器实验:保留字识别与ELSE语句扩展实现

PL/0编译器实验:保留字识别与ELSE语句扩展实现

简介:这份资源是面向计算机专业学生的编译原理实验配套资料,以经典教学型编译程序PL/0为改造对象,帮助学习者在读懂词法分析、语法分析与语义处理流程的基础上完成程序扩充任务。实验要求增加ELSE、FOR、TO、DOWNTO、RETURN等保留字&#xff…

2026/10/17 9:24:36 阅读更多 →
VSCode Remote-SSH + Copilot 远程AI编程环境搭建指南

VSCode Remote-SSH + Copilot 远程AI编程环境搭建指南

1. 项目概述:这不是“让ChatGPT连服务器”,而是打通本地开发环境与远程计算资源的神经通路Codex、ChatGPT、SSH、VSCode——这几个词堆在一起,很多人第一反应是“想用AI写代码,但本地算力不够,得把AI请求转发到有GPU的…

2026/10/17 9:24:36 阅读更多 →
DMD为什么需要“正确初始化“:Causal-Forcing的曝光偏差问题与ODE vs AR扩散对比全解

DMD为什么需要“正确初始化“:Causal-Forcing的曝光偏差问题与ODE vs AR扩散对比全解

【免费下载链接】Causal-Forcing [ICML 2026] Official codebase for "Causal Forcing: Autoregressive Diffusion Distillation Done Right for High-Quality Real-Time Interactive Video Generation" & Causal Forcing 项目地址: https://gitcode.…

2026/10/17 9:23:36 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →