【仓颉 + 鸿蒙 + AI Agent】CangjieMagic框架(17):PlanReactExecutor

news2025/4/22 20:04:00

CangjieMagic框架:使用华为仓颉编程语言编写,专门用于开发AI Agent,支持鸿蒙、Windows、macOS、Linux等系统。

这篇文章剖析一下 CangjieMagic 框架中的 PlanReactExecutor。

1 PlanReactExecutor的工作原理

用户提问
PlanReactExecutor
知识提取
问题分解
生成多个子任务
执行子任务
汇总结果
返回最终答案

当你要组织一场生日派对时,你会怎么做?你不会一头扎进去就开始准备,而是会先:

  1. 了解寿星的喜好(知识提取)
  2. 分解任务:场地、食物、娱乐、礼物(问题分解)
  3. 一个个完成这些子任务(执行子任务)
  4. 最后把所有准备工作整合起来,举办一场成功的派对(汇总结果)

PlanReactExecutor就是这样工作的!它不会直接尝试解决一个复杂问题,而是先分析、分解,然后一步步解决,最后整合答案。

2 深入代码:构造函数和核心组件

我们先来看看PlanReactExecutor的构造函数:

protected class PlanReactExecutor <: AgentExecutor {
    protected PlanReactExecutor() { }
    
    // 其他成员...
}

这个构造函数非常简单,它背后连接了几个强大的组件:

PlanReactExecutor
知识提取器
问题分解器
ReactWorker
结果汇总器

就像一个专业厨师虽然看起来很简单地做了一道菜,但背后有一套完整的厨具和步骤一样,PlanReactExecutor看似简单,实则整合了多个专业组件。

3 同步执行流程:像项目经理一样工作

现在,让我们看看同步执行函数的实现:

override public func run(agent: Agent, request: AgentRequest): AgentResponse {
    // Extract necessary knowledge
    let knowledge = knowledgeExtract(agent, request)
    // Decompose the problem
    let subtasks: Array<Subtask> = problemDecompose(agent, request)
    let planTask = PlanTask(agent, request, subtasks, knowledge)
    // Solve each subtask
    for (subtask in subtasks) {
        let worker = ReactWorker(planTask)
        let result = worker.solve(subtask)
        subtask.result = result
    }
    // Summarize the result
    let result = resultSummarize(planTask)
    LogUtils.info(agent.name, "Summarized answer: ${result}")
    return AgentResponse(result)
}

我们来用一个房屋装修的例子来理解这个过程:

用户 PlanReactExecutor 知识提取 问题分解 ReactWorker 结果汇总 我要装修一套北欧风格的房子 提取需求和关键信息 返回用户喜好和关键需求 分解成多个施工任务 返回水电、木工、油漆等任务 分配子任务 完成子任务并报告 loop [每个子任务] 整合所有工作成果 提供最终验收报告 交付装修完成的房子 用户 PlanReactExecutor 知识提取 问题分解 ReactWorker 结果汇总
  1. 知识提取:就像设计师了解业主的喜好和需求

    let knowledge = knowledgeExtract(agent, request)
    
  2. 问题分解:就像项目经理将装修分解为水电、木工、油漆等工序

    let subtasks: Array<Subtask> = problemDecompose(agent, request)
    
  3. 创建计划任务:汇总需求和任务清单,形成施工方案

    let planTask = PlanTask(agent, request, subtasks, knowledge)
    
  4. 执行每个子任务:安排工人团队依次完成各个工序

    for (subtask in subtasks) {
        let worker = ReactWorker(planTask)
        let result = worker.solve(subtask)
        subtask.result = result
    }
    
  5. 汇总结果:整合所有工作,形成最终成果

    let result = resultSummarize(planTask)
    
  6. 返回结果:向业主交付完工的房子

    return AgentResponse(result)
    

这个过程既有条理又高效,每个步骤都有明确的职责,就像一个专业的项目团队!

4 异步执行流程:实时查看进度的魔力

当我们需要实时查看任务执行进度时,就可以使用异步执行函数:

override public func asyncRun(agent: Agent, request: AgentRequest): AsyncAgentResponse {
    let planTask = PlanTask(agent, request)
    // Create the worker thread
    let fut: Future<Iterator<String>> = spawn {
        try {
            return workFn(planTask)
        } catch(ex: Exception) {
            planTask.execInfo.verboseChannel.close()
            throw ex
        }
        throw UnsupportedException("Unreachable")
    }
    return AsyncAgentResponse(IteratorWrapper(planTask, fut), execInfo: planTask.execInfo)
}

