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

什么是 Agent 状态
记住一件事,Agent 状态就是某一时刻的任务快照。它记录了系统当前处于什么阶段、此前发生过什么,以及下一步可以从哪里继续。
以一个代码修复任务为例,Agent 的状态可能包含:
-
当前目标:修复登录接口的 Token 过期问题;
-
当前阶段:正在验证修改结果;
-
已完成事项:定位相关代码、修改刷新逻辑;
-
待处理事项:修复失败的单元测试;
-
已修改文件:
auth/token.py、tests/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_step、status 和 last_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_error 和 pending_actions;如果执行环境意外重启,系统则会加载 cp-002、重新打开工作区并恢复任务进度,并从测试验证阶段继续执行。
此时,Agent 不用重新阅读全部日志,也不用再次判断哪些文件已经修改。它只要获得当前状态、必要的历史轨迹和最新的环境信息,就能继续推进任务。
状态保存的工程边界
保存的信息越多,可恢复的执行现场就越完整。但是存储、加载和上下文成本也会随之增加。因此,系统需要合理控制状态保存的粒度。
审计和调试需要完整的日志,而当前决策一般只需要提炼后的任务状态。如果可以低成本重建进程,Agent 系统只用保存配置和脚本;如果进程的重建代价较高,再考虑保存更完整的环境快照。对于跨会话长期保留的信息,还需要经过筛选,避免将临时错误、过期计划和敏感数据带入后续任务。
一个可靠的状态系统,至少应满足几个条件:状态结构清晰,更新来源可追踪,关键阶段设有检查点,旧版本状态可以迁移,任务恢复后也能判断外部环境是否仍与保存时一致。
结语
Agent 状态保存解决的是任务连续性问题。系统需要记录任务走到哪里、执行现场发生了什么,以及下一步应该从哪里继续。
当任务状态、执行轨迹和环境状态都能被结构化保存,Agent 才能暂停后恢复、失败后重试,并在长时间运行中保持行动连贯。