OpenClaw Context Engine要做成可插拔原因解析(详解支持的策略类型与接入方式)

OpenClaw 把上下文管理从核心代码里抽出来,做成了排他的插件槽位(slot),目的是让上下文策略可替换、可组合、可独立演进,不必改一行核心代码。同一个 ContextEngine 接口,能跑默认的滑动窗口压缩,也能跑基于 DAG 的无损保留、RAG 检索组装、冷热分层存储和任务感知裁剪。下文拆解这层抽象的动机、接口契约和可落地的策略。

一、为什么要抽这层

OpenClaw 2026.3.7 之前,上下文逻辑写死在核心里,只有滑动窗口压缩一条路:对话过长就摘要旧消息,给新消息让路。这条路能跑,但三个问题躲不开。

痛点 具体表现 后果
压缩必丢信息 50 轮前定义的函数被摘要抹掉 写代码场景引用失效
关了就忘 会话结束上下文清零 没有跨会话记忆
换策略无门 RAG、对话分支、自管 token 预算都无扩展口 只能 fork 或 monkey-patch

社区被迫用 monkey-patch 内部模块、fork 核心代码、外面套一层编排来绕,都不是长久之计。把上下文生命周期抽成接口、开放为槽位,是为了把这层从“碰不得的黑盒”变成“可插拔的能力”。

二、接口契约与槽位机制

2.1 槽位不是钩子

ContextEngine 在插件体系里是槽位(slot),不是钩子(hook)。区别决定行为:钩子叠加,十个插件能同时监听 onMessage;槽位排他,同一时间只有一个 ContextEngine 在跑。启动时 OpenClaw 读 plugins.slots.contextEngine 配置值,找到对应工厂方法实例化,找不到直接报错退出,不偷偷回退默认引擎。

{
  plugins: {
    slots: {
      // 选当前上下文引擎,默认 legacy
      // 设为插件 id 即启用插件引擎
      contextEngine: "legacy"
    }
  }
}

2.2 七个钩子管住上下文一生

ContextEngine 接口给出七个钩子,从引擎启动到子 agent 收工,每个关键节点都能插手。

  1. bootstrap:引擎初始化跑一次,连数据库、建图结构、加载上次状态;
  2. ingest(message):每来一条新消息触发,决定怎么存、怎么建索引;
  3. assemble(budget):调模型前调用,带着 token 预算问你要给模型看什么;
  4. compact:上下文撑破硬上限时瘦身,可摘要、可砍图节点、可不做事;
  5. afterTurn(turn):一轮结束,存状态、写持久化、跑后台索引;
  6. prepareSubagentSpawn(parentContext):派子 agent 时控制带走哪些信息;
  7. onSubagentEnded(result):子 agent 回来时决定结果怎么合进父级上下文。

插件通过 api.registerContextEngine(id, factory) 注册,核心零侵入。

export default function (api) {
  api.registerContextEngine("lossless-claw", (ctx) => ({
    info: { id: "lossless-claw", name: "Lossless Claw", ownsCompaction: true },
    async ingest { return { ingested: true }; },
    async assemble({ messages, sessionKey, availableTools, citationsMode }) {
      return {
        messages,
        estimatedTokens: 0,
        systemPromptAddition: buildMemorySystemPromptAddition({
          availableTools: availableTools ?? new Set,
          citationsMode,
          agentId: resolveSessionAgentId({ config: ctx.config, sessionKey }),
          agentSessionKey: sessionKey,
        }),
      };
    },
    async compact { return { ok: true, compacted: false }; },
  }));
}

2.3 ownsCompaction 的两种模式

压缩是 ContextEngine 的职责之一,ownsCompaction 标记决定谁干。设为 true 走自有模式,自己实现压缩算法;设为 false 走委托模式,compact 调 delegateCompactionToRuntime(...) 用 OpenClaw 内置压缩。注意 false 不等于自动回退,no-op 的 compact 不安全,会关掉正常压缩路径。

三、能支撑哪些策略

同一套接口,能跑出完全不同的上下文管理思路。

策略类型 assemble 思路 compact 思路 适用场景
legacy 滑动窗口 按时间顺序拼最近消息 线性摘要最早消息 默认、轻量对话
RAG 检索组装 按语义相关性捞历史 不主动压缩 长对话多话题
冷热分层 按需从不同层拉取 旧数据下沉到冷层 超长会话
任务感知 按任务类型动态取舍 保留任务关键节点 写代码 vs 闲聊
DAG 无损保留 图节点遍历 旧片段摘要、原文留图 长程引用、合规审计

3.1 已落地的两个插件

Lossless-Claw(Martian Engineering 出品)是第一个有分量的 ContextEngine 插件。每条消息变成 DAG 节点,按话题相关性分组成片段,预算超了摘要旧片段但原文留图里,后面再聊到旧内容直接取回原文,不将就摘要。MemOS Cloud Plugin(MemTensor 出品)更轻,启动时从 MemOS Cloud 召回相关记忆,每轮结束存回,组装时注入,做跨会话记忆。

3.2 自己接一个引擎的步骤

  1. 实现 ContextEngine 接口,七个钩子按需实现;
  2. 在插件 bootstrap 里调 api.registerContextEngine("my-engine", factory);
  3. 配置 plugins.slots.contextEngine: "my-engine" 切换;
  4. 用 openclaw doctor 验证引擎加载正常;
  5. 出错时引擎被隔离,OpenClaw 回退 legacy 保证用户轮次能回复,修复后再上。

这层抽象的真正价值不在某个策略多强,而在于把 agent 体验里最难也最值钱的一层——上下文质量——开放给生态。插件开发者、企业合规、研究者、模型厂商各自能在自己关心的点上发力。

常见问题(FAQ)

Q1:换引擎后旧会话怎么办?

旧会话沿用当前历史,新引擎接管后续运行,无需迁移。

Q2:ownsCompaction 设 false 能不实现 compact 吗?

不能,no-op 会关掉压缩路径,须委托给 runtime。

Q3:插件引擎崩了会拖垮整个 agent 吗?

不会,引擎被隔离,回退 legacy 保证回复,修复后再上。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 qiqicto@qq.com 举报,一经查实,本站将立刻删除。
赞 (0)
套餐观察官的头像套餐观察官普通用户

相关推荐

返回顶部