面向 agent 的超长程任务运行时——LoopForge
做 agent 应用的人,大概率都遇到过这个场景:一个复杂的任务链跑着跑着,某一步调外部接口超时了,整个流程直接崩掉。你回头一看日志,前面十几个步骤已经执行完的结果、中间状态、上下文数据,全都跟着进程一起消失了。最要命的是,这类任务往往不是几分钟就能跑完的,你要它做的是一整套持续几个小时的深度调研、一次跨周的数据自动化处理,甚至是无人值守的批量生产调度。一次偶然的失败,意味着从头再来。
LoopForge 就是冲着这个问题去的。它是一套面向 agent 的超长程任务运行时,核心思路是把“一次性生成”的对话式 agent 调用,改造成“可恢复、可续跑、可观测”的持久化任务流。名字拆开看很直白:Loop 是循环,Forge 是锻造,合起来就是把循环打磨成能扛住真实生产压力的运行引擎。这篇东西我会从设计动机、核心机制、关键配置、踩坑实录几个维度完整拆一遍,适合正在做 agent 工程化落地、被长任务稳定性折磨的开发者,也适合想了解 agent 基础设施到底在解决什么问题的朋友。
1. 为什么需要一整套“运行时”来跑长任务
1.1 超长程任务的三个典型特征
先说清楚我们说的“超长程”到底意味着什么。它不是一次模型推理,也不是一个多步骤的函数链,而是具备三个特征的执行过程:
时间跨度大。单次任务从触发到结束,可能持续几十分钟、几小时甚至几天。比如让 agent 每天抓取一批行业数据、清洗、分析、生成报告并自动归档,这类任务天然就不是一次 HTTP 请求能承载的。
外部副作用多。执行过程中 agent 会反复调用搜索接口、数据库、文件系统、第三方 API。每一步都是有真实副作用的,比如某一步已经给客户发了一封邮件,这个动作不会因为后面任务失败就被撤销。
状态持续累积。任务不是孤立执行的,中间产出的临时结论、中间数据、已执行步骤的决策记录,都会成为后续步骤的依赖。一旦中断,这些累积状态如果没有被妥善保存,任务就无法从断点继续,只能推倒重来。
这三个特征放在一起,意味着长任务本质上是一个“带外部副作用的持久化状态机”,而不是一个“大函数”。
1.2 现有 agent 方案的硬伤在哪
我见过太多团队在这个问题上走弯路。最典型的做法是用一个循环脚本驱动大模型:把整个任务描述塞进 prompt,模型输出一个动作,代码执行动作,把结果加回 prompt,再让模型继续。看起来没问题,实际跑几次就露馅了。
首先是上下文无限膨胀。每一轮都往 prompt 里追加历史记录,十几轮之后 token 消耗大幅上升,模型开始遗忘早期关键信息,回答质量明显下滑。有团队尝试做上下文裁剪,但裁剪逻辑写不好,经常把跟后续步骤强相关的中间结论给裁掉。
其次是进程死亡等于任务死亡。服务发布、机器宕机、网络分区,任何一次基础设施抖动,都会让内存里的循环状态彻底丢失。等进程恢复,agent 完全不记得自己干到哪一步了。
还有就是错误恢复能力几乎为零。第 7 步调 API 失败,第 1 到第 6 步的查询结果、分析结论全部作废。有人尝试在每个步骤后把结果写到数据库里,但任务一复杂,恢复到哪个步骤、依赖哪些状态、哪些副作用需要补偿,这笔账很快就算不清楚了。
1.3 LoopForge 的设计前提
LoopForge 的思路是换一个框架来看问题:不要再去扩展单次调用的能力,而是把整个任务生命周期托管给一个专门的运行时。这个运行时负责四件事:调度每一步执行、持久化每一步状态、在失败时重建执行现场、在外部条件具备后续跑。
这有点像数据库事务和普通函数调用的区别。普通函数调用的状态在栈里,函数返回就没了;事务的状态在日志里,崩溃了还能靠 redo log 恢复。LoopForge 做的事情,就是给 agent 长任务加一层类似 redo log 的机制,让任务的“记忆”不再寄生在进程内存里,而是落在一个可查询、可恢复、可审计的持久层上。
这个理念还有一个重要的推论:任务执行不再要求进程连续存活。进程可以崩溃,容器可以重启,机器可以迁移,只要持久层还在,任务就能在任意时间点被重新拉起,从最近的检查点继续执行。
2. 循环驱动的核心执行模型
2.1 把一个长任务拆成可恢复的步骤序列
LoopForge 把任务定义为一个有向步骤图,每个节点是一个可独立执行的“步骤”。步骤可以是模型调用、工具调用、代码执行、人工审批,甚至是一个等待外部事件的挂起点。步骤之间通过数据依赖关系连接:上一个步骤的输出经过序列化后,成为下一个步骤的输入之一。
这听起来像工作流引擎,但和传统工作流有本质区别。传统工作流的节点是固定写死的逻辑,LoopForge 的节点是 agent 根据任务目标动态决策出来的。换句话说,步骤图不是静态的流程图,而是由 agent 在运行时根据中间结果不断展开的动态执行计划。
举个例子。任务目标是“调研某个垂直行业近半年的投融资动态并形成简报”。第一步,agent 决策出“先确定行业关键词范围”这个子目标,执行搜索;拿到结果后,它可能发现某些细分领域信息稀疏,于是动态插入一个“扩宽检索来源”的步骤;简报写到一半,它发现需要补一张数据表,于是又插入一个“调用制表工具”的步骤。整个过程不是预先编排好的,而是像一个人在做事一样,边做边决定下一步。
这种动态性也带来了一个核心矛盾:步骤序列不确定,但状态必须稳定。LoopForge 的解法是任务 ID + 步骤 ID + 检查点的三层定位体系,后面我会详细展开。
2.2 步骤状态机与循环展开器
LoopForge 内部维护了一个非常明确的步骤生命周期模型。每个步骤的状态流转是:
PENDING -> RUNNING -> SUCCEEDED -> FAILED -> RETRYING -> PENDING -> BLOCKED -> PENDING这个状态机是所有恢复逻辑的基础。运行时记录在案的不仅是“任务执行到第几步”,而是“每个步骤当前处于什么状态、尝试了多少次、上次失败的原因是什么、已有产出物存放在哪”。有了这层信息,即使某个步骤一直失败,也可以把它标记为 BLOCKED,把 CPU 让给其他可并行推进的步骤,等人为干预或外部条件满足后再重新激活。
循环展开器(Loop Expander)是另一个关键组件。它负责决定“下一步做什么”。它接收当前任务目标、已完成步骤的产出摘要、底层模型的自省信号,输出下一步的步骤描述。这个设计把“任务的推进逻辑”和“步骤的具体执行逻辑”解耦:推进逻辑由模型驱动,执行逻辑由具体的工具适配器驱动。这样一来,即使某个工具升级了、换了 API,也不影响整个任务流的推进规划。
2.3 检查点持久化:不再依赖进程内存
LoopForge 的检查点分两层。基础层是步骤级快照:每个步骤完成后,把输出、状态、耗时、依赖信息写入持久存储。增强层是任务级快照:特定时机(比如一个大的子目标完成、或用户强制触发)把当前整个任务的步进状态、上下文索引、待办队列做一个整体归档。
两层配合,恢复开销完全不同。如果是步骤级快照,恢复时需要从任务最初的步骤开始逐个重放,但好处是不需要额外的存档动作;如果是任务级快照,恢复时可以直接加载归档结果,快速跳转到快照点之后继续。
实际使用中我会这么取舍:高风险长任务开任务级快照,短任务只用步骤级快照。存储成本相差不大,但恢复时间差异非常明显。
# 示例:任务定义时指定快照策略 task = ForgeTask( name="industry_research_2025", entry="调研目标行业的投融资动态并输出简报", checkpoint_policy=CheckpointPolicy( level=CheckpointLevel.TASK_SNAPSHOT, trigger_after_steps=5, persist_path="s3://forge-checkpoints/{task_id}" ) )设计这个持久化方案时还有一个容易忽略的细节:依赖的外部资源句柄不能持久化。数据库连接、HTTP 会话、临时文件句柄,这些东西在进程重启后必然失效。LoopForge 的做法是只持久化“如何重新获取这些资源”的元信息,恢复时重新建立连接,而不是尝试恢复一个已经断开的连接对象。
2.4 上下文整理策略:对抗膨胀
长任务跑久了,累积的中间结果和决策记录会让模型调用越来越慢、越来越贵、越来越不准。LoopForge 的上下文整理模块负责把“原始交互历史”转换成“精简任务记忆”。
它做的不是简单的截断,而是三种操作:压缩(把多轮相似尝试合并成一条结论)、提炼(从中间结果中抽出跟任务目标强相关的关键信息)、归档(把非关键信息推到外部存储,只保留引用索引)。核心原则是:传给模型的上下文始终包含“任务当前进展、近期决策依据、待办事项”,而不再包含“历史上每一条 tool 响应原文”。
和很多 naive 实现不同的是,上下文整理本身也是可恢复的。每次压缩动作都会记录压缩前后的映射关系,万一后续步骤发现某个被压缩掉的信息其实仍然必要,运行时可以回溯到原始记录,而不是只能对着摘要干瞪眼。
3. 超长任务的关键机制深度拆解
3.1 步骤定位与运行现场重建
恢复一个超长任务,最困难的不是“找到步骤 N”,而是“重建执行到步骤 N 时的现场环境”。现场环境包括输入数据、变量状态、决策链、外部资源句柄、以及未完成队列。
LoopForge 为此引入了“步骤定位符”的概念。每个步骤的输出不仅保存结果本身,还会附带一份“依赖指纹”——记录了该步骤依赖了哪些上游步骤、引用了哪些上下文片段、使用了哪个工具版本。恢复时,运行时校验这些指纹,如果发现上游数据缺失或已变更,就自动触发重新执行上游步骤;如果一切匹配,就安全复用已有结果。
这个机制的额外收益是可追溯性。任何一步的产出,都可以追溯到它的完整输入链。做 agent 应用的人都知道,模型决策是个黑盒,出了问题根本不知道它为