XAgent 数据结构详解:TaskSearchTree 任务搜索树的实现原理与实战
AI Agent大模型后端任务调度【免费下载链接】XAgentAn Autonomous LLM Agent for Complex Task Solving项目地址https://gitcode.com/gh_mirrors/xa/XAgent点击查看免费下载TaskSearchTree 是 XAgent 内部用于组织复杂任务求解过程的核心树状数据结构它以ToolNode为节点记录 Agent 在解决每个子任务时逐步调用工具、产生思考与输出结果的完整链路。本文以 XAgent/data_structure/tree.py 与配套文档 Markdown_Docs/XAgent/data_structure/tree.md 为骨架结合节点实现与 ReACT 搜索算法源码深入讲解树的构造、深度/子树统计、父子关系建立以及它在真实任务执行中的调用方式帮助你理解 XAgent 是如何把一次次的 LLM 推理与工具调用沉淀成一棵可回溯、可统计、可提交的任务树。TaskSearchTree 类概览一棵承载任务搜索行为的树在 XAgent 的代码库中TaskSearchTree被定义在 XAgent/data_structure/tree.py其类注释明确说明TaskSearchTree 表示一棵具有特定任务搜索行为specific task searching behavior的树数据结构。它的职责不是通用意义上的多叉树工具类而是为内层循环搜索算法inner loop search提供一棵记录当前子任务从开始到结束每一步操作的链式树。类定义如下class TaskSearchTree: TaskSearchTree represents a tree data structure with specific task searching behavior. Attributes: root (ToolNode): Root node of the tree. now_expand_num (int): Maintains current expanding number for nodes during traversal. def __init__(self): self.root: ToolNode ToolNode() self.root.expand_num 0 self.now_expand_num 1从属性设计上可以看到它的两个核心成员属性类型语义rootToolNode树的根节点默认是一个新建的空ToolNode其expand_num被固定为 0now_expand_numint遍历过程中维护的当前扩展编号用于给新加入的节点按扩展顺序编号与 Plan 树的区别两种树各司其职XAgent 中还存在另一棵树——由 XAgent/data_structure/plan.py 中的Plan类构成的计划树Plan Tree它管理任务计划含子任务 ID、状态、父子关系。而TaskSearchTree管理的是每个子任务内部的执行过程当某个子任务被真正执行时Agent 每推理并调用一次工具就会在树上新增一个节点。因此两者是计划级与执行级两个不同粒度的树结构读者不应混淆。构造方法__init__初始化根节点与扩展编号__init__方法不接收任何参数内部只做三件事def __init__(self): self.root: ToolNode ToolNode() self.root.expand_num 0 self.now_expand_num 1创建根节点直接实例化一个ToolNode并赋给self.root。根节点代表任务尚未开始的初始状态它不携带任何真实的 Agent 行为数据。根节点不参与扩展self.root.expand_num 0将根节点的扩展编号固定为 0表示根节点本身不会被当作一次扩展。从 1 开始计数self.now_expand_num 1表示当前下一个将要被扩展的节点编号为 1即树中第一个真实操作节点将从编号 1 开始。注意点沿用文档说明并结合源码该函数无参数创建TaskSearchTree()即可完成初始化初始化的根节点默认不会被扩展如果业务上需要根节点也参与扩展可以通过修改其expand_num属性实现不过在当前 ReACT 实现中根节点始终只作为起始锚点now_expand_num表示下一个可分配的扩展编号它随每次建立父子关系自增实际反映树上真实节点不含根的数量。查询方法get_depth与get_subtree_sizeTaskSearchTree的深度与子树大小查询都采用委托给根节点的实现方式def get_depth(self): return self.root.get_depth() def get_subtree_size(self): return self.root.get_subtree_size()这里的关键在于树本身不维护任何统计信息所有统计逻辑都定义在ToolNode上见 XAgent/data_structure/node.py。ToolNode 上的深度计算ToolNode.get_depth通过递归回溯父节点计算深度def get_depth(self): if self.father None: return 0 return self.father.get_depth() 1根节点的father为None因此深度为0每个子节点深度 父节点深度 1由于TaskSearchTree.get_depth()委托给self.root.get_depth()返回的正是整棵树的最大深度。使用注意get_depth依赖父子关系被正确建立即father指针正确否则计算结果会出现偏差同时因为它采用递归实现极端情况下过深的链可能引起递归开销需要配合配置中的max_subtask_chain_length限制链长详见后文。ToolNode 上的子树大小计算ToolNode.get_subtree_size采用递归累加的方式统计以当前节点为根的子树节点总数def get_subtree_size(self): if self.children []: return 1 now_size 1 for child in self.children: now_size child.get_subtree_size() return now_size叶子节点children为空子树大小为1非叶子节点的大小 自身 1 所有子节点子树大小的累加对TaskSearchTree而言调用get_subtree_size()即得到整棵任务树的总节点数。值得注意的语义细节在ToolNode层面子树大小包含当前节点自身叶子返回 1而关联文档对TaskSearchTree.get_subtree_size的说明中提到子树的节点数不包括根节点本身这一说法与node.py的实现存在表述差异。以源码为准TaskSearchTree.get_subtree_size()返回的是root.get_subtree_size()其中根节点计入统计根没有子节点时返回 1。读者在实际阅读旧文档或调试时应以 XAgent/data_structure/node.py 的实际行为为准避免被注释误导。建边方法make_father_relation建立父子关系并编号make_father_relation(father, child)是树从单节点生长为链/树的唯一入口源码如下def make_father_relation(self, father, child): if not (isinstance(father, ToolNode) and isinstance(child, ToolNode)): raise TypeError(Father and child both need to be instances of ToolNode.) child.expand_num self.now_expand_num self.now_expand_num 1 child.father father father.children.append(child)其执行流程分为三步类型校验father与child必须同时是ToolNode实例否则抛出TypeError提示信息为Father and child both need to be instances of ToolNode.分配扩展编号把当前的now_expand_num写入child.expand_num然后now_expand_num 1从而保证树中每个真实节点都拿到唯一的、按加入顺序递增的扩展编号双向建边将child.father指向father并把child追加到father.children列表中完成父认子、子认父的双向关联。注意使用前必须确保father与child节点均已创建并存在于树中传入非ToolNode类型会直接抛异常因此调用方如 ReACT 算法总是用agent.message_to_tool_node(...)生成的ToolNode来调用expand_num不仅用于标识顺序还能配合now_expand_num推导当前树上真实扩展节点的数量。节点基石ToolNode 的完整结构要真正用好TaskSearchTree必须理解其节点类型ToolNode。它继承自抽象基类Node见 XAgent/data_structure/node.py初始化时定义了如下字段self.father: ToolNode None self.children: list[ToolNode] [] self.expand_num 0 self.data { content: , thoughts: { properties: { thought: , reasoning: , plan: , criticism: , }, }, command: { properties: { name: , args: , }, }, tool_output: , tool_status_code: ToolCallStatusCode.TOOL_CALL_SUCCESS, } self.history: MessageHistory MessageHistory() self.workspace_hash_id 各字段含义字段类型说明fatherToolNode父节点指针childrenlist[ToolNode]子节点列表expand_numint扩展顺序编号由make_father_relation分配datadict节点核心数据内容、thoughts思考/推理/计划/批评、command命令名与参数、工具输出、工具调用状态码historyMessageHistory该节点对应的消息历史见 XAgent/message_history.pyworkspace_hash_idstr工作区哈希 ID用于关联文件系统快照此外ToolNode还提供两个对树的运行至关重要的方法process属性从当前节点一路回溯到根节点把沿途每个节点的data按根→当前顺序拼成一个列表供 ReACT 算法构造你已经完成的步骤提示词使用to_json对data做深拷贝并把tool_status_code枚举值转换成其名称字符串如TOOL_CALL_SUCCESS得到 JSON 兼容格式便于持久化或回放展示。ToolNode的详细字段说明与示例可见配套文档 Markdown_Docs/XAgent/data_structure/node.md。实战TaskSearchTree 在 ReACT 内层搜索中的调用链TaskSearchTree并非孤立存在它被内层循环搜索算法ReACTChainSearch直接使用实现在 XAgent/inner_loop_search_algorithms/ReACT.py 中。该算法继承自 XAgent/inner_loop_search_algorithms/base_search.py 的BaseSearchMethod在初始化时维护了一个树列表class ReACTChainSearch(BaseSearchMethod): def __init__(self, xagent_core_components: XAgentCoreComponents): super().__init__() self.tree_list [] self.finish_node None self.xagent_core_components xagent_core_components每轮尝试生成一棵新树在generate_chain方法中每次尝试attempt都会追加一棵全新的TaskSearchTreeself.tree_list.append(TaskSearchTree()) now_attempt_tree self.tree_list[-1] now_node now_attempt_tree.root也就是说tree_list中每棵树对应一次完整的链式搜索尝试多次尝试max_try失败或成功后由run方法统一判定搜索状态SearchMethodStatusCode.HAVE_AT_LEAST_ONE_ANSWER/FAIL见 XAgent/utils.py 中的枚举定义。循环生长深度受限的链式扩展树的生长发生在while循环中其终止条件直接使用树的深度while now_node.get_depth() config.max_subtask_chain_length: ... new_tree_node agent.message_to_tool_node(new_message) ... tool_output, tool_output_status_code, need_for_plan_refine, using_tools \ self.xagent_core_components.function_handler.handle_tool_call(new_tree_node) ... now_attempt_tree.make_father_relation(now_node, new_tree_node) ... now_node new_tree_node关键点深度即进度now_node.get_depth()表示当前链已走了多少步当它达到配置的max_subtask_chain_length时循环停止防止无限生长节点来源new_tree_node由agent.message_to_tool_node(new_message)生成——该方法见 XAgent/agent/tool_agent/agent.py把 LLM 返回的 message含content、arguments、function_call转换为一个携带思考与命令的ToolNode其中data[command][properties][name]就是 Agent 决定调用的工具名边即操作记录make_father_relation(now_node, new_tree_node)把上一步节点与新节点连成链expand_num按 1、2、3……依次分配状态即结束信号当tool_output_status_code为SUBMIT_AS_SUCCESS或SUBMIT_AS_FAILED时中断循环self.finish_node now_node记录终点节点供上层如 XAgent/workflow/working_memory.py 中注册子任务并记录finish_node.get_depth()作为处理长度使用。节点数据如何回放给 LLM树的链式结构还被用于构造下一轮推理的上下文make_message(now_node, ...)读取now_node.process即从根到当前节点的所有data序列并在config.enable_summary开启时用summarize_action压缩后作为你已经完成的步骤注入用户消息。这样 LLM 每走一步都能看到整条历史链而历史链正是由TaskSearchTree一步步累积起来的。配置联动用max_subtask_chain_length约束树高树的高度上限来自全局配置项max_subtask_chain_length默认配置见 assets/gpt-3.5-turbo_config.ymlmax_subtask_chain_length: 15配套的常用配置还包括max_plan_refine_chain_length: 3 # 计划精炼链长度 max_plan_tree_depth: 3 # 计划树最大深度 max_plan_tree_width: 5 # 计划树最大宽度 enable_ask_human_for_help: False # 是否允许向人类求助同一套配置也出现在 assets/xagentllama.yml。从源码看max_subtask_chain_length在 ReACT.py 中被三处使用作为while循环终止条件、判断是否强制调用subtask_submit当now_node.get_depth() config.max_subtask_chain_length - 1时最后一步必须提交子任务、以及作为提示词中的max_length占位符。由此可见调大该值可让 Agent 在单个子任务内执行更多步骤链更深但也意味着更长的上下文与更多工具调用调小则会更快进入subtask_submit收尾。最小可运行示例手动搭建一棵任务树综合 Markdown_Docs/XAgent/data_structure/tree.md 的示例输出与源码实现可以手动构造一棵任务树并验证各方法行为from XAgent.data_structure.node import ToolNode from XAgent.data_structure.tree import TaskSearchTree # 1. 初始化一棵任务树 tree TaskSearchTree() print(tree.get_depth()) # 0初始只有根节点 print(tree.get_subtree_size()) # 1根节点自身计为 1 # 2. 构造两个真实操作节点并建立父子关系 father ToolNode() child ToolNode() tree.make_father_relation(tree.root, father) # father 的 expand_num 1 tree.make_father_relation(father, child) # child 的 expand_num 2 print(tree.get_depth()) # 2root - father - child print(tree.get_subtree_size()) # 3三个节点 print(father.expand_num, child.expand_num) # 1 2 print(child.father is father, father.children) # True [child] # 3. 类型校验非 ToolNode 会抛 TypeError try: tree.make_father_relation(father, not a node) except TypeError as e: print(e) # Father and child both need to be instances of ToolNode.小结TaskSearchTree 的设计要点组合而非继承TaskSearchTree内部持有ToolNode根节点统计逻辑全部下沉到节点层树类只做转发职责清晰编号机制now_expand_num与expand_num配合为每个操作节点提供全局唯一的扩展顺序号深度受限树的生长深度由配置max_subtask_chain_length控制从源头规避了递归统计与上下文无限膨胀的风险贯穿执行主链路从 ReACT 搜索到工作记忆注册TaskSearchTree提供的深度、终点节点与process链式数据是 XAgent 实现复杂任务多步求解、可回溯、可总结、可提交的底层支撑。如果需要进一步了解节点细节与搜索算法整体流程可继续阅读仓库内的 Markdown_Docs/XAgent/data_structure/node.md 与 Markdown_Docs/XAgent/inner_loop_search_algorithms/ReACT.md。赞分享AI Agent大模型后端任务调度【免费下载链接】XAgentAn Autonomous LLM Agent for Complex Task Solving项目地址https://gitcode.com/gh_mirrors/xa/XAgent点击查看免费下载相关推荐快速完整的微信聊天记录导出备份、统计一次搞定快速完整的微信聊天记录导出备份、统计一次搞定 WeChatMsg 是一款本地运行的微信聊天记录导出工具能把记录导出为 HTML、Word、CSV 三种格式Swift Algorithm Club 之 Trie 字典树Swift 前缀树数据结构的原理与实现详解Swift Algorithm Club 之 Trie 字典树Swift 前缀树数据结构的原理与实现详解 导读 Trie又称前缀树 prefix tree、示例工程教程高级树结构解析B树、三元搜索树在C-Sharp-Algorithms中的实现原理高级树结构解析B树、三元搜索树在C Sharp Algorithms中的实现原理 C Sharp Algorithms是一个功能强大的C 算法库提供了标准数后端上一篇flow-to-typescript-codemod与React从React.Node到React.ReactNode的转换技巧下一篇【亲测免费】 使用node-neo4j连接Neo4j数据库教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

