Agent 小知识|长任务不重来:Agent 状态保存的工程设计

上一期我们聊了工具调用的输入输出契约 Agent 会调用工具了,但新的问题又冒出来了。Agent 一轮轮地执行任务,会积累大量的信息:哪些步骤完成了,哪些工具调用仍在执行,哪些文件刚刚被修改,最近一次测试为什么会失败,以及下一步准备做什么。

这些信息构成了本文要讲的主题------Agent 的状态。

懒人图解版

什么是 Agent 状态

记住一件事,Agent 状态就是某一时刻的任务快照。它记录了系统当前处于什么阶段、此前发生过什么,以及下一步可以从哪里继续。

以一个代码修复任务为例,Agent 的状态可能包含:

  • 当前目标:修复登录接口的 Token 过期问题;

  • 当前阶段:正在验证修改结果;

  • 已完成事项:定位相关代码、修改刷新逻辑;

  • 待处理事项:修复失败的单元测试;

  • 已修改文件:auth/token.pytests/test_token.py

  • 最近一次错误:Mock 数据缺少 expires_at 字段;

  • 当前环境:工作目录、Git 分支、Python 环境;

  • 执行预算:已运行 8 轮,最多允许 20 轮。

看得出来,Agent 状态会同时包含任务进度、执行结果、环境信息和资源预算等多类信息。这些内容会影响下一步行动,但它们又与上下文、记忆的作用不同。Agent 状态负责回答"任务现在进行到哪里",上下文决定"这一轮让模型看到什么",而记忆保存"以后还可能用到什么"。

因为大模型 API 不会保存完整的执行现场,所以 Harness 需要把当前 Agent 状态整理成状态栏,放入本轮上下文,好让模型基于这些信息判断下一步行为。

所以,Agent 的状态需要由模型外部的系统持续维护。任务结束后,临时状态可以被清理,其中具有长期价值的部分则会沉淀为任务历史或长期记忆。

Agent 状态的四个层次

上面提到 Agent 的状态由多种信息组成,尤其是一个长期运行的 Agent。一般来说,有这 4 种信息:

对话轨迹

对话轨迹记录的是用户消息、模型回复、工具调用请求和工具执行结果。它保存了任务的完整过程,也是 Agent 回顾此前决策的主要依据。

除了消息内容,系统还为每条记录保存了时间戳、Token 数量、重要性、压缩状态和工具调用 ID。这样后续可以方便地恢复状态,也方便审计和排查问题。

不过,对话轨迹像是一份完整的工作日志。它能告诉系统发生过什么,却不能直接说明当前任务进行到哪里。因此,如果只依赖对话轨迹,随着日志不断变长,模型还要重新扫描历史,才能判断哪些步骤完成了。

任务进度

任务进度记录的是流程上的推进情况,例如:

  • 哪些子任务完成了;

  • 哪些任务正在执行;

  • 哪些任务仍在等待;

  • 当前处于规划、执行、验证还是人工确认阶段;

  • 是否达到最大轮次、时间或成本限制;

  • 最近保存的检查点位于哪里。

这类任务状态会被表示为 TODO 列表、任务图或状态机。对于流程固定的任务,可以用 PLANNING、EXECUTING、WAITING_FOR_HUMAN、DONE 等阶段标记当前状态;对于开放式任务,则更适合动态维护当前计划,并记录各个子任务是待执行、进行中、已完成还是被依赖项阻塞。

Agent 内部状态

除了任务进度,Agent 还要保存自己的当前判断,例如:

  • 当前计划;

  • 已经确认的事实;

  • 仍待验证的假设;

  • 已发出但尚未返回结果的工具调用;

  • 最近一次失败及其原因;

  • 当前采用的解决路径。

这些判断会直接影响模型的下一轮决策。如果 Agent 已经确认登录异常来自 Token 刷新逻辑,那么在恢复任务时,就不应该重新排查网络连接和数据库状态。

Agent 内部状态的关键是区分已经确认的信息和仍然不确定的判断。否则,Agent 早期产生的错误猜测也可能被当成事实保存下来,持续影响后面的执行。

执行环境

Agent 的行动发生在具体环境中。对于 Coding Agent,环境状态可能包括:

  • 当前工作目录;

  • Git 分支和未提交变更;

  • 已安装的依赖包;

  • 环境变量;

  • 已激活的虚拟环境;

  • 后台运行的开发服务器;

  • 浏览器会话与 Cookie;

  • 文件系统和数据库的当前内容。

这些状态不一定全部出现在聊天记录里,但会实打实地影响工具执行的结果。例如,Agent 刚刚通过 cd 进入项目目录,如果下一条命令在新的 Shell 中执行,工作目录就会恢复为默认路径;同样,它启动的本地服务也只存在于当前执行环境中,一旦环境重启,后台进程就会消失。

