feat: subagent功能增强#8152
Conversation
There was a problem hiding this comment.
Sorry @elecvoid243, your pull request is larger than the review limit of 150000 diff characters
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive SubAgent management system, supporting both static and dynamic subagent orchestration with features like shared context, history retention, and background task execution. Key components include a new SubAgentManager and several management tools. Feedback highlights critical issues regarding global state modification in session-specific logic, which could cause cross-session interference. Other identified improvements include fixing inconsistent tool names in blacklists, addressing code duplication in subagent registration, ensuring timezone consistency for timestamps, and resolving configuration inconsistencies where certain parameters are currently ignored or have conflicting defaults.
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Modifications / 改动点
一、概述
resolve #6954
本PR为subagent能力进行了功能扩充,使得astrbot能够执行更复杂的任务。支持两种使用方式:
subagent_orchestrator.agents在配置文件中预定义子代理,并伴随整个astrbot声明周期存在所有子代理(无论静态还是动态)都由统一的
SubAgentManager管理,支持以下高级功能:独立上下文记忆、独立工具隔离、工作目录隔离、技能隔离、公共上下文共享、超时限制、后台任务模式等。当前PR为重新提交,较之前版本有较大改动,提升稳健性
核心特性
SubAgentManager统一管理create_subagent在运行时动态创建子代理wait_for_subagent阻塞式等待输出二、配置说明
2.1 新增配置项说明
在
cmd_config.json中通过subagent_orchestrator配置块进行设置:2.2 配置项详解
main_enablefalseremove_main_duplicate_toolsfalserouter_system_prompt""agents[]enabledfalsemax_dynamic_subagent_count3auto_cleanup_per_turntruerule_prompttools_blacklisttools_inherenttime_prompt_enabledtruehistory_enabledtruetrue可以保留跨多轮对话的记忆shared_context_enabledfalseshared_context_maxlen300subagent_history_maxlen300execution_timeout1200.0三、核心文件
3.1 subagent_manager.py
文件路径:
astrbot/core/subagent_manager.py核心数据结构:
核心类:
SubAgentManagerconfigure()get_execution_timeout()is_auto_cleanup_per_turn()is_shared_context_enabled()is_history_enabled()register_blacklisted_tool(tool_name)register_inherent_tool(tool_name)create_subagent(session_id, config, protected=False)register_static_subagent(session_id, handoff_tool, skills, workdir)remove_subagent(session_id, agent_name)cleanup_session_turn_end(session_id)cleanup_expired_sessions()protect_subagent(session_id, agent_name)is_protected(session_id, agent_name)update_subagent_history(session_id, agent_name, current_messages)get_subagent_history(session_id, agent_name)clear_subagent_history(session_id, agent_name)build_subagent_system_prompt(session_id, agent_name, runtime)build_subagent_extra_content_parts(session_id, agent_name)build_task_router_prompt(session_id)get_subagent_tools(session_id, agent_name)add_shared_context(session_id, sender, context_type, content, target)get_shared_context(session_id, filter_by_agent)_build_shared_context_prompt(session_id, agent_name)create_pending_subagent_task(session_id, agent_name)get_pending_subagent_tasks(session_id, agent_name)get_latest_task_id(session_id, agent_name)store_subagent_result(session_id, agent_name, success, result, task_id, error, execution_time, metadata)get_subagent_result(session_id, agent_name, task_id)has_subagent_result(session_id, agent_name, task_id)clear_subagent_result(session_id, agent_name, task_id)get_subagent_status(session_id, agent_name)get_all_subagent_status(session_id)set_subagent_status(session_id, agent_name, status)cleanup_shared_context_by_agent(session_id, agent_name)clear_shared_context(session_id)set_shared_context_enabled(session_id, enabled)set_history_enabled(session_id, enabled)get_handoff_tools_for_session(session_id)cleanup_session(session_id)3.2 subagent_tools.py
文件路径:
astrbot/core/subagent_tools.py该文件包含所有子代理管理工具的类定义,这些工具供主Agent在运行时调用以创建、管理和与子代理交互。
核心工具类:
CreateSubAgentToolcreate_subagentRemoveSubagentToolremove_subagentListSubagentsToollist_subagentsResetSubAgentToolreset_subagentManageSubagentProtectionToolmanage_subagent_protectionBroadCastSharedContextToolbroadcast_shared_contextSendSharedContextToolsend_shared_contextViewSharedContextToolview_shared_contextWaitForSubagentToolwait_for_subagent四、功能实现
4.1 静态子代理
功能描述
静态子代理是原版的子代理实现,由配置文件预定义人格和工具分配。
为了实现统一管理,静态子代理在
build_main_agent()时自动注册到SubAgentManager,可以享受历史记忆、公共上下文、Skills调用等增强功能(如果开启)。实现方式
astrbot/core/subagent_orchestrator.pySubAgentOrchestrator.register_static_subagents_to_manager()astr_main_agent.py的_apply_subagent_manager_tools()中注册流程
build_main_agent()构建主Agent时调用_apply_subagent_manager_tools()_apply_subagent_manager_tools()调用so.register_static_subagents_to_manager(session_id)SubAgentOrchestrator.handoffs中的所有静态 handoff 工具SubAgentManager.register_static_subagent()register_static_subagent()内部:HandoffTool提取 agent 信息SubAgentConfigcreate_subagent(session_id, config, protected=True)4.2 动态子代理
功能描述
当动态子代理功能开启时,主Agent可以通过
create_subagent工具动态创建子代理,每个子代理拥有独立的人设、工具、技能和工作目录配置。随后系统会创建对应的transfer_to_xxx工具供主Agent调用实现方式
astrbot/core/subagent_tools.pyCreateSubAgentToolname: 子代理名称system_prompt: 子代理的人设和系统提示tools: 可用工具列表(字符串名称)skills: 可用技能列表(字符串名称)workdir: 子代理工作目录(绝对路径,可选)provider_id: 子代理使用的LLM提供商ID(可选,默认跟随全局设置)使用示例
名称验证规则
^[a-zA-Z][a-zA-Z0-9_]{0,31}$)创建后流程
astrbot_execute_shell,astrbot_execute_python。若公共上下文启用,还会添加send_shared_context)SubAgentConfig配置对象Agent和HandoffTool对象SubAgentManager__DYNAMIC_TOOL_CREATED__标记的消息,触发工具schema刷新工作目录安全检查
CreateSubAgentTool._check_path_safety()对传入的workdir进行安全验证:..windows,system32,syswow64,boot等/etc,/bin,/sbin,/root等/System,/Library,/private/var,/usr等验证失败时,工作目录回退到
Path(get_astrbot_workspaces_path()) / normalized_umo / agent_name,即主Agent默认工作目录下对应子agent名称的文件夹工具黑名单与固有工具
4.3 动态子代理委派 (transfer_to_xxx)
功能描述
创建子代理后,主Agent使用
transfer_to_xxx工具将任务委派给对应子代理。实现方式
astrbot/core/astr_agent_tool_exec.pyFunctionToolExecutor._execute_handoff()/_execute_handoff_background()子代理Prompt构建
委派执行流程
transfer_to_xxx工具ToolLoopAgentRunner._handle_function_tools()在SubAgentManager中查找handoff工具HandoffTool对象FunctionToolExecutor._execute_handoff()执行委派send_shared_context工具到子代理工具集provider_id使用不同的LLM提供商(默认与主Agent一致)_get_subagent_execution_timeout()获取超时时间asyncio.wait_for()添加执行超时控制_handle_subagent_timeout()将状态设为 "FAILED"历史上下文注入流程
subagent_histories获取历史消息Message对象begin_dialogs之前runner_messages(Agent运行期间的所有消息)追加到历史subagent_history_maxlen(默认300条),超出时保留最新的。(此处仅用于约束SubAgentManager中的列表长度,实际上下文长度仍由astrbot的truncate管理)执行超时控制
4.4 后台任务等待
功能描述
当主Agent认为某个任务耗时很长时,可以让SubAgent以后台模式运行,主Agent不会被阻塞,可继续执行其他可并行的任务
原版Subagent结束任务时,会通过
_wake_main_agent_for_background_result唤醒主Agent如果Subagent耗时很长,Agent的理想做法是等待,例如执行
time.sleep()的python代码。但我们要假设LLM是愚蠢的,事实上,许多情况下,主Agent会觉得迟迟拿不到结果而试图自己执行,导致同一任务完成两遍。因此引入了一个
wait_for_subagent工具,主Agent需要拿到Subagent结果时,可进行主动的阻塞式等待,避免此类情况发生实现方式
astrbot/core/astr_agent_tool_exec.py_execute_handoff_background()- 执行后台委派_do_handoff_background()- 后台任务执行逻辑_register_subagent_task()- 注册SubAgent任务_handle_subagent_background_result()- 处理SubAgent结果_maybe_wake_main_agent_after_background()- 智能唤醒主Agent。Subagent完成任务时,如果主Agent已经结束运行,才执行_wake_main_agent_for_background_result,否则把结果存到subagent_background_results里执行流程
主Agent状态检测
后台任务完成后,需要决定是否通知用户。关键逻辑:
这依赖
AstrAgentContext.extra字段,在build_main_agent()中注入:主动等待工具
WaitForSubagentTool 轮询逻辑
task_id,获取最新的 pending 任务IDLE→ 返回错误:子代理未在运行任务COMPLETED→ 返回执行结果FAILED→ 返回失败信息RUNNING→ 继续等待后台Subagent任务管理
每个subagent都会储存结果到
subagent_background_results中。同一个subagent可以有多个任务,通过task_id来区分(每次创建任务递增)创建任务
获取结果
4.5 子代理历史记忆
功能描述
history_enabled=true时,子代理可以保留跨轮对话的历史上下文,实现连续对话能力。实现方式
SubAgentSession.subagent_historiessubagent_history_maxlen(默认300条)SubAgentManager.is_history_enabled()/set_history_enabled()历史管理机制
runner_messages(Agent运行期间的消息)追加到历史role=system的消息_MAX_TOOL_RESULT_LEN(2000字符)的tool结果截断,附加...[truncated]subagent_history_maxlen时,保留最新的消息Message对象,合并到contexts历史清理
reset_subagent工具主动清除指定子代理的历史4.6 动态子代理工作目录隔离
功能描述
每个子代理可配置独立的工作目录,未指定时,或工作目录非法时,默认使用
Path(get_astrbot_workspaces_path()) / normalized_umo / agent_name,即主代理默认目录下的子代理文件夹。实现方式
SubAgentConfig.workdirCreateSubAgentTool._check_path_safety()_build_workdir_prompt()注入的工作目录提示
4.7 动态子代理行为规范注入
功能描述
子代理自动注入安全模式、输出规范和时间信息等行为约束。
注入内容
角色定义
build_subagent_system_prompt():# Role Your name is {agent_name}(used for tool calling) {base_instructions}行为规范
_build_rule_prompt(),可由用户在配置中决定。默认配置:动态时间信息
_build_time_prompt():前两项是静态的,加入到system prompt中;时间信息则加入到附加信息中# Current Time 2026-04-14 23:09 (CST)4.8 Skills隔离
功能描述
修复了Subagent无法使用skills的问题,每个子代理可分配不同的Skills,相互隔离。
注入逻辑
SubAgentConfig.skills)SkillManager.list_skills()获取所有可用技能build_skills_prompt()生成提示词build_subagent_system_prompt()注入到子代理的system_prompt4.9 公共上下文
功能描述
当
shared_context_enabled=true时,维护一个所有子代理共享的、实时更新的群聊区域。在SubAgent每次调用LLM之前,公共上下文的内容会被注入到子代理的追加信息中。公共上下文中每条信息的格式
上下文类型
statusmessagesystem公共上下文注入方式
按类型和优先级分组注入到子代理的追加信息中,让Agent可以更清晰地获取共享上下文的信息,并知道哪些需要优先处理。
实现方式
astrbot/core/subagent_manager.pySubAgentManager._build_shared_context_prompt()Prompt结构
容量管理
shared_context_maxlen时,保留最近90%的消息公共上下文特点
4.10 主Agent路由提示
功能描述
当
dynamic_agents.enabled=true时,在主Agent的System Prompt中注入动态SubAgent能力说明,包括创建指南和委派流程。如果dynamic_agents.enabled=false,则仍然使用router_system_prompt动态子代理路由的注入内容
核心方法:
SubAgentManager.build_task_router_prompt()4.11 动态子代理的自动清理
功能描述
当
auto_cleanup_per_turn=true时,每轮对话结束后,自动清理产生的动态子代理。auto_cleanup_per_turn=true,但又想要保留某个子代理留作后续使用,可以由主agent调用manage_subagent_protection管理工具为子代理添加保护,防止被自动清理。主Agent也可以根据需要,手动通过
manage_subagent_protection移除保护,或直接通过remove_subagent工具清理某个子代理。清理规则
remove_subagent()进行清理(移除配置、handoff工具、历史、后台结果)触发时机
在
internal.py的 agent 结束流程中:4.12 动态子代理数量限制
功能描述
限制单个会话中子代理的最大数量,防止资源耗尽。
注意:替换已存在的同名子代理不增加计数。
4.13 执行超时控制
功能描述
除了原有的工具调用超时外,为每个子代理设置总的执行超时时间,避免无限等待。这是一项全局设置,对所有子代理有效
实现方式
SubAgentConfig.execution_timeout(默认1200秒)subagent_orchestrator.execution_timeoutSubAgentManager.get_execution_timeout()超时处理流程
4.14 会话过期清理
功能描述
为防止内存泄漏,SubAgentManager 会自动清理长时间未活跃的会话。默认超时时间为30分钟。
实现方式
_session_timeout_seconds(默认1800秒 = 30分钟)cleanup_expired_sessions()cleanup_session_turn_end()每轮结束时自动调用清理逻辑
内置/reset命令扩展
/reset用户指令现在会连同当前会话的subagent一起清理五、工具列表
5.1 主Agent新增可用工具
create_subagentremove_subagentlist_subagentsmanage_subagent_protectionview_shared_contextbroadcast_shared_contextwait_for_subagent5.2 子代理可用工具
send_shared_contexttools_inherent给出六、修改文件清单
astrbot/core/subagent_manager.pySubAgentManager,包含会话管理、后台任务管理、历史信息、公共上下文、Prompt构建、会话过期清理等;以及配套的SubAgentConfig,SubAgentSession数据结构astrbot/core/subagent_tools.pyastrbot/core/astr_agent_tool_exec.py_execute_handoff()(静态/动态Prompt构建、历史注入、超时控制);_execute_handoff_background()(pending任务创建);新增_do_handoff_background()(结果存储与智能唤醒逻辑);新增_register_subagent_task();新增_load_subagent_history、_build_subagent_system_prompt、_save_subagent_history、_handle_subagent_timeout、_is_managed_subagent、_handle_subagent_background_result、_maybe_wake_main_agent_after_background等方法封装核心逻辑astrbot/core/astr_main_agent.py_apply_subagent_manager_tools(),在enable_dynamic=True时注册动态管理工具。在build_main_agent()中注入main_agent_runner到AstrAgentContext.extraastrbot/core/subagent_orchestrator.pyregister_static_subagents_to_manager()方法;静态subagent自动注册到SubAgentManager享受增强功能astrbot/core/pipeline/process_stage/method/agent_sub_stages/internal.pyastrbot/core/agent/runners/tool_loop_agent_runner.py_handle_function_tools()中集成动态SubAgent工具查找;新增_resolve_dynamic_subagent_tool()和_maybe_register_dynamic_tool_from_result()方法astrbot/core/config/default.pydynamic_agents、time_prompt_enabled、history_enabled、shared_context_enabled、shared_context_maxlen、subagent_history_maxlen、execution_timeout等配置项astrbot/core/astr_agent_context.pyextra字段的类型改成dict[str, Any],使得可以记录任意类型的extra信息。例如在本PR中,它存储了一个Agent对象astrbot/core/star/context.pytool_loop_agent()支持runner_messages参数(通过kwargs传递),用于记录SubAgent历史astrbot/builtin_stars/builtin_commands/commands/conversation.py/reset命令处理中新增 subagent 清理逻辑,调用SubAgentManager.cleanup_session()清理当前会话的所有子代理astrbot/dashboard/routes/subagent.pydashboard/src/i18n/locales/en-US/features/subagent.jsondashboard/src/i18n/locales/ru-RU/features/subagent.jsondashboard/src/i18n/locales/zh-CN/features/subagent.jsondashboard/src/views/SubAgentPage.vue七、使用流程
7.1 静态子代理使用流程
与原版一致,但子代理获得增强
7.2 动态子代理使用流程
7.3 带保护的多轮对话流程
7.4 带公共上下文的协作流程
7.5 后台任务并行处理流程
7.6 后台任务与共享上下文结合
八、API 参考
8.1 SubAgentManager 核心方法
配置与生命周期
configure(max_subagent_count, auto_cleanup_per_turn, shared_context_enabled, shared_context_maxlen, subagent_history_maxlen, tools_blacklist, tools_inherent, execution_timeout, history_enabled, rule_prompt, time_prompt_enabled, timezone)get_execution_timeout() -> floatis_auto_cleanup_per_turn() -> boolis_shared_context_enabled() -> boolis_history_enabled() -> boolset_history_enabled(session_id, enabled)register_blacklisted_tool(tool_name)register_inherent_tool(tool_name)cleanup_expired_sessions() -> dict子代理管理
create_subagent(session_id, config, protected=False) -> tupleregister_static_subagent(session_id, handoff_tool, skills, workdir) -> tupleremove_subagent(session_id, agent_name) -> strprotect_subagent(session_id, agent_name)is_protected(session_id, agent_name) -> boolset_subagent_status(session_id, agent_name, status)cleanup_session_turn_end(session_id) -> dictcleanup_session(session_id) -> dictget_handoff_tools_for_session(session_id) -> listget_subagent_tools(session_id, agent_name) -> list | None历史管理
update_subagent_history(session_id, agent_name, current_messages)get_subagent_history(session_id, agent_name) -> listclear_subagent_history(session_id, agent_name) -> strPrompt构建
build_task_router_prompt(session_id) -> strbuild_subagent_system_prompt(session_id, agent_name, runtime) -> strbuild_subagent_extra_content_parts(session_id, agent_name) -> list后台任务管理
create_pending_subagent_task(session_id, agent_name) -> strget_pending_subagent_tasks(session_id, agent_name) -> list[str]get_latest_task_id(session_id, agent_name) -> str | Nonestore_subagent_result(session_id, agent_name, success, result, task_id, error, execution_time, metadata)get_subagent_result(session_id, agent_name, task_id) -> SubAgentExecutionResult | Nonehas_subagent_result(session_id, agent_name, task_id) -> boolclear_subagent_result(session_id, agent_name, task_id)get_subagent_status(session_id, agent_name) -> strget_all_subagent_status(session_id) -> dict公共上下文管理
add_shared_context(session_id, sender, context_type, content, target)get_shared_context(session_id, filter_by_agent) -> listset_shared_context_enabled(session_id, enabled)cleanup_shared_context_by_agent(session_id, agent_name)clear_shared_context(session_id)8.2 SubAgentExecutionResult 数据结构
8.3 SubAgentConfig 数据结构
8.4 SubAgentSession 数据结构
Screenshots or Test Results / 运行截图或测试结果
Dashboard页面
运行示例
截图
日志记录
详细测试报告
详见
test_report.zip
Checklist / 检查清单
😊 If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
/ 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。
👀 My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
/ 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。
🤓 I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in
requirements.txtandpyproject.toml./ 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到
requirements.txt和pyproject.toml文件相应位置。😮 My changes do not introduce malicious code.
/ 我的更改没有引入恶意代码。