Back to News
Tutorial
ACP 一次性任务明明已写入 .jsonl,但 sessions_history 可能返回空:怎么判断、怎么止损

ACP 一次性任务明明已写入 .jsonl,但 sessions_history 可能返回空:怎么判断、怎么止损

OpenClaw News 编辑部

OpenClaw News 编辑部

OpenClaw 的一个新 bug 报告指出:在某些 ACP one‑shot(sessions_spawn(runtime="acp", mode="run")) 场景里,任务已经成功完成、并且本地 transcript(.jsonl)里已经有完整的用户输入与助手输出,但你用 sessions_history(以及 sessions_list(...messageLimit=...))去“回看”时,却可能看到一个 空会话。

来源 Issue: openclaw/openclaw#51328

这类问题的危险点在于:它会把“已经跑完的任务”伪装成“没跑/卡住/没产出”,从而导致误判、重复执行、甚至重复产生副作用。

现象长什么样

报告环境大意(OpenClaw 2026.3.13、macOS、ACP backend 为 acpx,Claude ACP one‑shot):

  • sessions_history(sessionKey, includeTools=true) 返回 messages: []
  • sessions_list(limit=..., messageLimit=2) 能看到 session,但最近消息为空
  • 但磁盘上 ~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl 里已经有:
    • 完整的用户 prompt
    • 完整的助手 completion
    • 正常的 DONE 结果

关键点:这不是 ACP 没执行成功。更像是“会话 API 的可见性/投影层”暂时没跟上。

可能原因(不需要猜对才能处理)

OpenClaw 的 ACP 运行通常有两层:

  • ACP backend 写入原始 transcript(.jsonl)
  • 会话 API(sessions_history / sessions_list)展示的是另一份“被加载/被索引/被投影”的结果

如果两层在短时间内不同步,就会出现“磁盘有内容、API 看起来为空”。可能触发因素包括:

  • 异步摄取/索引延迟(写入先完成,但索引更新滞后)
  • watcher/polling 触发慢
  • 写入关闭/锁竞争导致的短暂读空窗口

你不必在现场定位根因,先按下面的步骤确认与止损更重要。

快速分流:这是“空 history”,还是任务其实根本没执行

现场最容易犯的错,是把所有“API 里没消息”都当成同一种故障。

更实用的判断顺序是:

  • 磁盘 transcript 已完整写入,API 暂时为空
    • 这更像本文讨论的投影/索引延迟,而不是真没执行。
  • 磁盘 transcript 也没有用户输入和助手输出
    • 这时就不能把问题直接归因到 sessions_history,要改查 ACP run 是否根本没启动或提前失败。
  • sessions_list 能看到 session,但 recent messages 为空
    • 更像可见性层滞后,而不是 session 本体不存在。
  • 不只是 one-shot,连 thread/session 模式都持续丢消息
    • 那就不该把范围只锁在 ACP one-shot,要扩大到更广泛的会话投影链路。

这个分流很关键,因为它决定你下一步该“避免重跑”,还是该先确认任务到底有没有真正执行。

实用排障与止损清单

1) 先把 .jsonl 当成“是否真的跑过”的地面真相

当你怀疑 ACP one‑shot 已经成功,但 sessions_history 却空时:

  1. 找到 transcript 文件:
    • ~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl
  2. 确认里面确实包含:用户输入 + 助手输出(最好还能看到 DONE/完成标记)

只要 .jsonl 已经完整,不要立刻重跑。

重跑的风险包括:

  • 重复 commit / 重复发布
  • 重复发送消息
  • 重复消耗模型额度
  • 让问题变得更难复盘(两次 run 混在一起)

2) 延迟 15–60 秒再查一次 API

这个问题在报告里是“spawn 后不久检查时出现”,所以可以做一个最小成本的确认:

  • 等 15–60 秒
  • 再调用一次 sessions_history(..., includeTools=true)

如果稍后恢复正常,基本就能确定是“投影/索引延迟”而非真实丢失。

3) 如果持续为空:收集对维护者最有用的证据

不要只截一句“空了”。建议收集:

  • 触发的 sessions_spawn 关键参数(runtime、agentId、mode 等)
  • 你用的 sessionKey
  • transcript .jsonl 的前 50 行 + 后 50 行(注意脱敏)
  • 两个 API 输出:
    • sessions_history(sessionKey, includeTools=true)
    • sessions_list(limit=..., messageLimit=2)

这能帮助判断:是索引没更新、读源不一致、还是在某个解析边界上失败。

4) 临时运维策略:避免“看到空历史就自动重试”

在问题修复前,如果你有自动化编排逻辑(或者团队 runbook):

  • 不要把 sessions_history 的空列表直接等价于“没跑/失败”
  • 增加一个短延迟 + 磁盘 transcript 兜底检查
  • 对任何会产生副作用的动作,尽量设计成幂等(idempotent)

为什么这个点对“生产化使用”很关键

