Skip to content

feat: subagent功能增强#8152

Open
elecvoid243 wants to merge 97 commits into
AstrBotDevs:masterfrom
elecvoid243:subagent
Open

feat: subagent功能增强#8152
elecvoid243 wants to merge 97 commits into
AstrBotDevs:masterfrom
elecvoid243:subagent

Conversation

@elecvoid243
Copy link
Copy Markdown
Contributor

Modifications / 改动点

一、概述

resolve #6954
本PR为subagent能力进行了功能扩充,使得astrbot能够执行更复杂的任务。支持两种使用方式:

  1. 静态配置:即原版的subagent,通过 subagent_orchestrator.agents 在配置文件中预定义子代理,并伴随整个astrbot声明周期存在
  2. 动态创建:主Agent在运行时通过工具调用动态创建子代理,在每轮对话结束后自动清理,也可由主Agent自主回收或加上清理保护

所有子代理(无论静态还是动态)都由统一的 SubAgentManager 管理,支持以下高级功能:独立上下文记忆、独立工具隔离、工作目录隔离、技能隔离、公共上下文共享、超时限制、后台任务模式等。

当前PR为重新提交,较之前版本有较大改动,提升稳健性

核心特性

特性 说明
统一实现 静态配置和动态创建的子代理都由 SubAgentManager 统一管理
动态创建 主Agent可通过create_subagent在运行时动态创建子代理
更好的后台任务模式 支持将耗时任务放到后台执行,主Agent可并行处理其他任务,也可通过wait_for_subagent阻塞式等待输出
自动清理 一轮对话结束时自动清理未受保护的子代理
上下文记忆 如开启,子代理可以保留跨轮对话历史,并支持历史截断和tool结果压缩
工作目录隔离 每个子代理可配置独立工作目录,并带有路径安全检查
Skills隔离 子代理可使用Skills,每个子代理拥有独立的技能配置
公共上下文 如开启,每个子代理可访问公共上下文,实现共享信息和协调工作
行为规范注入 如开启,为子代理自动注入安全模式、输出规范、时间信息等行为约束
数量限制 可配置的子代理最大数量限制
工具管理 除了主Agent动态分配的工具,用户可配置黑名单:防止子代理获得管理类工具;固有名单:子代理可拥有固有工具保证基础能力
执行超时控制 除了工具调用超时限制外,支持为子代理设置执行总长超时,避免无限等待
会话过期清理 自动清理长时间(30分钟)不活跃会话的子代理,防止内存泄漏

二、配置说明

2.1 新增配置项说明

cmd_config.json 中通过 subagent_orchestrator 配置块进行设置:

  "subagent_orchestrator": {
    "main_enable": true,
    "remove_main_duplicate_tools": false,
    "router_system_prompt": "You are a task router. Your job is to chat naturally, recognize user intent, and delegate work to the most suitable subagent using transfer_to_* tools. Do not try to use domain tools yourself. If no subagent fits, respond directly.",
    "agents": [
      {
        "name": "static_subagent",
        "persona_id": "测试人格",
        "public_description": "测试子代理(静态)",
        "enabled": true,
        "provider_id": "kimi-code/kimi-for-coding"
      }
    ],
    "dynamic_agents": {
      "enabled": true,
      "max_dynamic_subagent_count": 3,
      "auto_cleanup_per_turn": true,
      "rule_prompt": "# Subagent Rules ...",
      "tools_blacklist": [
        "broadcast_shared_context",
        "create_subagent",
        "manage_subagent_protection",
        "reset_subagent",
        "remove_subagent",
        "list_subagents",
        "wait_for_subagent",
        "view_shared_context"
      ],
      "tools_inherent": [
        "astrbot_execute_shell",
        "astrbot_execute_python"
      ]
    },
    "time_prompt_enabled" : true,
    "history_enabled": true,
    "shared_context_enabled": false,
    "shared_context_maxlen": 300,
    "subagent_history_maxlen": 300,
    "execution_timeout": 1200
  }

2.2 配置项详解

配置项 类型 默认值 说明
main_enable bool false 总开关,启用SubAgent编排功能(静态+动态)
静态子代理(原版)
remove_main_duplicate_tools bool false 是否从主Agent移除已分配给子代理的工具(静态)
router_system_prompt str "" 主Agent路由提示词(仅启用静态且未开启动态时有效)
agents list [] 静态子代理配置列表
动态子代理(新增)
enabled bool false 是否允许主Agent动态创建子代理
max_dynamic_subagent_count int 3 单个会话允许的最大子代理数量,包含动态和静态
auto_cleanup_per_turn bool true 每轮对话结束后自动清理非保护子代理
rule_prompt str 默认规则提示词 动态子代理的固定提示词(例如行为规范)
tools_blacklist list 预设黑名单列表 动态subagent工具黑名单列表,例如禁止subagent获得管理工具
tools_inherent list 预设固有工具列表 动态subagent固有工具列表
通用配置
time_prompt_enabled bool true 是否启用子代理的时间信息注入
history_enabled bool true 是否启用子代理的上下文历史功能,为true可以保留跨多轮对话的记忆
shared_context_enabled bool false 是否启用子代理间公共上下文共享
shared_context_maxlen int 300 公共上下文消息最大数量(条);该项仅控制管理类的变量长度,实际子代理仍受到truncate逻辑控制
subagent_history_maxlen int 300 每个子代理最多保留的历史消息(条);该项仅控制管理类的变量长度,实际子代理仍受到truncate逻辑控制
execution_timeout float 1200.0 SubAgent执行超时时间(秒),-1表示不限制

三、核心文件

3.1 subagent_manager.py

文件路径astrbot/core/subagent_manager.py

核心数据结构

@dataclass
class SubAgentConfig:
    name: str
    system_prompt: str = ""
    tools: set[str] | None = None        # 分配的工具名称集合
    skills: set[str] | None = None       # 分配的技能名称集合
    provider_id: str | None = None       # 可选的LLM提供商ID
    description: str = ""                # handoff工具描述
    workdir: str | None = None           # 子代理工作目录
    execution_timeout: float = 600.0    # SubAgent 执行超时时间(秒)

@dataclass
class SubAgentExecutionResult:
    task_id: str          # 任务唯一标识符(递增数字字符串)
    agent_name: str
    success: bool
    result: str | None = None
    error: str | None = None
    execution_time: float = 0.0
    created_at: float = 0.0
    completed_at: float = 0.0
    metadata: dict = field(default_factory=dict)

@dataclass
class SubAgentSession:
    session_id: str
    subagents: dict = field(default_factory=dict)       # 存储SubAgentConfig对象
    handoff_tools: dict = field(default_factory=dict)
    subagent_status: dict = field(default_factory=dict) # 工作状态: "IDLE" "RUNNING" "COMPLETED" "FAILED"
    protected_agents: set = field(default_factory=set)  # 受保护agent不会被自动清理
    history_enabled: bool = True                        # 是否保存子代理历史
    subagent_histories: dict = field(default_factory=dict) # 每个子代理的历史上下文
    shared_context: list = field(default_factory=list)  # 公共上下文列表
    shared_context_enabled: bool = False                # 是否启用公共上下文
    subagent_background_results: dict = field(default_factory=dict)  # 后台subagent结果存储
    background_task_counters: dict = field(default_factory=dict)  # 任务计数器
    last_activity_at: float = field(default_factory=time.time)  # 最后活跃时间

核心类SubAgentManager

