跳到主要内容

超时感知的智能体设计:如何返回部分结果而非静默失败

· 阅读需 11 分钟
Tian Pan
Software Engineer

一个智能体成功创建了 GitHub Issue、开启了 Jira 工单,并更新了共享表格。然后在发送 Slack 通知之前超时了。框架将此次运行记录为"已交付"。用户从未收到通知。副作用存在于三个系统中,而对人类真正重要的结果却没有送达。

这是生产智能体系统中最常见的超时失败模式,但几乎从来不是团队预先准备好的那种。大多数智能体实现把超时当作普通异常处理:捕获、记录、返回错误。即使智能体完成了 90% 的工作,用户也什么都得不到。问题不在于是否设置超时——每个生产系统都需要超时。问题在于当时钟走完时,智能体该如何应对。

截止失败的解剖

智能体在截止时间处的失败分为两大类。第一类是显式的:智能体崩溃、抛出异常,调用方看到错误。令人烦恼,但可以恢复。第二类才是真正造成破坏的:智能体完成了不可逆的副作用——写入、通知、外部 API 调用——然后在向用户交付结果之前失败了。

这种区别至关重要,因为这两种失败模式需要完全不同的缓解方案。显式失败需要重试逻辑和熔断器。静默的部分完成失败需要事务纪律:理解哪些操作可以回滚、哪些不能,并据此排序。

还有第三种失败模式是团队很少考虑到的:初始化税。一个资源充足的智能体在初始化内存存储、凭证系统和技能注册表时,可能在 300 秒的预算里烧掉 75 秒,然后才开始做任何实质性工作。你的超时看起来是 300 秒,但实际表现得像 225 秒。按挂钟测试(跳过冷启动)来计算大小的系统,往往会在生产中以令所有人惊讶的速度失败。

为什么智能体会完全失败而非部分失败

根本原因是架构性的。大多数智能体实现将完整任务建模为单一原子单元。任务要么成功要么失败;没有中间状态的表示。当超时触发时,运行时没有检查点可以返回,没有部分模式可以填充,除了"超时"之外没有任何信号可以发送给调用方。

这与成熟分布式系统处理截止时间的方式形成鲜明对比。超时的数据库查询仍然可以返回取消之前已扫描的行。流式 API 会向客户端发出信号以优雅关闭。文件下载可以从字节偏移处恢复。这些模式之所以有效,是因为底层协议在设计时就考虑了部分完成——模式允许它,客户端期待它,超时成为进度门控而非硬停止。

智能体循环没有继承任何这些。ReAct 循环——观察、推理、行动、重复——没有自然的提前退出钩子。LangChain 的 AgentExecutor 添加了 max_iterationsmax_execution_time 参数,有助于控制失控行为。但它们没有添加在中断时刻打包已有进度的结构化方式。智能体在第 4 步(共 10 步)停下来,而它在这四步中学到的一切都消失了。

三种真正有效的模式

检查点优先执行

最健壮的方法将每个智能体步骤视为持久状态转换而非短暂函数调用。在每次 LLM 调用和每次工具返回之后,系统写入检查点:当前上下文、累积结果、待处理操作。当超时触发时,执行在最近的检查点处干净停止,而不是在任意的中间步骤中断。

像 Temporal 这样的持久化执行框架会自动实现这一点。每个工作流步骤都捕获在事件历史中;如果进程在运行中途崩溃,新的工作节点会从事件日志重放并从上一个工作节点停止的地方恢复。智能体永远不会重做已完成的工作,已完成的结果也永远不会丢失。

这种模式有成本。检查点写入会为每个步骤增加延迟,事件日志的增长与执行时长成正比。对于短时运行的智能体(30 秒以内),开销通常不值得。对于预计运行数分钟的智能体,检查点是使部分进度对调用方可见的唯一方式。

结构化部分结果模式

检查点存储进度以供恢复。部分结果模式将该进度传达给调用方。区别在于受众:检查点是为系统服务的,部分结果是为用户服务的。

为部分完成设计的模式将字段标记为可选,并包含状态信封。与其返回完整的分析对象或什么都不返回,智能体返回:

{
"status": "partial",
"completed_steps": ["competitor_pricing", "market_share"],
"missing_steps": ["financial_projections"],
"reason": "timeout",
"results": { ... }
}

调用方——无论是 UI、另一个智能体还是编排器——现在可以对要显示的内容做出明智的决定。10 家竞争对手中有 8 家的定价信息比什么都没有要有用得多。当管理者在决定是否下紧急订单时,部分库存报告比没有要好。

关键的设计纪律是区分读操作和写操作。部分结果适用于读取:分析、总结、信息检索。它们不适用于写入。部分执行支付转账或半途而废地处理数据库迁移的智能体,会让世界处于不一致的状态。写操作需要在事务级别强制执行"完成或放弃"语义。如果预算不足以支撑完成,超时应该阻止写入开始,而不是中途打断它。

提前退出信号

第三种模式让智能体意识到自己的截止时间。与其让运行时在 T=超时时强制取消智能体,系统在 T=(超时 - 缓冲)时向智能体发送软信号:你还有 N 秒,请给出当前最佳答案。

