作者:互联网 时间: 2026-07-17 08:46:00
XAgent 的核心编排器是 TaskHandler(XAgent/workflow/task_handler.py),它把一次用户 Query 的处理拆成两层:

用户 Query→ PlanAgent.initial_plan_generation() [PlanGenerateAgent]→ while (下一个 TODO 子任务):[Outer Loop,中序遍历计划树] inner_loop()[Inner Loop,ReACT + ToolAgent] → 推理 → 工具调用 → 观察结果 → 直到 subtask_submit 或达步数上限 posterior_process()[ReflectAgent] working_memory.register_task() if need_for_plan_refine: plan_refine_mode()[PlanRefineAgent,最多 N 步] pop_next_subtask()[线性前进,不回溯]
Outer Loop 负责按子任务顺序推进全局计划;Inner Loop 负责在单个子任务内用 ReACT 范式反复「思考 → 行动 → 观察」。两层解耦是后续所有可靠性设计的基础:计划修改和工具执行不在同一个循环里打架。
available_agents 的 4 个执行 Agent在 XAgent/core.py 中注册:
| Agent | 能力枚举 | 核心职责 |
|---|---|---|
| PlanGenerateAgent | plan_generation | 将用户 query 分解为 2–4 个子任务的初始计划树 |
| PlanRefineAgent | plan_refinement | 子任务完成后,按 split/add/delete/exit 操作迭代修正未来子任务 |
| ToolAgent | tool_tree_search | Inner Loop 内:推理 → 调工具 / subtask_submit |
| ReflectAgent | reflection | 子任务结束后提取后验知识(summary、plan reflection、tool reflection) |
DispatcherAgent 不执行任务本身,而是为其他 Agent 按当前子任务动态生成附加 user prompt。它通过 XAgentDispatcher.dispatch() 被调用:
enable=True:调用 DispatcherAgent.parse() 生成定制化附加 promptbuild_agent() 实例化目标 Agent注意:当前默认配置 enable=False(core.py),生产路径直接使用静态 prompt 模板,不经 Dispatcher 动态 refine。
| 类 | 路径 | 职责 |
|---|---|---|
| PlanAgent | workflow/plan_exec.py | 计划生命周期:初始生成 →(可选)记忆 refine → plan_refine_mode |
| TaskHandler | workflow/task_handler.py | 主编排器:outer loop + inner loop + posterior_process |
| ReACTChainSearch | inner_loop_search_algorithms/ReACT.py | 单链 ReACT 执行器,驱动 ToolAgent |
| WorkingMemoryAgent | workflow/working_memory.py | 跨子任务记忆(chat_with_other_subtask 工具,handle 未完整实现) |
| 函数 | 调用时机 | 作用 |
|---|---|---|
summarize_action() | ReACT 每步 make_message() | 压缩工具调用历史,提取 key_actions |
summarize_plan() | ReACT / PlanRefine / Reflect / TaskHandler 多处 | 按 token 预算压缩计划树 |
与 ReflectAgent 的分工:summarize 压缩原始轨迹,Reflect 输出结构化后验知识供下一子任务消费。
task_evaluator:枚举在 utils.py,无实现类summarization:有 SummarizationTrieTree 骨架,未接入主流程每个 Agent 通过 RequiredAbilities 枚举声明单一能力集合,由 AgentDispatcher.agent_markets 按能力路由。好处:
| PlanGenerate | PlanRefine | |
|---|---|---|
| 时机 | 任务开始 | 子任务完成后 |
| 权限 | 创建完整初始计划 | 只能修改 subtask_id > now_dealing_task 的未来任务 |
| 操作 | 一次性分解 | split / add / delete / exit,最多 3 步 |
| 约束 | 2–4 个子任务 | 树深 ≤ 3、树宽 ≤ 5 |
把「从零规划」和「局部修正」拆开,避免执行中的 Agent 随意改已完成任务,这是防扯皮的第一道防线。
ToolAgent 在 Inner Loop 只做三件事:思考、调工具、提交(subtask_submit)。它不修改计划,若发现后续子任务需要调整,通过 subtask_submit.suggestions_for_latter_subtasks_plan.need_for_plan_refine 把意图交给 PlanRefineAgent。
ReflectAgent 在子任务结束后单次调用,输出 action_list_summary、posterior_plan_reflection 等,供后续子任务读取。没有「ToolAgent 和 PlanRefine 同环对话」的设计,从根本上杜绝多 Agent 来回辩论。
所有工具调用(含 intrinsic tools:subtask_submit、ask_human_for_help)都经 FunctionHandler.handle_tool_call() 路由,集中做:
ToolCallStatusCode)long_result_summary)Agent 层不直接碰 HTTP,降低耦合。
ReACT 每步可能积累大量工具输出。summarize_action / summarize_plan 在写入 message history 前做压缩(clip_text、LLM 摘要),防止上下文爆炸导致 LLM 调用失败或成本失控。
| 位置 | 机制 | 配置 |
|---|---|---|
ToolAgent.parse() | @retry(stop=stop_after_attempt(max_retry_times)) | max_retry_times: 3 |
openai.py chatcompletion_request | tenacity 指数退避 61–293s;不重试 Auth/Permission/BadRequest | max_retry_times + 3 次 |
obj_generator.py chatcompletion | Schema 校验失败重试 3 次 | 内置 |
上下文超长时自动降级到更大模型(gpt-4 → gpt-4-32k 等),见 openai.py 第 69–90 行。
此外,obj_generator.chatcompletion() 通过 recorder.query_llm_inout() 查缓存;experiment.redo_action: false 时优先用缓存,避免重复 LLM 调用。
obj_generator.py:
function_call_refine():校验 function name 是否在允许列表;幻觉工具名时注入 system error message 再抛 FunctionCallSchemaError 触发重试dynamic_json_fixes():broken JSON 时让 LLM 修复后重新校验load_args_with_schema_validation():参数 schema 失败时自动修复一次ToolAgent.parse()(OpenAI 模式):
# tool_agent/agent.py 第 116–125 行jsonschema.validate(tool_call_args, schema)# 失败 → objgenerator.dynamic_json_fixes() → 再 validate
双重校验确保 LLM 输出的 function call 结构合法,减少「调了个不存在的工具」的情况。
HTTP 状态码 → ToolCallStatusCode:
| HTTP | 状态码 | 含义 |
|---|---|---|
| 200 | TOOL_CALL_SUCCESS | 成功 |
| 404 | HALLUCINATE_NAME | 工具名不存在 |
| 422 | FORMAT_ERROR | 参数格式错误 |
| 450 | TIMEOUT_ERROR | 超时 |
| 500 | TOOL_CALL_FAILED | 执行失败 |
| 503 | SERVER_ERROR | 服务不可用(抛异常) |
超时重试(function_handler.py 第 219–231 行):
MAX_RETRY = 10while retry_time < MAX_RETRY and status == TIMEOUT_ERROR and detail['type'] == 'retry':time.sleep(3)# 用 detail['next_calling'] + detail['arguments'] 重试
ToolServer 可通过异常 type='retry' 告知客户端「这次超时但可重试」,最多 10 次、每次间隔 3 秒。超过上限则返回友好错误信息,不抛异常阻断主流程。
关键设计:失败不阻断 ReACT 循环
工具失败时,tool_status_code 写入 ToolNode.data,结果作为 system message 追加到 history,ReACT 继续下一步(除非触发 subtask_submit)。Agent 可以从错误中学习,而不是一失败就 crash。
long_result_summary():网页类工具调用 parse_web_text 压缩;字符串 >2000 字符有 summarize 占位clip_text(file_archi, 1000) 限制文件系统结构展示summary.single_action_max_length: 4096、max_return_length: 8192 控制摘要输出TIME_LIMIT_EXCEEDED 枚举存在但未使用tool_call_count 在 TaskHandler 中初始化为 0 但从未递增ReACT.py 第 220–312 行:
while now_node.get_depth() < config.max_subtask_chain_length:# 默认 15...if now_node.get_depth() == config.max_subtask_chain_length - 1:function_call = {"name": "subtask_submit"}# 最后一步强制提交if tool_output_status_code == SUBMIT_AS_SUCCESS:breakelif tool_output_status_code == SUBMIT_AS_FAILED:break
| 机制 | 值/行为 |
|---|---|
| 硬循环上限 | max_subtask_chain_length: 15 |
| 最后一步强制提交 | 不允许无限调工具 |
| Prompt 预算提醒 | "You can at most use {{max_length}} steps" |
| 多链重试 | max_try=1(默认不重试整条链) |
| 退出条件 | subtask_submit 的 success/failed |
尽管类名含 Search 且维护 TaskSearchTree,实际是单链而非树搜索分支——没有 backtracking,不会在同一子任务内反复探索多条路径。
plan_exec.py plan_refine_mode():
while modify_steps < max_step:# max_plan_refine_chain_length: 3...if operation == 'exit':output_status_code = PLAN_REFINE_EXITif output_status_code in (PLAN_REFINE_EXIT, MODIFY_SUCCESS):returnmodify_steps += 1
exit 操作可随时退出MODIFY_SUCCESS 即 returnPlan.pop_next_subtask() 只取当前任务之后第一个 TODO 子任务,不回溯已完成任务deal_subtask_split/delete/add 中 can_edit 逻辑限制只能改未来子任务这三条合在一起,解决了 Agent 系统里最常见的两类「扯皮」:
interaction.interrupt 时用户可改写 goal(outer loop)或 thoughts(inner loop)ask_human_for_help 是同步阻塞等待用户输入,然后继续循环——这是「等人」,不是 Agent 间辩论enable_summary: true 时 ReACT 每步用 summarize_action / summarize_plan 压缩历史,避免 message 无限增长导致 LLM 反复因 context 超长而失败重试,形成隐性死循环。
来源:assets/gpt-3.5-turbo_config.yml
max_retry_times: 3# LLM 调用重试max_subtask_chain_length: 15# ReACT 单链子任务最大步数max_plan_refine_chain_length: 3 # 计划修正最大迭代max_plan_tree_depth: 3# 计划树深度上限max_plan_tree_width: 5# 计划树宽度上限max_plan_length: 4096enable_summary: true# 上下文压缩开关summary:single_action_max_length: 4096max_return_length: 8192enable_ask_human_for_help: falseexperiment:redo_action: false# false = 使用 LLM/Tool 缓存
flowchart TBsubgraph Entry["入口"]Server["XAgentServer"]endsubgraph Core["XAgentCoreComponents"]Dispatcher["XAgentDispatcher<br/>(enable=False)"]FH["FunctionHandler"]TSI["ToolServerInterface"]WM["WorkingMemoryAgent"]endsubgraph OuterLoop["Outer Loop — TaskHandler"]PA["PlanAgent"]PGen["PlanGenerateAgent"]PRef["PlanRefineAgent"]Refl["ReflectAgent"]endsubgraph InnerLoop["Inner Loop — ReACTChainSearch"]TA["ToolAgent"]Sum["summarize.py"]endServer --> TH["TaskHandler"]TH --> PAPA -->|plan_generation| Dispatcher --> PGenTH -->|per subtask| InnerLoopInnerLoop --> Dispatcher --> TATA --> FH --> TSIInnerLoop --> SumTH -->|posterior| ReflTH -->|plan_refine| PRefTH --> WM
| 缺口 | 影响 |
|---|---|
SummarizationTrieTree 未接入主流程 | Trie 增量摘要能力闲置 |
task_evaluator 无实现 | 无法自动评估子任务质量 |
tool_call_count 未使用 | 无法做全局工具调用预算 |
| 无 Circuit Breaker | ToolServer 故障可能拖垮整条链 |
| Dispatcher 默认关闭 | 动态 prompt 能力未在生产路径启用 |
ReACTChainSearch 实为单链 | 命名与实现不符,无真正树搜索 |
WorkingMemoryAgent handle 未完整 | 跨子任务对话能力预留但未落地 |
XAgent 的多 Agent 拆分遵循一条清晰原则:不同认知任务用不同 Agent,用硬上限和单向流水线约束协作边界。
如果你在做自己的 Agent 框架,最值得抄的三件事是:FunctionHandler 统一中介、subtask_submit 驱动计划变更、summarize 控制 token 预算。其余部分(Dispatcher 动态 prompt、WorkingMemory 跨任务通信)在源码里还是半成品,正好留给你改进的空间。