buildah umount 命令完全指南:卸载工作容器根文件系统的原理与实战

buildah umount 命令完全指南:卸载工作容器根文件系统的原理与实战

云原生 【免费下载链接】buildah A tool that facilitates building OCI images. 项目地址: https://gitcode.com/gh_mirrors/bu/buildah 点击查看 免费下载 buildah umount 是 Buildah 提供的容器卸载命令,用于将处于挂载状态的工作容器(wo…

2026/9/26 7:34:00 阅读更多 →
高效文本润色指南:优化措辞与提升表达流畅度

高效文本润色指南:优化措辞与提升表达流畅度

好的,请把需要整理语言的内容发给我。我会在保留原意的前提下,优化措辞、调整结构、提升表达流畅度,并按要求重新输出。

2026/9/25 7:11:38 阅读更多 →
仓库货位识别系统实战:OpenCV图像处理与Tesseract识别落地指南

仓库货位识别系统实战:OpenCV图像处理与Tesseract识别落地指南

简介:一套基于Python和计算机视觉的仓库货位识别系统项目实例,面向具备Python基础、熟悉OpenCV或深度学习框架的开发者、高校学生及仓储自动化从业者。系统以摄像头采集货架与标签图像,结合YOLO目标检测、PaddleOCR文字识别及透视变换&#x…