这就像你在手机APP上订购一份外卖,可以实时看到"商家接单→厨师制作→骑手取餐→配送中→已送达"的全过程,而不是只能干等结果。

用户请求
创建计划任务
创建工作线程
异步执行workFn
返回异步响应
实时进度更新
用户界面

这里的关键是spawn表达式,它创建了一个新的工作线程来执行workFn函数,这样主线程就不会被阻塞。用生活中的例子来说,这就像你在餐厅点菜后,服务员会给你一个电子呼叫器,你可以去做其他事情,等菜好了会通知你。

5 workFn函数:异步工作的实际执行者

workFn函数是实际执行异步工作的地方,让我们仔细看看它的实现:

private func workFn(planTask: PlanTask): Iterator<String> {
    let agent = planTask.agent
    let request = planTask.request
    // Extract necessary knowledge
    planTask.knowledge = knowledgeExtract(agent, request)
    // Decompose the problem
    let subtasks: Array<Subtask> = problemDecompose(agent, request)
    planTask.subtasks = subtasks
    if (request.verbose) {
        let strBuilder = StringBuilder()
        strBuilder.append("# The Plan\n")
        for (subtask in subtasks) {
            strBuilder.append(subtask.toMarkdown())
            strBuilder.append("\n")
        }
        planTask.execInfo.verboseChannel.put(strBuilder.toString().withTag(ReactTag.PLAN))
    }
    // Solve each subtask
    for (subtask in subtasks) {
        if (request.verbose) {
            planTask.execInfo.verboseChannel.put("Solve the subtask: ${subtask.name}".withTag(ReactTag.PLAN))
        }
        let worker = ReactWorker(planTask)
        let asyncResp = worker.asyncSolve(subtask, verbose: request.verbose)
        if (request.verbose) {
            // Transfer the internal information from the react worker to this agent
            for (data in asyncResp.execInfo.getOrThrow().verboseInfo) {
                planTask.execInfo.verboseChannel.put(data)
            }
        }
        subtask.result = asyncResp.content
        if (request.verbose) {
            planTask.execInfo.verboseChannel.put("# Subtask DONE!\n${subtask.toMarkdown()}".withTag(ReactTag.INFO))
        }
    }
    if (request.verbose) {
        planTask.execInfo.verboseChannel.close()
    }
    // Summarize the result
    return asyncResultSummarize(planTask)
}

让我们用一个建造乐高模型的例子来理解这个过程:

用户 PlanReactExecutor 计划 子任务 ReactWorker 结果 准备阶段 我想搭建一个乐高城堡 提取关键信息 生成搭建计划 展示整体计划和分步骤 执行阶段 开始执行当前步骤 使用合适的零件和工具 完成当前部分 实时展示搭建进度 loop [每个搭建步骤] 完成阶段 整合所有部分 展示完整的乐高城堡 用户 PlanReactExecutor 计划 子任务 ReactWorker 结果

在这个过程中,最有价值的部分是用户可以看到计划和每个子任务的执行过程,这就是verbose模式的作用:

if (request.verbose) {
    let strBuilder = StringBuilder()
    strBuilder.append("# The Plan\n")
    for (subtask in subtasks) {
        strBuilder.append(subtask.toMarkdown())
        strBuilder.append("\n")
    }
    planTask.execInfo.verboseChannel.put(strBuilder.toString().withTag(ReactTag.PLAN))
}

这段代码就像是向用户展示乐高说明书的全貌,让用户知道接下来会发生什么。然后在执行每个子任务时,不断更新进度:

if (request.verbose) {
    planTask.execInfo.verboseChannel.put("Solve the subtask: ${subtask.name}".withTag(ReactTag.PLAN))
}

这就像是告诉用户"现在正在搭建城堡的塔楼部分",让用户了解当前进度。

6 与其他执行器的对比

执行器类型
NaiveExecutor
ReActExecutor
PlanReactExecutor
特点: 简单直接
场景: 简单问答
特点: 思考-行动-观察循环
场景: 需要使用工具
特点: 先规划后执行
场景: 复杂多步骤问题

如果用餐厅来比喻三种执行器:

  • NaiveExecutor:快餐店,直接点餐、直接出餐
  • ReActExecutor:普通餐厅,厨师根据订单现做现卖
  • PlanReactExecutor:高档餐厅,主厨先设计菜单,然后团队分工协作制作多道菜肴,最后组合成一顿完美的大餐