因此,保存 Agent 状态时,既要保存它"知道什么",也要保存外部环境"已经变成什么样"。长任务环境还可以把文件系统、浏览器 Cookie 和数据库内容序列化到磁盘,供后续恢复使用。

从完整轨迹到显式状态

只保存系统的完整轨迹,会导致 Agent 状态信息被淹没在大量原始记录中。

假设一个客服 Agent 最多能给同一个商家拨打三次电话。三次通话记录都保存在上下文中,但模型每次决定是否继续拨打电话时,都要重新查找并统计这些记录。随着网页搜索、用户回复和其他工具结果的不断插入,模型可能数错次数,拨打第四次电话。

比较可靠的方式是由 Harness 直接维护一条结构化状态:

Plain 复制代码
当前任务:协商降低套餐费用
电话调用:3/3
当前结果:已确认降至每月 59 美元
待处理事项:等待用户确认
约束检查:已达到电话调用上限

这种信息可以通过 Agent 状态栏放在上下文末尾,让模型直接看到已经提炼好的结论。状态栏还可以动态注入任务规划、工具调用次数、系统时间、工作目录、错误信息和可用能力等内容。

不过,状态栏只是面向模型的状态视图,并不等同于底层保存的完整状态。Harness 会根据工具调用、环境变化和任务进度持续更新结构化状态,再从中选取本轮真正需要的部分组装成状态栏。这样既能保留完整的执行记录,也能避免模型每次都从原始轨迹中重新梳理和统计。

状态 Schema 与更新规则

生产级 Agent 会为状态定义明确的 Schema。它会规定有哪些字段、每个字段代表什么,以及不同节点应该如何读取和更新。

一个简化的任务状态可以写成:

JSON 复制代码
{
  "task_id": "task-20260805-001",
  "goal": "修复登录 Token 过期问题",
  "status": "executing",
  "current_step": "运行单元测试",
  "completed_steps": [
    "定位刷新逻辑",
    "修改 auth/token.py"
  ],
  "pending_actions": [
    "修复 Mock 数据",
    "重新运行测试"
  ],
  "changed_files": [
    "auth/token.py",
    "tests/test_token.py"
  ],
  "last_error": {
    "type": "AssertionError",
    "summary": "Mock 数据缺少 expires_at 字段"
  },
  "environment": {
    "working_directory": "/workspace/project",
    "git_branch": "fix/token-refresh"
  },
  "iteration_count": 8,
  "checkpoint_id": "cp-004"
}

有了明确的状态 Schema,Agent 的不同执行节点就能围绕同一份数据进行协作:

Plain 复制代码
规划节点读取目标和待处理事项
        ↓
工具节点更新执行结果
        ↓
验证节点写入测试状态
        ↓
路由逻辑根据 status 决定下一步

Schema 中的不同字段要用不同的方式进行更新。一般会持续追加的字段有消息和日志,会被新值覆盖的有 current_stepstatuslast_error。而已完成任务可以按集合或列表维护,文件变更则可以按修改顺序记录,或以文件路径为键进行更新。

状态结构(Schema)还得带上版本信息。Agent 的功能持续增加后,状态字段也会随之变化:旧任务中可能没有 checkpoint_id,新版本也可能将单一的错误字段拆分为错误类型、错误阶段和恢复建议。明确版本号和迁移规则,可以避免系统升级后无法读取此前保存的任务状态。

状态 Schema 也可以看作执行节点之间的接口契约。越早定义清楚,后续的暂停与恢复、并行执行、调试和迁移就越容易。

检查点与任务恢复

在持续更新状态的同时,系统还需要定期生成检查点(Checkpoint)。

检查点是某一时刻可恢复的状态快照。一般来说,它会包含任务进度、对话轨迹、当前计划、工具结果、环境信息和生成的中间产物。任务中断后,系统可以加载最近一次的有效检查点,重新构建上下文和执行环境,再从相应步骤继续。

Plain 复制代码
执行子任务
    ↓
更新任务状态
    ↓
保存检查点
    ↓
继续下一步

检查点特别适合放在这些关键位置:

  • 一个耗时较长的子任务完成后;

  • 文件、数据库或外部系统发生重要变化后;

  • 准备等待用户确认之前;

  • 即将执行高风险操作之前;

  • 一轮验证通过、可以进入下一阶段时。

例如,一个研究型 Agent 已经完成了资料搜索和文档整理,正在等待用户确认提交的报告提纲。此时,Agent 系统可以保存一个检查点并暂停任务。等后面用户回复修改意见后,Agent 只用加载已有状态、加入新的反馈,就能继续生成报告,不用重新搜索和整理全部资料。

除了支持暂停和恢复任务,检查点也可以用来调试。这样,开发者可以回到某个历史状态,更换 Prompt、模型或工具配置后再重新执行任务,对比不同设置产生的结果。一些基于图结构编排工作流的 Agent 框架,还会在节点完成执行后保存当前状态,从而支持暂停恢复、人工审批和历史回放。