2026/9/25 7:11:38 阅读更多 →

最新新闻

OpenClaw 给了每个人“数字分身”,但企业更需要可靠的 AI 员工:用 TaoToken 统一 Key 打通 Agent 配置

OpenClaw 给了每个人“数字分身”,但企业更需要可靠的 AI 员工:用 TaoToken 统一 Key 打通 Agent 配置

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

2026/9/26 13:02:09 阅读更多 →
GLM-5.3本地部署实战:量化、vLLM推理与生产级API集成

GLM-5.3本地部署实战:量化、vLLM推理与生产级API集成

1. 项目概述:为什么是GLM-5.3,又为什么必须本地跑?最近在几个技术群和开源社区里,几乎每天都能看到“GLM-5.3 本地部署”被反复刷屏。不是因为某个新功能发布会,也不是厂商营销推波助澜,而是真实的一线开发…

2026/9/26 13:02:09 阅读更多 →
从0到1搭建AI Agent平台:从Function Calling到业务落地

从0到1搭建AI Agent平台:从Function Calling到业务落地

最近被问得最多的问题,就是AI Agent到底怎么落地。不是那种PPT层面的"我们规划了Agent战略",而是真正动手,从零搭一个能用的Agent平台出来。我自己从最早接触大模型API到现在,前后折腾了大半年,从只会调接口…

