---
title: 长任务支持
date: 2026-09-09
category: tech
summary: 长任务不是把上下文压小，而是让状态可恢复。从 Maka 的 append-only log 到 Bubu 的中断恢复。
draft: false
---

bubu agent 的设计理念就决定了它必定要有执行 24h+ 任务的能力，但碍于模型限制，注定了这是一个非常复杂的工程。

业内早期的压缩方案是保留首次 System Prompt + user 消息，对之后的 System Prompt 进行删减，保留之后每次的 user input 和 Model Response。之后的方案是使用 AI 对上下文生成摘要。但这些方案要不然就是压缩性能太差，要不然就是丢失细节太多，这些缺点在长工作中是致命的，生产环境中不允许出现这种风险。

bubu 一直在寻找能支持实际生产的长任务执行解决方案，最终在 maka 里找到了最符合需求的。

Maka 的这篇 Log Is the Runtime: Managing Agent State and Context with Append-Only Logs 讲得很清楚，地址是 <https://github.com/apache/maka/blob/main/docs/blogs/log-is-the-runtime.md>。

简单说就是 maka 用了多种优秀的系统思维来设计 Agent，在 maka 中，一个会话实际上是多个分页。

在一个窗口中产生的所有记录格式化后以 log 形式存入 SQLite，在 maka 中被称为日志。每条日志的正文是若干种事件内容之一：Text、Thinking、FunctionCall、FunctionResponse、Error。除了内容，事件还挂着一组动作字段，比如 stateDelta、permissionRequest、permissionDecision、tokenUsage、toolDispatch、toolRecovery 和 endInvocation。下次模型调用会重新组装，日志存档完毕后会做校验。为此设计了一整套系统，详细在 maka 的 blog 里，这里就不展开说了。

这种优秀的工程思维给 bubu 带来了启发，bubu 设计了一套轻量的任务中断恢复系统。一次用户请求进入执行后，Bubu 会在会话上打上 open_turn 标记，表示这条任务的执行边界尚未闭合。Turn 正常结束、用户主动停止、或应用有序退出并等完落盘，标记都会被清掉。

需要区分的是用户主动点停止，它不属于这种线索。停止会闭合 turn，不是崩溃，因此不会在重启后自动续跑。

SQLite 里的消息链是用户请求、模型给出的工具调用（T1）、工具结果（T2）。工具执行被拆成两个可观察的状态：T1 Dispatch 表示模型已决定调用、意图已落盘，T2 Outcome 表示结果已落盘、历史配对完成。

崩溃若发生在两者之间，系统面对的是「副作用可能已经发生，也可能没有」。Bubu 在这里采用与 Maka 相同的保守原则：无法证明幂等与安全时，禁止静默重做；能证明的，才允许静默重试。

于是恢复策略有两个清晰的规则。只读类工具，比如读文件、搜索、回忆记忆，恢复时直接静默重跑，把真实结果补回历史。会改环境的工具，比如写文件、改文件、跑命令，则不自动重做，系统写入一条明确的中断结果：不要假设成败，先核对工作区再决定是否重试，模型带着这份事实继续推理。

在配对完未完成的工具调用之后，Bubu 会在没有新的用户输入的情况下再次打开 agent loop，让模型从已恢复的前缀上继续任务。恢复开始时，界面会给出一条明确提示：检测到未完成任务、正在自动恢复；哪些步骤已静默重试；哪些写操作或命令已挂起待核对。用户可以关掉提示，续跑本身不受影响。
