前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
返回 AI 情报前线
All News · 全部资讯9915
  • 英伟达扩充智能体模型,覆盖云端与本地
  • 日合并超三万次,Anthropic 重构版本控制
  • CLiF 将智能体运行记录转为训练评测资产
  • GitHub 代码扫描智能体修复正式可用
  • Webhook 驱动 Agent 的可靠性要点
  • 用 TypeScript 为 Agent 补齐应用连接器
  • 177 项科研技能补齐智能体领域知识
  • 发现 AI 擅自决策:简单审查胜过复杂流水线
  • WhatsApp 智能体上线后的工程难题
  • Netflix 为编程智能体接入 IDE 代码分析引擎
  • PentAGI 用多智能体执行渗透测试
  • MCP 排错日志里的凭据泄露隐患
  • Jev新版加入图像输入与26.2万上下文
  • 微软用知识编译降低智能体延迟与耗量
  • Grok语音模型升级,接口与价格保持不变
  • 把 ClickUp 项目记录变成 Agent 可查询记忆
  • Matrix-Game 4.0 开源单卡实时生成游戏
  • Agent 接入外部服务前先检查失败恢复能力
  • 多模型网关踩坑:推理预算吃光了回答
  • Step 5 Preview 开放权重,可部署百万上下文
  • AI 工具写操作防重:执行前先抢占
  • 给 n8n 的模型输出加一道契约检查
  • 自托管 AI 工具漏洞公告可能漏过扫描
  • 本地运行 Gemma 4:推测解码与草稿模型
  • AI 代码上线前先排查这些安全漏洞
  • Copilot更新HydraFusion并新增Max
  • MCP工具数量实测:准确率之外更要看成本
  • Apigee 支持在自有集群运行 MCP 工具
  • 编程 Agent 源码研究:架构比功能清单耐用
  • 把 GPU 内核调优变成夜间并行搜索
  • AI 生成的 Supabase 权限代码可能允许提权
  • Agent 成本控制要先预留并发调用预算
  • 全 AI 编码项目如何靠质量关卡持续交付
  • AI反编译加速老游戏移植,也带来风险
  • 用 AgentCore 构建可适应新格式的文档处理
  • 用 Issue 标签驱动 AI 分析与提 PR
  • AI 辅助六天串起 Chrome 漏洞利用链
  • Claude Code 改造电商站的操作与复盘
  • Agent 平台缺少身份配置却开放管理权限
  • 英特尔将至强推理调优封装进容器
  • 用 AgentCore 将企业文档生成演示文稿
  • 用 Bedrock Agent 编排云安全修复
  • Orion-1 面向网络防御,试补通用模型限制
  • 用 JumpStart 完成模型部署与性能测试
  • GPT-4 系列部分 API 据报将停用
  • 工厂智能排产应先建约束模型
  • 法律 RAG 的核心是有据回答与可靠拒答
  • Agent 如何调用工具:从函数接口到 MCP
  • 给 AI 功能算清每月 API 账单
  • 用可验证进度训练长任务 Agent
  • Agent 数据架构怎么选:五种方案对照
  • 已加载 51 / 9915
8.0
热点
AI SCORE
技术实践2026-10-15 09:41

AI 工具写操作防重:执行前先抢占

dev.to · AI#智能体#幂等性#并发
Editor brief · 编辑速览

文章指出,执行操作后再记录幂等键,即使有唯一约束,也可能在并发请求下产生重复写入。提出先抢占执行资格,再由抢占结果决定是否执行操作。

文章思维导图
Knowledge map
拖拽缩放
Full translation

完整中文译文

Assistant 调用了一个执行写入的工具。同一次调用可能到达两次:模型重试了调用,同一个确认被处理了两次,或者进程在执行途中重启了。

第二次到达时,绝不能再写入一次。常见做法是使用幂等键,并在这个键上添加唯一约束,但单靠它还不够。约束是在记录写入时生效的,而记录是在操作完成后才写入的。最终,执行记录表里只有一条记录,目标系统却已经被写入了两次。

唯一约束保护的是执行记录,不是操作本身。

本文提出的做法是:在操作运行之前先取得执行权,再由执行权决定谁来执行。其余设计都由此展开。

1. 为什么“先检查,再执行”还不够

先看最容易写出来的版本。

执行之前,检查键是否存在。如果不存在,就执行操作,之后再记录这个键。

只有一个请求正在处理时,这样做没有问题。一旦出现并发,它就失效了。两个请求都读到“还不存在”,于是都执行了操作。等它们随后记录各自的键时,唯一约束会拒绝第二条记录。但操作早已发生。

所以,约束阻止的是第二次记录,不是第二次写入。这就是前面那句话的具体含义:执行记录表上的约束,管不到已经发生在表外的操作。

这种模式有个名字:先检查,再执行。决策和操作之间存在一个时间窗口,而决策无法感知这个窗口内发生的事情。

2. 修复方法:先取得执行权,再由执行权裁决

改动很小:把检查换成执行权申领。

执行之前,先向执行权表插入一条记录。表上的唯一约束就是裁决点:

  • 插入成功,说明本次执行权归我,我继续执行。
  • 插入失败,原因是键已被占用,说明已经有人持有本次执行权,我不再运行操作。

