Guides
Resume
用 resume 模式从已持久化的会话恢复未完成的输出,无需追加新消息。
概述
We0Agent 的每次运行都带一个运行模式 mode,取值为 prompt 或 resume:
prompt:追加新的用户消息并运行,是默认模式。resume:不追加任何新消息,基于已持久化的会话历史,恢复上一轮中断在半途的 assistant message 或工具调用,并继续把这一轮跑完。
resume 适用于上一次运行没有正常收口的场景:进程崩溃、被 abort 打断、网络中断后留下的「未完成 assistant message」或「pending/running 状态的工具调用」。只要这些状态已经落库,用同一个 session_id 以 resume 模式再跑一次,engine 就会接着上次断点往下走。
resume 完全依赖此前已持久化的消息和 part。如果换用一个空的
MemoryPersistence去 resume,会因为没有历史可读而无事可做。参见 Persistence。
调用形态
三个运行入口 stream()、invoke()、build_request() 都接受 mode 参数。resume 时传入与上一轮相同的 session_id,并且不传 messages。
import asyncio
# 流式恢复:继续消费上次断点之后的事件
async for event in agent.stream(
abort=asyncio.Event(),
mode="resume",
session_id="ses_demo", # 与上一轮完全相同的会话标识
):
if event["type"] == "text-delta":
print(event["text"], end="", flush=True)需要最终结果而非事件流时,用 invoke():
result = await agent.invoke(
abort=asyncio.Event(),
mode="resume",
session_id="ses_demo",
)
# result.result 为 "stop" 或 "compact"mode 默认值是 prompt,因此恢复会话时必须显式写 mode="resume"。
与 prompt 模式互斥
messages 参数在两种模式下的约束是互斥的,由 build_request() 在入口处校验:
| 模式 | messages | 校验行为 |
|---|---|---|
prompt | 必填 | 省略时抛出 ValueError("messages is required in prompt mode.") |
resume | 必须省略 | 传入时抛出 ValueError("messages is not allowed in resume mode.") |
也就是说,恢复一段会话和追加一条新消息是两件不能合并的事。如果你既想补充新输入又想继续上一轮,应当先用 resume 把上一轮收口,再用 prompt 追加新消息。
# 错误:resume 模式不允许携带 messages,会直接抛 ValueError
await agent.invoke(
abort=asyncio.Event(),
mode="resume",
session_id="ses_demo",
messages=[user_message("继续")], # ✗
)两种模式在运行启动阶段也不同。prompt 会先 ensure_session()、清理 revert 状态、中断上一轮遗留的未完成工具、再写入新的用户消息;resume 只做 ensure_session(),随后直接进入恢复与运行循环,不写入任何新消息。
恢复语义
进入运行循环后,engine 在每个 step 之前都会检查 transcript 中最后一条 assistant message 是否需要恢复。判定基于两类信号:
| 信号 | 判定依据 | 含义 |
|---|---|---|
| 未完成 assistant message | assistant_message.time.completed is None | 上一轮 assistant 输出没有正常收口。 |
| 未完成工具调用 | 存在状态为 ToolStatePending 或 ToolStateRunning 的 ToolPart | 工具调用发起后没有写回终态结果。 |
两类信号都不存在时,恢复无操作,直接按正常流程跑下一个 step。
工具调用恢复
对最后一条 assistant message 里的每个工具 part,resume 模式按其状态和执行策略决定动作:
| 工具状态 | 动作 | 说明 |
|---|---|---|
ToolStateCompleted | keep | 已完成,保留结果。 |
ToolStateError | keep | 保留错误结果;若该工具配置为出错阻断后续,会阻断其后未完成的工具。 |
ToolStatePending / ToolStateRunning(无副作用) | recall | 重新执行该工具调用,补齐结果。 |
ToolStatePending / ToolStateRunning(有副作用) | interrupt | 标记为中断,不重复执行,避免副作用被执行两次。 |
| 被前序中断阻断的未完成工具 | interrupt | 一旦前面出现 interrupt 或阻断性错误,后续未完成工具一律标记中断。 |
这里是 resume 与 prompt 的关键区别:prompt 模式会把所有未完成工具一律按中断处理(reason 为 prompt),不重新执行;而 resume 模式会尽可能重放那些无副作用的工具(recall),只对有副作用或被阻断的工具做中断收口。
是否「有副作用」由工具自身的执行策略决定。读取类工具通常可安全重放,写入、命令执行等会改变外部状态的工具会被判为有副作用,恢复时只做中断而不重跑。参见 AnyToolDefinition。
assistant message 恢复
如果最后一条 assistant message 的 time.completed 为空,恢复会把它标记为已完成,并在没有既有错误时写入一个恢复错误:
| 字段 | 值 |
|---|---|
error.reason | "UnfinishedAssistantMessage" |
error.message | "Assistant message was not completed before recovery." |
error.metadata | {"recovered": True, "mode": "resume"} |
收口后运行循环会继续推进:把恢复后的状态作为新的起点,让模型基于补齐的工具结果和已收口的历史继续生成后续 step,直到这一轮自然结束。
与 abort 的配合
resume 最常见的来源就是被 abort 打断的上一轮运行。abort 会让 engine 在当前阶段收口并把已产生的状态落库,但这一轮的 assistant 输出可能仍是未完成的。此时用同一个 session_id 以 resume 模式再跑一次,即可从断点继续。参见 Abort。
abort = asyncio.Event()
# 第一轮:运行中被打断
try:
await agent.invoke(
abort=abort,
mode="prompt",
session_id="ses_demo",
messages=[user_message("整理当前目录并生成报告。")],
)
except asyncio.CancelledError:
pass
# 第二轮:用新的 abort 信号从断点恢复,不再追加新消息
await agent.invoke(
abort=asyncio.Event(),
mode="resume",
session_id="ses_demo",
)默认行为与易错点
mode默认是prompt,恢复会话必须显式写mode="resume"。resume模式下传messages会抛ValueError;要补充新输入请改用prompt模式单独发起。resume不会创建用户消息,也不清理会话的 revert 状态,它只做会话头校验加恢复运行。resume依赖已落库的历史。空的或换过的持久化端口没有历史可恢复。跨进程恢复请使用SqlPersistence,参见 Persistence。- 有副作用的工具在恢复时只做中断收口,不会被重新执行;只有无副作用的工具会被重放。
- 当前 agent 配置了结构化输出时,
stream()会抛ValueError,结构化结果只能通过invoke()获取,这一约束在prompt和resume两种模式下一致。