跳到主要内容

为部分完成而设计:当你的智能体完成 70% 后停止

· 阅读需 11 分钟
Tian Pan
Software Engineer

每个生产级智能体系统最终都会遭遇一个没有人预料到的故障:智能体订好了机票,却找不到酒店,留给用户的是半张已确认的行程单,以及毫无头绪的后续。这不是崩溃,也不是拒绝执行,只是一个停止运行的智能体——带着真实的副作用,却没有任何后续计划。

对智能体故障的标准认知是二元的——要么成功,要么中止。重试逻辑、指数退避、回退提示词——这些机制都假设"任务运行中"与"任务完成"之间存在清晰的边界。但真实的智能体会在中途失败,而当这种情况发生时,缺乏部分完成设计本身就是 bug。你不需要更智能的模型,你需要的是一个任务状态机。

介于开始与完成之间的四种失败模式

在为部分完成进行设计之前,有必要准确分类任务中途中断的根源。共有四种不同成因,每种都需要不同的设计应对。

持续时间溢出是最可量化的。当前前沿模型在四分钟以内完成任务的可靠性接近完美;而对于超过四小时的任务,成功率会跌破 10%。这并非偶然——这是一条可预测的退化曲线。智能体在长序列过程中会因上下文漂移、累积的不确定性以及工具调用错误的叠加而逐渐失去连贯性。任何可能耗时数小时的工作流,都需要从一开始就设计为可中断的。

执行中途发现的授权缺口更为隐蔽。智能体以合理的权限范围开始任务,随后遭遇一个需要它并不具备的凭证的步骤——对某个系统的写操作而它只有读权限、超过审批阈值的金融交易、隐藏在额外认证层后的 API 端点。任务初始化时的静态权限授予无法预见完整的执行树。智能体就此卡住,往往悄无声息。

上下文耗尽会导致智能体在触碰硬性限制之前就已退化。每个前沿模型在输入长度增长时都会退化——通常早在声明上下文窗口的 30–50% 时便开始。智能体不会在接近限制时崩溃;它们开始做出更差的决策,遗忘早期上下文,最终产生前后矛盾的输出。65% 的企业 AI 生产故障被归因于上下文漂移,而非触达硬性限制。

不确定性与置信度崩溃发生在智能体到达一个决策点时——正确行动真的不明朗,而猜错的代价又很高。若缺乏对这类情况的显式处理,智能体要么猜测(产生难以追溯的错误),要么以晦涩的报错信息停止,让运维人员无从下手。

检查点优先设计原则

优雅应对上述任何情况的前提,是状态外部化。将所有任务状态保存在上下文窗口中的智能体没有任何恢复空间。一旦失败,它对自己已做之事的所有认知都会消失。

检查点架构将任务的每个步骤视为离散的、可持久化的事件。执行某个步骤前,写入意图;完成后,写入结果。持久化的状态构成恢复、回滚和审计的基础——与智能体的下一次运行是否还记得任何内容无关。

实现方式的选择至关重要。对于小型检查点(350 KB 以下),将序列化状态直接写入 DynamoDB 并附上线程 ID 和时间戳就足够了。对于包含工具输出、文档或中间产物的大型检查点,模式会转变:将有效载荷写入 S3,在 DynamoDB 中存储引用指针。检查点器只是一个指针存储,实际状态存在于对象存储中。

关键的区分在于工作流状态会话状态。工作流状态是持久的——任务完成了什么、产生了哪些产物、在执行序列中处于哪个位置。会话状态是短暂的——当前对话上下文、进行中的工具调用、智能体的工作内存。许多团队混淆了这两者,最终在每次服务器重启后都要重建工作流进度,因为他们把所有东西都存在了会话里。

工作流状态应能在进程重启、智能体模型升级以及智能体之间的交接中存活。会话状态按定义不需要。在任务设计中内置检查点,意味着在写第一行智能体代码之前就决定好什么属于哪个类别。

人机协作恢复的三种模式

一旦拥有持久化的任务状态,问题就变成了人类如何与部分完成的工作交互。生产系统中呈现出三种模式,选择哪种取决于任务对延迟的容忍度、错误成本以及实际需要干预的频率。

同步审批门在预定义的节点暂停执行,并在继续之前要求人工确认。智能体执行到该节点,序列化其状态,并向用户呈现包含完整上下文的审查界面:已做了什么、下一步打算做什么、用户拒绝时会发生什么。当下一步不可逆或代价高昂时——提交采购订单、发送对外通信、执行数据库写操作——这是正确的模式。代价是延迟;人工审批周期会为任务执行时间增加数分钟乃至数小时。对于错误步骤的下游代价超过等待代价的工作流,这是正确的权衡。

异步审计队列让智能体完全自主运行,同时将每个决策及其足够的上下文记录到日志,以供事后审查。智能体不会阻塞等待人工输入,但一个决策队列会不断积累,供运维人员审查、标记或用于系统调优。当任务延迟受到严格约束且单个错误可以恢复时,这种模式是合适的——例如处理工单的客服智能体、生成草稿的内容生成流水线。风险在于,当一个糟糕的决策浮现在队列中时,影响可能已经扩散。