关键不在于这条记录本身,而在于插入发生在操作之前。插入是原子的,因此在任何操作运行之前,执行权归属就已经确定,中间没有可乘之机。

这也解释了为什么不能根据完成状态推断执行权归属。如果唯一能观察到的状态是“写入已完成”,那么两个并发请求在各自行动之前,看到的都会是“尚未完成”,于是又回到了先检查、再执行的老路。

3. 幂等键由什么组成

这一部分值得单独讨论,因为它决定了什么才算同一次写入。

我们的做法是把四项内容放在一起计算 hash:

hash( who : which conversation : which tool : arguments with keys sorted )

谁发起的。 不同用户使用相同的工具、传入相同的参数,属于不同的写入。

哪段对话。 同一段对话内的重复调用属于重试。跨两段对话发生的两次相同调用,则是两个事件。

哪个工具。 这一项无需解释。

参数,而且要先对参数的键排序。 这一项至关重要。排序能让同一次调用的两种写法算出相同的键。如果不排序,{a:1,b:2} 和 {b:2,a:1} 就会生成两个键,同一次调用会被当成两次写入,幂等机制也就有了漏洞。

这四项回答的是:这是不是同一次调用。它们并不回答:这次写入会影响什么。这是两个不同的问题,把它们塞进同一个字段会引出另一组问题,那是另一个话题。

4. 取得执行权后,如果写入失败,要不要释放执行权

这是最难的部分。我们的答案既不是“要”,也不是“不要”,而是分成两种情况,依据我们实际掌握的信息来选择。

本地写入:我们知道结果。 失败就是失败,已经落库的记录就是已经落库了。这种情况下,可以释放执行权,让重试真正重新执行;也可以保留执行权,如实记录失败。无论选择哪一种,重点都是:我们清楚自己知道什么。

外部写入:我们不知道结果。 请求已经发出,却没有收到响应,或者连接断开了。在前面这三种情况下,对方完全可能已经收到了请求。如果此时释放执行权,放行重试,那么重试就真的是第二次写入。

因此,外部写入这一分支会有意保留执行权,并在结果中明确说明:

这次请求可能已经到达目标系统,结果应由目标系统报告,这里不会进行任何重试。

这句话不是措辞上的选择,而是实际行为。结果未知时,我们不会放行重试,因为重试会把“未知”变成“可能执行两次”。

5. 第二次到达时返回什么

第二个请求不应该再次写入,也不应该被报告为失败。它并没有做错什么。

我们的做法是重放结果。命中已有记录时,将记录下来的结果返回给本次调用,并标记为复用:

{ id: <the id recorded the first time>, idempotent: true }

调用方拿到的结果与第一次调用相同。从它的角度看,“我调用了一次,并得到了答复”这件事成立。

复合写入还需要多做一步。一次调用写入多条记录时,基础键由根成员持有,因此命中时必须重放整组结果,而不能只返回根成员。如果只返回根成员,调用方就会丢失其他成员的信息,而这些成员之后也再不会被返回。

6. 我们无法跨越的边界

以上所有机制,都只能阻止我们发送两次。

它不能保证端到端的实际效果只发生一次。要做到这一点,目标系统必须认可这个键:我们通过 header 将键一并发送过去,但对方是否据此去重,由对方决定。

准确地说:我们能保证自己不重复发送,却不能保证对方只接收一次。

我们把这一点写进结果消息,而不是留给读者自行发现。

7. 你可以自行检查的几个问题

四个问题。任何一个没有可靠答案,都意味着存在一个时间窗口。

决策和操作之间是否存在间隙? 如果代码先检查、再执行,这个间隙就存在。

什么定义了“同一次写入”? 如果键中缺少用户或对话信息,那么不同用户或不同会话只要参数相同,就会被合并成同一次写入。这是另一种错误。

计算 hash 之前,是否对参数的键进行了排序? 如果没有,同一次调用的两种写法就会算出两个键。

失败之后,重试会做什么? 如果答案不是“取决于我们是否知道对方已经收到请求”,那多半只是在猜。

回到那句话:唯一约束保护的是执行记录,不是操作本身。记住这一点,第一个检查就很自然了,因为问题变成了:决策究竟发生在操作之前,还是操作之后。

我们的做法是:操作前先取得执行权,由执行权裁决谁来执行;根据用户、对话、工具以及排序后的参数生成键;根据已知信息选择失败处理策略;同一次调用再次到达时,重放原始结果。

有两点需要明确说清。第一是前面提到的边界:我们不保证对方只接收一次。第二是机制本身的限制:只有参数完整表达了写入行为时,这套机制才成立。如果工具的行为还依赖参数之外的因素,比如当前时间、一次随机抽样或外部状态,那么相同参数出现两次,并不代表同一次写入,基于这些参数生成的键也就无法作出任何有效判断。这样的工具必须先改造,把这些因素也作为参数传入。在那之前,幂等键只是摆设。

本文由 AI assistant 协助起草。系统、观点和错误均由我本人负责。

如需采取进一步行动,你可以考虑屏蔽此人和/或举报滥用行为。

Original source

本文由 AI 翻译整理自 dev.to · AI,原文版权归原作者所有。

阅读英文原文
上一篇
Step 5 Preview 开放权重,可部署百万上下文
下一篇
给 n8n 的模型输出加一道契约检查