PlanReactExecutor最适合那些需要多步骤、多角度思考的复杂问题。

7 实际应用案例

案例一:学术研究助手

当用户请求研究神经网络的最新进展时,执行过程可能是:

用户请求: 研究神经网络最新进展
知识提取: 确定研究领域为神经网络和图像识别
问题分解
子任务1: 查找最新论文
子任务2: 阅读关键论文
子任务3: 总结主要发现
子任务4: 比较不同方法
执行子任务
汇总: 综合报告
最终结果: 全面的研究报告

案例二:旅行规划助手

想象一个用户想规划一次欧洲之旅:

用户: 请帮我规划一次为期7天的法国巴黎和意大利罗马的旅行,包括景点、住宿和交通。

使用PlanReactExecutor,执行过程可能是:

  1. 知识提取:了解用户想去巴黎和罗马,时间为7天
  2. 问题分解
    • 子任务1:规划巴黎部分的行程(3天)
    • 子任务2:规划罗马部分的行程(3天)
    • 子任务3:规划两地之间的交通(1天)
    • 子任务4:提供住宿建议
    • 子任务5:整合完整行程
  3. 执行每个子任务:分别解决每个子任务
  4. 汇总结果:生成完整的7天旅行计划

案例三:复杂数学问题求解

用户: 请求解下列方程组:
3x + 2y - z = 10
2x - 3y + 2z = -5
x + y + z = 7

使用PlanReactExecutor解决这个问题:

  1. 知识提取:确定这是一个三元一次方程组
  2. 问题分解
    • 子任务1:使用消元法消去z变量
    • 子任务2:解出x和y的关系
    • 子任务3:代回求解x、y、z的值
    • 子任务4:验证结果是否正确
  3. 执行子任务:依次解决每个数学步骤
  4. 汇总结果:提供完整的解答和解释

8 核心组件深度解析

PlanReactExecutor不是独立工作的,它依赖几个核心组件:

PlanReactExecutor
knowledgeExtract
problemDecompose
ReactWorker
resultSummarize
功能: 提取关键知识
实现: 使用LLM分析问题
功能: 分解为子任务
实现: 让LLM进行任务规划
功能: 解决单个子任务
实现: 使用ReAct方法
功能: 整合所有结果
实现: 让LLM综合所有信息
  1. knowledgeExtract:就像研究生开始论文前的文献综述,先了解相关知识

  2. problemDecompose:就像建筑师在开工前绘制详细的施工图纸

  3. ReactWorker:就像专业工人按照图纸完成具体工作

  4. resultSummarize:就像编辑将多篇文章整合成一本完整的书

这些组件协同工作,使得PlanReactExecutor能够处理非常复杂的问题。

9 PlanReactExecutor的优势与局限

PlanReactExecutor
优势
局限
能解决复杂问题
思路清晰可追踪
结果全面系统
可并行执行子任务
执行时间较长
资源消耗较大
简单问题反而复杂化

优势:

  1. 解决复杂问题:像专业律师处理复杂案件,有条不紊
  2. 思路清晰:用户可以看到完整的思考过程,增强可信度
  3. 结果全面:考虑问题的多个方面,不会遗漏重要内容
  4. 可追踪性:出现问题可以定位到具体哪个子任务

局限:

  1. 执行时间长:就像做一道复杂的菜肴,需要更多时间
  2. 资源消耗大:需要更多的API调用和计算资源
  3. 简单问题反而复杂化:用大炮打蚊子,对简单问题过度设计

10 何时选择PlanReactExecutor?

简单
复杂
只需一两个工具
需要多步规划
面对一个问题
是否复杂?
使用NaiveExecutor
需要工具吗?
使用ReActExecutor
使用PlanReactExecutor

适合使用PlanReactExecutor的场景:

  1. 多步骤问题:如规划旅行、制定学习计划
  2. 需要多角度分析:如进行SWOT分析、评估风险
  3. 需要综合信息:如撰写研究报告、市场分析
  4. 组织创作内容:如写一本书的大纲、设计课程体系

不适合的场景:

  1. 简单问答:如"今天天气怎么样"
  2. 单一工具调用:如"计算123 + 456"
  3. 快速响应场景:如紧急情况下的决策

11 总结