多层监督对不同类别的操作分配不同的监督级别。低风险、边界明确的步骤自主运行;超过成本阈值、触及敏感系统或置信度跌破基线的步骤同步上报。智能体本身根据初始化时收到的策略做出上报决策。这是大多数生产部署最终收敛到的模式——它将人类的注意力分配到最需要的决策上。

三种模式的底层要求是相同的:智能体必须能够清晰地表达其状态,以便人类能够做出有意义的决策。一个呈现"任务在第 7 步失败"的中断不是审批门——那是报错。真正的中断应呈现:已完成什么、存在哪些中间产物、下一步的提议是什么、以及如果人类做出不同选择时各分支的结果。

在上下文成为紧急情况之前主动管理

大多数上下文管理策略是被动的——在智能体已经深陷退化时才被触发。主动的方法将上下文视为需要在整个任务执行过程中管理的预算,而不是在耗尽时才去补救。

触发主动上下文管理的实用阈值约为可用预算的 70%。在此时,智能体应将已完成的任务历史压缩为紧凑表示,丢弃已处理完毕的冗长工具输出,并仅携带完成剩余步骤所需的事实信息。这个压缩摘要将替换后续上下文窗口中的原始对话历史。

风险在于有损压缩——摘要可能丢弃事后证明重要的细节。缓解措施就是检查点优先:所有原始数据都存储在持久化的工作流状态中。智能体不需要在上下文中保存所有内容,因为它可以按需检索特定产物。上下文成为工作索引,而非权威存储。

在执行不可逆步骤之前规划回滚

智能体系统中的回滚并非数据库意义上的事务性操作。你无法回滚一封已发出的邮件、一个已创建的 API 资源或一个已确认的预订。你能做的是在执行任何具有持久影响的步骤之前,规划好补偿路径。

该模式是将不可逆操作视为配对:一个执行步骤和一个补偿步骤。如果智能体在第 3 步订了机票,而第 5 步的酒店预订失败,执行树中包含一条预定义路径来取消第 3 步的预订。这个补偿步骤从执行步骤被写入的那一刻起就存在于工作流状态中,而非在失败发生时临时寻找。

这一区分对多智能体系统至关重要。当子任务被委托给专业智能体时,编排者需要追踪哪些智能体已执行了不可逆操作,并确保其补偿步骤保持可访问。一个丢失了这种追踪的编排者——因为它只在会话状态中维护——就无法编排有意义的回滚。

选择性回滚几乎总是优于完整任务重启。如果一个 10 步任务的第 1 到第 6 步已成功完成,回退到第 1 步会浪费所有工作并引入新的错误面。目标是在回滚受影响分支的同时保留已完成的步骤。

向用户呈现进度:部分完成实际上是什么样的

一个陷入停滞的智能体的用户体验往往比彻底失败更糟糕,因为用户无法判断发生了什么或下一步该怎么做。良好设计的部分完成状态应让当前位置清晰可见。

有用的进度信号包括:任务完成了多少比例、哪些产物或结果已可用、阻塞条件是什么、用户有哪些选项(提供额外授权、放弃任务、转向其他路径)。这与进度条不同——进度条告诉你经过了多少时间,有用的进度信号告诉你存在什么以及什么是可能的。

阻塞条件值得特别关注。"需要授权"是可操作的,"错误:权限拒绝"则不是。"对意图不确定——你希望按解读 A 还是解读 B 继续?"是可操作的,"任务失败"则不是。中断的表述方式决定了用户是否能够有意义地回应,还是必须从头重来。

在你的第一个智能体上线前应构建什么

这些模式在从一开始就加以设计时效果最好。将检查点架构改造进一个已经完全在上下文中管理所有状态的智能体,是一次重大重写。

上线前,请验证你的智能体设计对以下五个问题有明确的答案:

  • 持久化工作流状态存储在哪里,智能体重启后如何从该状态恢复?
  • 人类可以在哪些节点中断执行,他们中断时会看到哪些信息?
  • 每个不可逆操作的补偿步骤是什么,记录在哪里?
  • 当上下文使用率接近 70% 时,什么会被压缩,什么会被原样保留?
  • 阻塞条件对用户来说是什么样的——它是否可操作?

如果这些问题中的任何一个没有具体答案,智能体最终将在任务中途停止,没有任何恢复路径。随之而来的失败不会看起来像一个 bug;它看起来像是模型犯了错误。但模型会没事的,缺失的设计才是问题所在。

部分完成不是边缘情况,而是任何运行超过几分钟、涉及多个系统或遭遇真实世界不确定性的智能体的正常运行状态。从一开始就将其视为设计要求,才能区分优雅降级的智能体与让用户比自己动手更糟糕的智能体。

References:Let's stay in touch and Follow me for more thoughts and updates