不过,恢复内部状态不代表能完全回滚外部世界。模型回复、任务进度和工作文件是可以恢复到旧版本,但已经发送的邮件、完成的付款或删除的远程数据是无法撤销的。因此,涉及不可逆操作时,系统还需要配合人工确认、幂等设计或补偿流程。

执行环境的分层持久化

执行环境中的状态可以分为文件状态和进程状态。其中,文件状态相对容易持久化。代码、数据、日志和中间产物可以保存在独立工作区中。即使销毁 Agent 进程或沙盒,这些内容也能在下次启动时重新加载。而进程状态会更加复杂点。工作目录、环境变量、虚拟环境和后台服务等信息,都强依赖当前运行的会话。

对于这类进程状态,有两种常见的处理方式:第一种是在任务活跃期间保留终端或沙盒,让后续命令继续在同一环境中执行,从而避免反复切换目录、安装依赖和启动服务。

第二种是在环境退出前,保存其中可以序列化的状态,例如工作目录、环境变量、依赖清单、启动脚本和后台任务列表。任务恢复时,Harness 再根据这些记录重新构建新的执行环境。

对于需要跨天运行的 Agent,长期保留所有进程会持续占用资源,还容易积累难以控制的运行状态。因此,推荐持久化那些可检查、可重建的状态描述:

Plain 复制代码
持久保存:
工作区文件
依赖清单
环境变量配置
后台任务清单
启动与恢复脚本

按需重建:
Shell 会话
开发服务器
临时进程
沙盒运行环境

这种设计不仅让 Agent 可以在中断后恢复工作,还保留清晰的审计边界。

测试修复场景里的状态流转

假设用户让 Agent 排查项目测试失败并尝试修复。任务开始时,Harness 创建初始状态为:

Plain 复制代码
目标:修复测试失败
状态:规划中
约束:不提交代码,不删除文件
待处理:读取测试结果、定位原因、修改代码、重新验证

Agent 运行测试后,将失败信息写入状态:

Plain 复制代码
当前阶段:问题定位
最近错误:数据库连接超时
已确认:依赖安装正常,Node 版本正常
下一步:检查测试数据库配置

Agent 修改配置文件后,文件系统保存实际改动,状态中记录修改范围,并创建检查点:

Plain 复制代码
已修改:config/test-db.js
检查点:cp-002
下一步:重新运行数据库相关测试

如果测试再次失败,Harness 会更新 last_errorpending_actions;如果执行环境意外重启,系统则会加载 cp-002、重新打开工作区并恢复任务进度,并从测试验证阶段继续执行。

此时,Agent 不用重新阅读全部日志,也不用再次判断哪些文件已经修改。它只要获得当前状态、必要的历史轨迹和最新的环境信息,就能继续推进任务。

状态保存的工程边界

保存的信息越多,可恢复的执行现场就越完整。但是存储、加载和上下文成本也会随之增加。因此,系统需要合理控制状态保存的粒度。

审计和调试需要完整的日志,而当前决策一般只需要提炼后的任务状态。如果可以低成本重建进程,Agent 系统只用保存配置和脚本;如果进程的重建代价较高,再考虑保存更完整的环境快照。对于跨会话长期保留的信息,还需要经过筛选,避免将临时错误、过期计划和敏感数据带入后续任务。

一个可靠的状态系统,至少应满足几个条件:状态结构清晰,更新来源可追踪,关键阶段设有检查点,旧版本状态可以迁移,任务恢复后也能判断外部环境是否仍与保存时一致。

结语

Agent 状态保存解决的是任务连续性问题。系统需要记录任务走到哪里、执行现场发生了什么,以及下一步应该从哪里继续。

当任务状态、执行轨迹和环境状态都能被结构化保存,Agent 才能暂停后恢复、失败后重试,并在长时间运行中保持行动连贯。

相关推荐
扯蛋4383 小时前
langchain1.x 时代的记忆系统 (二)
javascript·llm·agent
leeyi4 小时前
Router / Parent 源码:多个知识库怎么查,切太碎怎么补上下文(第75篇-E61)
aigc·agent·ai编程
Loveyourself4 小时前
🔥 claude code auto compact源码解析
面试·agent
王中阳Go4 小时前
用TRAE Work批量优化学员简历,原来2天的活现在2小时就干完了
后端·面试·agent
安逸sgr4 小时前
Zero-shot、Few-shot 和 One-shot Prompt 有什么区别?
人工智能·ai·大模型·agent·智能体
Bolt4 小时前
一个超级简单的 coding agent,100 行就可以做任何事
llm·agent·bun
AI办公探索者5 小时前
多租户架构下数据隔离的三种实现方案对比
数据库·ai·oracle·架构
long3165 小时前
Codex 团队开发入门到精通学习资料
ai·团队开发·个人开发·ai编程
孙启超6 小时前
【AI应用开发】Agent 无限 loop(反复调用同一个工具)如何规避?
人工智能·python·算法·llm·agent·loop·ai应用开发