【插件】OpenClaw 上下文引擎指南

上下文引擎 (Context Engine)是 OpenClaw 的核心组件,负责构建、压缩和管理每一次模型调用的上下文------它决定哪些历史消息被保留、如何总结早期对话,以及如何在子智能体(subagent)之间传递记忆。


🎯 上下文引擎

LLM 的上下文窗口是有限的(例如 128k tokens),但会话可能持续数千轮。传统做法是简单地"先进先出"或"滑动窗口",但这会丢失关键信息。OpenClaw 的上下文引擎提供了一套可插拔的生命周期钩子,让你可以:

  • 精准控制:哪些消息进入模型?顺序如何?如何压缩?
  • 跨会话回忆:通过外部存储(如向量数据库)实现长期记忆。
  • 子智能体隔离:为子任务创建独立或继承的上下文环境。
  • 故障隔离:即使引擎出错,也不会导致主回复流程中断。

🚀 快速开始:

1️⃣ 检查当前引擎

bash 复制代码
openclaw doctor
# 或直接查看配置
cat ~/.openclaw/openclaw.json | jq '.plugins.slots.contextEngine'

默认输出为 "legacy",即内置的经典引擎。

2️⃣ 安装一个插件引擎

安装方式与普通插件一致:

  • 从 npm 安装openclaw plugins install @martian-engineering/lossless-claw
  • 从本地路径安装 (开发调试):openclaw plugins install -l ./my-context-engine

3️⃣ 启用并配置引擎

编辑 ~/.openclaw/openclaw.json(JSON5 格式):

json5 复制代码
{
  plugins: {
    slots: {
      contextEngine: "lossless-claw", // 必须与插件注册的引擎 id 一致
    },
    entries: {
      "lossless-claw": {
        enabled: true,
        // 插件专属配置(参考其文档)
      },
    },
  },
}

配置完成后重启 Gateway 网关即可生效。

4️⃣ 切回旧版引擎(可选)

只需将 contextEngine 设置为 "legacy" 或直接删除该键(默认即为 "legacy")。


⚙️ 工作原理:生命周期