方法 功能
configure() 配置管理器全局设置(数量限制、自动清理、公共上下文、历史记忆、时区等)
get_execution_timeout() 获取SubAgent执行超时时间
is_auto_cleanup_per_turn() 检查是否启用自动清理
is_shared_context_enabled() 检查是否启用公共上下文
is_history_enabled() 检查是否启用子代理历史记忆
register_blacklisted_tool(tool_name) 注册不应被子Agent使用的工具
register_inherent_tool(tool_name) 注册子Agent默认拥有的工具
create_subagent(session_id, config, protected=False) 创建子代理,返回handoff工具
register_static_subagent(session_id, handoff_tool, skills, workdir) 注册静态子代理到管理器(自动protected=True)
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) 更新子代理历史(支持system消息过滤和tool结果截断)
get_subagent_history(session_id, agent_name) 获取子代理历史
clear_subagent_history(session_id, agent_name) 清除子代理历史
build_subagent_system_prompt(session_id, agent_name, runtime) 构建子代理系统提示词(工作目录、行为规范、Skills)
build_subagent_extra_content_parts(session_id, agent_name) 构建子代理追加内容部分(公共上下文、时间信息)
build_task_router_prompt(session_id) 构建主Agent的路由提示词(配额信息、创建指南、生命周期等)
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) 获取公共上下文(支持按Agent过滤)
_build_shared_context_prompt(session_id, agent_name) 分块构建公共上下文提示(按类型和优先级分组)
create_pending_subagent_task(session_id, agent_name) 为SubAgent创建pending任务,返回task_id
get_pending_subagent_tasks(session_id, agent_name) 获取SubAgent的所有pending任务ID列表
get_latest_task_id(session_id, agent_name) 获取SubAgent的最新任务ID
store_subagent_result(session_id, agent_name, success, result, task_id, error, execution_time, metadata) 存储SubAgent的执行结果
get_subagent_result(session_id, agent_name, task_id) 获取SubAgent的执行结果
has_subagent_result(session_id, agent_name, task_id) 检查SubAgent是否有结果
clear_subagent_result(session_id, agent_name, task_id) 清除SubAgent的执行结果
get_subagent_status(session_id, agent_name) 获取SubAgent的状态:IDLE/RUNNING/COMPLETED/FAILED
get_all_subagent_status(session_id) 获取所有SubAgent的状态
set_subagent_status(session_id, agent_name, status) 设置SubAgent的状态
cleanup_shared_context_by_agent(session_id, agent_name) 清理与指定Agent相关的公共上下文消息
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) 获取会话的所有handoff工具
cleanup_session(session_id) 清理整个会话

3.2 subagent_tools.py

文件路径astrbot/core/subagent_tools.py

该文件包含所有子代理管理工具的类定义,这些工具供主Agent在运行时调用以创建、管理和与子代理交互。

核心工具类

工具类 名称 说明
CreateSubAgentTool create_subagent 创建子代理
RemoveSubagentTool remove_subagent 移除子代理
ListSubagentsTool list_subagents 列出子代理
ResetSubAgentTool reset_subagent 重置子代理历史
ManageSubagentProtectionTool manage_subagent_protection 保护/取消保护子代理(合并了protect/unprotect功能)
BroadCastSharedContextTool broadcast_shared_context 主Agent广播公共上下文(替代原send_shared_context_for_main_agent)
SendSharedContextTool send_shared_context 子Agent发送公共上下文
ViewSharedContextTool view_shared_context 查看公共上下文
WaitForSubagentTool wait_for_subagent 等待后台SubAgent结果

四、功能实现

4.1 静态子代理

功能描述

静态子代理是原版的子代理实现,由配置文件预定义人格和工具分配。

为了实现统一管理,静态子代理在 build_main_agent() 时自动注册到 SubAgentManager,可以享受历史记忆、公共上下文、Skills调用等增强功能(如果开启)。

实现方式

  • 文件astrbot/core/subagent_orchestrator.py
  • 核心方法SubAgentOrchestrator.register_static_subagents_to_manager()
  • 调用时机astr_main_agent.py_apply_subagent_manager_tools()

注册流程

  1. build_main_agent() 构建主Agent时调用 _apply_subagent_manager_tools()
  2. _apply_subagent_manager_tools() 调用 so.register_static_subagents_to_manager(session_id)
  3. 遍历 SubAgentOrchestrator.handoffs 中的所有静态 handoff 工具
  4. 对每个 handoff 调用 SubAgentManager.register_static_subagent()
  5. register_static_subagent() 内部:
    • HandoffTool 提取 agent 信息
    • 创建 SubAgentConfig
    • 调用 create_subagent(session_id, config, protected=True)
  6. 静态子代理注册完成,自动受保护(防止自动清理)

4.2 动态子代理

功能描述

当动态子代理功能开启时,主Agent可以通过create_subagent工具动态创建子代理,每个子代理拥有独立的人设、工具、技能和工作目录配置。随后系统会创建对应的transfer_to_xxx工具供主Agent调用

实现方式

  • 文件astrbot/core/subagent_tools.py
  • 核心类CreateSubAgentTool
  • 参数
    • name: 子代理名称
    • system_prompt: 子代理的人设和系统提示
    • tools: 可用工具列表(字符串名称)
    • skills: 可用技能列表(字符串名称)
    • workdir: 子代理工作目录(绝对路径,可选)
    • provider_id: 子代理使用的LLM提供商ID(可选,默认跟随全局设置)

使用示例

create_subagent(
    name="data_analyst",
    system_prompt="你是一个专业的数据分析师,擅长分析数据并给出见解",
    tools=["astrbot_execute_shell", "astrbot_execute_python"],
    skills=["excel", "pdf"],
    workdir="/path/to/workspace",
    provider_id="kimi-code/kimi-for-coding"
)

