☰
Agent 三个工具同时被调用,我的工单重复创建了三条:一个并发踩坑实录
2026/10/3 12:51:27 网站建设 项目流程

咱们做开发的都知道:单线程没问题的地方,并发一上准出事。

Agent 也一样。这两天万能 AI 盒里出了个 BUG,排查过程挺有意思,是一个教科书级的并发问题——只不过"并发线程"换成了"并行的工具调用"。把这个坑记下来,给正在做 Agent 应用的老铁提个醒。

现象:一个工单,三条记录

用户提交了一条售后工单,Agent 判断需要同时做三件事:创建工单、给负责人发通知、写入日志。

从 Agent 的视角看,这是三个独立操作,它并行发起了三个工具调用——这在技术上完全正确,还能省时间。

然后数据库里出现了三条一模一样的工单。

用户收到了三次通知。

排查:五分钟定位,但汗流浃背了

第一反应是"创建工单"这个工具被调了三次?看日志——不是,三次调用参数完全相同。

再想,明白了:Agent 的规划器把"创建工单"这个动作放了三次——一次在主任务里,两次在两个子任务的上下文里。并行执行时谁也不知道谁的存在。

这暴露了两个层面的坑:

坑一:工具的无副作用声明是谎言

我们的工具描述里写着"创建售后工单"。在 Agent 的理解里,这跟"查询工单列表"没区别——都是"操作"。它不知道"创建"这个词意味着调三次就有三条。

人类开发者看到 `createOrder` 和 `listOrders` 会本能地分化对待,但模型只看描述文本。副作用信息不在描述里,对 Agent 就不存在。

坑二:并行调用之间没有隔离机制

传统服务里我们防这种事靠的是幂等键、分布式锁、唯一索引。但 Agent 的工具调用层如果只是裸包了一层 API,这些防线一个都没带上去。

解法:三道锁,一层都不能少

第一道:工具描述里写明副作用与幂等约定

改前:

```

创建售后工单,传入用户ID和问题描述

```

改后:

```

创建售后工单(⚠️写操作,有副作用)。

  • 同一请求上下文内只允许调用一次
  • 幂等键 idempotency_key 必传,重复提交返回原工单号

```

第二道:服务端幂等键兜底

工具对应的 API 加幂等逻辑:相同 key 的请求 10 分钟内返回首次结果。这是老手艺了,但做 Agent 工具封装时特别容易忘——因为"包一层就行"的心态。

第三道:规划器层加"写操作互斥"

在 Agent 的任务规划器里加规则:同一批次并行调用中,写操作(create/update/delete/submit 类)最多出现一次;需要多个写操作时,改为串行确认。

第三道是我们最后加的,也是最有效的——前两道防的是"重复的相同调用",这道防的是"重复的等价调用"(参数不同但语义重复)。

顺手整理的 Agent 工具设计检查单

这轮踩坑后我把工具设计规范重新整理了一遍,核心就四条:

1.写操作必须在描述里显式标注副作用——"有副作用""不可重入""需幂等键",字越少越要写

2.所有写操作工具,幂等键服务端强制校验——不依赖 Agent 自觉

3.并行批次内写操作互斥——规划器层面控制,别等数据库报错

4.危险操作加确认步骤——删除、支付、对外发送类,工具描述里写明"执行前需用户确认",让 Agent 学会先问再做

结尾

这个 BUG 表面上是"Agent 不懂事",本质是我们把"给人用的 API"直接丢给了 Agent,而人有的常识(创建类操作不能乱点),Agent 没有。

工具描述就是 Agent 的世界说明书。说明书里没写的规矩,它真的不知道。

上回聊了怎么让 Agent 选对工具(写清边界),这回补上了"选对了也不能瞎调"(幂等与互斥)。凑齐了工具治理的另一半拼图。

下回咱们聊 Agent 的"记忆"设计——多轮对话里哪些该记住、哪些该扔,这又是一个上下文预算的精细活。感兴趣的老铁蹲一下。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询