Long-running Agent 并不一直运行

发布于:2026-08-28 3,113 字 10 分钟阅读

我们通常把“长期运行”理解为一个进程长期存活。数据库、消息队列和 Web 服务启动以后,会持续占用内存、监听请求,直到进程退出。按照这种直觉,一个 Long-running Agent 似乎也应该是某个一直在线、始终思考的模型实例。

Agent 采用另一种连续方式。它可能几小时没有执行任何推理,所在的进程可能已经退出,机器可能已经释放,下一次启动时甚至可能换了一种模型。只要此前的目标、历史和判断能够恢复,我们仍会把它视为“同一个 Agent”。Long-running Agent 的“长期”来自状态可以被反复重建。

Agent 大部分时间并没有在运行

传统的 Long-running Service 通常遵循这样的生命周期:

Text
UTF-8|1 Line|
进程启动 → 持续运行 → 进程退出

它的连续性和进程存活高度相关。进程一旦退出,内存中的状态也会随之消失。为了让服务继续工作,我们需要重启进程、恢复数据,并重新建立连接。

Long-running Agent 更接近另一种模式:

Text
UTF-8|6 Lines|
被唤醒
  → 加载持久状态
  → 组装当前上下文
  → 执行一次 Turn
  → 保存结果
  → 进入休眠

在两次唤醒之间,它可能没有模型实例,没有运行中的推理任务,也不消耗推理资源。比如,一个 Agent 周一收到任务,分析了代码并记录下一步计划;周三因为新的事件再次被唤醒,继续修改同一个项目。中间两天没有发生任何计算,但周三恢复出的 Agent 知道自己在做什么、已经做过什么、接下来应该做什么。这两次运行因此构成了一个连续过程。

分清 Agent、Conversation、Session 和 Turn

讨论 Long-running Agent 时,四个概念经常被混在一起:

  • Agent:一个可以长期延续的身份及其行为约束。
  • Conversation:与这个 Agent 相关的持久对话历史。
  • Session:用户或系统与 Agent 的一次活动连接。
  • Turn:模型被实际调用并完成一次推理的过程。

一次 Session 可以包含多个 Turn,一个 Conversation 可以跨越多个 Session,一个 Agent 又可以参与多个 Conversation。浏览器关闭后,Session 可能结束,Conversation 仍然存在;运行模型的容器被释放后,本次 Turn 已经结束,Agent 保存的目标和记忆仍可在下一次连接时加载。换机器、换运行时,甚至换模型,都不一定会破坏连续性。关键在于恢复出的身份、历史、目标和行为能否保持足够的一致性。

这里的“身份”并不神秘。它通常由一组可持久化的材料构成:系统指令、用户关系、任务状态、长期记忆、对话历史,以及运行环境中的资源和权限。

这些材料会在一次具体运行中重新组合,由此产生的行为结果构成了当下的 Agent。

Harness 是 Agent 的操作系统

一次模型调用只能看到传入上下文窗口的内容。调用结束后,模型不会自动保存这次经历,也不会在下一次调用时自然地“想起”上一次发生了什么。保存和恢复工作由模型外部的 Harness 完成。Harness 可以理解为承载 Agent 的运行系统:它管理对话、记忆、工具、环境和模型调用,并在每个 Turn 开始之前决定哪些信息应该进入上下文。

这个关系很像程序与操作系统:

Agent 系统操作系统
Context window物理内存
Conversation history磁盘
Compaction压缩与换页
Recall按需重新调入
Long-term memory持久化结构化存储
Harness操作系统

Conversation 可以持续增长,但模型的 Context window 始终有限。这就像磁盘可以存储大量数据,而一个进程只能把当前需要的工作集放进有限内存。

当对话超过上下文限制时,Harness 必须压缩旧内容、保留近期消息,并根据当前任务检索相关历史。它实际上在做一件类似内存管理的工作:决定什么留在当前工作集里,什么暂时移出,以及什么时候重新调入。

Harness 每次调用模型之前,都要据此重新构造 Agent 当下的“意识”。