名称验证规则

  1. 必须以字母开头
  2. 只允许英文字母、数字和下划线
  3. 长度1-32字符(正则:^[a-zA-Z][a-zA-Z0-9_]{0,31}$
  4. 子代理名称可能会作为文件夹名的一部分(具备独立工作目录),因此不允许Windows保留文件夹名

创建后流程

  1. 验证名称格式和工作目录安全性
  2. 检查子代理数量是否达到上限
  3. 从工具列表中移除黑名单工具(如管理类工具)
  4. 自动添加固有工具(如 astrbot_execute_shell, astrbot_execute_python 。若公共上下文启用,还会添加 send_shared_context
  5. 创建 SubAgentConfig 配置对象
  6. 创建 AgentHandoffTool 对象
  7. 注册到 SubAgentManager
  8. 初始化子代理历史和状态("IDLE")
  9. 返回带有 __DYNAMIC_TOOL_CREATED__ 标记的消息,触发工具schema刷新

工作目录安全检查

CreateSubAgentTool._check_path_safety() 对传入的 workdir 进行安全验证:

检查项 说明
绝对路径 必须是绝对路径
路径遍历 不允许包含 ..
Windows危险目录 禁止访问 windows, system32, syswow64, boot
Linux危险目录 禁止访问 /etc, /bin, /sbin, /root
macOS危险目录 禁止访问 /System, /Library, /private/var, /usr
路径存在性 路径必须实际存在

验证失败时,工作目录回退到 Path(get_astrbot_workspaces_path()) / normalized_umo / agent_name,即主Agent默认工作目录下对应子agent名称的文件夹

工具黑名单与固有工具

_tools_blacklist: set[str] = {
    "broadcast_shared_context",
    "create_subagent",
    "manage_subagent_protection",
    "reset_subagent",
    "remove_subagent",
    "list_subagents",
    "wait_for_subagent",
    "view_shared_context",
}

_tools_inherent: set[str] = {
    "astrbot_execute_shell",
    "astrbot_execute_python",
}
  • 黑名单工具:创建子代理时自动从子代理工具列表中移除,防止子代理获得管理能力
  • 固有工具:创建子代理时自动添加到子代理工具列表,确保基础执行能力

4.3 动态子代理委派 (transfer_to_xxx)

功能描述

创建子代理后,主Agent使用 transfer_to_xxx 工具将任务委派给对应子代理。

实现方式

  • 文件astrbot/core/astr_agent_tool_exec.py
  • 核心方法FunctionToolExecutor._execute_handoff() / _execute_handoff_background()

子代理Prompt构建

# 基础角色定义(由主Agent给出)
subagent_system_prompt = f"# Role\nYour name is {agent_name}(used for tool calling)\n{tool.agent.instructions}\n"

# 其他系统提示词(工作目录、行为规范、Skills)
subagent_system_prompt += SubAgentManager.build_subagent_system_prompt(umo, agent_name, runtime)

# 追加内容(公共上下文、时间信息)
extra_content_parts = SubAgentManager.build_subagent_extra_content_parts(umo, agent_name)

委派执行流程

  1. 主Agent调用 transfer_to_xxx 工具
  2. ToolLoopAgentRunner._handle_function_tools()SubAgentManager 中查找handoff工具
  3. 匹配后返回完整的 HandoffTool 对象
  4. 调用 FunctionToolExecutor._execute_handoff() 执行委派
  5. 构建子代理工具集(包含分配的tools + runtime computer tools + 固有工具),以及子代理的skills
  6. 如果公有上下文启用,自动注入 send_shared_context 工具到子代理工具集
  7. 支持指定 provider_id 使用不同的LLM提供商(默认与主Agent一致)
  8. 加载历史上下文(如果有),合并到contexts中
  9. 通过 _get_subagent_execution_timeout() 获取超时时间
  10. 通过 asyncio.wait_for() 添加执行超时控制
  11. 超时发生时调用 _handle_subagent_timeout() 将状态设为 "FAILED"
  12. 执行完成后,保存运行时消息到历史记录

历史上下文注入流程

  1. 子代理执行前,从 subagent_histories 获取历史消息
  2. 将历史消息转换为 Message 对象
  3. 历史消息插入到 begin_dialogs 之前
  4. 执行完成后,runner_messages(Agent运行期间的所有消息)追加到历史
  5. 过滤system消息,对超过2000字符的tool结果进行截断
  6. 历史消息总数不超过 subagent_history_maxlen(默认300条),超出时保留最新的。(此处仅用于约束SubAgentManager中的列表长度,实际上下文长度仍由astrbot的truncate管理)

执行超时控制

# 获取子代理的超时时间
execution_timeout = cls._get_subagent_execution_timeout()

# 添加执行超时控制
if execution_timeout > 0:
    try:
        llm_resp = await asyncio.wait_for(
            _run_subagent(), timeout=execution_timeout
        )
    except asyncio.TimeoutError:
        error_msg = f"SubAgent '{agent_name}' execution timeout after {execution_timeout:.1f} seconds."
        logger.warning(f"[SubAgent:Timeout] {error_msg}")
        cls._handle_subagent_timeout(umo=umo, agent_name=agent_name)
        # 返回超时错误信息
        yield mcp.types.CallToolResult(
            content=[mcp.types.TextContent(type="text", text=f"error: {error_msg}")]
        )
        return
else:
    # 不设置超时
    llm_resp = await _run_subagent()

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

执行流程

1. 主Agent调用 transfer_to_xxx(background_task=True)
2. 触发 _execute_handoff_background() 方法
3. 调用 _register_subagent_task() 在 SubAgentManager 中创建 pending 任务
   - 如果当前子代理状态为 RUNNING,不允许创建新任务
   - 生成递增的 task_id(数字字符串)
4. 设置子代理状态为 "RUNNING"
5. 返回 task_id 给主Agent(此时主Agent不会被阻塞)
6. SubAgent 在后台异步执行任务(_do_handoff_background)
7. 任务完成后:
   - 结果存储到 subagent_background_results
   - 更新子代理状态为 "COMPLETED" 或 "FAILED"
   - 调用 _maybe_wake_main_agent_after_background() 检查主Agent是否仍在运行
   - 仅在主Agent已结束时,通过 _wake_main_agent_for_background_result 通知用户

主Agent状态检测

后台任务完成后,需要决定是否通知用户。关键逻辑:

# 通过 main_agent_runner 判断主Agent是否仍在运行
context_extra = getattr(run_context.context, "extra", None)
main_agent_runner = context_extra.get("main_agent_runner") if context_extra else None
main_agent_is_running = main_agent_runner is not None and not main_agent_runner.done()

if main_agent_is_running:
    return False  # 主Agent仍在运行,不唤醒,主Agent会自己取出结果
else:
    await cls._wake_main_agent_for_background_result(...)  # 唤醒通知用户
    return True

这依赖 AstrAgentContext.extra 字段,在 build_main_agent() 中注入:

astr_agent_ctx = AstrAgentContext(
    context=plugin_context, event=event, extra={"main_agent_runner": agent_runner}
)

主动等待工具

# 等待特定任务的结果
wait_for_subagent(
    subagent_name="analyst",
    task_id="1",          # 可选,不填则获取最新任务结果
    timeout=60,           # 最大等待时间(秒)
    poll_interval=5       # 轮询间隔(秒)
)

WaitForSubagentTool 轮询逻辑

  1. 如果未指定 task_id,获取最新的 pending 任务
  2. 轮询子代理状态:
    • IDLE → 返回错误:子代理未在运行任务
    • COMPLETED → 返回执行结果
    • FAILED → 返回失败信息
    • RUNNING → 继续等待
  3. 超时后返回提示信息,可再次调用继续等待。

后台Subagent任务管理

每个subagent都会储存结果到subagent_background_results中。同一个subagent可以有多个任务,通过task_id来区分(每次创建任务递增)

subagent_background_results: dict = field(
        default_factory=dict
    )  # 后台subagent结果存储: {agent_name: {task_id: SubAgentExecutionResult}}
    # 任务计数器: {agent_name: next_task_id}
background_task_counters: dict = field(default_factory=dict)

创建任务

    @classmethod
    def create_pending_subagent_task(cls, session_id: str, agent_name: str) -> str:
        """为 SubAgent 创建一个 pending 任务,返回 task_id

        Args:
            session_id: Session ID
            agent_name: SubAgent 名称

        Returns:
            task_id: 任务ID,格式为简单的递增数字字符串
        """

获取结果

    @classmethod
    def get_subagent_result(
        cls, session_id: str, agent_name: str, task_id: str | None = None
    ) -> SubAgentExecutionResult | None:
        """获取 SubAgent 的执行结果

        Args:
            session_id: Session ID
            agent_name: SubAgent 名称
            task_id: 任务ID,如果为None则获取最新完成的任务结果

        Returns:
            SubAgentExecutionResult 或 None
        """

4.5 子代理历史记忆

功能描述

history_enabled=true时,子代理可以保留跨轮对话的历史上下文,实现连续对话能力。

实现方式

  • 存储结构SubAgentSession.subagent_histories
  • 配置subagent_history_maxlen(默认300条)
  • 开关SubAgentManager.is_history_enabled() / set_history_enabled()

历史管理机制

  1. 存储:每次子代理执行完成后,runner_messages(Agent运行期间的消息)追加到历史
  2. 过滤
    • 自动移除 role=system 的消息
    • 对超过 _MAX_TOOL_RESULT_LEN(2000字符)的tool结果截断,附加 ...[truncated]
  3. 截断:历史消息总数超过 subagent_history_maxlen 时,保留最新的消息
  4. 注入:子代理执行前,历史消息转换为 Message 对象,合并到 contexts

历史清理

  • 主Agent可以通过 reset_subagent 工具主动清除指定子代理的历史
  • 如果开启了公共上下文,清理时同时清理与该Agent相关的公共上下文消息

4.6 动态子代理工作目录隔离

功能描述

每个子代理可配置独立的工作目录,未指定时,或工作目录非法时,默认使用 Path(get_astrbot_workspaces_path()) / normalized_umo / agent_name,即主代理默认目录下的子代理文件夹。

实现方式

  • 配置SubAgentConfig.workdir
  • 安全检查CreateSubAgentTool._check_path_safety()
  • Prompt注入_build_workdir_prompt()

注入的工作目录提示

# Working Directory
Your working directory is `{workdir}`. Unless specified by the user, all generated files are saved by default in this directory.

4.7 动态子代理行为规范注入

功能描述

子代理自动注入安全模式、输出规范和时间信息等行为约束。

注入内容

角色定义build_subagent_system_prompt()

# Role
Your name is {agent_name}(used for tool calling)
{base_instructions}

行为规范 _build_rule_prompt(),可由用户在配置中决定。默认配置:

# Behavior Rules
## Safety
{LLM_SAFETY_MODE_SYSTEM_PROMPT}
## Output Guidelines
- If output is long, save it to file. Summarize in your response and provide the file path.
- Mark all generated code/documents with your name and timestamp (if given).

动态时间信息 _build_time_prompt():前两项是静态的,加入到system prompt中;时间信息则加入到附加信息中

# Current Time
2026-04-14 23:09 (CST)

4.8 Skills隔离

功能描述

修复了Subagent无法使用skills的问题,每个子代理可分配不同的Skills,相互隔离。

注入逻辑

  1. 获取子代理分配的技能列表(SubAgentConfig.skills
  2. 通过 SkillManager.list_skills() 获取所有可用技能
  3. 过滤只保留分配的技能
  4. 调用 build_skills_prompt() 生成提示词
  5. 通过 build_subagent_system_prompt() 注入到子代理的 system_prompt

4.9 公共上下文

功能描述

shared_context_enabled=true 时,维护一个所有子代理共享的、实时更新的群聊区域。在SubAgent每次调用LLM之前,公共上下文的内容会被注入到子代理的追加信息中。

公共上下文中每条信息的格式

message = {
    "type": context_type,  # status, message, system
    "sender": sender,
    "target": target,
    "content": content,
    "timestamp": time.time(),
}

上下文类型

类型 说明 使用场景
status 状态更新 子代理报告任务进度
message 消息传递 子代理间直接通信
system 系统公告 主Agent发布全局信息

公共上下文注入方式

按类型和优先级分组注入到子代理的追加信息中,让Agent可以更清晰地获取共享上下文的信息,并知道哪些需要优先处理。

实现方式

  • 文件astrbot/core/subagent_manager.py
  • 核心方法SubAgentManager._build_shared_context_prompt()

Prompt结构

---
# Shared Context - Collaborative communication area among different agents

## Message Type Definition
- **@ToMe**: Message send to current agent(you), you may need to reply if necessary.
- **@System**: Messages published by the main agent/System that should be followed with priority
- **@AgentName -> @TargetName**: Communication between other agents (for reference)
- **@Status**: The progress of other agents' tasks (can be ignored unless it involves your task)

## Handling Priorities
1. @System messages (highest priority) > @ToMe messages > @Status > @OtherAgents
2. Messages of the same type: In chronological order, with new messages taking precedence

## @System - System Announcements
[时间戳] System: 系统公告内容...

## @ToMe - Messages sent to @当前代理名
 **These messages are addressed to you. If needed, please reply using `send_shared_context`**
[时间戳] @发送者 -> @当前代理名: 消息内容

## @OtherAgents - Communication among Other Agents (Last 10 messages)
[时间戳] AgentA -> AgentB: 消息内容

## @Status - Task progress of each agent (Last 10 messages)
[时间戳] AgentA: 已完成数据清洗
[时间戳] AgentB: 开始数据可视化
---

容量管理

  • 公共上下文消息数超过 shared_context_maxlen 时,保留最近90%的消息
  • 子代理清理时自动移除相关公共上下文消息
  • 所有子代理都被清理后,清除全部公共上下文

公共上下文特点

  • 优先级明确:System消息 > ToMe消息 > Status > 其他Agent之间的通信
  • 相关性过滤:只显示与当前Agent相关的消息
  • 信息精简:其他Agent间通信和状态只显示最近10条,避免信息过载

4.10 主Agent路由提示

功能描述

dynamic_agents.enabled=true 时,在主Agent的System Prompt中注入动态SubAgent能力说明,包括创建指南和委派流程。如果dynamic_agents.enabled=false,则仍然使用router_system_prompt

动态子代理路由的注入内容

核心方法SubAgentManager.build_task_router_prompt()

# Sub-Agent Orchestration
You can manage sub-agents with isolated instructions, tools and skills. Maximum 3 subagents.

## When to Use
Create sub-agents ONLY when:
- Task has ≥2 independent workstreams with clear inputs/outputs
- Context exceeds your effective processing window

## Workflow: Plan → Create → Delegate → Collect → Cleanup
### 1. Create Sub-agent
**Name**: 1 to 32 characters (letters, numbers, or underscores), starting with a letter.
**Required fields:**
| Field | Description |
|-------|-------------|
| Role | Expertise + work style |
| Context | Parent goal, this step, sibling agents |
| Instruction | Input → Process → Output (step-by-step) |
| Tools | **Minimum necessary only** |

### 2. Delegate
- Sequential: `transfer_to_*(...)` — block until return
- Parallel: `transfer_to_*(..., background_task=True)``wait_for_subagent(name, timeout=secs)`

### 3. Collect & Cleanup
- Merge independent outputs by concatenation
- Resolve conflicts by preferring explicit data over inference
- Sub-agents auto-destroy per turn; use `manage_subagent_protection` for multi-turn stateful tasks

4.11 动态子代理的自动清理

功能描述

auto_cleanup_per_turn=true时,每轮对话结束后,自动清理产生的动态子代理。

auto_cleanup_per_turn=true,但又想要保留某个子代理留作后续使用,可以由主agent调用manage_subagent_protection管理工具为子代理添加保护,防止被自动清理。

主Agent也可以根据需要,手动通过manage_subagent_protection移除保护,或直接通过remove_subagent工具清理某个子代理。

清理规则

  1. 遍历所有非保护的子代理
  2. 调用 remove_subagent() 进行清理(移除配置、handoff工具、历史、后台结果)
  3. 清理公共上下文中与被移除Agent相关的消息
  4. 清理后,如果没有子代理剩余,清除全部公共上下文

触发时机

internal.py 的 agent 结束流程中:

if build_cfg.subagent_orchestrator.get("main_enable"):
    if SubAgentManager.is_auto_cleanup_per_turn():
        SubAgentManager.cleanup_session_turn_end(session_id)

4.12 动态子代理数量限制

功能描述

限制单个会话中子代理的最大数量,防止资源耗尽。

注意:替换已存在的同名子代理不增加计数。


4.13 执行超时控制

功能描述

除了原有的工具调用超时外,为每个子代理设置总的执行超时时间,避免无限等待。这是一项全局设置,对所有子代理有效

实现方式

  • 配置SubAgentConfig.execution_timeout(默认1200秒)
  • 全局配置subagent_orchestrator.execution_timeout
  • 核心方法SubAgentManager.get_execution_timeout()

超时处理流程

1. 调用 _get_subagent_execution_timeout() 获取超时时间
2. 通过 asyncio.wait_for() 包装子代理执行协程
3. 超时时:
   a. 记录警告日志
   b. 调用 _handle_subagent_timeout() 将状态设为 "FAILED"
   c. 返回超时错误信息给调用者
4. 执行完成后,正常返回结果

4.14 会话过期清理

功能描述

为防止内存泄漏,SubAgentManager 会自动清理长时间未活跃的会话。默认超时时间为30分钟。

实现方式

  • 核心属性_session_timeout_seconds(默认1800秒 = 30分钟)
  • 核心方法cleanup_expired_sessions()
  • 触发时机cleanup_session_turn_end() 每轮结束时自动调用

清理逻辑

1. 检查所有会话的 last_activity_at 时间
2. 超过 _session_timeout_seconds 的会话标记为过期
3. 清理过期会话中的所有子代理
4. 记录日志:会话ID、不活跃时间、清理的子代理数量

内置/reset命令扩展

/reset用户指令现在会连同当前会话的subagent一起清理


五、工具列表

5.1 主Agent新增可用工具

工具名 功能 参数 条件
create_subagent 创建子代理 name, system_prompt, tools, skills, workdir, provider_id enable_dynamic=true
remove_subagent 清理子代理(支持"all") name enable_dynamic=true
list_subagents 列出子代理及其状态和工具 include_status enable_dynamic=true
manage_subagent_protection 保护/取消保护子代理 name, protected (bool) enable_dynamic=true, auto_cleanup_per_turn=True
view_shared_context 查看公共上下文 - shared_context_enabled=true
broadcast_shared_context 广播公共上下文(以System身份广播,或单独给某个Subagent发指令) context_type, content, target shared_context_enabled=true
wait_for_subagent 等待并获取后台SubAgent结果 subagent_name, task_id, timeout, poll_interval 始终注册

5.2 子代理可用工具

工具名 功能 参数 说明
send_shared_context 发送公共上下文 context_type, content, sender, target shared_context启用时自动分配该工具
主Agent分配的工具 - - -
固有工具 无论主Agent是否分配,都会注入的工具 - 由配置文件tools_inherent给出

六、修改文件清单

文件路径 修改说明
astrbot/core/subagent_manager.py 新增:为本PR的核心实现,定义了Subagent管理类SubAgentManager,包含会话管理、后台任务管理、历史信息、公共上下文、Prompt构建、会话过期清理等;以及配套的SubAgentConfigSubAgentSession数据结构
astrbot/core/subagent_tools.py 新增:所有子代理管理工具的类定义(create_subagent、remove_subagent、list_subagents、manage_subagent_protection、reset_subagent、broadcast_shared_context、send_shared_context、view_shared_context、wait_for_subagent 等),这些工具供主Agent进行运行时管理
astrbot/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_runnerAstrAgentContext.extra
astrbot/core/subagent_orchestrator.py 修改:新增 register_static_subagents_to_manager() 方法;静态subagent自动注册到 SubAgentManager 享受增强功能
astrbot/core/pipeline/process_stage/method/agent_sub_stages/internal.py 修改:读取新版SubAgent配置、每轮结束后调用清理逻辑
astrbot/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.py 修改:默认配置文件格式,新增dynamic_agentstime_prompt_enabledhistory_enabledshared_context_enabledshared_context_maxlensubagent_history_maxlenexecution_timeout等配置项
astrbot/core/astr_agent_context.py 修改:把extra字段的类型改成dict[str, Any],使得可以记录任意类型的extra信息。例如在本PR中,它存储了一个Agent对象
astrbot/core/star/context.py 修改:tool_loop_agent() 支持 runner_messages 参数(通过kwargs传递),用于记录SubAgent历史
astrbot/builtin_stars/builtin_commands/commands/conversation.py 修改:在 /reset 命令处理中新增 subagent 清理逻辑,调用 SubAgentManager.cleanup_session() 清理当前会话的所有子代理
astrbot/dashboard/routes/subagent.py 修改:Dashboard后端API,新增动态子代理配置项的读取和保存支持
dashboard/src/i18n/locales/en-US/features/subagent.json 修改:英文国际化文件,新增动态子代理相关翻译词条
dashboard/src/i18n/locales/ru-RU/features/subagent.json 修改:俄文国际化文件,新增动态子代理相关翻译词条
dashboard/src/i18n/locales/zh-CN/features/subagent.json 修改:中文国际化文件,新增动态子代理相关翻译词条
dashboard/src/views/SubAgentPage.vue 修改:Dashboard前端页面,新增动态子代理配置界面(全局设置、运行参数、共享上下文、工具策略等分区)

七、使用流程

7.1 静态子代理使用流程

与原版一致,但子代理获得增强

1. 在 subagent_orchestrator.agents 中配置子代理,并设置 subagent_orchestrator.main_enable = true
2. 主Agent自动获得 transfer_to_xxx 工具
3. 主Agent使用 transfer_to_xxx 委派任务
4. 子代理执行任务并返回结果
5. 主Agent整合结果回复用户
6. 如果配置文件中允许,静态子代理可以被赋予历史上下文记忆、公共上下文交互等增强功能

7.2 动态子代理使用流程

1. 设置 subagent_orchestrator.main_enable = true
2. 设置 subagent_orchestrator.enable_dynamic = true
3. 主Agent识别需要创建子代理,调用 create_subagent 工具
4. 系统在运行时创建子代理和 transfer_to_xxx 工具
5. 主Agent使用 transfer_to_xxx 委派任务
6. 子代理执行任务并返回结果
7. 主Agent整合结果回复用户
8. 动态子代理被自动清理(如果auto_cleanup_per_turn = true)

7.3 带保护的多轮对话流程

当动态子代理被保护时,不会被自动清理

第1轮:
  用户 -> 主Agent: 创建分析师,帮我分析数据
  主Agent -> create_subagent(analyst)
  主Agent -> manage_subagent_protection(analyst, protected=true)
  主Agent -> transfer_to_analyst(分析这份数据)
  分析师 -> 返回分析结果
  用户 <- 主Agent <- 分析结果
  (轮结束后,analyst因受保护不会被清理)

第2轮:
  用户 -> 主Agent: 继续分析另一份数据
  主Agent -> transfer_to_analyst(分析新数据)  // 分析师带历史上下文
  分析师(带历史上下文) -> 返回新分析结果
  用户 <- 主Agent <- 新结果

7.4 带公共上下文的协作流程

1. 启用 shared_context_enabled=true
2. 主Agent创建多个SubAgent
3. 子代理A: send_shared_context(status, "已完成数据清洗"), send_shared_context(message, A, B, "请子代理B开始数据可视化")
4. 子代理B: send_shared_context(status, "开始数据可视化"), send_shared_context(message, B, A, "我已收到,开始执行数据可视化")
5. 子代理C: 可看到A和B的状态更新
6. 主Agent: 公共上下文不会自动注入给主Agent,但可以调用view_shared_context() 查看,或通过 broadcast_shared_context() 广播消息

7.5 后台任务并行处理流程

复杂场景:用户要求同时进行数据分析、文件处理、报告生成三个任务。同时用户要求打开浏览器。
        该过程可以同时包含前台和后台任务,并具有复杂的数据相关

主Agent决策:
  1. 分析四个任务可以并行执行,而数据分析任务可能要执行多步,执行的步数依赖于上一次分析的结果。
  2. 系统给出了3个Subagent的最大限制,因此创建三个SubAgent,分别负责前三个不同任务。自己负责剩下的浏览器任务
  3. 使用 background_task=True 委派任务

执行流程:
  主Agent -> create_subagent(data_analyst)
  主Agent -> create_subagent(file_processor)
  主Agent -> create_subagent(report_generator)

  主Agent -> transfer_to_data_analyst(分析数据, background_task=True)
  主Agent -> transfer_to_file_processor(处理文件, background_task=True)
  主Agent -> transfer_to_report_generator(生成报告, background_task=True)

  # 主Agent此时可以继续处理其他不依赖SubAgent的任务
  主Agent 可以去处理其他事情(打开浏览器)

  # 或者主Agent有任务需要等待某个SubAgent的结果
  主Agent -> wait_for_subagent(subagent_name="data_analyst")
  # 获取到数据分析师的结果后
  主Agent -> 评审数据分析师的结果,判断是否继续分析
  主Agent -> transfer_to_data_analyst(分析剩余的少量数据, background_task=false)
  主Agent -> 由于是background_task=false,直接能拿到结果

  # 所有任务完成后,整合结果
  主Agent -> wait_for_subagent(subagent_name="file_processor")
  主Agent -> wait_for_subagent(subagent_name="report_generator")
  主Agent -> 整合所有结果回复用户

7.6 后台任务与共享上下文结合

场景:多个SubAgent并行处理数据,最后汇总结果

1. 创建处理Agent和汇总Agent
   主Agent -> create_subagent(handler_a, ...)
   主Agent -> create_subagent(handler_b, ...)
   主Agent -> create_subagent(summarizer, ...)

2. Handler A和B以后台模式并行处理
   主Agent -> transfer_to_handler_a(处理数据A, background_task=True)
   主Agent -> transfer_to_handler_b(处理数据B, background_task=True)

3. 处理完成后,发布状态到共享上下文
   handler_a -> send_shared_context(status, "数据A处理完成,结果保存到文件X")
   handler_b -> send_shared_context(status, "数据B处理完成,结果保存到文件Y")

4. 汇总Agent看到状态后,开始汇总
   summarizer 可以看到:
     @Status: handler_a - 数据A处理完成,结果保存到文件X
     @Status: handler_b - 数据B处理完成,结果保存到文件Y

   主Agent -> transfer_to_summarizer(汇总处理结果)
   summarizer -> 读取文件X和Y,生成汇总报告

5. 主Agent获取最终结果
   主Agent -> wait_for_subagent(subagent_name="summarizer")
   主Agent -> 将汇总报告发送给用户

八、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() -> float 获取执行超时时间
is_auto_cleanup_per_turn() -> bool 检查是否启用自动清理
is_shared_context_enabled() -> bool 检查是否启用公共上下文
is_history_enabled() -> bool 检查是否启用子代理历史记忆
set_history_enabled(session_id, enabled) 启用/禁用指定会话的子代理历史记忆
register_blacklisted_tool(tool_name) 注册不应被子Agent使用的工具
register_inherent_tool(tool_name) 注册子Agent默认拥有的工具
cleanup_expired_sessions() -> dict 清理过期会话,防止内存泄漏

子代理管理

方法签名 说明
create_subagent(session_id, config, protected=False) -> tuple 创建子代理,返回(tool_name, handoff_tool)
register_static_subagent(session_id, handoff_tool, skills, workdir) -> tuple 注册静态子代理到管理器(自动protected=True)
remove_subagent(session_id, agent_name) -> str 移除子代理(name="all"移除全部)
protect_subagent(session_id, agent_name) 保护子代理
is_protected(session_id, agent_name) -> bool 检查是否受保护
set_subagent_status(session_id, agent_name, status) 设置子代理状态
cleanup_session_turn_end(session_id) -> dict 结束时清理
cleanup_session(session_id) -> dict 清理整个会话
get_handoff_tools_for_session(session_id) -> list 获取会话的handoff工具列表
get_subagent_tools(session_id, agent_name) -> list | None 获取子代理的工具列表

历史管理

方法签名 说明
update_subagent_history(session_id, agent_name, current_messages) 更新历史(自动过滤system消息、截断tool结果)
get_subagent_history(session_id, agent_name) -> list 获取历史
clear_subagent_history(session_id, agent_name) -> str 清除历史

Prompt构建

方法签名 说明
build_task_router_prompt(session_id) -> str 构建主Agent路由提示,告诉主Agent可以动态创建和管理子代理
build_subagent_system_prompt(session_id, agent_name, runtime) -> str 构建subagent系统提示(人格、工作目录、行为规范、Skills)
build_subagent_extra_content_parts(session_id, agent_name) -> list 构建追加内容(公共上下文、时间信息)

后台任务管理

方法签名 说明
create_pending_subagent_task(session_id, agent_name) -> str 创建pending任务,返回task_id
get_pending_subagent_tasks(session_id, agent_name) -> list[str] 获取所有pending任务ID
get_latest_task_id(session_id, agent_name) -> str | None 获取最新任务ID
store_subagent_result(session_id, agent_name, success, result, task_id, error, execution_time, metadata) 存储执行结果
get_subagent_result(session_id, agent_name, task_id) -> SubAgentExecutionResult | None 获取执行结果
has_subagent_result(session_id, agent_name, task_id) -> bool 检查是否有结果
clear_subagent_result(session_id, agent_name, task_id) 清除执行结果
get_subagent_status(session_id, agent_name) -> str 获取状态:IDLE/RUNNING/COMPLETED/FAILED
get_all_subagent_status(session_id) -> dict 获取所有SubAgent状态

公共上下文管理

方法签名 说明
add_shared_context(session_id, sender, context_type, content, target) 添加公共上下文消息
get_shared_context(session_id, filter_by_agent) -> list 获取公共上下文
set_shared_context_enabled(session_id, enabled) 启用/禁用公共上下文
cleanup_shared_context_by_agent(session_id, agent_name) 清理与指定Agent相关的消息
clear_shared_context(session_id) 清除所有公共上下文

8.2 SubAgentExecutionResult 数据结构

# 用于记录每个subagent的执行结果
@dataclass
class SubAgentExecutionResult:
    task_id: str           # 任务唯一标识符(递增数字字符串)
    agent_name: str        # SubAgent名称
    success: bool          # 是否成功
    result: str | None     # 执行结果
    error: str | None      # 错误信息
    execution_time: float  # 执行耗时(秒)
    created_at: float      # 创建时间戳
    completed_at: float    # 完成时间戳
    metadata: dict         # 额外元数据

8.3 SubAgentConfig 数据结构

# 用于定义每个subagent
@dataclass
class SubAgentConfig:
    name: str                          # subagent名字
    system_prompt: str = ""            # subagent系统提示词
    tools: set[str] | None = None      # subagent工具集合
    skills: set[str] | None = None     # subagent skill集合
    provider_id: str | None = None     # subagent provider id
    description: str = ""              # subagent 描述,对应handoff_tool的描述
    workdir: str | None = None         # subagent工作目录
    execution_timeout: float = 600.0   # 执行超时时间(秒)

8.4 SubAgentSession 数据结构

# 存储每个会话的subagent所有相关信息
@dataclass
class SubAgentSession:
    session_id: str                                     # 会话ID
    subagents: dict = field(default_factory=dict)       # 存储SubAgentConfig对象
    handoff_tools: dict = field(default_factory=dict)   # 存储handoff工具列表
    subagent_status: dict = field(                      # 存储每个subagent的工作状态,{agent_name: status} 
      default_factory=dict                              # 状态包括 "IDLE" "RUNNING" "COMPLETED" "FAILED"
    )  
    protected_agents: set = field(                      # 受保护的subagent列表,若某个agent受到保护,则不会被自动清理
        default_factory=set
    ) 
    history_enabled: bool = True                        # 是否保存子代理历史
    subagent_histories: dict = field(default_factory=dict)  # 存储每个subagent的历史上下文
    shared_context: list = field(default_factory=list) # 公共上下文列表
    shared_context_enabled: bool = False               # 是否启用公共上下文
    subagent_background_results: dict = field(
        default_factory=dict
    )                                                  # 后台subagent结果存储: {agent_name: {task_id: SubAgentExecutionResult}}
    background_task_counters: dict = field(default_factory=dict)   # 任务计数器: {agent_name: next_task_id}
    last_activity_at: float = field(default_factory=time.time)  # 最后活跃时间戳

Screenshots or Test Results / 运行截图或测试结果

Dashboard页面

suabgent_dashboard

运行示例

截图

subagent_example

日志记录

[18:09:56.103] [Core] [INFO] [core.event_bus:61]: [Astrbot专家] [webchat(webchat)] astrbot/astrbot: 请创建三个不同风格的诗人子代理,分别写一首诗,并由你汇总为一个.md文件
[18:09:56.228] [Core] [INFO] [core.subagent_manager:710]: [SubAgent:History] Subagent history enabled
[18:09:56.228] [Core] [INFO] [core.subagent_manager:720]: [SubAgent:SharedContext] Shared context enabled
[18:09:56.233] [Core] [INFO] [respond.stage:183]: Prepare to send - astrbot/astrbot:
[18:09:56.233] [Core] [INFO] [respond.stage:199]: 应用流式输出(webchat)
[18:10:02.980] [Core] [INFO] [core.astr_main_agent:976]: Generated chatui title for session 14c57255-2002-4e8d-ab6a-a4b420b765fe: 创建诗人子代理并汇总诗作
[18:10:18.385] [Core] [INFO] [runners.tool_loop_agent_runner:976]: Agent 使用工具: ['create_subagent', 'create_subagent', 'create_subagent']
[18:10:18.386] [Core] [INFO] [runners.tool_loop_agent_runner:1042]: 使用工具:create_subagent,参数:{'name': 'classical_poet', 'system_prompt': '你是一位中国古典风格诗人,精通唐诗宋词的格律与意境。\n\n创作风格:\n- 讲究平仄对仗,意境深远\n- 善用典故,借景抒情\n- 语言凝练典雅,富有画面感\n- 主题多为山水、离别、怀古、人生感悟\n\n输出要求:\n- 创作一首古典风格的诗歌(律诗或绝句形式)\n- 在诗后附上简短的赏析(2-3句话)\n- 标注诗歌体裁(如:七言绝句、五言律诗等)'}
[18:10:18.397] [Core] [INFO] [core.subagent_manager:843]: [SubAgent:Create] Created subagent: classical_poet (protected=False)
[18:10:18.398] [Core] [INFO] [runners.tool_loop_agent_runner:1491]: [SubAgent] Tool created: transfer_to_classical_poet
[18:10:18.399] [Core] [INFO] [runners.tool_loop_agent_runner:1510]: [SubAgent] Added transfer_to_classical_poet to func_tool set
[18:10:18.400] [Core] [INFO] [runners.tool_loop_agent_runner:1245]: Tool create_subagent Result: DYNAMIC_TOOL_CREATED:transfer_to_classical_poet:transfer_to_classical_poet:Created. Use transfer_to_classical_poet to delegate.
[18:10:18.401] [Core] [INFO] [runners.tool_loop_agent_runner:1042]: 使用工具:create_subagent,参数:{'name': 'modern_poet', 'system_prompt': '你是一位中国现代派诗人,受新月派、朦胧诗等现代诗歌流派影响。\n\n创作风格:\n- 打破传统格律,追求自由表达\n- 善用意象叠加与隐喻象征\n- 关注现代都市生活与个体精神困境\n- 语言简洁但富有张力,留白与跳跃感并存\n\n输出要求:\n- 创作一首现代自由诗(8-16行)\n- 在诗后附上简短的创作手记(2-3句话)\n- 标注诗歌主题'}
[18:10:18.411] [Core] [INFO] [core.subagent_manager:843]: [SubAgent:Create] Created subagent: modern_poet (protected=False)
[18:10:18.412] [Core] [INFO] [runners.tool_loop_agent_runner:1491]: [SubAgent] Tool created: transfer_to_modern_poet
[18:10:18.412] [Core] [INFO] [runners.tool_loop_agent_runner:1510]: [SubAgent] Added transfer_to_modern_poet to func_tool set
[18:10:18.413] [Core] [INFO] [runners.tool_loop_agent_runner:1245]: Tool create_subagent Result: DYNAMIC_TOOL_CREATED:transfer_to_modern_poet:transfer_to_modern_poet:Created. Use transfer_to_modern_poet to delegate.
[18:10:18.414] [Core] [INFO] [runners.tool_loop_agent_runner:1042]: 使用工具:create_subagent,参数:{'name': 'romantic_poet', 'system_prompt': '你是一位浪漫主义诗人,深受西方浪漫主义与中国抒情传统影响。\n\n创作风格:\n- 情感浓烈奔放,直抒胸臆\n- 歌颂自然之美、爱情之纯、理想之光\n- 想象瑰丽,善用夸张与排比\n- 语言华丽优美,节奏舒缓如歌\n\n输出要求:\n- 创作一首浪漫主义风格的抒情诗(12-20行)\n- 在诗后附上简短的情感寄语(2-3句话)\n- 标注诗歌献给的对象或主题'}
[18:10:18.425] [Core] [INFO] [core.subagent_manager:843]: [SubAgent:Create] Created subagent: romantic_poet (protected=False)
[18:10:18.426] [Core] [INFO] [runners.tool_loop_agent_runner:1491]: [SubAgent] Tool created: transfer_to_romantic_poet
[18:10:18.427] [Core] [INFO] [runners.tool_loop_agent_runner:1510]: [SubAgent] Added transfer_to_romantic_poet to func_tool set
[18:10:18.429] [Core] [INFO] [runners.tool_loop_agent_runner:1245]: Tool create_subagent Result: DYNAMIC_TOOL_CREATED:transfer_to_romantic_poet:transfer_to_romantic_poet:Created. Use transfer_to_romantic_poet to delegate.

[SYSTEM NOTICE] By the way, you have executed the same tool create_subagent 3 times consecutively. Double-check whether another tool, different arguments, or a summary would move the task forward better.
[18:10:26.487] [Core] [INFO] [runners.tool_loop_agent_runner:976]: Agent 使用工具: ['transfer_to_classical_poet', 'transfer_to_modern_poet', 'transfer_to_romantic_poet']
[18:10:26.487] [Core] [INFO] [runners.tool_loop_agent_runner:1042]: 使用工具:transfer_to_classical_poet,参数:{'input': '请以"初夏黄昏"为主题,创作一首古典风格的诗歌。要求体现初夏时节黄昏时分的景色与心境,包含对时光流逝的淡淡感慨。请直接输出诗歌内容、体裁标注和赏析。', 'background_task': True}
[18:10:26.488] [Core] [INFO] [core.astr_agent_tool_exec:924]: [SubAgent:BackgroundTask] Created background task 1 for classical_poet
[18:10:26.520] [Core] [INFO] [runners.tool_loop_agent_runner:1245]: Tool transfer_to_classical_poet Result: Background task submitted. subagent_task_id=1. SubAgent 'classical_poet' is working on the task. Use wait_for_subagent(subagent_name='classical_poet', task_id='1') to get the result.
[18:10:26.520] [Core] [INFO] [runners.tool_loop_agent_runner:1042]: 使用工具:transfer_to_modern_poet,参数:{'input': '请以"城市霓虹下的独行者"为主题,创作一首现代自由诗。要求体现都市夜晚的孤独感与现代人的精神漂泊,同时保留一丝对未来的希望。请直接输出诗歌内容、主题标注和创作手记。', 'background_task': True}
[18:10:26.521] [Core] [INFO] [core.astr_agent_tool_exec:924]: [SubAgent:BackgroundTask] Created background task 1 for modern_poet
[18:10:26.534] [Core] [INFO] [runners.tool_loop_agent_runner:1245]: Tool transfer_to_modern_poet Result: Background task submitted. subagent_task_id=1. SubAgent 'modern_poet' is working on the task. Use wait_for_subagent(subagent_name='modern_poet', task_id='1') to get the result.
[18:10:26.535] [Core] [INFO] [runners.tool_loop_agent_runner:1042]: 使用工具:transfer_to_romantic_poet,参数:{'input': '请以"致远方的星辰"为主题,创作一首浪漫主义风格的抒情诗。要求表达对遥远理想的追寻与对美好事物的永恒向往,情感真挚热烈。请直接输出诗歌内容、主题标注和情感寄语。', 'background_task': True}
[18:10:26.536] [Core] [INFO] [core.astr_agent_tool_exec:924]: [SubAgent:BackgroundTask] Created background task 1 for romantic_poet
[18:10:26.554] [Core] [INFO] [runners.tool_loop_agent_runner:1245]: Tool transfer_to_romantic_poet Result: Background task submitted. subagent_task_id=1. SubAgent 'romantic_poet' is working on the task. Use wait_for_subagent(subagent_name='romantic_poet', task_id='1') to get the result.
[18:10:30.621] [Core] [INFO] [runners.tool_loop_agent_runner:976]: Agent 使用工具: ['wait_for_subagent', 'wait_for_subagent', 'wait_for_subagent']
[18:10:30.622] [Core] [INFO] [runners.tool_loop_agent_runner:1042]: 使用工具:wait_for_subagent,参数:{'subagent_name': 'classical_poet', 'timeout': 60}
[18:10:35.649] [Core] [INFO] [runners.tool_loop_agent_runner:1245]: Tool wait_for_subagent Result: SubAgent 'classical_poet' execution completed
Task id: 1
Execution time: 5.4s
--- Result ---

初夏黄昏

七言绝句

绿槐高柳咽新蝉,
薰风初入小庭前。
斜阳影里人独立,
一霎微凉又一年。


赏析

此诗以初夏黄昏为背景,前两句写绿槐高柳间新蝉初鸣、薰风轻过小庭之景,声色交融,尽显初夏生机;后两句转入抒情,斜阳独立之人忽觉微凉,顿感流光易逝,"又一年"三字将淡淡惆怅轻轻托出,余韵悠长。全诗以景起以情结,含蓄蕴藉,颇得唐人绝句风神。

[18:10:35.650] [Core] [INFO] [runners.tool_loop_agent_runner:1042]: 使用工具:wait_for_subagent,参数:{'subagent_name': 'modern_poet', 'timeout': 60}
[18:10:44.899] [Core] [INFO] [runners.tool_loop_agent_runner:976]: Agent 使用工具: ['astrbot_file_write_tool']
[18:10:44.899] [Core] [INFO] [runners.tool_loop_agent_runner:1042]: 使用工具:astrbot_file_write_tool,参数:{'path': '城市霓虹下的独行者.md', 'content': '# 城市霓虹下的独行者\n\n> 作者:modern_poet \n> 创作时间:2026-05-11 18:10 (CST)\n\n---\n\n## 霓虹之下\n\n地铁口的风卷起一张旧报纸,\n像只折翼的鸟,撞向玻璃幕墙——\n碎成二十四楼的倒影。\n\n便利店永远亮着,\n关东煮在塑料盒里浮沉,\n如同我们,在格子间里\n数着秒针,等一个不会来的春天。\n\n天桥上有人弹唱,\n吉他箱里躺着几枚硬币,\n和一张去远方的车票,\n日期是昨天。\n\n而霓虹从不熄灭,\n它把每个人的影子\n拉得很长,很长——\n长到可以当作一条回家的路。\n\n---\n\n主题:城市霓虹下的独行者\n\n---\n\n创作手记:\n\n这首诗以都市夜晚的典型意象——地铁口、便利店、天桥弹唱者——构建了一幅现代漂泊者的精神图景。霓虹既是围困的光,也是指引的灯;旧报纸与远方车票暗示着被折叠的梦想,而"影子拉成回家的路"则在孤独中保留了一丝温柔的期盼。我希望读者能在这些碎片中,看见自己,也看见彼此。\n'}
[18:10:44.906] [Core] [INFO] [runners.tool_loop_agent_runner:1245]: Tool astrbot_file_write_tool Result: File written successfully: F:\github\Astrbot\data\workspaces\webchat_FriendMessage_webchat_astrbot_14c57255-2002-4e8d-ab6a-a4b420b765fe\城市霓虹下的独行者.md
[18:11:00.677] [Core] [INFO] [runners.tool_loop_agent_runner:1245]: Tool wait_for_subagent Result: SubAgent 'modern_poet' execution completed
Task id: 1
Execution time: 33.9s
--- Result ---
诗歌已创作完成并保存至文件。以下是内容展示:


霓虹之下

地铁口的风卷起一张旧报纸,
像只折翼的鸟,撞向玻璃幕墙——
碎成二十四楼的倒影。

便利店永远亮着,
关东煮在塑料盒里浮沉,
如同我们,在格子间里
数着秒针,等一个不会来的春天。

天桥上有人弹唱,
吉他箱里躺着几枚硬币,
和一张去远方的车票,
日期是昨天。

而霓虹从不熄灭,
它把每个人的影子
拉得很长,很长——
长到可以当作一条回家的路。


主题:城市霓虹下的独行者


创作手记

这首诗以都市夜晚的典型意象——地铁口、便利店、天桥弹唱者——构建了一幅现代漂泊者的精神图景。霓虹既是围困的光,也是指引的灯;旧报纸与远方车票暗示着被折叠的梦想,而"影子拉成回家的路"则在孤独中保留了一丝温柔的期盼。我希望读者能在这些碎片中,看见自己,也看见彼此。


📄 文件路径F:\github\Astrbot\data\workspaces\webchat_FriendMessage_webchat_astrbot_14c57255-2002-4e8d-ab6a-a4b420b765fe\城市霓虹下的独行者.md

[18:11:00.678] [Core] [INFO] [runners.tool_loop_agent_runner:1042]: 使用工具:wait_for_subagent,参数:{'subagent_name': 'romantic_poet', 'timeout': 60}
[18:11:00.681] [Core] [INFO] [runners.tool_loop_agent_runner:1245]: Tool wait_for_subagent Result: SubAgent 'romantic_poet' has no pending tasks. Latest completed task id: 1. Task id 1 Results:

致远方的星辰


致远方的星辰

当夜幕垂落如深蓝的绸缎,
我便仰望你,那遥远的光点。
亿万里的虚空无法冷却我的凝望,
你是理想在天穹点燃的火焰!

我穿越荆棘丛生的山谷与荒原,
只为追逐你抛洒的一线银辉。
风暴撕裂我的斗篷,泥泞吞没我的步履,
可你依然高悬——我永恒的方位。

啊,星辰!你是诗人梦中的圣殿,
是旅人寒夜里不灭的灯盏。
纵使穷尽一生也无法抵达你的身旁,
我仍将整个灵魂,化作向你飞翔的翅膀。

让世俗在脚下沉沦成灰色的尘埃吧,
我的心,永远向着璀璨的存在!


主题:致远方的星辰——献给所有追寻理想与美好的人们

情感寄语:愿我们都能成为自己的星辰,在漫长黑夜里为彼此照亮前路。理想或许永远在前方,但追寻本身已让生命绽放光芒。


romantic_poet | 2026-05-11 18:10 (CST)

[SYSTEM NOTICE] By the way, you have executed the same tool wait_for_subagent 3 times consecutively. Double-check whether another tool, different arguments, or a summary would move the task forward better.
[18:11:30.271] [Core] [INFO] [runners.tool_loop_agent_runner:976]: Agent 使用工具: ['astrbot_file_write_tool']
[18:11:30.272] [Core] [INFO] [runners.tool_loop_agent_runner:1042]: 使用工具:astrbot_file_write_tool,参数:{'path': 'D:\AstrbotWorkSpace\三诗人合集.md', 'content': '# 三诗人合集\n\n> 编者注:本合集由三位不同风格的诗人子代理独立创作,分别代表古典、现代、浪漫三种诗歌美学。\n>\n> 汇总时间:2026-05-11 18:10 (CST)\n> 编者:AstrBot 开发专家\n\n---\n\n## 一、古典诗人 · 初夏黄昏\n\n体裁:七言绝句\n\n> 绿槐高柳咽新蝉, \n> 薰风初入小庭前。 \n> 斜阳影里人独立, \n> 一霎微凉又一年。\n\n赏析:此诗以初夏黄昏为背景,前两句写绿槐高柳间新蝉初鸣、薰风轻过小庭之景,声色交融,尽显初夏生机;后两句转入抒情,斜阳独立之人忽觉微凉,顿感流光易逝,"又一年"三字将淡淡惆怅轻轻托出,余韵悠长。全诗以景起以情结,含蓄蕴藉,颇得唐人绝句风神。\n\n---\n\n## 二、现代诗人 · 霓虹之下\n\n主题:城市霓虹下的独行者\n\n> 地铁口的风卷起一张旧报纸, \n> 像只折翼的鸟,撞向玻璃幕墙—— \n> 碎成二十四楼的倒影。\n>\n> 便利店永远亮着, \n> 关东煮在塑料盒里浮沉, \n> 如同我们,在格子间里 \n> 数着秒针,等一个不会来的春天。\n>\n> 天桥上有人弹唱, \n> 吉他箱里躺着几枚硬币, \n> 和一张去远方的车票, \n> 日期是昨天。\n>\n> 而霓虹从不熄灭, \n> 它把每个人的影子 \n> 拉得很长,很长—— \n> 长到可以当作一条回家的路。\n\n创作手记:这首诗以都市夜晚的典型意象——地铁口、便利店、天桥弹唱者——构建了一幅现代漂泊者的精神图景。霓虹既是围困的光,也是指引的灯;旧报纸与远方车票暗示着被折叠的梦想,而"影子拉成回家的路"则在孤独中保留了一丝温柔的期盼。我希望读者能在这些碎片中,看见自己,也看见彼此。\n\n---\n\n## 三、浪漫诗人 · 致远方的星辰\n\n献给:所有追寻理想与美好的人们\n\n> 当夜幕垂落如深蓝的绸缎, \n> 我便仰望你,那遥远的光点。 \n> 亿万里的虚空无法冷却我的凝望, \n> 你是理想在天穹点燃的火焰!\n>\n> 我穿越荆棘丛生的山谷与荒原, \n> 只为追逐你抛洒的一线银辉。 \n> 风暴撕裂我的斗篷,泥泞吞没我的步履, \n> 可你依然高悬——我永恒的方位。\n>\n> 啊,星辰!你是诗人梦中的圣殿, \n> 是旅人寒夜里不灭的灯盏。 \n> 纵使穷尽一生也无法抵达你的身旁, \n> 我仍将整个灵魂,化作向你飞翔的翅膀。\n>\n> 让世俗在脚下沉沦成灰色的尘埃吧, \n> 我的心,永远向着璀璨的存在!\n\n情感寄语:愿我们都能成为自己的星辰,在漫长黑夜里为彼此照亮前路。理想或许永远在前方,但追寻本身已让生命绽放光芒。\n\n---\n\n## 编后记\n\n三首诗,三种时空,三种心境:\n\n- 古典诗人在小庭斜阳中感怀流年,以二十八字道尽中国文人的时间意识;\n- 现代诗人在霓虹倒影里打捞都市人的碎片,用断裂的意象拼贴当代精神图谱;\n- 浪漫诗人向星辰敞开灵魂,以炽热的宣言捍卫理想主义的最后堡垒。\n\n它们共同构成了一幅人类情感的完整光谱——从含蓄到直白,从孤独到热烈,从回望到追寻。\n\n> "诗无达诂,而心有灵犀。"\n\n---\n\n本文档由 AstrBot Agent Harness 编排生成 \n生成时间:2026-05-11 18:10 (CST)\n'}
[18:11:30.278] [Core] [INFO] [runners.tool_loop_agent_runner:1245]: Tool astrbot_file_write_tool Result: File written successfully: D:\AstrbotWorkSpace\三诗人合集.md
[18:11:32.338] [Core] [INFO] [runners.tool_loop_agent_runner:976]: Agent 使用工具: ['remove_subagent']
[18:11:32.339] [Core] [INFO] [runners.tool_loop_agent_runner:1042]: 使用工具:remove_subagent,参数:{'name': 'all'}
[18:11:32.340] [Core] [INFO] [core.subagent_manager:953]: [SubAgent:Cleanup] All subagents cleaned.
[18:11:32.342] [Core] [INFO] [runners.tool_loop_agent_runner:1245]: Tool remove_subagent Result: SUBAGENT_REMOVED: All subagents have been removed.
[18:11:42.244] [Core] [INFO] [result_decorate.stage:189]: 流式输出已启用,跳过结果装饰阶段

详细测试报告

详见
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.txt and pyproject.toml.
    / 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到 requirements.txtpyproject.toml 文件相应位置。

  • 😮 My changes do not introduce malicious code.
    / 我的更改没有引入恶意代码。

@dosubot dosubot Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label May 11, 2026
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @elecvoid243, your pull request is larger than the review limit of 150000 diff characters

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread astrbot/core/subagent_manager.py Outdated
Comment thread astrbot/core/subagent_manager.py Outdated
Comment thread astrbot/core/subagent_manager.py Outdated
Comment thread astrbot/core/subagent_manager.py Outdated
Comment thread astrbot/core/subagent_manager.py
Comment thread astrbot/core/astr_main_agent.py Outdated
Comment thread astrbot/core/subagent_orchestrator.py
elecvoid243 and others added 6 commits May 11, 2026 18:55
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] 增强版的SubAgent功能

1 participant