# AI 能断点续跑，账单不能再来一遍

> Pi Durable 把代理从崩溃中接回来，也把一个难题摆上桌面：请求只收一次，不代表外面的事只做一次。敢接长任务的 AI，得先学会对账。

- 作者：芝士AI吃鱼
- 发布日期：2026-10-04
- 栏目：[AI锐评](https://ai-knowledgepoints.cn/commentary)（观点与分析）
- 主题：AI锐评、Agent、Pi Durable、可靠性
- HTML 正文：[https://ai-knowledgepoints.cn/blog/commentary-2026-10-04-durable-agent-receipt](https://ai-knowledgepoints.cn/blog/commentary-2026-10-04-durable-agent-receipt)
- Markdown 永久链接：[https://ai-knowledgepoints.cn/blog/commentary-2026-10-04-durable-agent-receipt/index.html.md](https://ai-knowledgepoints.cn/blog/commentary-2026-10-04-durable-agent-receipt/index.html.md)
- 原始来源：[Earendil 发布说明、Pi 源码与 Stripe 官方文档](https://earendil.com/posts/pi-durable/)

引用本文时，请注明作者与 HTML 正文链接。Markdown 版本用于机器阅读，与 HTML 正文共享同一内容来源。

## 正文

先摆一个假想场景。

你让 AI 助手替一场活动采购物料。订单提交，商家收款，助手所在的进程恰好在“保存成功结果”之前崩了。

重启以后，聊天记录还在，计划还在，助手很有干劲：“刚才中断了，我继续。”

你盯着那句“继续”，突然希望它别那么积极。采购清单只要一份，账单可不想要双份。

这不是某个产品的真实事故，而是一个恢复过程里的故障窗口：外面的事情已经发生，里面的记录还没来得及写。聊天界面看起来只是少了一句回复，后面的系统却要判断一件很要命的事：刚才到底做没做成？

10 月 1 日，Earendil 发布 [Pi 1.0](https://earendil.com/posts/pi-1-0/)，同时推出仍处于实验阶段的 Pi Durable。后者面向长时间运行的 Agent 应用。官方[介绍](https://earendil.com/posts/pi-durable/)把保存进度、进程崩溃后恢复，以及提交请求去重放在了显眼位置。

这些能力当然值得做。一个查资料查到半夜、容器重启就把工作丢干净的助手，很难让人放心托付长任务。但读完实现，我更在意它在哪些地方没有急着继续。

Pi 的[工具执行源码](https://github.com/earendil-works/pi/blob/200387122ca450d6387f033949423114a270b96c/packages/durable/src/harness/tool.ts#L85-L113)在执行前保存参数和重放策略。没有声明时，默认按 `unsafe` 处理。恢复时，只有当时保存的策略和现在的工具声明都为 `safe`，才重新执行；否则返回中断结果，提醒模型这次调用可能已经部分运行。

这句“可能已经”，比一个漂亮的恢复动画更值钱。

它没有把“本地没看到成功”擅自翻译成“外面肯定没做”。查一遍资料通常可以再查，已经提交的订单就不能只凭聊天记录决定再下一遍。即使都是一个工具调用，重复的后果也完全不同。

项目的[恢复测试](https://github.com/earendil-works/pi/blob/200387122ca450d6387f033949423114a270b96c/packages/durable/test/harness-tools-recovery.test.ts#L109-L163)专门覆盖了这条分界：保存和当前策略都允许才重跑；原先不允许，后来改成允许，也不能替那次已经发生的调用补上可安全重放的依据。这里说的是对源码和测试用例的核对，本文没有运行 Pi 的故障注入实验。

不过，停住一次旧调用，还没有替整个应用解决重复执行。中断信息返回模型后，模型可能提出一次新的调用。假如应用把所有新调用照单全收，同一件采购仍然可能再做一遍。这是从调用边界推出来的产品风险，不是本文发现了 Pi 的重复扣款事故。

收银台的小票没打印出来，不能让收银员换个窗口就当一笔新生意。

![假想采购的恢复窗口：本地保存执行意图，外部订单已生效，但本地成功回执尚未保存时进程中断。恢复须区分请求去重、工具安全重放与外部订单核验，未知状态不能直接重下订单。](https://ai-knowledgepoints.cn/images/articles/durable-agent-commentary/receipt-gap.svg)

AI 辅助制作的原创机制示意，非事故记录或性能实验。Pi 的提交去重和工具恢复策略有各自边界；外部动作仍需业务幂等、查询核验或人工处理。

[查看竖版大图](https://ai-knowledgepoints.cn/images/articles/durable-agent-commentary/receipt-gap-mobile.svg)

最容易让人误会的词，是 exactly-once。

Pi 文档里这项承诺有明确对象：同一会话内，带同一个 `requestId` 的提交会去重。它解决的是客户端没收到回应后重发，别把原来的任务又登记一遍。[对应测试](https://github.com/earendil-works/pi/blob/200387122ca450d6387f033949423114a270b96c/packages/durable/test/harness-submissions.test.ts#L82-L107)也检查了会话边界；另一个会话使用相同 ID，并不会被当成原来的提交。

就像前台认得同一张采购委托单，客人再递一次，不必再登记一次任务。这很有用，却不能据此推断后台每一个动作都只会发生一次。任务登记处和商家订单系统，毕竟没有因为一句“持久化”就共用一本账。

也不能反过来宣布，外部动作永远做不到明确的去重保证。支付等系统已经有可用的办法。关键是保证落在哪一层、满足什么条件，而不是给整个 Agent 贴一个听起来很踏实的词。

以 [Stripe 的幂等请求文档](https://docs.stripe.com/api/idempotent_requests)为例，客户端为同一次操作带上幂等键，在端点开始执行后，服务端保存首次请求的状态码和响应体，后续同键请求返回原结果；参数验证失败或与正在执行的请求冲突时，没有开始执行，就不会缓存该结果。文档也列出了边界：参数需匹配，键可在至少 24 小时后清理，清理后再用旧键可能形成新请求。这个 24 小时来自 Stripe 的规则，不能移植成所有服务的通用保证。

这时真正有价值的，是重启前后仍能认出“同一笔生意”。如果助手每次恢复都生成一个新键，或者换了一次对话就把业务身份丢了，接了幂等接口也白搭。编号换了，柜台当然可能按一笔新订单办理。反过来，把两笔真正不同的订单错误地塞进同一个键，也会出问题。

所以我对长任务 Agent 的判断是：一个醒来后肯先核对订单、再决定做什么的产品，比一个永远能流畅接话的产品更值得信任。流畅感可以展示，未知状态必须处理。

这里的难处，不全在模型会不会推理。应用得保住业务编号，拿得到外部回执，知道何时还能安全重试；没有查清的，要把“结果待确认”作为真实状态留给人看。让模型再读一遍聊天记录，不能补出一张根本没被保存、也没向商家查询的小票。

还有一种“恢复”同样容易过度承诺：取消。

取消一个任务，可以意味着不再继续；对已经发生的效果，有时还需要退款、撤销或补偿。Pi 的[任务设计说明](https://github.com/earendil-works/pi/blob/200387122ca450d6387f033949423114a270b96c/packages/durable/docs/spec.md#L1849-L1860)明确把外部动作夹在“保存意图”和“保存结果”之间，并要求恢复逻辑选择安全重试、查询外部句柄或记录中断。这个分层提醒我们：本地状态能恢复到哪一步，要和外部世界已经走到哪一步分开看。

即使退款成功，也是一笔后来发生的新动作。货已经发出，收件人已经读到邮件，生产环境已经对用户提供过一次错误响应，都不能靠把对话退回上一条消息当作没发生。程序很擅长回到旧状态，现实通常不提供那么整齐的撤销按钮。

这不意味着所有 Agent 都要先造一套复杂交易系统。只读检索、草稿生成，或者可以丢弃重建的临时文件，往往可以采用更轻的恢复办法。重新生成一份摘要，与重新付一笔钱，没必要背同样重的包袱。具体外部服务如果已经提供稳定的业务去重和查询能力，也应该用好，不必重复造轮子。

值得警惕的是，产品把能力从“帮你想”扩展到“替你办”，交付标准却仍停留在“崩了以后聊天还能接上”。事情越做越长，碰到的外部系统越多，那些过去藏在演示之外的半张小票，就越可能成为主要工作。

如果让我挑一个演示环节，我会把断点设在最不讨巧的位置：外部已经受理，本地还没记下成功。然后看产品怎样找回这笔操作，怎样显示不确定，怎样避免把同一件事换个调用编号再办一次。这是本文建议的验收场景，不是声称 Pi 已经替每个接入服务完成了验证。

一个系统愿意在这里承认“还没查清”，未必显得聪明。它只是在替用户认真保管那张账单。

AI 可以说“我接着干”。在动手以前，先把上一张小票找回来。

资料核对：2026 年 10 月 4 日。发布事件为 10 月 1 日；Pi Durable 当时标注为 experimental。源码与测试引用固定于 `200387122ca450d6387f033949423114a270b96c`，不代表独立运行验证，也不承诺后续版本行为不变。采购场景与配图为假想示意；产品判断和验收建议为本文分析，未声称发生真实重复扣款事故。所述 exactly-once 边界不否认下游幂等接口或事务设计在明确条件下能提供的保证。

想继续拆解 Agent 的工程细节，可以看 [AI 实践路线](https://ai-knowledgepoints.cn/planet)；公众号入口在[关于页](https://ai-knowledgepoints.cn/about#wechat)。

本文文字与图解由 AI 辅助制作，事件、源码和文档来源已在正文列明。