PlanReactExecutor就像一位经验丰富的项目经理,能够将复杂问题分解为可管理的小任务,然后一步步解决,最终整合成完整的解决方案。在处理复杂问题时,它的表现远超简单的执行器。

当你的AI应用需要处理复杂的多步骤问题时,不妨考虑使用PlanReactExecutor,它将帮助你的Agent像专业团队一样有条不紊地解决问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2340317.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WSL2-Ubuntu22.04安装URSim5.21.3

WSL2-Ubuntu22.04安装URSim5.21.3 准备安装启动 准备 名称版本WSL2Ubuntu22.04URSim5.21.3VcXsrvNaN WSL2安装与可视化请见这篇:WSL2-Ubuntu22.04-配置。 安装 我们是wsl2-ubuntu22.04&#xff0c;所以安装Linux版本的URSim&#xff0c;下载之前需要注册一下&#xff0c;即…

blender 录课键位显示插件(图文傻瓜式安装)

1、下载 点击这个链接进行下载https://github.com/nutti/Screencast-Keys 下载好不用解压 2、安装 打开blender进行安装 点击编辑选择偏好设置 选择插件再点击这个下箭头 选择从磁盘安装 然后找到自己刚刚下载好的&#xff0c;点击从磁盘安装 安装完成后勾选上插件 …

天翼云手机断开连接2小时关机

2025-04-21 天翼云手机断开连接2小时自动 天翼云手机 4元1个月 天翼云手机永不关机 天翼云手机不休眠 天翼云手机断开连接时&#xff0c;界面显示&#xff1a;离线运行&#xff0c;2小时后自动关机 电脑每小时自动连接一次 手机每小时自动连接一次

基于 FFmpeg 的音视频处理基础原理与实验探究

目录 1 基本知识1.1 解封装1.2 AAC和ADTS说明 1.3 H2641.3.1 H264编码结构解析1.3.2 NALU1.3.2 分类 2 实验1 探究音视频信息2.1 重要结构体介绍2.2 相关的API 3 实验二 提取AAC数据4 实验三 提取h264 1 基本知识 1.1 解封装 封装的逆向操作&#xff1a;封装是把音频流、视频流…

我用deepseek做了一个提取压缩文件夹下pdf和word文件工具

由于最近需要把大量的压缩文件的pdf和word文件统一复制到一个文件夹中。 我们一般正常操作方式的是把一个压缩文件一个一个解压&#xff0c;然后在把一个的解压好的文件夹下文件复制到另外一个文件夹中。 这个也需太繁琐了&#xff0c;从以往统计的需要花费两个小时间&#x…

机器人进阶---视觉算法(五)仿射变换和投影变换有什么区别

