ADK 故障恢复还需监测与任务锁
文章指出,Google ADK 可通过事件历史和原调用 ID 恢复执行,但进程崩溃后的检测与重新调用仍需外部机制。多副本部署还需协调锁,作者随后介绍了将恢复职责交给运行时的集成方案。
AI 深度解读
Google ADK 能记住 Agent 已经完成的工作,但进程崩溃后,谁负责发现它、再把它拉起来?原文讨论的是这段恢复链路:有执行记录,不代表任务会自动继续。
作者提出,把故障发现、恢复调度和多副本协调交给 Dapr 工作流运行时。对部署长任务 Agent 的团队,这个区分很实用:检查点解决「从哪里继续」,运行时还得解决「什么时候继续、由谁继续」。
ADK 记得进度,为什么任务仍会停住
ADK 会把用户消息、LLM 响应、工具调用、工具结果和状态变化记录成不可变的 Event。开启 ResumabilityConfig(is_resumable=True),再用原来的 invocation_id 重新调用,已完成工具的结果可以从事件历史取回,只重新执行失败的工具。
问题在「重新调用」这一步。
作者举了一个场景:任务已经运行四分钟,三个工具中的前两个执行完毕,第三个刚开始,pod 就被驱逐。进程恢复以后,任务没有继续,因为 ADK 内部没有负责发现这次崩溃的机制。
从外部观察,任务已完成、工具执行缓慢、进程已经死亡,也可能难以区分。调用方需要判断状态,再带着正确的 ID 发起恢复。
多个副本还会带来另一层问题:按原文描述,ADK 没有跨副本协调层,缺少外部锁时,两个 runner 可能接手同一个任务。
执行记录、故障发现和任务归属,是持久执行的三个不同问题。
ADK 已经提供第一项,后两项需要额外补齐。
把恢复交给 Dapr,实际改变了什么
作者给出的接入方式是安装适配包并初始化 Dapr:
pip install "diagrid[adk]"
dapr init
随后保留普通 ADK Agent 定义,用 DaprWorkflowAgentRunner 承接执行:
from google.adk.agents import LlmAgent
from google.adk.tools import FunctionTool
from diagrid.agent.adk import DaprWorkflowAgentRunner
def book_venue(city: str) -> str:
return f"Venue held in {city}"
def order_catering(headcount: int) -> str:
return f"Catering ordered for {headcount}"
def send_invites(city: str) -> str:
return f"Invites sent for {city}"
agent = LlmAgent(
name="event_planner",
model="gemini-2.5-flash",
tools=[FunctionTool(book_venue), FunctionTool(order_catering), FunctionTool(send_invites)],
instruction="Plan an event by calling the three tools in sequence.",
)
runner = DaprWorkflowAgentRunner(name="event-planner", agent=agent, max_iterations=10)
runner.start()
out = runner.run_sync(user_message="Plan a 40-person meetup in Copenhagen", session_id="cph-meetup")
print(out.final_response)
runner.shutdown()
重点看创建 runner 的那一行:Agent 仍由 LlmAgent 和 FunctionTool 定义,执行入口交给了工作流 runner,示例设置 max_iterations=10。
启动命令为 dapr run --app-id event-planner -- python planner.py。
接入后,每次工具调用成为一个 Dapr 工作流活动(activity)。可以把活动理解成工作流里单独记录进度的一步。它的输入、输出和状态写入工作流日志,与 ADK 的事件历史分开保存。
按作者描述,进程死亡后,未完成活动对应的持久提醒会触发,工作流在健康副本上重新激活,从最后完成的活动之后继续。恢复走的是工作流日志,不再依赖调用方携带 invocation_id 发起 ADK 回放。
工作流实例也有单一 ID,并且同一时刻在一处运行,用来协调多个副本对任务的接管。
我的判断
作者把「能回放」和「能自动恢复」分开讨论,这个判断成立。只验证工具结果已经保存,还不足以证明 pod 消失后业务会继续执行。
但原文提供的是机制说明和接入示例,没有展示故障注入过程、恢复耗时或与其他方案的对照数据。示例里的三个工具也只返回字符串,并没有真的预订场地、下单或发送邀请。它能说明接法,不能证明真实业务的恢复效果。
还有一个需要补问的问题:工具已经完成外部操作,却来不及把完成状态写入日志,此时恢复会怎样?原文没说清。单个工作流由一个 worker 执行,不等于外部业务操作只发生一次。 涉及下单、发信等副作用时,仍应验证幂等处理。
替代方案是自行补上 watcher、锁和重新调用路径。已有成熟任务调度设施的团队,可以沿用这些能力;缺少这类设施、又有长任务恢复需求的团队,才更有理由评估 Dapr。接入价值要和额外运行时的部署、运维成本一起算,原文没有给出成本比较。
能拿来做什么
- 先排查运行时间最长的 ADK Agent,明确 pod 消失后由谁发现、由谁重新调用,以及原始
invocation_id保存在哪里。 - 用示例验证接入后,再替换成真实工具,分别测试工具执行中退出、外部操作完成后退出,以及多个副本同时接管的情况。
- 对发送邀请、创建订单这类工具设置业务幂等标识,验证恢复重试不会造成重复操作。
- 如果现有调度系统已经具备故障发现和任务互斥能力,先评估补齐 ADK 回放路径的成本,再决定是否引入 Dapr。