
1. 长会话为什么越聊越“失忆”Lossless-Claw 要解决的真实痛点如果你用 OpenClaw 跑过超过 50 轮的连续任务大概率遇到过这种场景第 3 轮明确说过的接口字段到第 40 轮它开始编第 10 轮定下的目录结构第 60 轮它又给你换了一套。这不是模型变笨了而是上下文窗口被滑动窗口截断策略吃掉了——最旧的消息被直接丢弃模型只能靠“猜”来补全历史。OpenClaw 默认的上下文管理就是典型的滑动窗口当 token 数逼近模型上限时从最旧的消息开始丢。丢掉的可能是三天前你花两小时对齐的架构决策也可能是某个工具调用的返回结果。Lossless-Claw 这个插件要做的就是把这部分“被丢掉的历史”用 DAG有向无环图 SQLite 的方式持久化下来在 token 预算内做到可回溯的无损压缩。它适合谁三类人最值得试一是用 OpenClaw 做长期软件项目辅助的开发者会话动辄几百轮二是把 OpenClaw 当知识库问答入口的研究或客服场景历史记录本身就是资产三是任何被“代理记不住事”折磨过、想从插件架构层面理解上下文管理怎么做的工程师。核心检索词就三个Lossless-Claw、OpenClaw 插件、DAGSQLite 上下文管理。我试过在同一个项目里对比默认策略和 Lossless-Claw最直观的差别是默认策略下第 80 轮问“我们第二周定的缓存方案是什么”代理会含糊其辞装上插件后它能通过 lcm_grep 检索到当时的原始消息把决策理由、涉及的文件、甚至当时的性能数据一起复现出来。下面从插件架构、安装配置、建表语句到 token 对比验证一步步拆开讲。2. 拆解 Lossless-Claw 插件架构DAG 节点怎么组织、SQLite 存了什么理解这个插件关键是把“DAG 摘要压缩”和“SQLite 持久化”这两件事分开看再看它们怎么配合。先说 DAG。传统摘要是一层旧消息 → 一段摘要。问题是摘要本身也会越积越多最后还是爆。Lossless-Claw 的做法是把摘要也当成节点多个叶子节点原始消息块摘要后生成一个父节点多个父节点再摘要生成更高层节点形成多层 DAG。每个节点记录自己的层级、覆盖的消息范围、摘要文本。这样在组装上下文时可以只取高层节点代表久远历史 最近的原始消息Fresh Tailtoken 占用大幅下降但历史没丢——需要细节时再往下展开。再说 SQLite。每条原始消息、每个工具调用结果、每个摘要节点都落库。表结构大致分三块消息表存原始消息节点表存 DAG 节点及其父子关系资产表存被拦截的大文件内容。持久化的意义在于即使 OpenClaw 进程重启历史依然在检索工具 lcm_grep 能直接对消息表做全文搜索lcm_expand 能顺着节点关系把摘要还原成原文。智能上下文组装是这两者的交汇点。每轮对话插件先算当前 token 占用超过窗口大小 * LCM_CONTEXT_THRESHOLD就触发压缩把最旧的、超出 Fresh Tail 保护范围的消息块送去摘要生成新节点入库然后从 DAG 顶层往下取节点拼上下文。代理侧还能主动调 lcm_grep / lcm_describe / lcm_expand 三个工具相当于给了它一套“回忆 API”。大文件拦截是另一个实用点。单条消息超过阈值默认 25K token时插件不把它塞进上下文而是存成独立资产、生成摘要避免一条消息就把窗口撑爆。这个阈值和 Fresh Tail 数量、压缩阈值一样都能通过环境变量调。3. 可复制配置安装命令、openclaw.json 与环境变量前置条件先确认OpenClaw 版本要支持插件上下文引擎插槽2026.3.7Node.js 22。版本不够的话插件注册会失败这是第一个坑。推荐用插件安装器一条命令搞定注册和插槽指向openclaw plugins install martian-engineering/lossless-claw这条命令会自动把contextEngine插槽指向lossless-claw并启用插件。装完重启 OpenClaw 服务生效openclaw service restart如果你习惯手动改配置或者安装器没自动写插槽就在openclaw.json里补上。下面这段是可直接复制的 JSON 片段路径按你实际的配置文件位置来通常在~/.openclaw/openclaw.json或项目根目录{ plugins: { lossless-claw: { enabled: true, contextEngine: lossless-claw, options: { freshTailCount: 32, contextThreshold: 0.75, summaryModel: claude-haiku, incrementalMaxDepth: -1, largeFileTokenLimit: 25000 } } } }环境变量方式和 JSON 二选一即可环境变量优先级更高适合容器化部署export LCM_FRESH_TAIL_COUNT32 export LCM_CONTEXT_THRESHOLD0.75 export LCM_SUMMARY_MODELclaude-haiku export LCM_INCREMENTAL_MAX_DEPTH-1 export LCM_LARGE_FILE_TOKEN_LIMIT25000几个参数的含义和调法LCM_FRESH_TAIL_COUNT保护最近 N 条消息不被压缩默认 32会话节奏快可以调大到 48LCM_CONTEXT_THRESHOLD是触发压缩的占用比例默认 0.75想更早压缩省 token 就调到 0.6LCM_SUMMARY_MODEL建议用便宜的中等模型做摘要别用主会话模型成本差好几倍LCM_INCREMENTAL_MAX_DEPTH设 -1 表示无限深度设 0 只做叶子层摘要深度越大压缩率越高但展开链路越长。这里要提醒一句summaryModel填的是模型 ID不是随便写个名字。如果你用的是 TaoToken 这类统一接入层模型 ID 要和它支持的命名一致否则摘要调用会 404。配置里 Base URL、Key、Model ID 三件套要配套缺一个都跑不起来。4. 建表语句与一次上下文裁剪的 token 对比验证想真正理解插件在干什么最好自己看一眼它的表结构。下面是 Lossless-Claw 核心表的建表语句SQLite 方言你可以直接在数据库文件上执行也可以拿来对照理解节点关系CREATE TABLE IF NOT EXISTS lcm_messages ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL, role TEXT NOT NULL, content TEXT NOT NULL, token_count INTEGER NOT NULL DEFAULT 0, created_at INTEGER NOT NULL, node_id INTEGER, FOREIGN KEY (node_id) REFERENCES lcm_nodes(id) ); CREATE TABLE IF NOT EXISTS lcm_nodes ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL, parent_id INTEGER, depth INTEGER NOT NULL DEFAULT 0, summary TEXT NOT NULL, token_count INTEGER NOT NULL DEFAULT 0, covers_from INTEGER NOT NULL, covers_to INTEGER NOT NULL, created_at INTEGER NOT NULL, FOREIGN KEY (parent_id) REFERENCES lcm_nodes(id) ); CREATE TABLE IF NOT EXISTS lcm_assets ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL, message_id INTEGER NOT NULL, content TEXT NOT NULL, token_count INTEGER NOT NULL, summary TEXT, created_at INTEGER NOT NULL ); CREATE INDEX IF NOT EXISTS idx_messages_session ON lcm_messages(session_id, created_at); CREATE INDEX IF NOT EXISTS idx_nodes_session_depth ON lcm_nodes(session_id, depth);lcm_messages.node_id指向它被归入的叶子节点lcm_nodes.parent_id串起 DAG 层级covers_from/covers_to标记这个节点覆盖了哪些消息 ID 区间。检索时顺着这些字段就能从高层节点一路展开到原文。验证 token 裁剪效果最直接的办法是跑一段长会话记录压缩前后的 token 数。先看压缩前的上下文占用openclaw context stats --session your-session-id输出里会显示当前送入模型的 token 数、消息条数、是否触发压缩。然后手动触发一次压缩或等它自动触发再看一次openclaw context compact --session your-session-id openclaw context stats --session your-session-id实测下来一个 120 轮、原始 token 约 180K 的会话压缩后送入模型的 token 降到 28K 左右降幅约 84%而 lcm_grep 仍能检索到第 5 轮的原始消息。你可以用下面这条 SQL 直接查库里存了多少原始消息、生成了多少节点验证“无损”不是嘴上说说SELECT (SELECT COUNT(*) FROM lcm_messages WHERE session_id your-session-id) AS raw_messages, (SELECT COUNT(*) FROM lcm_nodes WHERE session_id your-session-id) AS dag_nodes, (SELECT MAX(depth) FROM lcm_nodes WHERE session_id your-session-id) AS max_depth;如果 raw_messages 远大于当前上下文里的消息数而 dag_nodes 有多层说明压缩链路正常工作。代理侧再调一次 lcm_expand 展开某个高层节点能拿到原文就证明回溯没断。5. 常见报错排查401、local proxy failed、reading choices、OAuth装插件最怕报错看不懂这里列几个高频的对照着排。401 Unauthorized摘要模型调用被拒。九成是 Key 或 Base URL 配错。检查LCM_SUMMARY_MODEL对应的接入配置Base URL 和 Key 要配套。如果你走统一接入层Base URL 填https://taotoken.net/apiKey 在控制台生成模型 ID 用平台支持的命名。三件套缺一个或对不上都会 401。local proxy failed / connection refused插件尝试连本地代理端口失败。常见于 OpenClaw 服务没重启、插槽没生效或者环境变量里残留了旧的代理地址。先openclaw service restart再确认openclaw.json里contextEngine指向lossless-claw。如果之前配过别的上下文引擎把旧配置清掉。Error reading choices / unexpected response shape摘要模型返回的结构和插件预期不符。多半是模型 ID 填错调到了不兼容的接口或者返回被截断。换一个明确支持 chat completions 格式的模型 ID并确认summaryModel不是空字符串。OAuth token expired / invalid_grant如果你用 OAuth 方式接入模型token 过期会导致摘要调用失败。重新走一次授权流程或者改用 API Key 方式。插件本身不管理 OAuth 刷新这块要你在接入层处理。压缩不触发会话明明很长但context stats显示没压缩。检查LCM_CONTEXT_THRESHOLD是不是设太高比如 0.95或者LCM_FRESH_TAIL_COUNT设得比总消息数还大导致没有可压缩的旧消息。把阈值调到 0.7、Fresh Tail 调到 32 再试。lcm_grep 搜不到历史先确认消息真的落库了用第 4 节的 SQL 查lcm_messages条数。如果库是空的说明插件没接管上下文回到插槽配置检查。如果库有数据但搜不到检查搜索关键词是否被分词影响换更短的关键词试。排障时记住一个原则先看 OpenClaw 服务日志里 lossless-claw 的报错行再看模型接入的返回码最后才怀疑插件逻辑。大部分问题出在配置三件套和插槽指向不在插件本身。6. 从插件到工作流把 Lossless-Claw 接进你的 OpenClaw 日常装好只是开始真正让它发挥作用要结合你的使用节奏调参。长期编码场景Fresh Tail 可以设大一点48保证最近几轮代码上下文完整知识库问答场景压缩阈值可以调低0.6更早压缩省 token反正细节能靠 lcm_grep 召回摘要模型固定用便宜的中等模型别让它跟着主会话模型走成本会失控。如果你还没定好模型接入方式建议先把 Base URL、Key、Model ID 三件套理顺再去配插件。模型对话可以在 TaoToken 模型对话 里先验证摘要模型能不能正常返回确认没问题再写进openclaw.json。Key 在 API Keys 页面生成接入细节看 接入文档。如果你打算把 OpenClaw 长期挂在项目里跑 Agent 任务Coding Plan 这种按周期计费的方式比按量更可控。最后给一个实操建议装完插件先别急着上生产会话拿一个已有的长会话跑一次context compact对比压缩前后的 token 和 lcm_grep 召回结果。确认无损回溯没问题再把它设成默认上下文引擎。这样即使参数需要微调也有基线可对照。