基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
  • 知识卡片碎片时间过考点
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
    • AI 热点每日 AI 资讯与动向
AI 工作台
简历
旧版
AIHT
内容
精选全部 AI 动态热点榜AI 日报收藏
分类
模型行业编程产品技术观点开源
更多
Agent 接入
返回首页开发者导航
AIHT
精选 / 资讯详情
8.0
热点
AI SCORE
技术实践2026-11-04 20:38

Agent 写入有日志,也未必能撤销

dev.to · AI#Agent#MCP#故障恢复
Editor brief · 编辑速览

作者审视自己的 MCP 文章编辑工具后发现,保存修改前后状态并要求确认,不等于具备撤销能力。案例中的工具会覆盖已发布文章,而目标平台没有版本历史,暴露了写入保护与恢复机制之间的差距。

文章思维导图
Knowledge map
拖拽缩放
AI deep read

AI 深度解读

给 AI Agent 的写入工具加上确认按钮,再把修改前后的内容记进日志,能不能算支持撤销?作者检查了自己用于修改 DEV.to 文章的 MCP server,发现答案是否定的:它能拦住未经确认的修改,也能查出改过什么,却无法安全地恢复已经写错的内容。

这篇文章的价值,在于把「有记录」和「能恢复」之间缺失的工程环节拆了出来。只要你的 AI 工具会修改线上内容,这个区别就值得认真检查。

确认过的修改,为什么仍然需要撤销

作者的 MCP server 提供了 update_article 工具,可以直接修改已经发布的 DEV.to 文章。按作者描述,DEV.to 没有文章版本历史,一次错误的 PUT 会覆盖原来的标题或正文。

因此,工具在写入之前会先读取当前文章。只要文章已经发布,而且本次修改涉及 title 或 body_markdown,调用方就必须显式传入 confirm=True。没有确认时,工具返回 applied: False,同时提供修改差异 diff 和内容指纹 fingerprint,让调用方先看清准备改什么。

这个设计解决了一个实际问题:Agent 不能直接覆盖线上正文,必须先经过确认。

但确认只能证明「当时同意执行」,不能证明「执行结果一定正确」。需求可能理解错,预览可能漏看,确认之后也可能才发现内容不合适。作者之前一直把「DEV.to 没有版本历史」当作设置确认门槛的理由,却没有继续追问:已经确认、已经写入的错误,准备怎么收拾?

事前确认负责控制写入,事后撤销负责恢复状态,两者不能互相替代。

日志保存了旧内容,却没有定义怎么恢复

作者确实记录了每次成功修改的前后状态。下面这段代码把发生变化的字段写入本地 JSONL 文件,解决的是追查修改的问题:

def _log_article_update(article_id, before, fields_changed, after):
    os.makedirs(os.path.dirname(_ARTICLE_UPDATE_LOG), exist_ok=True)
    entry = {"article_id": article_id, "fields_changed": sorted(fields_changed), "url": after.get("url")}
    for field in fields_changed:
        entry[f"{field}_before"] = before.get(field)
        entry[f"{field}_after"] = after.get(field)
    with open(_ARTICLE_UPDATE_LOG, "a") as f:
        f.write(json.dumps(entry) + "\n")

关键在 entry[f"{field}_before"] 和 entry[f"{field}_after"]:它们保存了恢复可能需要的数据,但没有把恢复变成一个可调用、带条件检查的操作。

直觉上,撤销似乎很简单:找到这篇文章最后一条日志,取出 fields_changed 对应的旧值,再调用 update_article(article_id, title=..., body_markdown=..., confirm=True) 写回去。

问题出在「再写回去」之前。

日志之后,文章可能已经被另一次工具调用改过,也可能有人在 DEV.to 网站手动编辑,或者同一套流水线并发运行了第二次。旧日志描述的是某次修改前后的状态,无法证明当前文章仍然停留在那次修改之后。

例如,下午 2 点改了标题,下午 3 点又改了正文。此时撤销 2 点的修改,如果直接拿整份旧内容覆盖,就可能顺手抹掉 3 点的正文编辑。即使只恢复标题,也得说明:允许保留后续正文修改的依据是什么?

作者把缺口归为三个部分:生成可执行的补偿写入、检查历史状态是否仍然适用、规定后续修改发生后的撤销语义。所谓补偿写入,就是通过一次新的写入抵消之前的修改,并不会让已经发生的操作从历史中消失。

