崩溃后自动复活Unreal Agent append-only 会话存储与 Resume 恢复机制深度解析【免费下载链接】unreal-agentAsync-first agent harness项目地址: https://gitcode.com/gh_mirrors/un/unreal-agentUnreal Agent是 Unreal Labs 出品的一个异步优先async-firstAI Agent 框架它的 append-only 会话存储和 Resume 恢复机制能让 Agent 在进程崩溃、断电、输出中断之后自动复活从上次未完成的位置继续执行而不是从零开始。本文用尽量少的代码带你彻底看懂这套崩溃恢复设计是怎么做到的。一、为什么 AI Agent 需要崩溃恢复传统的 AI Agent 进程一旦崩溃所有中间状态——用户消息、模型回复、执行到一半的工具调用——全部丢失。下次运行只能从头再来既浪费 token又可能重复执行有副作用的操作比如跑过一半的 shell 命令。Unreal Agent 的解法很直接把会话当成一本只能往后写的账本。 核心思想会话历史是 append-only仅追加的持久化日志任何时刻崩溃重启后重放账本就能精确恢复到崩溃前的状态。在 README 的项目术语表里官方对 Session 的定义就是一句话append-only persisted history that can be forked可分叉的仅追加持久化历史见 README.md。二、append-only 会话文件一行一条记录的 JSONL 账本2.1 会话文件长什么样每个会话对应一个以.session.jsonl结尾的本地文件由 store.go 中的Store结构体管理。仓库里的测试黄金文件 golden-session.session.jsonl 展示了一条完整记录流行号记录类型含义第 1 行session会话头格式版本 会话 ID 创建时间第 2 行item外部输入用户消息第 3 行item新一轮turn开始第 4 行item模型响应第 5 行item工具调用状态 初始化的操作第 6 行operation操作状态更新awaiting → 后续状态每条记录独占一行、以换行符结尾这是刻意为之的——它是崩溃安全的基石。2.2 追加写入的三步安全流程真正的写入逻辑在 appendFile 函数里只有三步却环环相扣以O_APPEND模式打开文件操作系统保证多个追加者不会互相覆盖Truncate(committedSize)丢弃残缺记录如果上次写入在换行符之前崩溃文件尾部会留下半行 JSON。重启后先截断到最后一条完整记录的位置半行直接作废WriteSync写完并强制刷盘确保落盘才算数。读取侧同样聪明decodeLog 先用LastIndexByte找到最后一个换行符committedSize之后的内容一律视为未提交数据——半行记录永远不会污染状态。 一句话总结以完整行为提交边界 刷盘落盘 重启截断残行 任意时刻崩溃都不丢已提交数据、不产生脏数据。三、Resume重启后如何精确复活崩溃后重新运行时入口是 Store.Resume。它做两件事3.1 重放账本重建内存状态decodeLog逐行重放记录把每条item和operation依次回放到内存状态机中。回放过程会严格校验记录序号必须连续递增缺号立即报错格式版本不匹配包括无法识别的旧版本 1会显式拒绝恢复而不是静默兼容每个操作的类型和版本号回放过程中不允许被篡改。这套校验来自 validateOperation保证重放出来的状态和崩溃前完全一致。3.2 找出没干完的活真正的复活逻辑在 resume() 里它扫描整本账本产出ResumeState定义见 sessionstore.go包含三部分字段作用Snapshot会话基本信息用于确认身份Operations所有未完成的操作——状态未到终态、或终态还没写进历史的操作都会被挑出来供操作管理器重新调度ExternalInputIDs已经接收但可能尚未处理完的外部输入 ID用于恢复输入幂等去重⚡ 举个例子Agent 正在执行一个 shell 操作时断电。重启后Resume发现该操作状态是awaiting未完成它就被放回Operations列表由操作管理器用持久化的幂等数据Idempotency继续推进而不会盲目前进。3.3 输入幂等重复投递不会造成重复执行恢复不仅是恢复操作还要恢复哪些输入已经收过。Unreal Agent 的 Inbox 是会话级、易失的去重层见 inbox.go崩溃后会清空ExternalInputIDs正是把已接收的外部输入重新注入 Inbox这样上游重发的同一条消息在恢复后被安全丢弃实现端到端幂等。仓库中的集成测试 resume_test.go 验证了完整链路输出中断 → 失败项已提交 → 重新运行 → 模型请求只发生一次且输入不重复证明复活后不会重复烧 token。四、Fork同一本账本还能分叉append-only 不只是为了恢复还是分叉的基础。Fork 可以把某个会话在指定 turn 处的历史复制成全新会话forkStoredState 负责找到分叉边界并继承历史测试样例 golden-fork.session.jsonl 里可以看到fork类型记录完整记录了父会话和分叉点。这意味着你可以让 Agent 从任意历史节点岔路探索不同方案而原会话毫发无损——因为账本只增不改。五、设计要点回顾这套机制做对了什么提交边界清晰一行一记录、换行符即提交点崩溃最多丢正在写的那半行且会被自动截断状态可由日志完整重建内存状态机不单独持久化一切以账本为准重放即可复活未完成工作显式化Resume精确挑出未终结的操作和待去重的输入恢复继续干而不是重新开始版本显式化格式带版本号不兼容时明确报错见 README.md 中An unsupported session version will always cause an explicit error on resume绝不悄悄猜可插拔Store是接口localfile 只是本地实现官方明确鼓励用代理实现把会话同步到远程沙箱等场景。六、上手试试体验崩溃恢复用仓库自带的 runner 就能直观感受这套机制详见 cmd/unreal-agent-runner/README.mdgo run ./cmd/unreal-agent-runner \ -workspace ./my-project \ -session-directory ./sessions \ -p Summarize this project.指定-session-directory后所有会话以 JSONL 账本形式落盘。执行过程中随时kill -9掉进程再用相同 session_id 发起请求Agent 就会从账本重放中恢复上下文并继续——这就是本文解析的崩溃后自动复活。七、总结Unreal Agent 的会话存储用最朴素的手段——仅追加的 JSONL 日志 换行符提交边界 全量重放——实现了工业级的崩溃恢复能力不丢已提交数据、不重复执行操作、不重发已接收输入。对于正在构建自己的 AI Agent 系统的开发者来说这套账本式设计append-only 日志、幂等输入、显式未完成状态、版本化格式几乎可以直接照搬。想深入细节可以从 harness/sessionstore/localfile/store.go 和 harness/sessionstore/localfile/state.go 两个文件开始读起。【免费下载链接】unreal-agentAsync-first agent harness项目地址: https://gitcode.com/gh_mirrors/un/unreal-agent创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
