一份基于真实诊断 session 的实战指南——从表面症状到完全闭环的 memory loop。
👀
大多数 Agent 的问题并不是模型的问题。它们是“管道”问题——正确的部件存在,但没有被连接起来。本指南记录了如何找到那些断开的管道、系统地验证它们,并正确地将它们连接起来。
激发本指南灵感的诊断 session 始于一个简单的抱怨:“我怀疑这个 Agent 缺乏文档和记忆的闭环,并且在 session 崩溃或 gateway 重启后无法恢复。” 两个小时后,一个一直处于闲置状态的复杂 vector memory(向量记忆)系统终于开始自动运行。以下是我们如何做到这一点的。
👀
在触碰任何东西之前,请先了解 OpenClaw 默认提供了什么,没有提供什么。
OpenClaw 自动处理的内容
Pre-compaction memory flush(压缩前记忆刷新) — 在 summary(总结)旧 context(上下文)之前,OpenClaw 会静默提示 Agent 将重要信息写入磁盘。此功能默认开启,但仅当 workspace 可写时才会运行。
Context overflow recovery(上下文溢出恢复) — 如果模型返回 context overflow(上下文溢出)错误,OpenClaw 会自动进行 compact(压缩)并重试原始请求。
Session persistence(Session 持久化) — 所有对话历史都存储在 ~/.openclaw/agents/<agentId>/sessions/ 目录下的 JSONL transcripts(记录)中。这些记录在 gateway 重启后依然留存。
BOOT.md execution(BOOT.md 执行) — 如果 workspace 根目录中存在 BOOT.md 文件,boot-md hook 会在每次 gateway 重启时运行它。
OpenClaw 不自动处理的内容
在 session 结束后运行你的自定义脚本
在崩溃后恢复超出已写入 memory 文件之外的 task(任务)状态
如果 primary(主模型)失败则回退到不同的模型(除非你配置了 fallbacks)
更新你自己构建的任何 vector index(向量索引)
这两个列表之间的差距,正是大多数 Agent 问题存在的地方。
👀
按顺序运行这些检查。每一步要么确认某一层级是健康的,要么暴露出下一个问题。
第 1 步:验证 workspace 身份
/context list这会揭示 workspace 路径、哪些文件正在被注入、是否有文件被截断 (truncated) 以及当前的 context 占用情况。检查:
workspace 路径是你所期望的吗?路径不匹配(例如,默认的 ~/.openclaw/workspace 与自定义路径不同)意味着 Agent 没有在读取你认为它在读的文件。
是否有任何文件显示为 TRUNCATED?大文件被静默截断,这意味着 Agent 只能看到部分自身的指令。
是否有一行显示 undefined: OK?这表明有一个未命名的文件正在被注入——值得调查。
第 2 步:检查运行时状态
/status这会显示 active model(活跃模型)、fallback 配置、session key、compaction count(压缩次数)以及 context 百分比。需要立即关注的两件事:
Model fallbacks(模型回退配置) — 如果 fallbacks 显示与 primary 相同的模型,那就不存在真正的 failover(故障转移)。速率限制 (rate limit) 或 API 宕机会让 Agent 彻底停止工作。
Compaction count(压缩次数) — 如果对于一个长期运行的 Agent 来说这个值是 0,要么是 context 从未满过(正常的),要么是 compaction 坏了(值得检查)。
第 3 步:审查 hook 系统
openclaw hooks list这是解决集成问题最重要的诊断步骤。它会显示每个已注册的 hook、其状态、它订阅的 events(事件),以及它是否处于 ready(就绪)状态。将此列表与 workspace 的 skills/ 目录中的每个自定义脚本进行交叉比对。
核心问题: 每个应该自动运行的脚本是否都在这里显示为 ✓ ready?
在本指南所基于的那个 session 中,一个精心设计的 vector memory 系统有一个定义了 on_dialog_end 的 session_hook.py 文件——但它根本没有出现在 hooks 列表中。它从未被注册。多年的设计工作,只是在空转。
第 4 步:验证模型配置
openclaw config get agents.defaults.modelopenclaw models status
检查:
fallbacks 包含一个与 primary不同 的模型
至少有一个 fallback 来自不同的 provider(提供商)(为了实现真正的冗余)
fallback 模型已配置了有效的 credentials(凭证)
第 5 步:检查记忆闭环 (memory loop) 端到端情况
直接问 Agent:“当一个 session 结束时,你的 memory 会自动发生什么?带我过一遍整个链条。”
一个健康的 Agent 应该这样描述:每日 memory 文件更新 → vector index 增量更新 → MEMORY.md 被定期提炼 (distilled)。如果 Agent 犹豫不决或描述了一个手动过程,说明这个 loop 存在断层。
👀
一个正常运作的 memory loop 有四个阶段。每个阶段都必须是自动的。
Session active (Session 活跃)│▼[on_user_message] ──► 从 vector index 检索相关 memory│ 在回复前注入到 context 中│▼[on_dialog_end] ──► 将 summary 追加到 memory/YYYY-MM-DD.md│ 运行增量 vector index 更新│▼[Heartbeat] ──► 定期将每日文件提炼到 MEMORY.md│ 如果需要,运行全量 vector reindex(重新索引)│▼[Gateway restart / BOOT.md] ──► 读取今天的 memory读取 MEMORY.md运行增量 index 更新检查 pending tasks(待办任务)通知用户
如果这条链中的任何一个箭头不是自动的,这个 loop 就是开放的 (open)。一个 open loop 意味着,一次崩溃的 session、一次被遗忘的 /compact,或是一次 gateway 重启,都有可能静默丢弃 Agent 无法恢复的 context。
👀
如果你有一个需要在 session events 发生时运行的自定义 Python 脚本,以下是如何将它正确接入 OpenClaw 的方法。
hook pack 结构
OpenClaw 要求一个 hook pack 必须是一个至少包含以下内容的文件夹:
HOOK.md — 元数据和描述
handler.ts(或 handler.js)— event handler(事件处理程序)
HOOK.md 格式
name: your-hook-namedescription: "这个 hook 的功能描述"metadata: {"openclaw":{"emoji":"🔧","events":["user:message","dialog:end"]}}# Your Hook Name简短描述。## Installbash openclaw hooks install path/to/hooks/openclaw openclaw hooks enableyour-hook-name
events 数组控制 handler 触发的时机。常见的 events 包括:
agent:bootstrap — 在 session 开始时,在 workspace 文件被注入之前触发
user:message — 在收到每一条用户消息时触发
dialog:end — 在对话片段结束时触发
handler.ts 格式
handler 将 OpenClaw 的 event 系统连接到你的 Python 脚本:
import { exec } from "child_process";import * as path from "path";const scriptPath = path.resolve(__dirname, "../../scripts/your_script.py");export async function onUserMessage(ctx: any) {const query = ctx?.message?.text ?? "";if (!query.trim()) return;exec(`python "${scriptPath}" --on-user-message "${query.replace(/"/g, '\\"')}"`);}export async function onDialogEnd(ctx: any) {const summary = ctx?.summary ?? "";exec(`python "${scriptPath}" --on-dialog-end "${summary.replace(/"/g, '\\"')}"`);}
更新你的 Python 脚本以接受 CLI 参数
handler 通过命令行调用脚本,因此脚本需要一个入口点:
if __name__ == "__main__":import argparseparser = argparse.ArgumentParser()parser.add_argument("--on-user-message", type=str, default=None)parser.add_argument("--on-dialog-end", type=str, default=None)args = parser.parse_args()if args.on_user_message:on_user_message(args.on_user_message)if args.on_dialog_end:on_dialog_end(args.on_dialog_end)
安装 hook
openclaw hooks install skills/your-skill/hooks/openclawopenclaw hooks enable your-hook-nameopenclaw hooks list
确认 hook 显示为 ✓ ready。然后重启 gateway 以加载它。
👀
BOOT.md 是每次 gateway 重启时 Agent 的第一条指令。如果没有它,重启后的 Agent 会读取其 workspace 文件(根据 AGENTS.md),但不会执行任何特定的恢复操作。有了它,Agent 就能确切知道该做什么来恢复 context。
一份最小但完整的 BOOT.md:
# Boot checklist- 读取今天的 memory 文件: memory/YYYY-MM-DD.md (使用当前日期)- 读取 MEMORY.md 获取核心约定和 long-term context- 运行增量 vector index 更新:python skills/local-vector-memory/scripts/index.py --workspace . --incremental- 检查 memory/pending/ 中未处理的提案 (如果为空则跳过)- 检查 Plans.md 获取开放的 tasks (如果文件不存在则静默跳过)- 如果在主 session 中: 通知用户 gateway 已重启且 context 已恢复
保持 BOOT.md 简短。它在每次重启时触发,所以太长的 checklist 会浪费 tokens。只包含对恢复真正必要的操作。
👀
进行更改后,通过三个针对性的测试进行验证。
测试 1:Memory 文件被写入
Get-Content memory\YYYY-MM-DD.md | Select-Object -Last 20发送 /new 或 /reset 以触发 session 边界。检查文件是否已更新。如果没有,说明 session-memory hook 或 on_dialog_end 没有触发。
测试 2:Vector index 被更新
Get-Item skills/local-vector-memory/data/chroma/chroma.sqlite3 | Select-Object LastWriteTime发送一条消息,等待 10 秒,再次检查。如果 LastWriteTime 没有改变,说明 on_dialog_end 没有到达 index 更新代码。
测试 3:BOOT.md 在重启时执行
openclaw gateway restartopenclaw logs --follow
在日志中寻找 boot-md hook 的执行记录。对于一个可选文件(比如 Plans.md)出现 ENOENT 错误是预期的、正确的现象——这意味着 hook 运行了,并正确地尝试读取该文件。对于必需文件出现错误则表明存在路径问题。
三个测试全部通过,意味着 loop 已闭环。
👀
对任何 Agent 都值得检查的 openclaw.json 设置的总结。
{"agents": {"defaults": {"workspace": "explicit/path/to/workspace","model": {"primary": "provider/primary-model","fallbacks": ["provider/different-model","other-provider/fallback-model"]},"compaction": {"model": "provider/lighter-model","mode": "safeguard"}}},"session": {"maintenance": {"mode": "enforce","pruneAfter": "30d","maxEntries": 500}}}
关键决策:
Workspace 路径 — 如果你将 workspace 从默认位置移走了,需要明确设置
Fallbacks — 始终使用一个不同的模型,理想情况下是不同的 provider
Compaction 模型 — 较轻量级的模型能在超长的 sessions 中节省 tokens;primary 模型不需要去总结它自己
Session 维护 — enforce 模式可防止无限制地增长;warn(默认值)只会发出警告报告
👀
这次诊断最重要的洞察是:Agent 的问题很少是因为缺少了什么——它们通常是关于已存在但未被连接的东西。这次 session 中的 vector memory 系统复杂且设计精良。on_dialog_end 函数写好了。ChromaDB 基础设施在运行。一切都在那里。
中间的断层仅仅是三个文件:一个 HOOK.md,一个 handler.ts,以及 Python 脚本底部的四行代码。
当诊断一个 Agent 时,从把你拥有的东西与 OpenClaw 期望的东西进行映射对比开始。阅读 hooks 列表。阅读 /context list。要求 Agent 描述它自己的 memory loop。断开的连接通常会在前十分钟内暴露出来。
然后连接它,测试它,并将它写入 memory。
诊断进行时间: 2026-04-03
OpenClaw 版本: 2026.3.13 (61d171a)
模型: volcengine-plan/ark-code-latest
夜雨聆风