智能体问题:可靠性与中途崩溃

· 2 minutes read · 326 字 · 系列:AI / 个人助理智能体

智能体的"半途而废"之痛

写代码的人都知道——程序崩溃不可怕,可怕的是崩溃后状态全丢,只能从头再来。

智能体面临的就是这个问题。一个 20 步的自动化任务,执行到第 15 步时 LLM API 超时了,所有中间状态消失。下次运行从第 1 步重新开始,前面的 14 步白做了。如果有副作用(已经发了一封邮件、已经创建了一条数据库记录),那就更麻烦——重做会导致重复操作。

Temporal 的技术博客 2026 年 4 月发表了一篇引起广泛共鸣的文章,核心观点是:AI 可靠性是一个十年前就该解决、现在仍然只解决了一半的问题。我们应该用基础设施手段而非更好模型来解决它

为什么智能体会中途崩溃?

原因一:LLM 推理本身就是不稳定的

传统软件的执行路径是确定性的——给定相同输入,永远走同一条路。LLM 不是。每一次推理都是一次概率采样,天生带有不确定性:

  • API 超时:模型推理慢时,HTTP 请求可能超时中断
  • Token 限制:上下文窗口满了,前面的轮次被截断
  • Rate Limit:API 调用频率受限,被 429 返回
  • 服务降级:高峰期模型响应质量下降
  • 随机中断:GPU 集群节点切换、负载均衡导致连接中断

这些问题不是偶尔发生的,在大规模生产环境中是常态

原因二:智能体状态是"内存态"的

大多数 Agent 框架把执行状态存在内存中:

# 典型的 Agent 循环
state = initial_state
for step in plan:
    state = llm_call(step, state)  # state 在内存
    state = tool_call(step, state)  # 一旦进程挂了,state 全丢

传统软件有数据库保驾护航——应用挂了重启后数据还在。Agent 框架呢?进程一死,所有中间推理、工具返回、上下文积累全部消失。

原因三:长链路任务的脆弱性

智能体任务越复杂,包含的步骤越多,执行成功率呈指数下降:

单步成功率 95%
10 步任务成功率: 0.95^10 = 59.9%
20 步任务成功率: 0.95^20 = 35.8%
50 步任务成功率: 0.95^50 = 7.7%

即使每步有 95% 的成功率(这已经是优秀的表现),一个 20 步任务就有近 2/3 的概率在某步失败。而大多数真实业务场景不止 20 步。

崩溃后的连锁反应

重复执行与副作用

智能体不是纯函数——它有副作用。已经发送的邮件不能撤回,已经创建的数据库记录不会因为重跑而消失。如果在第 15 步崩溃重跑,前 14 步的副作用又来一遍:

  • 发了两封同样的邮件通知
  • 创建了两条重复的订单
  • 两次调用了支付接口

这就是非幂等操作在没有持久化状态保障下重跑的必然结果。

部分完成的尴尬

第 15 步崩溃后,前 14 步的产出已经混入了真实业务系统——客户看到了一半的订单、部分更新的库存、不完整的报告。此时你是继续补完还是回滚?两者都很棘手。

上下文丢失

如果智能体跑了 30 轮对话,中间积累了大量上下文(检索到的文档、用户的多次反馈、工具调用结果的交叉关联),一旦崩溃重启,这些上下文全部丢失。重新开始意味着:

  • 用户要重新描述需求
  • 之前检索过的文档要重新查
  • 已确认的中间结论要重来

体验极差。

根本原因:把"推理"当"计算"来处理

传统软件工程建立在一组假设上:

  • 计算是确定性的
  • 失败是异常(exception),可以用 try-catch 处理
  • 重做是安全的(幂等性)

智能体打破了所有三条:

  • 推理是非确定性的(同样的 prompt 不一定产生同样的输出)
  • 失败是常态(LLM API 的 429、503 是日常)
  • 重做可能不安全(非幂等的工具调用导致副作用重复)

但大多数 Agent 框架仍然用传统软件工程的思维来设计——内存中运行、try-catch 错误处理、无状态重启。这个根本性的错配是崩溃问题的根源。

解决方案:从"更聪明的模型"到"更可靠的管道"