每当 OpenClaw 需要调用模型时,上下文引擎会依次经历以下阶段:
#mermaid-svg-78vYPb7KBP5Cpttz{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-78vYPb7KBP5Cpttz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-78vYPb7KBP5Cpttz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-78vYPb7KBP5Cpttz .error-icon{fill:#552222;}#mermaid-svg-78vYPb7KBP5Cpttz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-78vYPb7KBP5Cpttz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-78vYPb7KBP5Cpttz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-78vYPb7KBP5Cpttz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-78vYPb7KBP5Cpttz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-78vYPb7KBP5Cpttz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-78vYPb7KBP5Cpttz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-78vYPb7KBP5Cpttz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-78vYPb7KBP5Cpttz .marker.cross{stroke:#333333;}#mermaid-svg-78vYPb7KBP5Cpttz svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-78vYPb7KBP5Cpttz p{margin:0;}#mermaid-svg-78vYPb7KBP5Cpttz .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-78vYPb7KBP5Cpttz .cluster-label text{fill:#333;}#mermaid-svg-78vYPb7KBP5Cpttz .cluster-label span{color:#333;}#mermaid-svg-78vYPb7KBP5Cpttz .cluster-label span p{background-color:transparent;}#mermaid-svg-78vYPb7KBP5Cpttz .label text,#mermaid-svg-78vYPb7KBP5Cpttz span{fill:#333;color:#333;}#mermaid-svg-78vYPb7KBP5Cpttz .node rect,#mermaid-svg-78vYPb7KBP5Cpttz .node circle,#mermaid-svg-78vYPb7KBP5Cpttz .node ellipse,#mermaid-svg-78vYPb7KBP5Cpttz .node polygon,#mermaid-svg-78vYPb7KBP5Cpttz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-78vYPb7KBP5Cpttz .rough-node .label text,#mermaid-svg-78vYPb7KBP5Cpttz .node .label text,#mermaid-svg-78vYPb7KBP5Cpttz .image-shape .label,#mermaid-svg-78vYPb7KBP5Cpttz .icon-shape .label{text-anchor:middle;}#mermaid-svg-78vYPb7KBP5Cpttz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-78vYPb7KBP5Cpttz .rough-node .label,#mermaid-svg-78vYPb7KBP5Cpttz .node .label,#mermaid-svg-78vYPb7KBP5Cpttz .image-shape .label,#mermaid-svg-78vYPb7KBP5Cpttz .icon-shape .label{text-align:center;}#mermaid-svg-78vYPb7KBP5Cpttz .node.clickable{cursor:pointer;}#mermaid-svg-78vYPb7KBP5Cpttz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-78vYPb7KBP5Cpttz .arrowheadPath{fill:#333333;}#mermaid-svg-78vYPb7KBP5Cpttz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-78vYPb7KBP5Cpttz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-78vYPb7KBP5Cpttz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-78vYPb7KBP5Cpttz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-78vYPb7KBP5Cpttz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-78vYPb7KBP5Cpttz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-78vYPb7KBP5Cpttz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-78vYPb7KBP5Cpttz .cluster text{fill:#333;}#mermaid-svg-78vYPb7KBP5Cpttz .cluster span{color:#333;}#mermaid-svg-78vYPb7KBP5Cpttz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-78vYPb7KBP5Cpttz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-78vYPb7KBP5Cpttz rect.text{fill:none;stroke-width:0;}#mermaid-svg-78vYPb7KBP5Cpttz .icon-shape,#mermaid-svg-78vYPb7KBP5Cpttz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-78vYPb7KBP5Cpttz .icon-shape p,#mermaid-svg-78vYPb7KBP5Cpttz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-78vYPb7KBP5Cpttz .icon-shape .label rect,#mermaid-svg-78vYPb7KBP5Cpttz .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-78vYPb7KBP5Cpttz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-78vYPb7KBP5Cpttz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-78vYPb7KBP5Cpttz :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ⚠️ 已超预算
✅ 未超预算
⚙ stubLargeToolPayloads=true
📨 新消息到达
📥 ingest 摄入持久化
🔍 assemble 组装前检查
🚑 紧急同步 compactUntilUnder
🧩 assemble 组装:摘要 + freshTail
🧠 模型推理
🔄 afterTurn 轮次结束
📊 记录阈值压缩债务
⏳ 后台异步排水 / maintain()
🌿 叶子摘要 / 凝聚摘要 生成
🗂️ 更新摘要 DAG
👤 用户触发 /compact
🔎 显式全量扫描压缩
💥 上下文窗口溢出
🚑 compactUntilUnder 急救压缩
📦 large_files 外部存储

阶段 关键配置 行为
📥 摄入 replayFloodThresholdExternal / Internal 防重放洪水守卫
🧩 组装 freshTailCountfreshTailMaxTokenspromptAwareEvictionstubLargeToolPayloads 保护新鲜尾部、按相关性/时间裁剪、大载荷存根
🗜️ 压缩 contextThreshold(默认 0.75)、leafChunkTokenssweepMaxDepthleafMinFanout 阈值触发、叶子大小、凝聚深度、扇出
⏳ 延迟模式 proactiveThresholdCompactionMode: deferred 非阻塞、后台排水
🚑 急救 compactUntilUnderDeadlineMs(默认 300s) 溢出恢复硬限预算
🛠️ 维护 autoRotateSessionFilestranscriptGcEnabled 轮转、GC

🔍 验证方式

快速检查 --- 运行状态命令:

bash 复制代码
/lossless          # 或
/lcm status

输出一览:

信息项 说明
当前 frontier token 当前前沿 token 位置
压缩比 摘要压缩比
待处理维护状态 pending / running / last-failure
摘要计数 摘要总数,含 broken / truncated 标记

深入排查 --- 查看独立日志:

bash 复制代码
tail -f /tmp/openclaw/lossless-claw-$(date +%F).log

💡 搜索关键词 [lcm] (compact|assembly|maintain|auto-rotate) 即可定位真实执行轨迹。

摄取(ingest)

当新消息(用户或助手)加入会话时,引擎可以将其存储到自己的数据存储中,或建立索引(例如用于后续检索)。

参数sessionId, message, isHeartbeat 等。