没有 Harness,模型只是一次性的计算函数。输入一段上下文,生成一段输出,然后结束。正是 Harness 把许多彼此分离的模型调用组织成了一个看似连续的行动主体。

连续性是一种编译结果

每次 Agent 被唤醒时,Harness 都会从多个来源收集材料:

Text
UTF-8|8 Lines|
system prompt
+ agent memory
+ conversation summary
+ recent messages
+ recalled history
+ current environment
+ available tools
= 本次模型实际看到的 Agent

这个过程更像编译,而不是回放。Harness 通常不会把 Agent 的全部历史原封不动地交给模型。它需要根据有限的上下文预算,对历史进行选择、压缩和重组,生成当前 Turn 可以使用的工作集。系统保存的是源材料,模型看到的是编译结果。

一段历史可以完整保存在数据库里,但如果它没有被放进当前上下文,模型此刻就不知道它。一次关键决策可能仍然存在于三个月前的消息中,但如果摘要没有保留、检索也没有命中,它对当前 Agent 就等于暂时不存在。

历史保存在数据库里,只说明材料仍可取回。Agent 的连续性取决于 Harness 能否针对当前任务,把正确的历史重新编译进有限上下文。

对话可以增长,记忆仍然受限

许多 Agent 产品允许对话持续很长时间,甚至给人一种上下文可以无限增长的感觉。Harness 可以隐藏底层限制,却无法消除它。只要模型的上下文有限,系统就必须做选择;选择意味着信息损失,也会带来几类典型问题。

1. 压缩损失

对话过长时,Harness 会把旧消息压缩成摘要。

摘要通常能够保留结论,却未必能够保留形成结论的完整过程。具体措辞、证据来源、被否决的方案,以及某个判断成立的条件,都可能在压缩中消失。

例如,原始讨论的结论可能是:

当前阶段选择方案 A,因为部署环境暂时不支持方案 B;如果环境升级,需要重新评估。

经过多轮压缩后,它可能只剩下:

项目决定使用方案 A。

结论看似保留了,适用条件却丢失了。Agent 仍然“记得决定”,却不再记得为什么做出决定,也不知道什么时候应该推翻它。

2. Recall 失败

有些信息不会一直放在上下文中,而是在需要时通过检索重新加载。

问题在于,检索取决于当前查询。如果用户使用了不同的说法,或者 Agent 没有意识到某段旧历史与当前问题有关,相关信息即使存在,也可能无法命中。

信息仍然存在,系统却不知道此刻应该去找它,这是一种检索层面的遗忘。

3. 身份漂移

如果重要经验只存在于对话历史中,却没有进入稳定的长期记忆,Agent 每次恢复出来的状态就可能略有不同。

一次摘要强调用户偏好,另一次摘要强调当前任务;一次检索找到了过去的约定,另一次没有。随着时间推移,Agent 的行为边界、表达习惯和判断依据都可能缓慢漂移。

这种变化不会在某次恢复后突然发生。Agent 会在许多次不完整恢复中,逐渐失去原来的部分特征。保存全部历史相对容易,困难的是在下一次行动发生时恢复最重要的内容。

用可恢复性衡量 Long-running Agent

如果接受这个视角,设计 Long-running Agent 的重点也会随之改变。

设计重点需要从进程 uptime 转向状态恢复:检查关键约束能否在需要时重新进入上下文,并区分近期工作集、对话档案、长期经验和当前环境。

一个 Agent 是否具有连续性,可以用几个更实际的问题判断:

  • 它醒来后是否知道自己正在完成什么目标?
  • 它是否知道此前已经采取了哪些行动?
  • 它能否恢复关键决定及其成立条件?
  • 它是否记得与用户之间长期有效的约定?
  • 当环境发生变化时,它能否区分旧事实与当前事实?
  • 即使更换模型或运行时,它的核心行为是否仍然稳定?

评估时,可以故意结束进程,让任务休眠一段时间,甚至更换运行时或模型,再重新唤醒 Agent。检查它能否恢复目标、已完成的行动、关键决定的适用条件和长期用户约定,也要检查它能否识别环境已经变化。只有数据库里保存着对话,而恢复后的 Agent 无法使用这些材料,连续性就没有建立起来。