方案一:检查点与断点续行(Checkpoint & Resume)

在每一步(或每 N 步)后持久化当前状态:

# 每步保存检查点
for i, step in enumerate(plan):
    state = execute_step(step, state)
    save_checkpoint(
        run_id=run_id,
        step=i,
        state=state,
        tool_outputs=state.tool_history
    )

# 崩溃后从最新检查点恢复
latest = load_latest_checkpoint(run_id)
resume_from(latest.step, latest.state)

关键设计决策:

  • 检查点粒度:每一步都存 vs 每 5 步存一次(频率 vs 开销)
  • 状态序列化:要保存哪些信息?(上下文、工具返回、推理中间结果)
  • 存储介质:本地文件?Redis?数据库?

方案二:持久化工作流引擎

把 Agent 任务的执行交给专业的工作流引擎(如 Temporal、Inngest、Trigger.dev),而不是在内存中跑 for 循环:

[工作流引擎] → 调度第 1 步 → 记录结果 → 调度第 2 步 → 记录结果 → ...
                    ↓ 崩溃
[工作流引擎恢复] → 读取第 N 步结果 → 调度第 N+1 步 → ...

工作流引擎的核心能力:

  1. 持久化:每步结果写入数据库,进程挂了数据不丢
  2. 重试策略:指数退避、最大重试次数、定制化重试逻辑
  3. 超时管理:每步有独立超时,不会一个慢步骤卡住整个流程
  4. 可观测性:全链路追踪,哪步成功、哪步失败,一目了然
  5. 信号与查询:支持外部干预(暂停、取消、修改参数)

Temporal 那篇文章的核心论点就是:不要把 AI Agent 当成一个函数调用,把它当成一个 workflow。函数调用可以超时崩溃,但 workflow 天然支持断点续行。

方案三:幂等设计

无论执行多少次,结果一致的接口设计:

# 非幂等——重跑会重复创建
def create_order(customer_id, items):
    return db.insert(Order, customer=customer_id, items=items)

# 幂等——重跑会返回已存在的记录
def create_order_idempotent(customer_id, items, idempotency_key):
    existing = db.find(Order, idempotency_key=idempotency_key)
    if existing:
        return existing  # 已存在,直接返回
    return db.insert(Order, customer=customer_id, items=items, 
                     idempotency_key=idempotency_key)

幂等设计让重跑变得安全——即使在第 N 步崩溃,从头重跑不会产生重复副作用。

方案四:任务分解与独立执行

把长链路任务分解为较小的独立子任务:

[大任务: 处理 100 个客户] 
    → 子任务 1: 处理客户 1-10  ← 独立运行,互不影响
    → 子任务 2: 处理客户 11-20
    → ...

子任务独立运行,一个子任务崩溃不影响其他。重新执行时只重跑失败的子任务。MapReduce 的思想完全适用于 Agent 场景。

实战建议

  1. 超过 5 步的任务必须加检查点:不要等崩溃了才开始想持久化
  2. 工具调用全部做幂等设计:所有写操作必须支持幂等键
  3. 长任务用工作流引擎:不要在内存中 for 循环跑 20 步 Agent 任务
  4. 设置合理的超时:LLM 调用 30s、工具调用 10s、整体任务 5min
  5. 监控完成率:不是看"有没有报错",而是看"有多少任务跑到了最后一步"
  6. 保留中间结果:即使最终步骤失败,前面步骤的输出仍然有价值

小结

智能体可靠性问题不是模型问题,是架构问题。我们用不稳定的推理引擎(LLM),套在为确定性计算设计的架构上(内存态、无持久化、同步执行),当然会频频崩溃。

解决方案也不在"更好的模型"——下一个 GPT 也不能保证 100% 不超时。正确思路是从架构层面承认不确定性,用检查点、持久化工作流、幂等设计这些经过时间验证的工程手段来保障端到端可靠性。

正如 Temporal 文章所说:“我们只需要解决另一半问题——不是让模型更聪明,而是让不聪明的管道更可靠。”

下一篇,我们来讨论智能体世界中的"团队协作"问题:多 Agent 协调

© 2026 CAO ZUOHUA. All rights reserved.