组装(assemble)

每次模型运行 调用,引擎返回一个有序消息列表 ,必须符合当前的令牌预算(tokenBudget)。同时可返回:

  • systemPromptAddition:追加到系统提示词前的字符串(如动态回忆指令)。
  • estimatedTokens:引擎估算的组装后总令牌数,用于压缩阈值判断。
  • promptAuthority:控制预检查使用哪个估算值(默认 "assembled",即基于组装后的结果检查溢出)。
  • contextProjection(可选):为支持持久化线程的后端(如 Codex app-server)提供"线程引导"模式,避免每轮重复投影。

压缩(compact)

当上下文窗口已满 ,或用户执行 /compact 命令时触发。引擎需要将较早的历史总结为更紧凑的形式(如摘要、向量摘要等)。

返回 CompactResult,可指明压缩后的新会话标识(sessionTarget),用于后续路由。

轮次结束后(afterTurn)

模型运行完成后调用,引擎可持久化状态、触发后台压缩或更新索引。

除此之外,引擎还可以实现:

  • maintain() :在引导启动、每轮成功完成或压缩后执行"维护任务",可通过 runtimeContext.rewriteTranscriptEntries() 安全重写对话记录。将 info.turnMaintenanceMode 设为 "background" 可使其异步执行,不阻塞回复。
  • 子智能体钩子
    • prepareSubagentSpawn:在子会话开始前准备共享上下文状态(接收父/子会话键、contextModeisolatedfork)等),可返回回滚句柄,在生成失败时调用。若请求 lightContext 且解析为 isolated,则跳过此钩子。
    • onSubagentEnded:子会话结束后的清理工作。

🏛️ 内置 Legacy 引擎 vs 插件引擎

旧版引擎(legacy)

  • 摄取:无操作(由会话管理器直接持久化)。
  • 组装:直接传递,由运行时的清理→验证→限制流水线处理。
  • 压缩:委托给内置的摘要机制,生成早期消息的摘要,保留近期完整消息。
  • 轮次结束后:无操作。
  • 不注册工具,不提供 systemPromptAddition
特性 Legacy 引擎 插件引擎(任意)
自定义存储/索引 ✅ 通过 ingest 自由实现
消息组装策略 固定(运行时流水线) 完全自由,可基于外部记忆
压缩算法 内置摘要 任意(DAG、向量检索等)
系统提示动态注入 systemPromptAddition
子智能体上下文控制 ✅ 通过 prepareSubagentSpawn
故障隔离 稳定(无需隔离) 被隔离后自动回退到 Legacy

🧩 开发一个插件引擎:接口详解

注册入口

typescript 复制代码
export default function register(api) {
  api.registerContextEngine("my-engine", (ctx) => ({
    info: {
      id: "my-engine",
      name: "My Context Engine",
      ownsCompaction: true, // 是否自主管理压缩
    },
    // ... 生命周期方法
  }));
}

核心必需成员

成员 类型 说明
info 属性对象 包含 id, name, version?, ownsCompaction
ingest(params) 异步方法 存储单条消息,返回 { ingested: boolean }
assemble(params) 异步方法 构建消息列表,返回 AssembleResult(见下文)
compact(params) 异步方法 压缩上下文,返回 CompactResult
AssembleResult 字段
字段 类型 必需 说明
messages Message\[\] 有序消息列表(发送给模型)
estimatedTokens number 引擎估算的总令牌数
systemPromptAddition string 可选 添加到系统提示之前
promptAuthority "assembled" | "preassembly_may_overflow" 可选 控制溢出预检查使用哪个估算值。若引擎 ownsCompaction: true,默认跳过预检查;设置此值为 "preassembly_may_overflow" 可强制保留预检查(取组装前后估算值较大者)。
contextProjection ContextEngineProjection 可选 为支持持久化线程的后端提供"线程引导"模式(mode: "thread_bootstrap" + epoch),避免每轮重新投影。
CompactResult 字段
  • ok: boolean
  • compacted: boolean
  • sessionTarget?:类型 ContextEngineSessionTarget,用于指示压缩后应切换到哪个后继会话。
  • sessionId?:后继会话的 ID(一般与 sessionTarget 结合使用)。