撤销要核对的,是原操作留下的状态

有意思的是,作者的工具已经具备一部分保护能力,只是用于正常写入,没有接到撤销流程上。

调用方可以把预览时取得的指纹,通过 expected_fingerprint 传回去。如果线上内容已经变化,工具就拒绝继续写入,避免拿旧预览确认新内容。

下面的函数根据标题和正文生成指纹,用来判断内容是否发生变化:

def _article_fingerprint(before):
    basis = "\x1f".join(f"{f}={before.get(f)!r}" for f in ("title", "body_markdown"))
    return hashlib.sha256(basis.encode()).hexdigest()[:16]

要看清第一行只纳入了 title 和 body_markdown,最后一行则把 SHA-256 的十六进制结果截取为前 16 个字符。它检查的是这两个字段组成的状态,并不代表文章所有属性。

正常写入时,比较基准是调用方预览过的内容;撤销时,比较基准应当是被撤销操作完成后留下的内容。

这也是为什么「撤销前重新读取一次,再用刚读到的指纹写回旧值」仍然不够。它只能确认这次读取之后有没有变化,不能确认历史操作之后有没有发生过其他编辑。历史记录必须与状态校验衔接起来,才能回答旧内容现在还能不能恢复。

遇到后续修改,工具还需要明确选择:直接拒绝撤销,还是允许只恢复部分字段。原文没有实现这套规则,也没有交付可用的 undo_last_update。作者明确表示,不会在刚想到方案的当天,就把未经充分测试的撤销函数放进修改公开博客的工具里。

我的判断

我赞同作者对安全边界的重新划分。日志回答「发生了什么」,撤销还要回答「现在执行什么,才能恢复且不覆盖后来发生的工作」。把这两个问题分开,能让工具的能力描述更准确。

不过,这是一篇代码自查和设计反思,没有完整实现,也没有对照测试。作者认为现有指纹机制已经解决了真正撤销中大部分困难,这仍属于经验判断,不能据此认定接上线就足够可靠。

从展示的代码看,还有一个需要继续验证的边界:状态检查与实际写入之间,如果又发生了修改,工具如何处理?原文没有说明 DEV.to API 是否提供条件写入能力,也没有展示这段间隔如何受到保护。指纹可以帮助发现过期状态,但仅凭文中的片段,无法确认并发覆盖已经得到完整解决。

与直接恢复旧快照相比,补偿写入能明确表达要恢复哪些字段,却需要额外定义冲突策略;与平台自带版本历史相比,本地日志的方案还要自行承担恢复入口和校验逻辑。作者案例中的前提,正是目标平台没有可直接使用的版本历史。换到已有版本管理的系统,应先检查现成恢复能力是否满足需要。

能拿来做什么

  • 给 AI 编程工具或 MCP 工具梳理一次写入能力,分别标出是否需要确认、是否保存旧值、是否提供恢复入口、是否检查后续修改,避免用「有日志」笼统代表安全。
  • 如果 Node 服务会调用外部 API 修改内容,可以先让修改记录包含明确的资源标识、变更字段和前后值,再设计这些数据如何转换为补偿请求,并关联原操作完成后的状态校验依据。
  • 第一版撤销可以采用保守规则:发现相关内容已经变化就拒绝自动恢复,并展示冲突供人工处理。等部分恢复的边界定义清楚,再支持跨越后续编辑撤销。
  • 为撤销验证补上「修改后又被编辑」的场景,覆盖人工修改、第二次工具调用和并发运行。只验证旧值成功写回,无法证明后来产生的内容不会被覆盖。
Original source

本文由 AI 通读原文后重新编写,观点部分为站内判断,细节以原文为准,来源 dev.to · AI,原文版权归原作者所有。

阅读原文
上一篇
用视觉模型和家庭助手记录口岸拥堵
下一篇
Claude Code 用量分析揭示上下文成本

资讯速览

dev.to · AI · 2026-11-04 20:38

AI 评分 8.0 / 10

相关标签

#Agent#MCP#故障恢复

继续阅读

  • 本地大模型显存预算不能只看权重
  • 用视觉模型和家庭助手记录口岸拥堵
  • Claude Code 用量分析揭示上下文成本
  • 直接修改模型权重能否修复推理循环
  • 用 LibreChat 搭建多租户 AI 服务