悬在两张日历上的多智能体死锁
Agent A 向 Agent B 请求完成其任务所需的一项数据。Agent B 在回答之前,向 Agent A 请求生成该数据所需的一项上下文。这两项请求在发出途中都跨越了“需要人工审核”的边界。第一项请求落入了由 Priya 监看的 Slack 审批频道。第二项落入了由 Marcus 监看的 Jira 队列。Priya 正在吃午饭。Marcus 正在接听客户电话。两人都不知道对方的存在。工作流挂起了 19 个小时,直到一次客户投诉迫使有人去询问为什么汇总结果从未送达,才有人注意到。
这不是一种新颖的失败模式。它是分布式系统中最古老的失败模式,只是换了一身新装。Coffman 条件——互斥(mutual exclusion)、占有且等待(hold and wait)、不可剥夺(no preemption)、循环等待(circular wait)——早在 1971 年就被命名了,而一个带有“人机协同”(human-in-the-loop)审批队列的多 Agent 系统默认满足这所有四个条件。新的麻烦在于,死锁中的“资源”之一是人的注意力,这意味着你的活性保证(liveness guarantee)现在受限于两个互不相识的人独立进行上下文切换的速度。
如果你正在构建 Agent 工作流,且其中任何工具调用都可以路由到人工审批,那么你正在运行一个延迟是不确定的调度器,而你的死锁检测器是“有人在每日站会上提问”。这不是一种策略。这是一场赌博,赌你每天都能走运。
四个条件的“转世”
带着 Agent 系统的思维来审视 Coffman 条件。无论你是否针对它们进行了设计,每一个都会出现在你的技术栈中。
互斥。 一个 Agent 会话持有开启的状态——线程 ID、进行中的工具租约、部分写入的内存条目、持久层中的检查点(checkpointer)行。另一个 Agent 无法并行恢复该会话;框架的持久化模型假设每个线程只有一个写入者。会话就是资源。它被独占持有。
占有且等待。 Agent 在 interrupt() 处暂停以等待人工回复,但它仍然持有会话、检查点、它正在生成的任何内容的打开文件句柄、对话上下文,以及它在暂停前抓取的任何上游资源。LangGraph 的持久层对此非常明确:当线程中断时,检查点会无限期地持有冻结状态,没有内置的生存时间(TTL)。
不可剥夺。 审批语义不允许系统撤回请求。你不能告诉 Priya “实际上我们改变主意了,放弃审核吧”。即便你可以,Agent 也必须回滚它已经提交的部分副作用:写入数据库的一行、初步安排的日历事件、等待发送的草稿邮件。大多数 Agent 框架都没有可以干净利落中止的事务性子图(transactional sub-graph)概念。
循环等待。 这是最致命的一点。Agent A 的请求在 Priya 的队列中;Priya 的审核依赖于一个只有 Agent B 才能提供的事实;Agent B 的请求在 Marcus 的队列中;Marcus 的审核依赖于一个只有 Agent A 才能提供的事实。这个循环跨越了两个人类、两个 Agent 和两个队列。四方中没有任何一方拥有图的全貌。这个循环是不可见的。
经典文献通过防止四个条件之一或通过检测并打破循环来解决这个问题。大多数 Agent 框架在发布时都没有内置这些原语。图形成了;没有东西监视循环;工作流挂起;最终由人类注意到这种沉默。
为什么人类不仅仅是“另一个工具”
一种诱人的设想是将人工审核员视为一个高延迟的工具——像调用其他工具一样调用它,等待响应,然后继续。这种设想很快就会崩溃。
一个工具调用具有服务水平协议(SLA)。你知道大概的 p50 和 p99 延迟。你可以设置超时。你可以重试。工具要么返回,要么在有限的窗口内失败。
人工审批者没有这些。一个人的响应延迟取决于他们的日历、时区、手机电量、是否注意到了通知、是否理解了请求,以及他们是否认为你的请求比他们手头的其他 17 件事更重要。没有 SLA。没有重试语义。没有活性保证。
你拥有的是一个调度策略对你透明、队列深度无法读取、且其工作线程池是那些并不拿薪水来当你的运行环境的人类的调度器。将其视为“慢速工具”是你交付一个尾部延迟(tail latency)以天计的系统的方式。
正确的框架借用了分布式系统:人工审批者是一个不确定的外部服务,没有发布的 SLO,没有健康检查端点,也没有前向进 展保证。你围绕这种服务构建的每个原语——熔断器、带升级的超时、死信队列、对队列深度的可观测性——都直接适用。大多数团队一个都没建,因为 Agent 框架的教程将 interrupt() 显示为一行代码的添加,使其看起来是免费的。
- https://docs.langchain.com/oss/python/langgraph/interrupts
- https://www.abstractalgorithms.dev/langgraph-human-in-the-loop
- https://en.wikipedia.org/wiki/Deadlock_(computer_science)
- https://www.geeksforgeeks.org/computer-networks/conditions-for-deadlock-in-distributed-system/
- https://www.geeksforgeeks.org/computer-networks/wait-for-graph-deadlock-detection-in-distributed-system/
- https://www.zenml.io/blog/what-1200-production-deployments-reveal-about-llmops-in-2025
- https://altaflow.com/blog/manual-approval-bottlenecks-causes-and-fixes
- https://aws.amazon.com/blogs/apn/how-temporal-uses-amazon-bedrock-agentcore-to-create-robust-ai-systems/
- https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/ai-agent-design-patterns