可选成员(增强功能)

成员 用途
bootstrap(params) 引擎首次看到会话时调用(例如导入历史记录)
maintain(params) 在引导、轮次成功或压缩后维护记录(可重写转录)
ingestBatch(params) 批量摄取一个完整轮次的所有消息(运行后调用)
afterTurn(params) 轮次结束后的持久化/后台压缩触发
prepareSubagentSpawn(params) 子会话开始前准备共享状态
onSubagentEnded(params) 子会话结束后的清理
dispose() 释放资源(网关关闭或插件重载时调用,非会话级)

🛠️ 高级特性与生产建议

🔐 运行时设置(runtimeSettings)

生命周期钩子会收到一个只读的 runtimeSettings 对象,包含当前执行环境的上下文信息:

  • schemaVersion:当前为 1
  • runtime:主机类型("openclaw" 等)、模式(normal/fallback/degraded
  • contextEngineSelection:所选引擎 ID 及来源
  • executionHost:调用界面的主机 ID 和标签
  • model:请求的模型、解析后的模型、提供商及系列
  • limits:提示词令牌预算、最大输出令牌数(若已知)
  • diagnostics:回退/降级原因代码(若已知)

若旧版引擎将 runtimeSettings 视为未知属性而拒绝,OpenClaw 会重试不带该属性,保证兼容性。

🖥️ 主机要求(hostRequirements)

引擎可以在 info.hostRequirements 中声明对宿主的能力要求。例如,若引擎必须通过 assemble() 完全控制提示词,则应声明 assemble-before-prompt

typescript 复制代码
info: {
  id: "my-engine",
  hostRequirements: {
    "agent-run": {
      requiredCapabilities: ["assemble-before-prompt"],
      unsupportedMessage: "请使用原生 Codex 或 OpenClaw 嵌入式运行时,或切换回 Legacy 引擎。",
    },
  },
}
  • 原生 Codex 和 OpenClaw 嵌入式运行时满足此能力。
  • 通用 CLI 后端不满足,因此该引擎在 CLI 进程启动前会被拒绝。

🧯 故障隔离

OpenClaw 会将选中的插件引擎与核心回复路径隔离。如果引擎缺失、契约验证失败、工厂抛出异常或生命周期方法抛出异常,系统会:

  1. 在当前 Gateway 进程中隔离该引擎。
  2. 自动降级 到内置 legacy 引擎,保证智能体继续响应。
  3. 记录错误日志,供运维人员修复。

主机要求失败属于硬性约束,会直接导致启动失败,以防引擎在不受支持的环境中损坏状态。

💾 ownsCompaction 的两种模式

该属性控制运行时是否自动启用内置的"单次尝试内压缩":

ownsCompaction 含义 推荐实现
true 引擎自己管理压缩,运行时跳过自动溢出压缩 compact() 中实现自己的压缩逻辑
false 或未设置 运行时保留 自动压缩路径,但插件仍需在 compact() 中调用 delegateCompactionToRuntime(...) 来实际触发内置压缩 调用 SDK 的委派函数,否则 /compact 和溢出恢复会失效

⚠️ 重要:ownsCompaction: false 并不意味着自动使用 Legacy 压缩------你必须显式委派。

🔗 与记忆(Memory)插件的关系

  • 记忆插件plugins.slots.memory)负责检索/搜索,例如从向量库中召回相关片段。
  • 上下文引擎 负责组装视图,决定模型到底看到什么。
  • 二者可协同:引擎可在 assemble 时调用记忆插件的数据,并通过 buildMemorySystemPromptAddition() 辅助函数将准备好的记忆提示词转换成 systemPromptAddition,无需暴露记忆插件的内部布局。

✂️ 会话裁剪

无论哪个引擎活动,OpenClaw 始终在内存中裁剪旧的工具结果(tool results),以保持基本的内存健康。


📝 配置参考(JSON5)