仿射变换和投影变换有什么区别 1. 定义2. 几何特性3. 变换矩阵4. 应用场景5. Python代码示例仿射变换投影变换6. 总结仿射变换和投影变换都是图像处理中常用的几何变换方法,但它们在变换性质、应用场景和变换矩阵等方面存在一些关键区别。 1. 定义 仿射变换 (Affine Transform…

如何在 Amazon EC2 上部署 Java(Spring Boot 版)

让我们学习如何将 Java Spring Boot Web 服务器部署到 Amazon EC2。每月只需 3 美元。 使用 Azure&#xff0c;您可能不知道要花费多少钱。 Spring Boot 项目示例 在本教程中&#xff0c;我们将重点介绍如何将 Java Spring Boot 服务器部署到 Amazon EC2&#xff0c;因此我们不…

IDEA打不开、打开报错

目录 场景异常原因解决 场景 1、本机已经安装了IDEA 2、再次安装另外一个版本的IDEA后打不开、打开报错 异常 这里忘记截图了。。。 原因 情况1-打不开&#xff1a;在同一台电脑安装多个IDEA是需要对idea的配置文件进行调整的&#xff0c;否则打不开 情况2-打开报错&#…

【React】项目的搭建

create-react-app 搭建vite 搭建相关下载 在Vue中搭建项目的步骤&#xff1a;1.首先安装脚手架的环境&#xff0c;2.通过脚手架的指令创建项目 在React中有两种方式去搭建项目&#xff1a;1.和Vue一样&#xff0c;先安装脚手架然后通过脚手架指令搭建&#xff1b;2.npx create-…

CSS例子 > 图片瀑布流布局(vue2)

<template><div class"container"><!-- 临时容器用于计算高度 --><div v-if"!isLayoutReady" class"temp-container"><divv-for"(item, index) in list":key"temp- index":ref"(el) > …

1.2软考系统架构设计师:系统架构的定义与作用 - 练习题附答案及超详细解析

系统架构定义与作用综合知识单选题 题目覆盖核心概念、发展历程、设计原则、评估标准及易混淆点&#xff0c;附答案解析&#xff1a; 1. 系统架构的标准定义源自于以下哪个标准&#xff1f; A. ISO/IEC 9126 B. IEEE 1471-2000 C. TOGAF 9.2 D. ITIL v4 答案&#xff1a;B 简…

关于springmvc的404问题的一种猜测解决方案

本文是记录关于在学习动力结点老杜的springmvc时候遇到的404报错的一种解决方式&#xff1b; 由于本人之前学过老杜的springmvc&#xff0c;且运行成功&#xff0c;当时使用的是tomcat10.1.19版本。 idea使用2023.3.2版本。 而这次进行回顾的时候&#xff0c;使用tomcat10.0.1…

使用Postman调测“获取IAM用户Token”接口实际操作

概述 Postman是网页调试与辅助接口调用的工具&#xff0c;具有界面简洁清晰、操作方便快捷的特性&#xff0c;可以处理用户发送的HTTP请求&#xff0c;例如&#xff1a;GET&#xff0c;PUT、POST&#xff0c;DELETE等&#xff0c;支持用户修改HTTP请求中的参数并返回响应数据。…

如何测试雷达与相机是否时间同步?

在多传感器融合系统中&#xff0c;相机与雷达的协同感知已成为环境理解的关键。相机通过捕捉纹理信息识别物体类别&#xff0c;而雷达利用激光或毫米波实现全天候精确测距。两者的数据融合既能避免单一传感器缺陷&#xff08;如相机受光照影响、雷达缺乏语义信息&#xff09;&a…

爆肝整理!Stable Diffusion的完全使用手册(二)

继续介绍Stable Diffusion的文生图界面功能。 往期文章详见: 爆肝整理&#xff01;Stable Diffusion的完全使用手册&#xff08;一&#xff09; 下面接着对SD的文生图界面的进行详细的介绍。本期介绍文生图界面的截图2&#xff0c;主要包含生成模块下的采用方法、调度类型、迭…

OpenCV day5

函数内容接上文&#xff1a;OpenCV day4-CSDN博客 目录 9.cv2.adaptiveThreshold(): 10.cv2.split()&#xff1a; 11.cv2.merge()&#xff1a; 12.cv2.add()&#xff1a; 13.cv2.subtract()&#xff1a; 14.cv2.multiply()&#xff1a; 15.cv2.divide()&#xff1a; 1…

基于Spring Boot+微信小程序的智慧农蔬微团购平台-项目分享

基于Spring Boot微信小程序的智慧农蔬微团购平台-项目分享 项目介绍项目摘要目录系统功能图管理员E-R图用户E-R图项目预览登录页面商品管理统计分析用户地址添加 最后 项目介绍 使用者&#xff1a;管理员、用户 开发技术&#xff1a;MySQLSpringBoot微信小程序 项目摘要 随着…

WPF的发展历程

文章目录 WPF的发展历程引言起源与背景&#xff08;2001-2006&#xff09;从Avalon到WPF设计目标与创新理念 WPF核心技术特点与架构基础架构与渲染模型关键技术特点MVVM架构模式 WPF在现代Windows开发中的地位与前景当前市场定位与其他微软UI技术的关系未来发展前景 社区贡献与…

Franka机器人ROS 2来袭:解锁机器人多元应用新可能

前言&#xff1a; 在机器人技术蓬勃发展的当下&#xff0c;每一次创新都可能为行业带来新的变革。2025年3月12日&#xff0c;Franka Robotics发布的Franka ROS 2软件包首次版本0.1.0&#xff0c;将著名的franka_ros软件包引入当前的ROS 2 LTS Humble Hawksbill&#xff0c;这一…

树莓派5+Vosk+python实现语音识别

简介 Vosk是语音识别开源框架&#xff0c;支持二十种语言 - 中文&#xff0c;英语&#xff0c;印度英语&#xff0c;德语&#xff0c;法语&#xff0c;西班牙语&#xff0c;葡萄牙语&#xff0c;俄语&#xff0c;土耳其语&#xff0c;越南语&#xff0c;意大利语&#xff0c;荷…