子代理完成第一个任务后,可能已经积累了有价值的上下文——探索了 50+ 个文件、找到了 15 篇论文、构建了依赖图。Resume 以重新开始成本的一小部分保留这些上下文用于后续跟进。而且不限于一次跟进——resume 支持多次顺序循环。
Resume 流程
- 首次查询:协调者调用 Task 工具 → 子代理运行 → 返回
ResultMessage - 捕获:从 ResultMessage 提取
session_id,从响应内容提取agentId - 跟进:调用
query(),带resume=session_id和引用 agentId 的 prompt
恢复的会话从上次结束的地方精确接续——所有工具结果、发现、推理和中间上下文完好无损。
数据:resume vs 新会话
多轮子代理工作流的生产对比:
| 指标 | 新会话(重新注入上下文) | Resume |
|---|---|---|
| 每次跟进的 prompt token | 8,000 | 1,200 |
| 每次跟进的延迟 | 15 秒 | 4 秒 |
| 答案质量 | 相同 | 相同 |
Token 减少 85%,延迟减少 73%,质量完全相同。 每个任务 3 次跟进的话:每任务节省约 20,400 token 和约 33 秒。
为什么差距这么大?新会话必须把上下文作为 prompt 文本重新注入(贵,有损)。Resume 的上下文已经在会话状态里了(免费,无损)。输入 token 少不代表信息少——恢复的 agent 有更多上下文,因为它保留了完整会话,而不只是一份摘要。
多次 resume 链式调用
Resume 不限于一次跟进。同一个 session_id 支持多次顺序 resume:
- 初始审计 → 发现漏洞
- Resume #1 → 协调者要求对最重要的问题提出修复建议
- Resume #2 → 协调者要求 agent 验证修复是否解决了发现的问题
- Resume #3 → 协调者要求最终摘要
每次 resume 累积上下文。3 个循环后,子代理拥有完整历史:初始发现、修复建议、验证结果。在任何一步重新开始新会话都会丢失这些累积的理解。
缓存所有 session_id
当协调者为一个研究任务派生 5 个子代理时,缓存全部 5 个 session_id——不只是你预期会跟进的那个。Session_id 是轻量的字符串标识符,没有持续存储成本。未使用的会话以零成本保持空闲。
SDK 支持恢复任何有效的 session_id,不只是最近完成的那个。如果一个意外的问题需要回到 5 个子代理中的 #2,缓存的 session_id 让它无需重新分析就能实现。
最常见的 resume bug
# 首次查询
result = await query(prompt="Audit the auth module", options=options)
# BUG: 这里没有捕获 session_id
# 跟进尝试
await query(prompt="Suggest fixes", options=ClaudeAgentOptions(resume=None))
# Error: "Cannot resume session: session_id is required"
协调者完成了首次查询但从未从 ResultMessage 捕获 session_id。Resume 调用的 resume=None。修复:总是在初始查询时捕获会话元数据,即使你不确定是否需要跟进。
错误消息很明确:“session_id is required”——不是 “session expired” 或 “topic mismatch”。SDK 不强制查询之间的主题相似性;只要 session_id 有效,任何跟进 prompt 都可以。
什么时候不该 resume
独立任务:如果跟进和第一个任务毫无关系,新会话更干净。恢复的会话带着所有之前的上下文,在无关历史上消耗上下文预算。
过时上下文:如果底层数据在首次查询后发生了显著变化(文件修改、数据库更新),子代理缓存的工具结果引用的是过时信息。用注入的先前发现摘要重新开始。
一句话总结: Resume 比新会话节省 85% token 和 73% 延迟且质量相同,支持在同一个 session_id 上链式多次跟进,需要从首次 ResultMessage 捕获 session_id——缓存所有 session_id,它们很便宜。