这之所以有效,是因为在明确提示时,LLM 在任务截断方面表现相当不错。知道自己时间不多的智能体可以整合已找到的内容,跳过优先级较低的子任务,并返回连贯的部分结果——这是硬取消无法做到的。Google 的 ADK 支持 escalate 标志,触发带质量阈值检查的智能体提前退出。LangChain 的 max_execution_time 可以与 return_intermediate_steps=True 结合,在中断时刻暴露进度。

软信号方法需要正确校准缓冲时间。太短则智能体没有足够时间整合;太长则浪费预算。一个合理的起点:测量你的智能体整合步骤(通常是一次 LLM 调用)的第 99 百分位时间,加上 20%,将其作为缓冲时间。

你必须首先做出的用户体验决策

在选择技术模式之前,你需要解决产品层面的问题:这是尽力而为操作还是完成或放弃操作?

尽力而为操作——研究、总结、分析、检索——可以优雅降级。用户得到 80% 的答案并知道缺少什么。这种模式的用户体验需要清晰地传达不完整性,而不是隐藏它。"在达到时间限制之前,我找到了 10 家竞争对手中 8 家的定价。以下是我得到的:"远比返回一个没有任何缺失数据提示的隐式不完整表格要好。

完成或放弃操作——金融交易、账户变更、数据库写入、触发下游工作流的通知——如果无法完成就不应该开始。分布式系统中的熔断器模式在这里直接适用:在开始之前测量操作在时间和令牌上的预期成本,与剩余预算进行核对,如果数学不成立则优雅拒绝。"我没有足够的时间预算来安全地完成这笔转账"是一个诚实且有用的回应。静默地半途执行转账则不是。

最糟糕的结果不是无法交付结果。而是交付了看起来完整但实际上不完整的结果——或者在没有交付结果的情况下完成了副作用。将你的操作排序以尽早呈现用户可见的结果,最后进行清理。先公告再归档。先通知再关闭工单。

生产系统实际上怎么做

Cox Automotive 的生产客户服务系统对成本和对话轮次都实施了硬熔断器。如果运行接近第 95 百分位的成本阈值,系统会自动停止智能体。如果对话超过大约 20 轮,无论任务完成状态如何,智能体都会停止。这些不是优雅的部分结果方案——它们是防止失控行为蔓延到其他会话的钝器。

在生产中运行 LangChain 的团队通常将 max_iterations 配置为 5 到 8,并设置 handle_parsing_errors=Truereturn_intermediate_steps=True。中间步骤提供了对智能体在停止前完成了什么的可观测性;解析错误处理器保持智能体在工具输出格式错误时也能正常运行。这两种模式都没有交付结构化的部分结果,但都降低了静默全局失败的概率。

2025 年和 2026 年正在发生的转变是从"由强大模型驱动的智能体"转向"由可靠框架治理的智能体"。执行框架——其超时策略、检查点纪律、部分结果模式和熔断器配置——越来越成为决定智能体是否适合生产的主要因素。在生产环境中,拥有健壮框架的较弱模型优于拥有朴素框架的较强模型,因为可靠性的复利方式与原始能力不同。

正确调整超时大小

生产部署中一个一致的发现:在开发中确定大小的超时在生产中是错误的。开发智能体跳过冷启动。它们在热缓存上运行。它们不争用 GPU 资源。在笔记本中有效的 30 秒超时,当智能体在具有真实初始化成本的共享基础设施上运行时,会成为持续失败的来源。

正确的方法是实证的:在生产中对你的智能体执行时间线进行埋点,识别每个阶段(初始化、每步 LLM 调用、工具调用、整合)的第 99 百分位,并将超时设置为 p99_total + 安全边距。如果完整运行的 p99 是 180 秒而你当前的超时是 60 秒,你不是在为偶发的慢速调整——你是在定期超时成功的智能体。

将启动时间与任务执行时间分开监控。当启动持续消耗预算的 30-40% 时,修复方法是缓存和惰性初始化,而不是更长的超时。容纳慢速初始化的更长超时隐藏了真正的问题,并使系统平均更慢。

首先构建什么

如果你的智能体当前在超时时返回错误,最高杠杆的变化是将 return_intermediate_steps 或等效配置添加到你的执行器配置中,然后构建一个知道如何处理部分响应的调用方。这是一天的工作,可以立即改善失败体验。

检查点优先方法需要更多基础设施投入,但解锁了可恢复性,这从根本上改变了长时运行智能体的经济学。一个能够在瞬态基础设施故障后从检查点恢复的智能体,比一个从头开始重启的智能体价值高得多。

提前退出信号模式在架构上最为优雅,但需要在框架端(发送信号)和智能体提示设计(教会它响应信号)两方面都做出改变。将其保留给频繁运行且优雅降级明显改善用户体验的智能体。

无论你实现哪种模式,都要明确地对每种操作类型做出尽力而为还是完成或放弃的决定,并将其记录下来。最常见的生产失败发生在团队假设某个操作可以优雅降级,然后在生产中发现它让世界处于不一致状态。

超时不是边缘情况。它们是塑造你的智能体中每一个其他架构决策的设计约束。将其视为事后考虑,意味着你隐式地选择静默全局失败作为你的生产行为——而这个选择会在最糟糕的时刻宣示自身。

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