Agent状态管理
2288 字约 8 分钟
domain/aiai/agents
2026-07-24
Agent 状态管理解决一个根本矛盾:LLM 本身是无状态的(每次调用独立),但 Agent 需要有状态(追踪任务进度、中间结果、当前步骤)。没有可靠的状态管理,Agent 就无法断点续跑、无法故障恢复、无法回放调试。
一句话解释
状态管理 = 追踪"Agent 当前在做什么、做到哪一步了、中间结果是什么",通过检查点(Checkpoint)机制实现断点续跑和故障恢复。
核心挑战
LLM 无状态 vs Agent 需要有状态
核心矛盾:LLM 的每次调用是独立的,但 Agent 的多步执行需要跨越多次调用维持状态。状态管理的职责就是在 LLM 调用之间"搬运"和"持久化"这些信息。
状态 vs 记忆
这是最容易混淆的概念,需要明确区分:
| 维度 | 状态(State) | 记忆(Memory) |
|---|---|---|
| 回答的问题 | "当前在做什么?" | "过去学到了什么?" |
| 生命周期 | 单次任务执行期间 | 跨任务、跨会话 |
| 内容 | 当前步骤、中间结果、上下文、错误信息 | 用户偏好、历史经验、学到的规则 |
| 持久化需求 | 任务级(可丢弃) | 长期级(需保留) |
| 类比 | 厨师正在做的菜 | 厨师的菜谱和烹饪经验 |
详见 Memory记忆系统。
状态的构成
一个 Agent 的完整状态包含什么
Agent State = {
// 任务信息
task: "用户的原始请求",
goal: "任务目标",
// 执行进度
current_step: 3,
total_steps: 5,
plan: ["step1", "step2", "step3", ...],
// 中间结果
intermediate_results: {
"step1": {"status": "success", "output": "..."},
"step2": {"status": "success", "output": "..."},
"step3": {"status": "running", "output": null},
},
// 上下文
messages: [对话历史],
tool_calls: [工具调用记录],
// 错误信息
errors: [],
retries: {"step2": 1},
// 元数据
started_at: "2026-07-21T10:00:00Z",
updated_at: "2026-07-21T10:05:30Z",
}状态的分类
| 状态类型 | 内容 | 存储位置 | 生命周期 |
|---|---|---|---|
| 任务状态 | 当前执行到哪一步、计划是什么 | 检查点存储 | 任务期间 |
| 对话状态 | 消息历史、上下文 | 上下文窗口/数据库 | 会话期间 |
| 工具状态 | 工具调用的参数和返回值 | 检查点存储 | 任务期间 |
| 错误状态 | 失败信息、重试次数 | 检查点存储 | 任务期间 |
| 环境状态 | 外部环境的变化(文件修改等) | 外部系统 | 持久 |
检查点(Checkpoint)机制
什么是检查点
检查点是在 Agent 执行的关键步骤保存完整状态的机制,类似于游戏存档:
检查点的触发时机
| 触发点 | 理由 | 示例 |
|---|---|---|
| 每步执行后 | 最细粒度恢复 | LangGraph 默认每步 Checkpoint |
| 工具调用前/后 | 工具是最可能失败的环节 | API 调用前保存状态 |
| LLM 调用前 | LLM 调用昂贵,保存以便回放 | 记录完整 Prompt |
| 人工审批节点 | 等待人类确认时暂停 | HITL 场景 |
| 定时触发 | 长任务的周期性保存 | 每 5 分钟或每 10 步 |
LangGraph 的 Checkpoint 实现
LangGraph 提供了目前最成熟的 Agent 状态管理:
LangGraph State Schema(TypedDict):
messages: list[Message]
current_step: str
results: dict
Checkpoint 流程:
1. 每个 Node 执行后,自动保存 State 到 CheckpointStore
2. 每个线程(thread_id)有独立的检查点链
3. 可以回溯到任意检查点(Time Travel)
4. 可以从指定检查点重新执行(分支执行)支持的持久化后端:
MemorySaver:内存存储(开发测试用)SqliteSaver:SQLite 文件(轻量部署)PostgresSaver:PostgreSQL(生产环境)RedisSaver:Redis(低延迟场景)
状态持久化方案对比
| 方案 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
| 内存 | 最快,无序列化开销 | 重启即丢失 | 开发测试、短任务 |
| 文件系统 | 简单,无额外依赖 | 并发写入困难 | 单机部署、简单场景 |
| SQLite | 轻量,嵌入式 | 单写入者 | 中小规模、单机部署 |
| PostgreSQL | ACID 事务,成熟 | 需要运维 | 生产环境、高可靠 |
| Redis | 低延迟,支持 TTL | 内存成本高 | 高频读写、短时状态 |
| 对象存储 | 低成本,可扩展 | 延迟高 | 归档、长任务历史 |
选型建议:
- 开发阶段:MemorySaver(零配置)
- 单机生产:SQLite(零运维)
- 分布式生产:PostgreSQL + Redis(持久化 + 缓存)
状态恢复与容错
断点续跑
容错策略
| 策略 | 描述 | 适用场景 |
|---|---|---|
| 重试 | 失败后从当前步骤重试 | 瞬时错误(网络超时) |
| 回退 | 回退到前一个检查点重试 | 当前步骤数据损坏 |
| 重规划 | 放弃当前计划,重新规划 | 计划本身有问题 |
| 降级 | 切换到更简单的方法 | 复杂方法失败 |
| 人工介入 | 暂停并等待人类处理 | 无法自动恢复的严重错误 |
与 Agent失败模式 的关系
状态管理是容错的基础——没有状态持久化,任何容错策略都无法实施。失败后的恢复路径取决于失败类型和已保存的状态。
状态迁移模型
状态机视角
Agent 的执行可以建模为一个状态机:
状态迁移的持久化
每次状态迁移都应记录到检查点,确保:
- 迁移历史可追溯(审计需求)
- 可从任意历史状态恢复(回放调试)
- 可分支执行(从某个检查点走不同路径)
多 Agent 系统的状态管理
状态共享 vs 状态隔离
| 模式 | 描述 | 优势 | 劣势 |
|---|---|---|---|
| 共享状态 | 所有 Agent 读写同一 State | 信息透明,简单 | 并发冲突,耦合高 |
| 隔离状态 | 每个 Agent 有独立 State | 无冲突,可并行 | 需要显式通信机制 |
| 分层状态 | 全局 State + Agent 局部 State | 平衡共享与隔离 | 设计复杂度高 |
LangGraph 的多 Agent 状态
LangGraph 通过 StateGraph 支持多 Agent 状态管理:
- 全局 State 在所有 Node 之间共享
- 每个 Node(Agent)可以读写全局 State
- 通过
Channel机制控制字段的读写权限 - 支持子图(Subgraph)实现状态嵌套
详见 多Agent协作。
实战场景
场景 1:长任务断点续跑
任务:分析 1000 篇论文并生成综述
问题:任务需要数小时,中途可能崩溃
方案:
1. 每处理 10 篇论文保存一次检查点
2. 崩溃后从最近检查点恢复
3. 记录已处理论文列表,避免重复处理场景 2:人工审批暂停/恢复
任务:Agent 执行金融交易
流程:
1. Agent 分析市场 → Checkpoint 1
2. Agent 生成交易方案 → Checkpoint 2
3. 暂停,等待人工审批 → 状态保持
4. 人工批准 → 从 Checkpoint 2 恢复执行
5. 人工拒绝 → 从 Checkpoint 1 重新分析场景 3:调试回放
问题:Agent 在生产环境中给出了错误结果
调试:
1. 从日志中找到出错任务的 thread_id
2. 加载该任务的检查点链
3. 逐步回放每个检查点
4. 定位出错的步骤和原因
5. 从出错前的检查点分支,尝试不同参数常见误区
- 状态和记忆不分:状态是"当前任务进度",记忆是"历史经验",两者持久化策略完全不同
- 检查点粒度太粗:只在任务开始和结束保存,中间步骤崩溃无法恢复
- 不处理环境状态:Agent 修改了外部系统(如文件),恢复时环境状态不一致
- 并发写入冲突:多个 Agent 同时修改共享状态,没有锁机制
- 状态无限增长:对话历史和中间结果不断追加,导致状态对象越来越大
可继续补充的方向
- 状态压缩与摘要策略(长任务的状态精简)
- 分布式 Agent 的状态一致性协议
- 状态版本管理与迁移(Schema 演进时的兼容性)
- 状态加密与隐私保护
关联笔记
- Agent工程架构 — 状态管理是架构四层之一
- Agent工作流 — 工作流节点的状态转移
- Agent任务队列 — 任务调度依赖状态管理
- Memory记忆系统 — 状态 vs 记忆的区别
- Agent失败模式 — 状态恢复是容错的基础