ACP one‑shot 常用于“做完就退出”的任务(写代码、修复、生成报告、跑测试等)。如果会话 API 错把成功的 run 显示为空,会导致:

  • 误触发重跑与重复副作用
  • 让运维以为 ACP 不稳定、误判为启动/路由失败
  • 增加排障成本与模型开销

常见上线判断问题

什么时候该停止怀疑 ACP agent 本身,改为优先怀疑会话投影延迟

如果磁盘里的 transcript .jsonl 已经有完整 prompt、完整 completion,且还能看到正常 DONE 标记,但 sessions_history 依然返回 messages: [],这时就不该继续把问题归因于“agent 没跑起来”。更安全的判断是:磁盘真实状态已经完成,但 session API 的投影/索引层还没跟上。

在这个 bug 还没修好前,怎样最安全地避免重复副作用

对任何准备重试的动作,先加一个两步保护:短暂等待,再检查磁盘 transcript 是否已经显示任务完成。如果已经完成,就不要自动重跑会产生副作用的动作,比如 commit、deploy 或对外发消息,除非有人明确判断第一次结果必须重做。

如果你是从 troubleshooting 入口进来,先分清 transcript 证据和 API 投影

这篇现在和 troubleshooting 总表、setup 流量出现在同一个 GA4 窗口里,说明读者大概率不是随便看一篇 bug 记录,而是在判断 ACP run 到底是丢了、延迟了,还是只是 session API 视图过旧。

升级事故前,先按三类分流:

  1. 没有 transcript 文件:先查启动、权限、sandbox 路径和 runtime 初始化,这还不是 empty history 投影问题。
  2. transcript 存在,但 sessions_history 为空:保留 .jsonl、session id、runtime 和时间戳,先按 transcript 继续交接,把 API 视图当作 stale。
  3. 多次检查后 transcript 和 API 仍不一致:把问题带回 troubleshooting 总表,对照 session timeout 或 Gateway 状态症状,再决定是否重启生产自动化。

这能让从泛排障搜索进来的高意图用户,快速完成“run 真丢了 vs API 视图过旧”的判断。

相关阅读

常见判断问题 FAQ

如果 .jsonl 已经有完整 completion,但 sessions_history 还是空,第一反应应该是什么?

第一反应不该是立刻重跑,而应该先把它当成 会话投影延迟 来处理。

因为这类故障最危险的点就在于:

  • 真正执行已经完成
  • 本地 transcript 已经落盘
  • 但 API 视图暂时没把结果显出来

这时马上重跑,最容易制造重复副作用。

什么时候更该怀疑“索引/可见性层没跟上”,而不是 ACP agent 本身没工作?

如果你同时看到:

  1. sessions_list 能看到 session
  2. .jsonl 里已经有用户输入和助手输出
  3. 只有 sessions_history 或 recent messages 为空

那就更该优先怀疑可见性层或索引层,而不是 agent 根本没执行。

搜 sessions_history empty but jsonl exists 的人,页面最该先帮他分哪三个支路?

最该先分这三个:

  1. 磁盘 transcript 是否已经完整写入
  2. 这是短时间检查时为空,还是长时间后仍持续为空
  3. 只有 one-shot 受影响,还是 thread/session 模式也一起异常

这三步最能帮助用户从“误以为任务没跑”收缩到“会话 API 投影延迟或可见性问题”。

如果你已经确认 transcript 在、API 视图却空,下一步先点哪两篇

如果你已经确认 .jsonl transcript 是完整的,但 sessions_history 或 sessions_list(...messageLimit=...) 仍然看起来像空会话,下一步最值得继续看的通常是这两篇:

  1. 先看 OpenClaw Agents 排障指南:任务卡住、工具不回、结果异常时先查什么,确认是不是还叠加了工具调用、权限或消息链路问题;
  2. 如果你的症状更像“session 还在,但重启或恢复后路径对不上”,再看 Gateway crash/restart 后 orphaned sessions 不会真正恢复,把会话投影延迟和恢复链路断开区分开。

这样做的意义,是把“API 看起来没历史”继续分流成更具体的消息可见性问题,而不是让用户停留在模糊的‘好像没跑’判断里。

相关阅读

交接给值班同事时,最少要留下哪 5 个证据

这类问题最怕只留一句“history 是空的”,因为下一班很容易误以为任务没跑。交接时至少留下:

  1. sessionKey、agentId、runtime、mode,避免下一步查错会话;
  2. .jsonl transcript 的文件路径,以及开头和结尾各一小段脱敏内容;
  3. sessions_history(..., includeTools=true) 的原始返回,保留空数组或缺字段细节;
  4. sessions_list(..., messageLimit=2) 的返回,确认列表视图和 history 视图是否同时为空;
  5. 是否已经执行过会产生副作用的动作,比如 commit、push、deploy、发消息或写外部 API。

有了这 5 个证据,后续判断就能从“任务是不是没跑”推进到“磁盘完成态、API 投影视图、列表摘要视图到底哪一层不同步”。这比直接重试更安全,也更适合生产化 runbook。

