上下文引擎 (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 |
防重放洪水守卫 |
| 🧩 组装 | freshTailCount、freshTailMaxTokens、promptAwareEviction、stubLargeToolPayloads |
保护新鲜尾部、按相关性/时间裁剪、大载荷存根 |
| 🗜️ 压缩 | contextThreshold(默认 0.75)、leafChunkTokens、sweepMaxDepth、leafMinFanout |
阈值触发、叶子大小、凝聚深度、扇出 |
| ⏳ 延迟模式 | proactiveThresholdCompactionMode: deferred |
非阻塞、后台排水 |
| 🚑 急救 | compactUntilUnderDeadlineMs(默认 300s) |
溢出恢复硬限预算 |
| 🛠️ 维护 | autoRotateSessionFiles、transcriptGcEnabled |
轮转、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:在子会话开始前准备共享上下文状态(接收父/子会话键、contextMode(isolated或fork)等),可返回回滚句柄,在生成失败时调用。若请求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: booleancompacted: booleansessionTarget?:类型ContextEngineSessionTarget,用于指示压缩后应切换到哪个后继会话。sessionId?:后继会话的 ID(一般与sessionTarget结合使用)。
可选成员(增强功能)
| 成员 | 用途 |
|---|---|
bootstrap(params) |
引擎首次看到会话时调用(例如导入历史记录) |
maintain(params) |
在引导、轮次成功或压缩后维护记录(可重写转录) |
ingestBatch(params) |
批量摄取一个完整轮次的所有消息(运行后调用) |
afterTurn(params) |
轮次结束后的持久化/后台压缩触发 |
prepareSubagentSpawn(params) |
子会话开始前准备共享状态 |
onSubagentEnded(params) |
子会话结束后的清理 |
dispose() |
释放资源(网关关闭或插件重载时调用,非会话级) |
🛠️ 高级特性与生产建议
🔐 运行时设置(runtimeSettings)
生命周期钩子会收到一个只读的 runtimeSettings 对象,包含当前执行环境的上下文信息:
schemaVersion:当前为1runtime:主机类型("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 会将选中的插件引擎与核心回复路径隔离。如果引擎缺失、契约验证失败、工厂抛出异常或生命周期方法抛出异常,系统会:
- 在当前 Gateway 进程中隔离该引擎。
- 自动降级 到内置
legacy引擎,保证智能体继续响应。 - 记录错误日志,供运维人员修复。
但主机要求失败属于硬性约束,会直接导致启动失败,以防引擎在不受支持的环境中损坏状态。
💾 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 的上下文引擎通过清晰的生命周期钩子 和强大的插件机制 ,让你能够完全掌控模型输入的构建过程。无论是简单的线性摘要,还是基于检索的复杂记忆系统,都能通过实现几个核心方法快速集成。同时,故障隔离 和自动回退保证了生产环境的稳定性,让你放心探索高级上下文策略。