把一批资料交给 AI,等它提取实体、整理关系,再检查生成结果。进度已经走了很远,任务却失败了。页面如果只给一个“重新开始”,用户很难知道:之前的等待、已经生成的内容,以及自己检查过的部分,还算不算数?
给任务加一个“继续”按钮,也没有自动回答这个问题。它可能重新调用模型,可能只恢复候选结果,也可能向正式数据重复提交一次操作。这几种动作的代价和风险差别很大。
TraceWise 在一次批量资料处理过程中,先后遇到了生成中断、候选结果缺失引用、提交接口约束和写后来源不可用。这些经历把问题从“能不能重试”推进了一步:恢复之前,系统需要证明哪些工作仍然有效,以及哪些操作已经发生。
下文的项目数字来自 2026 年 9 月 11—12 日保存的本地运行与验收记录。它们说明具体恢复路径及其限制,没有测量真实用户节省了多少时间。
先区分四种看起来一样的失败
从用户界面看,它们都可能是一条红色提示。但产品接下来应该做的事不同。
| 失败发生在哪里 | 先确认什么 | 合适的下一步 | 容易付出的额外代价 |
|---|---|---|---|
| 生成到一半中断 | 已保存结果对应哪些输入,是否仍有效 | 复用有效单元,继续未完成部分 | 全量重算产生新结果,增加复核负担 |
| 生成完成,结果校验失败 | 缺陷能否定位,是否影响其他部分 | 恢复草稿,修复有问题的依赖 | 为少量缺陷重新生成整批内容 |
| 提交失败或没有收到响应 | 哪些操作已生效,重试是否代表同一次意图 | 修复确定的阻塞,或核对回执后继续 | 重复写入,或把部分成功显示成完全失败 |
| 输入或任务要求发生变化 | 旧结果的适用前提是否还成立 | 使受影响结果失效,再决定重算范围 | 复用过期结论,保住了进度却做错了任务 |
这张表是从项目经验中提炼的判断方法。尤其是输入变化后的完整失效策略,是设计建议,不能据此认为 TraceWise 已经实现了所有分支。
生成中断:保留的是可识别的工作单元
在一份 26 个文件的续跑记录中,系统保留了 55 个已经完成的旧单元,将未完成尾部重新切成 459 个单元,形成 514 个单元的混合计划。保存的运行快照显示进度走到 56/514,说明续跑已经越过保留部分;这份快照本身不能证明整批完成。
这里值得关注的不是进度条重新动了,而是旧结果能够与旧输入对应。假如只保存“完成了 55 段”,随后又重新切分全文,第 56 段的含义就可能变了。进度数字相同,不代表恢复位置正确。
因此,我倾向于把输入身份、单元边界和生成结果一起保存。切分策略改变时,应明确哪些单元沿用旧定义,哪些使用新定义。这样才能解释为什么某个结果被复用,也才能在复用出错时找到依据。
这一选择有成本。更小的单元可以缩小失败后的重做范围,却可能增加调用次数、跨段关系处理和合并工作。如果任务高度依赖全文语境,机械地缩小单元还会损害结果。恢复粒度需要同时考虑生成质量与失败代价,不能只追求“丢得越少越好”。
持久化也需要说清保存到了哪里。LangGraph 的官方文档把线程状态检查点与跨线程存储分开,并明确指出,内存型检查点会在进程重启时丢失。这提醒我们:看到刷新页面后仍有内容,与验证服务重启后能恢复,是两种不同的检查。LangGraph Persistence
暂停同样有边界。TraceWise 当时采用协作式暂停:等待当前单元成功保存,再进入暂停状态。受控测试覆盖了暂停、恢复和重启,正在运行的付费任务没有为了验收被主动暂停。这里能承诺的是保存边界上的暂停;用户点击以后,当前模型请求是否立即停止、是否停止计费,需要另行验证。
校验失败:把生成成果与可采用结果分开
后来的另一份完成记录保留了全部 514 个单元的抽取结果,包含 12,468 个节点候选和 11,200 条关系候选。但其中 38 条关系缺少可解析的端点引用,最终预览校验没有通过。
如果把“最终校验失败”直接处理成“任务没有结果”,之前已经完成的生成就会一起消失。用户重新运行后得到的可能是另一份候选图,原来检查过的内容也需要重新比较。
这次恢复先读取已经保存的输出,重新形成草稿并校验,返回需要修复的状态。恢复接口没有重新调用模型,也没有把草稿提交或批准为正式知识。随后,针对 11 个受影响单元的定向修复解决了 38 条缺失引用,合并后增加了 23 个节点定义,原始检查点保持不变。
局部修复成立的原因,是问题能够定位到缺失的引用,且修复要求补充的节点具有精确原文引句。它建立了引用完整性和原文绑定,仍然不能证明所有实体理解、关系方向和知识判断都正确。
这也给局部修复划出了适用条件。如果错误来自全文主题误判,或者同一个实体被系统性地分成多个概念,补齐端点可能只会让一份错误结果变得“结构合法”。此时应该重新审视生成方法,必要时扩大重算范围。
原始输出、校验结论和修复结果分开保存,才能同时保留已有工作与重新判断它的可能。 只覆盖成一份“最新正确结果”,会丢掉解释变化所需的材料。
提交出错:先确认发生了什么
引用修复以后,任务又卡在提交阶段。当时依赖的公开操作类型把位置限制在 255 以内,而这份提案有 23,691 个操作。真实操作在位置 256 触发类型校验失败。
这种确定的接口约束不会因为再次生成资料而消失。继续调用模型只会增加等待,还可能改变已经修好的候选结果。合适的恢复工作在提交契约及其拥有者那里:保存草稿与阻塞原因,明确升级依赖或另行设计执行方案所需的条件。
另一类情况更难判断:请求已经发出,客户端没有收到响应。此时“我不知道成功没有”不能直接翻译成“没有执行”。AWS 的幂等 API 案例讨论了这种歧义,并使用调用方提供的请求标识表达同一次意图;相同参数也可能代表用户确实希望创建两个相同资源,不能只靠内容相等推断重复。Making retries safe with idempotent APIs
由此推到 AI 工作流,我的判断是:恢复正式写入前,需要核对已批准内容、执行身份和已生效结果。重新生成一份看起来相似的提案,再把它当成旧提案重试,会把生成变化与执行恢复混在一起。
项目后续的定向补齐记录提供了一个更具体的例子:执行计划分 348 个批次完成了剩余 11,136 个关系操作,最终观测到的图指纹与计划预期一致。这是针对剩余操作的执行核对,不能把这些数字解释成又生成了一遍整份资料,也不能扩展为跨存储原子事务的证明。
图已经写入,用户的任务仍可能没有恢复
在后续本地浏览器记录里,图显示了 12,491 个节点和 11,200 条关系,来源查看请求却仍返回 409。图的数量与来源可用性给出了不同答案。
如果用户只是要看图的结构,已经恢复的部分可能有价值;如果用户要逐条检查知识依据,来源不可用就仍然挡住了工作。一个统一的“完成”会掩盖这个差别。
因此,恢复验收需要回到用户接下来要做的动作:能否看到保留内容,能否定位待修复部分,能否确认批准范围,能否打开依赖的来源。接口成功、数据存在和工作可以继续,应分别检查。
页面也应该把状态解释成具体影响。对于上述记录,合适的表达可以是“图已写入,来源暂不可查看”,并提供对应的恢复入口。这是依据已知状态提出的呈现建议;那份浏览器记录并未证明完整的来源恢复已经完成。
什么时候应该放弃复用
已经付出的时间,很容易让团队把“保留全部进度”当成默认目标。但旧结果的价值取决于它是否仍适用于当前任务。
例如,用户替换了原始资料,实体定义发生变化,或审核要求从“整理可能的关系”改成“只保留有直接引句的事实”。即使旧检查点完整无缺,继续使用它也可能完成一个已经过时的任务。
更稳妥的设计是记录复用所依赖的条件:输入版本、任务要求、影响输出含义的处理规则,以及结果依赖。变化只影响局部且依赖可追踪时,可以局部失效;影响范围无法可靠判断时,重新生成可能更合适。这是建议采用的设计原则,本文案例没有覆盖自动识别所有变化的实现。
短任务也可能不值得建设复杂恢复机制。如果重新生成很便宜、没有外部写入、用户尚未投入复核,而维护检查点与失效规则的成本更高,全量重算就是合理选择。相反,模型调用昂贵、人工审核较多、部分操作已经产生效果时,清楚的恢复边界会更重要。
以后评估这类投入,可以记录一次失败重做了多少有效单元、恢复是否产生重复写入、多少人工修改得以保留,以及用户多久能够继续原来的动作。这些是建议测量的指标,本文没有相应的用户效果数据。
恢复机制值得保留的,是仍然有效的工作。每一次“继续”都应该能解释:沿用的结果依赖哪些条件,这次会执行哪些动作,以及完成后用户能够继续做什么。