json5 复制代码
{
  plugins: {
    slots: {
      // 选中的上下文引擎 ID,默认为 "legacy"
      contextEngine: "legacy",
    },
    entries: {
      // 引擎插件的启用状态及配置
      "my-engine": {
        enabled: true,
        // ... 引擎特定配置
      },
    },
  },
}
  • 该槽位具有排他性:每次运行或压缩只解析一个引擎。
  • 若卸载当前选中的引擎,OpenClaw 会自动将槽位重置为 "legacy"(记忆槽位同理),无需手动编辑。

💡 实用小贴士

  • openclaw doctor 随时验证引擎是否加载成功。
  • 切换引擎不会影响已有会话的历史记录,后续运行由新引擎接管。
  • 开发时使用 openclaw plugins install -l ./my-engine 链接本地目录,无需每次复制。
  • 若插件引擎发生错误,会记录并隔离,但用户轮次会回退到 Legacy,请及时修复插件。

🧪 完整插件示例(TypeScript)

typescript 复制代码
import { buildMemorySystemPromptAddition } from "openclaw/plugin-sdk/core";

export default function register(api) {
  api.registerContextEngine("my-engine", (ctx) => ({
    info: {
      id: "my-engine",
      name: "My Engine",
      ownsCompaction: false,
      hostRequirements: {
        "agent-run": {
          requiredCapabilities: ["assemble-before-prompt"],
        },
      },
    },

    async ingest({ sessionId, message }) {
      // 存储到自定义 DB
      await myDB.store(sessionId, message);
      return { ingested: true };
    },

    async assemble({ sessionId, messages, tokenBudget, availableTools, citationsMode, agentSessionKey }) {
      // 自定义排序/筛选/检索
      const contextualMessages = await myRetriever.retrieve(sessionId, messages, tokenBudget);
      const addition = buildMemorySystemPromptAddition({
        availableTools: availableTools ?? new Set(),
        citationsMode,
        agentSessionKey,
      });
      return {
        messages: contextualMessages,
        estimatedTokens: countTokens(contextualMessages),
        systemPromptAddition: addition,
      };
    },

    async compact({ sessionId, force }) {
      // 使用内置委派(因为 ownsCompaction: false)
      return await delegateCompactionToRuntime({ sessionId, force });
    },

    async afterTurn({ sessionId }) {
      // 异步更新索引
      await myIndexer.update(sessionId);
    },
  }));
}

📚 总结

OpenClaw 的上下文引擎通过清晰的生命周期钩子强大的插件机制 ,让你能够完全掌控模型输入的构建过程。无论是简单的线性摘要,还是基于检索的复杂记忆系统,都能通过实现几个核心方法快速集成。同时,故障隔离自动回退保证了生产环境的稳定性,让你放心探索高级上下文策略。

相关推荐
Rocky Ding*1 小时前
【三年面试五年模拟】2026-08-18_哔哩哔哩AI应用岗Agent开发一面面经全解析(含完整答案)
论文阅读·人工智能·深度学习·机器学习·aigc·ai-native·ai agent
geneculture1 小时前
基于融智学框架的领军人才实训实操示范基地建设: 课题、课程与项目的系统工程(人机三双协同即人机双脑双智双语协同)
人工智能·融智学的重要应用·哲学与科学统一性·融智时代(杂志)·序位逻辑的实例化·人机三双协同
key_3_feng1 小时前
智能体 Loop 工程:循环架构与状态机
人工智能·loop·智能体
冬奇Lab1 小时前
Code Agent 解剖(08):一个任务太复杂,怎么拆给子 agent 做?
人工智能·开源
冬奇Lab1 小时前
开源项目第195期:OpenTelemetry Demo(Astronomy Shop)— 官方出品的分布式系统可观测性实战教材
人工智能·开源·前端工程化
云烟成雨TD1 小时前
LlamaIndex 系列【5】智能体开发:大语言模型接入与基础调用
ai·agent·rag·llamaindex
海兰1 小时前
【原理】OpenClaw Agent 运行时回顾一文清
人工智能·agent
民乐团扒谱机1 小时前
【微实验】物理启发神经网络(PINN):当AI学会遵守物理定律(附matlab代码))
人工智能·神经网络·matlab
极客互动API2 小时前
企业微信 iPad 协议消息接口开发:文本 / 图片 / 群发消息的统一封装
人工智能·ios·微信·机器人·企业微信·ipad