2026/9/26 13:02:09 阅读更多 →
老旧管网非开挖检测:声波+AI的真实精度解析

老旧管网非开挖检测:声波+AI的真实精度解析

1. 这不是“听个响”,而是把地下管网变成一张会说话的活地图你有没有见过这样的场景:市政人员蹲在井盖边,手里捏着一个巴掌大的探头,往管道口一塞,几秒钟后平板上就跳出“DN300铸铁管,距井口4.2米处存在环向…

2026/9/26 13:02:09 阅读更多 →
鸿蒙状态管理深度解析:LocalStorage与AppStorage选型与实战

鸿蒙状态管理深度解析:LocalStorage与AppStorage选型与实战

1. 状态管理怎么分层:LocalStorage和AppStorage到底解决了什么问题写鸿蒙UI,不管你是刚入门的新手,还是已经做过几个完整项目的老手,都会碰到一个绕不开的问题:多个组件、多个页面之间的数据,到底怎么共享、…

2026/9/26 13:02:09 阅读更多 →
AI重构Obsidian知识库:从四千条乱笔记到可检索资产

AI重构Obsidian知识库:从四千条乱笔记到可检索资产

1. 先别急着整理:几千条笔记乱成一团,根子不在懒而在系统设计 说个我自己的真实场景:上个月我想用Obsidian找几条关于"项目复盘"的资料,搜索框敲下去,直接跳出两百多条结果,其中几十条标题都是&q…

2026/9/26 13:01:09 阅读更多 →

日新闻

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、…

2026/9/26 0:00:25 阅读更多 →
学校官网模拟全流程实践:从页面布局到后端接口与部署

学校官网模拟全流程实践:从页面布局到后端接口与部署

如果你正在找一门 Web 大作业的题目,或者刚开始接触 Web 前端开发想做点能拿来展示的东西,“学校官网模拟”几乎是最稳的选择。题目看着简单,但要把导航、新闻列表、轮播 Banner、二级页面、后台数据都串起来,其实已经把前端布局、…

2026/9/26 0:00:25 阅读更多 →
超级玛丽游戏源码C++:从零搭建横版跳跃游戏工程

超级玛丽游戏源码C++:从零搭建横版跳跃游戏工程

简介:这是一份面向游戏开发初学者与C进阶学习者的超级玛丽(超级马里奥)游戏源码,基于C面向对象编程实现,适合想通过经典项目理解游戏主循环、角色类设计、地图关卡加载与物理碰撞检测的读者参考。压缩包共49个文件&…

2026/9/26 0:00:25 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/25 19:27:14 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/25 11:15:26 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/25 20:29:09 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/25 20:29:43 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/25 20:29:31 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/25 19:27:26 阅读更多 →