智能体的"半途而废"之痛
写代码的人都知道——程序崩溃不可怕,可怕的是崩溃后状态全丢,只能从头再来。
智能体面临的就是这个问题。一个 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 步 → ...
工作流引擎的核心能力:
- 持久化:每步结果写入数据库,进程挂了数据不丢
- 重试策略:指数退避、最大重试次数、定制化重试逻辑
- 超时管理:每步有独立超时,不会一个慢步骤卡住整个流程
- 可观测性:全链路追踪,哪步成功、哪步失败,一目了然
- 信号与查询:支持外部干预(暂停、取消、修改参数)
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 场景。
实战建议
- 超过 5 步的任务必须加检查点:不要等崩溃了才开始想持久化
- 工具调用全部做幂等设计:所有写操作必须支持幂等键
- 长任务用工作流引擎:不要在内存中 for 循环跑 20 步 Agent 任务
- 设置合理的超时:LLM 调用 30s、工具调用 10s、整体任务 5min
- 监控完成率:不是看"有没有报错",而是看"有多少任务跑到了最后一步"
- 保留中间结果:即使最终步骤失败,前面步骤的输出仍然有价值
小结
智能体可靠性问题不是模型问题,是架构问题。我们用不稳定的推理引擎(LLM),套在为确定性计算设计的架构上(内存态、无持久化、同步执行),当然会频频崩溃。
解决方案也不在"更好的模型"——下一个 GPT 也不能保证 100% 不超时。正确思路是从架构层面承认不确定性,用检查点、持久化工作流、幂等设计这些经过时间验证的工程手段来保障端到端可靠性。
正如 Temporal 文章所说:“我们只需要解决另一半问题——不是让模型更聪明,而是让不聪明的管道更可靠。”
下一篇,我们来讨论智能体世界中的"团队协作"问题:多 Agent 协调。