判定已恢复前,再做 4 个关闭检查

当 sessions_history 后来终于能看到消息时,也不要马上把事故关掉。先补 4 个关闭检查:

  1. 同一 sessionKey 复查:确认恢复的是原来的会话,不是后来重跑出来的新会话。
  2. list 与 history 对齐:同时对比 sessions_list(...messageLimit=2) 和 sessions_history(...includeTools=true),确认摘要视图与详情视图都能看到同一批消息。
  3. 工具消息可见性:如果该 run 调过工具,确认 tool call 与 tool result 没有只存在于 .jsonl,却在 API 里缺失。
  4. 副作用没有重复:核对 commit、push、deploy、外部消息或 API 写入次数,确认恢复过程中没有因为空 history 误触发第二次执行。

这 4 个关闭检查能把“页面终于不空了”升级成真正可交接的恢复结论,也能服务搜索 sessions_list messageLimit empty、ACP transcript exists history empty 的运维读者。

信任空 session API 响应前,先补这份证据清单

当 transcript 明明存在,但 session API 返回空 history 时,不要立刻把它当成真实丢失。先把 API 响应当作一个投影视图,按下面四项补证据:

  1. Transcript 路径与时间戳:记录本地 transcript 文件、最后写入时间,以及能证明任务确实执行过的 message id 或 turn。
  2. API 入口与调用上下文:说明空响应来自 sessions_history、dashboard 投影,还是其他 wrapper。
  3. Session 身份映射:对齐可见 session key、ACP session id、持久化 run id,避免把投影错配误判成 history 丢失。
  4. 新鲜度窗口:短暂等待后复查,再判断是 projection lag、查错 session,还是确实 ingestion 失败。

这样值班同事不会因为一个 API 视图暂时为空,就误删仍然有价值的 transcript。

搜索入口分流:transcript 有内容但 session API 空历史先看什么

如果你是从 “ACP transcript exists but history empty”、“session API returns empty history” 或 “OpenClaw 会话记录读不到” 搜到这里,先把问题拆成四层:

  1. 确认 transcript 与 session API 是否读同一个来源:本地 transcript 文件存在,不等于 API 查询的 session id、workspace 或 run scope 一致。
  2. 确认历史读取窗口:有些接口会按 active session、thread、agent runtime 或 resume id 过滤,导致文件有内容但 API 返回空数组。
  3. 确认写入和索引时序:crash、重启、后台子代理结束、flush 延迟,都可能让 transcript 先落盘而 session 索引尚未更新。
  4. 保留三段证据:transcript 路径、session API 请求参数、返回的空 history,比单独截图“没历史”更容易定位。

这类问题不要只在 UI 层刷新重试。最短路径是同时核对 transcript 文件、session 标识、API 过滤条件和索引刷新时序。

相关阅读

什么时候空 history 应该阻断自动化

大多数 empty-history 事故应该让 runbook 降速,而不是让所有人停工。只有当缺失的 history 可能掩盖不可逆副作用时,才应该阻断自动化。让 cron、部署机器人或重试循环继续前,先用这条规则:

  1. 立刻阻断:上一次 run 可能已经 commit、push、deploy、发送外部消息、扣费,或写过第三方 API。
  2. 允许只读继续:下一步只是收集 transcript 路径、session id、日志或公网页面状态。
  3. 要求人工检查点:transcript 已证明任务完成,但 API 视图为空,而下一步会重复同一个副作用。
  4. 恢复自动化:只有当 transcript、sessions_list、sessions_history 对原始 run 达成一致,或重复副作用检查完成后再恢复。

这能回答高意图搜索里的 sessions_history empty retry or wait:涉及副作用先等证据,不要重复执行;只读诊断则继续推进。

来源

从搜索进来后的 3 分钟分流:run 丢失、API 过旧,还是查错 session

如果你是通过 sessions_history empty、jsonl exists 或 ACP transcript empty history 搜到这里,先不要重跑任务。用 3 分钟把风险分到正确层:

  1. 没有 .jsonl 文件或文件为空:优先查 ACP 启动、工作目录、权限和 sandbox 挂载,这还不是 API 投影问题。
  2. .jsonl 已经有 prompt 与 completion,但 API 为空:把磁盘 transcript 当作临时事实源,暂停自动重试,先补 session id、时间戳和 API 原始响应。
  3. list 能看到 session,history 看不到消息:优先怀疑 summary/history 投影不同步,而不是 agent 没执行。
  4. 不同 session key 查到不同结果:先对齐 visible session key、ACP session id 和持久化 run id,避免把身份映射错误误判成历史丢失。

这一步能把高意图排障流量从“看起来没跑”推进到“执行态、投影视图、身份映射哪一层不一致”,降低重复 commit、重复 deploy 或重复外部写入的概率。

© 2025 OpenClawNews.org
保留所有权利。
这是一个独立的资讯网站。与 OpenClaw 官方没有任何关联、认可或连接。OpenClaw 是其各自所有者的商标。
加入等候名单:

OC NEWS