Subagents状态监控与日志

监控子代理运行状态和日志

一、子代理状态概览

在 Claude Code 的 Subagents 系统中,主代理通过系统通知实时了解各个子代理的运行状态。每当子代理发生状态变化时,系统会自动发送通知给主代理,这是一种高效的非阻塞通信机制,让主代理无需轮询即可掌握全局。

🟢 运行中 (Running)
子代理正在执行某个后台任务,此时占用系统资源,不能接收新任务。主代理可以通过 TaskOutput 获取中间结果。
⚪ 空闲 (Idle)
子代理已完成当前任务,正在等待主代理分配新的任务。这是子代理的默认状态,表示可以立即接收新的指令。
✅ 已完成 (Completed)
任务执行完毕,子代理成功返回结果。主代理可以通过 TaskOutput 获取最终的输出内容。
❌ 错误 (Error)
执行过程中发生异常,子代理无法继续。错误信息会通过 notification 发送给主代理,便于排查问题。
🔌 已关闭 (Shutdown)
子代理已被终止或关闭,释放所有系统资源。通常在任务彻底结束或异常无法恢复时进入此状态。
核心要点:主代理不会主动轮询子代理状态,而是被动接收 notification。这种方式极大降低了系统开销,使主代理可以专注于更高层次的调度工作。

二、Output文件查看

每个后台运行的子代理都会生成一个独立的 output 文件,该文件完整记录了子代理在整个任务周期内的全部对话、思考过程和最终输出。这是调试和理解子代理行为的最直接手段。

Output文件路径获取

当使用 run_in_background 参数启动 Bash 工具时,系统会在返回结果中附带 output 文件路径。例如:

{ "output_file": ".claude/outputs/20260508/101942_subagent_32111.log", "status": "running", "task_id": "subtask_20260508101942_32111" }

查看Output内容

使用 Read 工具可以直接查看 output 文件的内容。Output 文件包含子代理的完整执行记录,包括:每一步的思考过程、工具调用及其结果、子代理的中间输出和最终返回结果。

使用建议:在查看大型 output 文件时,建议使用 offsetlimit 参数分段阅读,避免一次性读入过多内容导致上下文溢出。可以先用 Bash 工具执行 wc -l 查看文件行数再决定读取范围。
注意:Output 文件可能包含大量内容,特别是长时间运行的子代理。如果整个文件读入可能会占据宝贵的上下文窗口。建议优先读取文件开头(查看任务设定)和结尾(查看最终结果)。

三、TaskOutput获取结果

TaskOutput 工具是主代理获取子代理执行结果的标准化接口。它支持同步等待和异步查询两种模式,灵活适应不同的使用场景。

工具参数说明

参数 类型 说明
task_id string 子代理的任务标识符,在启动子代理时由系统生成并返回
output_file string 指定要读取的 output 文件路径(可选),与 task_id 二选一
block boolean 是否阻塞等待任务完成。设为 true 时,工具会等待直到子代理执行完毕;设为 false 则立即返回当前状态
timeout number 最大等待时间(毫秒)。即使 block 为 true,达到 timeout 后也会返回当前进度,避免无限阻塞

典型用法示例

# 非阻塞查询:立即返回,不等待 TaskOutput(task_id="subtask_20260508101942_32111", block=false) # 阻塞等待:一直等到任务完成 TaskOutput(task_id="subtask_20260508101942_32111", block=true) # 带超时的阻塞等待:最多等60秒 TaskOutput(task_id="subtask_20260508101942_32111", block=true, timeout=60000)

返回值解析

TaskOutput 的返回值包含以下关键信息:标准输出(stdout)——子代理打印到控制台的所有输出内容;错误信息(stderr)——子代理产生的错误和异常信息;退出码(exit_code)——任务执行结果状态码,0 表示成功;执行状态(status)——子代理当前所处的状态。

最佳实践:对于耗时较长的子代理任务,推荐先用非阻塞模式(block=false)获取即时状态,定期轮询;对预期很快完成的任务,使用带超时的阻塞模式更加高效。这样既能保证及时响应,又不会浪费上下文空间。

四、消息通知机制

消息通知机制是 Subagents 系统的核心通信方式。当子代理的状态发生变化时,系统会自动向主代理发送 notification,主代理可以借此实时了解所有子代理的最新动态。

通知类型

📋 任务完成通知
子代理任务执行完毕时自动发送。通知中包含任务 ID、执行状态(成功/失败)和结果摘要 summary,主代理可据此决定下一步操作。
⏳ 空闲状态通知
子代理完成任务进入空闲状态时发送。通知表明子代理已就绪,可以接收新任务。主代理可以将新的子任务分配给空闲的子代理以提升整体效率。
🔔 错误报告
子代理执行出错时发送的紧急通知。包含错误类型、错误信息和出错位置,帮助主代理快速定位问题并决定是否重试或终止任务。
💬 子代理间通信摘要
当子代理之间通过 peer DM 机制互相通信时,通信摘要会被发送给主代理。这让主代理能了解子代理之间的协作情况而无需介入每一步交流。

Notification消息结构

{ "type": "subagent_completed", "task_id": "subtask_20260508101942_32111", "status": "completed", "summary": "成功提取了100条数据,耗时3.2秒", "output_file": ".claude/outputs/20260508/101942_subagent_32111.log" }
提示:主代理应当对 notification 中的 summary 字段进行语义解析,判断任务结果是否符合预期,而不仅仅是检查 status 字段。这有助于及早发现"执行成功但结果异常"的情况。

五、进度跟踪实践

在实际开发中,经常需要同时管理多个子代理并行工作。良好的进度跟踪机制可以确保所有子代理协调有序,及时发现并处理异常情况。

使用TaskList查看整体进度

TaskList 工具可以列出当前所有子代理及其状态,提供全局视角。调用方式简单,返回所有活跃子代理的概要信息。

# 列出所有子代理任务 TaskList() # 典型输出: - task_id: subtask_001 | status: running | elapsed: 12.5s - task_id: subtask_002 | status: idle | elapsed: 0.0s - task_id: subtask_003 | status: error | elapsed: 8.2s - task_id: subtask_004 | status: completed| elapsed: 15.1s

子代理主动报告进度

在子代理任务中,可以通过在任务逻辑中插入定期的状态报告语句,让子代理在执行过程中主动向 output 文件写入进度信息。主代理则可以通过 TaskOutput 结合非阻塞模式定期检查这些进度信息。

# 子代理内部主动报告进度的示例 echo "【进度报告】已处理 30/100 条数据,当前耗时 5.2s" echo "【进度报告】已处理 60/100 条数据,当前耗时 10.8s" echo "【进度报告】已处理 100/100 条数据,处理完成"

异常子代理处理流程

  1. 发现异常:通过 TaskList 发现状态为 error 的子代理,或者收到 error notification
  2. 查看详情:使用 TaskOutput(task_id="xxx", block=false) 获取错误信息,或直接读取 output 文件
  3. 分析原因:根据错误信息判断是临时性错误(如网络超时)还是根本性问题(如参数错误)
  4. 采取措施:临时性错误可以重试任务;根本性问题则需要调整参数或任务设计后重新启动
  5. 记录总结:将异常原因和处理方案记录下来,避免同类问题再次发生

核心要点:建立系统化的进度跟踪和异常处理机制,是保障多子代理系统稳定运行的关键。推荐采用"定期检查 + 被动通知"的双重监控策略,既通过 TaskList/TaskOutput 主动获取状态,也通过 notification 被动接收状态变化通知,最大限度地覆盖所有异常场景。