做 Agent 的同学迟早会撞上同一堵墙你的 Agent 跑着跑着就死了——不是模型报错而是进程被杀、网络抖动、上游超时或者干脆是你自己半夜发布代码把它重启了。然后你发现一个尴尬的事实Agent 没有恢复能力它从头再来把已经完成的步骤又执行了一遍甚至把已经发出去的邮件又发了一次。这个问题的本质就是标题里那句话当 Agent 从跑一次就结束的脚本变成长期运行的分布式进程它就不再是单纯的 Prompt 调用而是一个分布式状态机。你如果不按状态机的思路去设计基础设施可靠性就永远是玄学。这篇文章我想把这块掰开揉碎讲清楚状态到底存什么、怎么存、怎么恢复以及生产环境里那些真实踩过的坑。适合正在做 Agent 开发、Agent 框架选型、或者已经被Agent execution terminated due to error折磨过的同学。1. 从一次性调用到长期运行进程Agent 的形态质变1.1 早期 Agent 为什么不需要考虑可靠性先回忆一下最早的 Agent 形态一个函数接收用户问题调用 LLM解析输出返回结果。整个过程几秒到几十秒无状态、无持久化、失败就重试一次重试不行就报错。这种模式下可靠性的定义很窄——只要 API 调用不挂就万事大吉。但 Agentic AI 真正落地之后场景完全变了。Agent 开始承担需要跑几十分钟甚至几小时的任务自动修复代码仓库里的 issue、跨多个系统完成一次企业级审批流、在浏览器里操作十几个页面完成一次数据迁移。这些任务的特点是时间长单个任务可能持续数小时期间模型要调用几十次甚至上百次。有副作用每一步都可能对外部系统产生真实影响比如发邮件、提交 PR、改数据库。跨进程任务可能分布在不同容器、不同机器、不同微服务里执行。需要等待要等外部系统回调、等用户审批、等定时任务触发。一旦你接受了这些特点就不得不承认Agent 运行的本质是一连串状态的迁移——每一步决策改变状态状态又决定下一步动作。这跟数据库里的状态机、工作流引擎里的流程实例在骨架上是一模一样的。1.2 状态机视角Agent 状态 事件 迁移如果你用状态机的语言去描述一个 Agent三样东西跑不掉状态State当前 Agent 执行到哪一步、积累了哪些信息、哪些子任务已完成。事件Event模型输出、工具调用结果、外部回调、定时器触发、用户中断。迁移Transition根据当前状态和收到的事件决定下一步动作的函数。有个类比特别好用传统 Web 开发里的 Session。一个用户登录后服务器靠 Session 记住你是谁、购物车里有什么。Session 丢了用户重新登录就行——损失几秒钟。但 Agent 的Session如果丢了损失的是几十分钟的计算量、已经产生的副作用、以及用户对系统的信任。所以 Agent 这个状态机必须比 Web Session 严格得多要有持久化、要有恢复点、要有幂等保护。这也是为什么现在很多 Agent 框架开始借鉴 Temporal、Cadence 这类分布式工作流引擎的设计——不是巧合是因为问题本质相同。你与其把 Agent 当成高级聊天机器人不如把它当成自带推理能力的分布式状态机这样的心智模型能帮你避开大量可靠性坑。1.3 从热词看行业共识Agent 基础设施正在成型最近 Agent 相关的热度非常高大家讨论的不再只是怎么让 Agent 画一张图而是 Agent 架构、Agent 框架与编排、Agent 记忆、Agent 安全、Agent evals、多 Agent 协作。这些话题其实指向同一个方向Agent 正在走向工程化而工程化的第一步就是把运行时的可靠性问题摆上台面。有一种很典型的误解是Agent 框架选个火的就行。实际上框架解决了怎么编排步骤但没解决步骤之间断了怎么办。编排像交通规则可靠性像道路养护——没有养护规则再完善跑着跑着路就塌了。下面我按状态拆解 → 可靠性支柱 → 落地选型 → 问题排查这条线把基础设施可靠性的完整路径梳理一遍。2. 拆解 Agent 的状态到底要持久化什么东西2.1 四类状态缺一不可要设计状态存储先得搞清楚状态有哪些。我按生产实践分了四类状态类型内容丢失后果典型存储会话上下文对话历史、用户意图、阶段性结论无法继续对话答非所问Redis、内存任务进度当前步骤、已完成子任务、待办队列重复执行或任务中断数据库表、检查点文件外部集成状态已创建的工单 ID、已发送的请求 token、webhook 端点重复创建工单、重复发送请求数据库 幂等表Agent 自身配置角色设定、工具列表、模型参数行为不一致配置中心、环境变量你可以看到前两类相对好丢丢了无非是重来后两类一旦丢了不只是重来的问题——是会产生重复副作用的问题。我见过一个真实事故Agent 在支付流程里因为重启丢失了已创建预支付订单的状态恢复后重新创建了一次订单用户被扣了两笔钱。这就是外部集成状态没持久化的代价。2.2 记忆体系短期、长期、永久记忆怎么落地热词里反复出现Agent 记忆尤其是短期、长期、永久记忆如何实现这里展开说一下因为它直接关系到状态存储的设计。短期记忆工作记忆当前任务轮次内的上下文本质就是对话历史 中间推理结果。实现最简单放内存或 RedisTTL 设成任务生命周期即可。但要注意 token 预算——对话历史无限膨胀最后成本会炸。长期记忆跨会话用户偏好、历史行为、领域知识。通常做向量化存储比如 Chroma、Milvus、pgvector按语义相似度召回。这里的坑是记忆污染——存进去的低质量信息会在后续会话中被错误召回所以写入前要有过滤和摘要。永久记忆事实与身份用户身份、不可变的事实记录、合规审计日志。必须放可靠存储数据库需要考虑并发写入冲突。很多框架把记忆做成了插拔式接口但我在实际项目里发现一个问题框架自带的内存管理比如自动总结、自动裁剪往往不够细。你自己设计时要明确一个策略——什么时候把短期记忆固化成长期记忆我的做法是任务成功结束后对对话历史做个摘要抽取用户偏好和事实再由开发者确认或者规则过滤后写入长期记忆。这个固化动作本身就是状态迁移的一部分丢了它记忆体系就断了。2.3 存储选型的现实约束状态存储没有银弹。关系型数据库PostgreSQL适合任务进度、幂等表这种强一致数据Redis 适合会话上下文这种高频读写对象存储适合大块的中间产物比如 Agent 生成的图片、报表文件向量库只负责长期记忆召回别什么都往里塞。一个高频踩坑点把 Redis 当成任务进度的唯一存储。Redis 持久化机制RDB/AOF在极端情况下会丢数据而且不适合存复杂的状态结构。任务进度表必须上数据库外加定期检查点。我的习惯是Redis 管热数据数据库管事实数据两者之间通过事件同步。热词里有人提到agent 记忆框架以及选型我的建议就一句话记忆选型看你的召回质量和写入频次别为了省事把四种状态塞进同一个存储。3. 基础设施可靠性的四个支柱3.1 支柱一检查点与故障恢复长期运行的 Agent 必须能从断点续跑而不是从头再跑。检查点Checkpoint就是定期把状态快照持久化。设计时有三个关键参数快照频率太频繁则开销大太低则丢失多。我一般按步骤级做快照——每完成一个工具调用就更新一次任务进度表而不是按时间间隔。因为 Agent 的每一步都是逻辑边界按步骤打点最自然。恢复粒度要能恢复到最近一个成功的步骤而不是整段重放。这就意味着状态里要记录每个步骤的输入输出尤其是工具调用的参数和结果。恢复动作恢复后不能简单重放要先用幂等检查确认这一步是否已经执行过。代码层面伪代码大致是这样def run_with_checkpoint(task_id, step_fn): state load_checkpoint(task_id) if state is None: state init_state(task_id) while not state.is_complete(): step state.next_step() # 恢复前检查幂等这一步的结果是否已存在 if not has_result(task_id, step.id): result execute_step_with_retry(step_fn, step, task_id) save_step_result(task_id, step.id, result) state advance_state(state, step, result) save_checkpoint(task_id, state) return state这个模式看着简单但它解决了一个大问题任何一步崩溃重启后都能精确找到断点。代价是你要为步骤结果设计存储——一张step_results表字段包括 task_id、step_id、输入摘要、输出摘要、状态、时间戳。3.2 支柱二幂等执行与消息投递语义Agent execution terminated due to error 这句报错本身不可怕可怕的是你重试之后产生了重复副作用。所以幂等设计比重试机制更优先。工具调用的幂等有三种策略自然幂等操作本身可重复执行比如读取文件。去重键给每个外部操作生成唯一键比如operation_id uuid下游系统按这个键去重。写数据库、发消息、创建订单都能配合。状态校验执行前先查这个动作是否已完成已完成则直接返回已存结果。实操中我建议所有非幂等的工具调用都包装一层幂等代理调用前生成 operation_id调用后把 operation_id 结果写入幂等表重试时先查表。这个包装看起来多写几行代码但能挡住九成的重复事故。消息投递语义也要想清楚Agent 之间通过消息队列协作时你用的是 at-most-once、at-least-once还是 exactly-once生产环境几乎只能做到 at-least-once剩下的靠消费端幂等来兜底。所以生产者保证不丢消费者保证不重是基本原则。我见过太多团队把 MQ 当成绝对不会丢的神器结果消费者一旦重复消费状态就乱了。3.3 支柱三一致性——从乐观锁到 Saga多 Agent 协作场景下一致性是个大课题。热词里大量出现多 Agent 协作但很少有人讲它的可靠性代价。核心问题是多个 Agent 同时读写同一份共享状态怎么保证不冲突我的经验是分三层解决乐观并发控制状态表里加version字段更新时WHERE version ?版本不匹配就重读重试。这能挡住绝大部分并发冲突。状态机约束Agent 状态迁移不是任意的要定义合法的迁移路径。比如已支付不可能迁移回待支付。这一步用代码约束比靠模型自觉可靠得多。Saga 模式跨系统的长事务不能靠数据库事务要拆成本地事务 补偿动作。Agent A 创建订单Agent B 扣库存Agent C 通知仓库——任何一步失败要能反向补偿。关于 Saga我补充一个实操细节补偿动作本身也要有状态记录和幂等保护否则补偿失败了怎么办业界做法是补偿的补偿更实用的做法是把补偿动作做成可重试的队列任务并且记录补偿状态人工介入时能看到完整链路。3.4 支柱四可观测性——追踪每一块状态没有可观测性的分布式系统等于瞎子摸象。Agent 基础设施的可观测性有三件套Trace一次 Agent 任务从触发到结束经过哪些步骤、调用了哪些工具、每一步耗时多少。用 OpenTelemetry 标准 把task_id作为 trace_id 的关联键。Metrics任务成功率、平均执行时长、工具调用失败率、重试率、token 消耗。这些指标直接反映基础设施健康度。Logging每步决策的输入输出摘要注意别把完整 Prompt 打进去又贵又泄露隐私。我踩过的坑是Agent 框架自带的 tracing 往往只覆盖框架内部覆盖不到你的业务状态迁移。所以要在状态检查点那个位置额外地埋点——每保存一次检查点就发一条结构化事件。这样排查问题时你可以把时间线拉出来几点几分执行到哪一步状态是什么下一步为什么没发生。热词里反复出现agent evals这也跟可观测性有关。Evals 不只是评估模型回答好不好更应该评估整个状态机的行为任务是否按预期状态序列走完、有没有状态卡死、有没有配置漂移。把 evals 的断言写到状态层面比只评文字输出可靠得多。4. 框架选型与实战落地4.1 框架与编排层先分清单 Agent和多 Agent热词里有个问题很有意思harness 和 agent 区别。Harness 在 Agent 语境里通常指运行 Agent 的脚手架环境——包括工具调用循环、上下文管理、错误处理。而 Agent 是决策主体。这个区分很重要你不用自己造 harness但你要选一个 harness 的可靠性是否满足状态持久化的需求。层面框架要解决的事自己要补的可靠性事单 Agent 编排工具调用循环、上下文管理、停止条件检查点、幂等、进度持久化多 Agent 协作消息传递、任务分配、结果汇总状态冲突处理、协调者高可用Agent 与外部系统工具协议、认证、请求重试幂等、补偿、外部状态记录主流框架LangGraph、AutoGen、CrewAI、以及一些国内 Agent 平台各有侧重。我的建议是选框架时别只看名气要看它对自己不擅长的场景是否留了扩展口。有些框架把状态持久化做成内置功能有些完全不管——后者你必须自己接存储。从可靠性角度看内置检查点和恢复能力的框架会省很多事但也要验证它的持久化是否经过生产考验。4.2 记忆体系与存储落地一个可复用的五步方案记忆选型高频出现在各类 Agent 讨论里我直接给一个亲测可用的落地路径短期记忆Redis 存对话上下文key 设计为session:{session_id}:contextTTL 跟任务超时对齐。长期记忆向量库存语义化摘要写入前用 LLM 做一轮抽取和去噪。永久记忆PostgreSQL 存用户事实和审计日志每条记录带来源和置信度。记忆固化触发任务正常结束时触发摘要生成异常结束时人工判断后再决定是否固化。记忆读取合并每次对话启动时合并三层层级记忆加上角色设定一起组织进 Prompt。这套方案的关键不在于技术多新而在于每一层记忆都有明确的写入时机和负责人。很多 Agent 记忆方案失败不是因为向量库不好而是因为没有人定义什么时候从短期固化到长期结果长期记忆里全是废话。4.3 部署拓扑从单进程到分布式部署层面长期运行的 Agent 至少要做到无状态的计算节点 有状态的状态存储Agent 计算实例可以随时重启、扩缩容状态全部在存储层。这跟 Web 服务无状态化的思路一脉相承。任务队列新任务进队列worker 从队列取任务执行。队列配合检查点天然支持断点续跑。心跳与租约多 worker 并发时必须防双跑——同一任务被两个 worker 同时执行。用数据库租约locked_by lock_expire_at或分布式锁来保证一个任务同时只有一个执行者。优雅退出Pod 被销毁前要收到信号把当前状态保存成检查点再退出。如果没做这一步强制 kill 会让 Agent 丢失最后几步的状态。我有一个偏好把 Agent 的执行逻辑写成纯函数——输入是当前状态 事件输出是新状态 动作。纯函数天然可测试、可重放、可恢复。分布式系统的复杂度已经够高了别再让业务逻辑里掺着状态修改的随机性。5. 生产环境典型问题与排查速查5.1 Agent execution terminated due to error 类问题这类报错最常见但根因五花八门。我整理一个排查顺序看 trace报错发生在哪一步是模型调用失败、工具调用失败还是框架内部的步骤超时看状态报错时任务进度表里记录的最后一步是什么恢复后是否从正确断点续跑看重试自动重试是否触发了重复副作用幂等表有没有记录看资源是不是内存暴涨、容器 OOM如果计算节点状态没外置OOM 就等于状态全丢。我曾经排查过一个Agent 每次跑到第 7 步就挂的问题最后发现不是代码问题而是第 7 步的工具返回了一个超大的 JSON把上下文撑爆了。解决方案是给工具输出加截断和摘要。这类问题提示我们中间产物体积管理也是可靠性的一部分。5.2 状态不同步、重复执行、无限循环问题可能原因排查手段状态不同步多 worker 并发写同一任务查租约记录、version 冲突日志重复执行重试未走幂等表查 operation_id 去重记录无限循环Agent 在状态 A/B 间反复迁移查 trace 中重复的状态序列加循环检测恢复后跳过步骤检查点保存时机不对核对 checkpoint 与 step_results 一致性无限循环是 Agent 特有的坑。大模型有时候会在两个状态之间反复横跳——比如读取文件报错 → 重试 → 再报错 → 再重试。光是靠模型自己意识到要停不可靠基础设施层必须有熔断连续相同状态迁移达到阈值比如 5 次就强制停止并转入人工处理队列。5.3 Agent 评估与安全防护热词里有 agent evals、agent安全、a-memguard 这类词都是当前生产环境绕不开的话题。我简单说两个落地建议Evals 要测状态行为不只测最终回答是否合理还要测状态迁移是否符合预期是否在限定步骤内完成是否有异常状态停留。把 eval 用例设计成状态机的路径测试能拦住大量回归问题。记忆安全要防投毒Agent 长期记忆如果接受不可信来源的内容攻击者可以用信息注入污染记忆导致后续所有会话都受影响。解决方案是写入记忆前做内容来源标记对不可信内容提高过滤强度同时对记忆内容做定期的重新评估。5.4 Agent 安全与权限边界多说一句 Agent 安全因为它跟可靠性其实是同一枚硬币的两面不可靠的基础设施会让 Agent 在错误的状态下执行高权限操作安全边界不清则会把一个小故障放大成一个大事故。至少要做最小权限工具授权Agent 只能调用它当前任务需要的工具、敏感操作人工确认发送外部消息、删除数据前必须经过审批、操作审计日志所有工具调用记录留痕可追溯。我之前在项目里加过一道安全闸门Agent 每次要调用写操作时必须获得一个短时效的一次性 token而这个 token 只有在当前状态允许该操作的条件下才会签发。实现不复杂但能挡住状态机乱跳导致误操作的大问题。说到底状态机可靠性不只是系统不挂,更是系统在正确的状态做正确的事。写在最后的实操体会做了这么久的 Agent 基础设施我最深的体会是Agent 可靠性和传统分布式系统可靠性的底层逻辑是一样的区别只在于 Agent 的状态迁移由不确定的大模型驱动而不是由确定的代码驱动。这导致你不能完全预测它的行为只能用更强的状态约束、更完整的检查点、更细的幂等控制去兜底。与其花时间调 Prompt 让它更听话不如把精力花在状态外置、步骤可重放、副作用可撤销这三件事上。这三件事做好了哪怕模型偶尔犯傻基础设施也能兜住。一个小技巧给每个 Agent 任务加一个task_manifest——一个描述任务目标、允许调用的工具、最大步数、完成后验收条件的结构化配置。恢复时Agent 靠 manifest 检查点就能无缝续跑不需要人肉回忆它刚才在干嘛。这是我实测下来投入产出比最高的一个设计。最后如果你刚开始改造现有 Agent别一次全上。先做任务进度持久化 外部调用幂等这两项跑通一次故障恢复演练再逐步加 Saga、加租约、加安全闸门。可靠性是迭代出来的不是一步到位的。