OpenClaw 3.7 最重磅更新:ContextEngine 插件接口源码级拆解 —— AI Agent 上下文管理从此告别硬编码

OpenClaw 3.7 最重磅更新:ContextEngine 插件接口源码级拆解 —— AI Agent 上下文管理从此告别硬编码

本文出自 AI Agent 记忆系统逆向工程 项目 —— 我们逆向拆解了 OpenClaw、nanobot、NullClaw、OpenFang 4 个开源 AI Agent 框架的记忆系统,源码级记录每一个设计细节。30+ 篇文档、全架构图,全部开源。如果觉得有价值,欢迎 ⭐ Star 支持。
导读: OpenClaw 3.7 beta 更新了 89 项代码提交,其中最重磅的一条是 ContextEngine 插件接口上线。社区有人评论"等这个接口等了快半年",点赞数秒过百。这篇文章不讲概念,直接拆源码,带你看清楚这个接口到底解决了什么问题、怎么解决的、以及你能从中学到什么。

一、先搞清楚:AI Agent 的上下文管理为什么是"最头疼的问题"?

你跟 AI 对话,每一轮历史消息都作为"上下文"送给模型。模型需要看到之前聊了什么,才知道你现在在问什么。

问题出在这里:模型的上下文窗口有大小限制

128K token 的窗口,你聊了 200 轮,加上工具调用的返回值,token 早就爆了。这时候系统得做决策——

  • 哪些消息留下?最近的肯定要,但"最近"的边界在哪?
  • 旧消息怎么处理?直接砍掉,还是压缩成摘要?
  • 送给模型时怎么排列?系统提示 + 历史 + 工具 schema,顺序和内容怎么组装?

这就是上下文管理(Context Management)。每个实用的 AI Agent 框架都绕不开。

关键在于:这些处理逻辑一旦写死在核心代码里,日后每次调整都是高风险手术。


二、旧架构有多痛?读完源码你就懂了

我们逆向了 OpenClaw v2026.3.7 之前的源码,旧的上下文管理是一条完全硬编码的流水线,散布在 5+ 个文件里,没有任何抽象层:

用户消息进来 → SessionManager 写入 JSONL → 加载全部历史消息 → sanitize(清洗,约 10 个步骤) → validate(按 provider 校验) → limit(暴力截断) → repair(修复孤儿消息) → 送给模型 

2.1 sanitize 有多复杂?

这个函数叫 sanitizeSessionHistory(),名字平平无奇,里面塞了大约 10 个处理步骤

  1. 标注跨会话用户消息
  2. 清理/缩放图片(不同模型有不同图片限制)
  3. 删除 <thinking>
  4. 规范化工具调用的名称和 ID
  5. 修复孤立的 tool_use → tool_result 配对
  6. 删除工具返回值中的冗余字段
  7. 清理过期的 assistant usage 快照
  8. 记录模型快照元数据
  9. 降级 OpenAI 推理格式(仅 OpenAI Responses API)
  10. 修复 Google/vLLM 的轮次顺序约束(仅 Google provider)

2.2 压缩逻辑是最大的坑

当 token 快要超限时,系统有个"压缩"机制——把旧对话总结成摘要,删掉原始消息。

这个逻辑在 compact.ts(约 763 行),是最大的痛点。为什么?因为压缩需要调模型来生成摘要,而调模型需要完整的上下文环境,于是 compact.tsattempt.ts大量环境构建代码复制了一遍

compact.ts 独立重复的逻辑: ├── resolveModel() — 模型解析(attempt.ts 也有一份) ├── resolveModelAuthMode() — 认证模式(attempt.ts 也有一份) ├── resolveSandboxContext() — 沙箱配置(attempt.ts 也有一份) ├── resolveChannelCapabilities() — 频道能力(attempt.ts 也有一份) ├── sanitize→validate→limit→repair — 完整管线(attempt.ts 也有一份) └── ...还有更多 

改一处忘了改另一处?上线即 bug。

2.3 三种压缩触发方式,全是硬编码

旧架构有三种压缩触发方式:

  • SDK 自动检测:Agent 运行期间检测到即将超限,主动触发
  • 用户手动 /compact:用户在对话中输入命令
  • Overflow 重试:模型返回 token 超限错误,自动重试(最多 3 次)

问题不在于触发方式不够多,而在于——你无法通过插件替换这些策略。想自定义"什么时候该压缩"的判断逻辑?只能改核心代码。

2.4 痛点总结

痛点具体表现
逻辑散落散布在 sanitize、validate、limit、repair、compact 5+ 个文件
大量重复compact.ts 复制了 attempt.ts 的模型解析、沙箱配置等大量代码
无法替换想换个压缩算法?必须改核心代码
策略硬编码三种压缩触发方式全硬编码在核心代码
无后处理Agent 一轮结束后没有任何钩子做后续优化
子 Agent 隔离父子 Agent 之间没有上下文共享/清理机制

微信文章里说的"改一处崩全程",指的就是这些。


三、ContextEngine 的核心思路:把"做什么"和"怎么做"分开

OpenClaw 3.7 的 ContextEngine 接口(PR #22201,44 个文件改动),解决方案其实很经典——定义一组接口,让核心运行时只关心"要做什么",具体"怎么做"交给可替换的引擎

用官方的话说,这叫零阻碍接入

翻译成人话:以后换个上下文处理算法,像换插件一样简单。

3.1 七个生命周期钩子

ContextEngine 定义了 7 个钩子,覆盖了上下文的完整生命周期:

会话开始 → ① bootstrap() — 初始化引擎状态 → ② ingest() — 每条消息摄入 → ③ assemble() — 组装模型上下文 → 调用模型 → ④ afterTurn() — 回合后处理 → ⑤ compact() — 需要压缩时执行 子 Agent 场景: → ⑥ prepareSubagentSpawn() — 准备子 Agent 上下文 → ⑦ onSubagentEnded() — 清理子 Agent 上下文 

用人话对照一下变化:

从前(硬编码)现在(ContextEngine 钩子)意味着什么
消息直接写入 JSONLingest() — 引擎决定怎么存可以存到向量库、做预处理
sanitize→validate→limit→repairassemble() — 引擎决定怎么组装可以用 RAG、用检索、用任何算法
三种硬编码压缩方式compact() — 引擎决定怎么压可以不压、可以自定义摘要策略
回合结束什么都不做afterTurn() — 引擎做后处理可以异步优化上下文
子 Agent 完全独立prepareSubagentSpawn() + onSubagentEnded()父子 Agent 可以共享上下文

3.2 接口定义(精简版)

interfaceContextEngine{readonly info: ContextEngineInfo;// 3 个必选 = 上下文管理的三件核心事ingest(params:{ sessionId, message }):Promise<IngestResult>;assemble(params:{ sessionId, messages, tokenBudget?}):Promise<AssembleResult>;compact(params:{ sessionId, sessionFile, tokenBudget?,...}):Promise<CompactResult>;// 4 个可选 = 增强能力 bootstrap?(params):Promise<BootstrapResult>; afterTurn?(params):Promise<void>; prepareSubagentSpawn?(params):Promise<SubagentSpawnPreparation |undefined>; onSubagentEnded?(params):Promise<void>;}

3 个必选方法覆盖了上下文管理最本质的三件事:消息怎么存、上下文怎么组、太多了怎么压。4 个可选方法提供增强能力,不实现也不影响基本运转。

这个设计非常克制——不多不少,刚好够用。


四、向后兼容的艺术:LegacyContextEngine 与绞杀者模式

引入新接口最怕什么?Breaking change

OpenClaw 用了一个经典的架构模式——Strangler Fig(绞杀者模式):在旧系统外面包一层新接口,旧逻辑原封不动跑在新接口里。

LegacyContextEngine 就是这个包装器:

方法实际做了什么效果
ingest()返回 { ingested: false },什么都不做SessionManager 照旧处理
assemble()原样返回 messages,不改动旧管线照旧跑
compact()调用原来的压缩函数压缩逻辑完全不变
afterTurn()空操作没有副作用

结果:不配置任何 context engine 插件时,系统行为和升级前 100% 一致。零风险升级。

这就是为什么 89 项代码提交能顺利上线的原因——不是蛮力堆功能,是架构上保证了不破坏已有行为。


五、注册与解析机制:怎么做到"换插件一样简单"?

5.1 进程全局注册表

// 通过 Symbol.for() 挂在 globalThis 上// 为什么?monorepo 构建可能把模块打包成多份拷贝// Symbol.for() 确保不管有几份 js 文件,注册表只有一个constREGISTRY= Symbol.for("openclaw.contextEngineRegistryState");registerContextEngine(id, factory);// 注册getContextEngineFactory(id);// 获取listContextEngineIds();// 列出所有

5.2 Slot 机制

constDEFAULT_SLOT_BY_KEY={ memory:"memory-core",// 记忆插件 contextEngine:"legacy",// 上下文引擎};

一个坑位只能站一个人。两个插件都声明 kind: "context-engine",只有被配置选中的那个加载。

5.3 一行配置搞定切换

{"plugins":{"slots":{"contextEngine":"lossless-claw"}}}

不配这一行 → 默认 "legacy" → 行为不变。

这就是"像换插件一样简单"的实现原理。


六、实战:10 分钟写一个自定义 Context Engine

这不是空谈,看代码:

exportdefaultfunctionregister(api){ api.registerContextEngine("my-rag-context",()=>({ info:{ id:"my-rag-context", name:"RAG Context", ownsCompaction:true},asyncingest({ sessionId, message }){// 每条消息写入向量数据库await vectorDb.insert(sessionId, message);return{ ingested:true};},asyncassemble({ sessionId, messages, tokenBudget }){// 不是暴力截断,而是 RAG 检索最相关的历史消息const relevant =await vectorDb.search(sessionId, latestQuery, tokenBudget);return{ messages: relevant, estimatedTokens:countTokens(relevant)};},asynccompact({ sessionId }){// RAG 模式下不需要压缩——assemble 时按需检索return{ ok:true, compacted:false};},}));}

三个核心方法,加起来不到 20 行。但效果是什么?你把上下文管理从"暴力截断"变成了"语义检索",而且没有改动 OpenClaw 的任何核心代码。


七、ContextEngine ≠ 记忆系统,别搞混了

很多人会混淆这两个概念。简单区分:

ContextEngine(上下文管理)Memory 插件(记忆系统)
管什么当前 session 内的消息流跨 session 的持久化知识库
核心问题哪些消息送给模型、何时压缩怎么索引、搜索、存取记忆
生命周期一个 session 内跨越所有 session
存储session JSONL 文件Markdown 文件 + SQLite/LanceDB

它们之间的桥梁是 Memory Flush——在 ContextEngine 执行压缩之前,先触发一个静默 Agent 回合,提醒 Agent 把值得保留的对话内容写入记忆文件。

上下文管理决定"模型这次能看到什么",记忆系统决定"Agent 下周还记得什么"。两者协同但独立。


八、从 ContextEngine 学到的架构思维

不管你用不用 OpenClaw,这次的 ContextEngine 设计有几个通用的工程模式值得带走:

8.1 绞杀者模式(Strangler Fig)

新接口包装旧逻辑,渐进式替换。不一口气重写,而是让新旧共存,逐步迁移。这在任何大型系统的重构中都适用。

8.2 接口 + 注册表 + 配置驱动

定义接口 → 工厂函数注册到全局注册表 → 配置文件选择用哪个引擎 → 运行时动态解析。这套模式在Java 的 SPI、Python 的 entry_points、Rust 的 trait 中都有对应。

8.3 Best-effort 回调

子 Agent 生命周期回调失败只记日志不阻断主流程。在分布式系统中,"让非关键路径的失败不影响主路径"是基本原则。

8.4 必选 + 可选方法分离

3 个必选方法保证核心能力,4 个可选方法扩展增强能力。实现者可以从最简开始,逐步增加功能。


九、这跟我们做的事有什么关系?

我们的项目(AI Agent 记忆系统逆向工程)做的事就是这个——逆向拆解 4 个火爆的开源 AI Agent 框架的记忆系统,源码级记录每一个设计细节

ContextEngine 只是 OpenClaw 分析的一部分。完整的文档覆盖了:

框架语言特点文档数
🦞 OpenClawTypeScript插件架构、混合搜索、优雅降级12 篇
🐈 nanobotPython极简主义,2 个 Markdown 文件搞定7 篇
NullClawZig10 种存储后端、9 阶段检索管线9 篇
🦀 OpenFangRust知识图谱、记忆衰减、统一 SQLite 底座10 篇

从 2 个 Markdown 文件到 10 种存储后端、从暴力截断到 9 阶段检索管线——4 种完全不同的设计哲学,让你一次看透 AI Agent 记忆系统的全貌。

适合谁?

  • 正在构建 AI Agent 的工程师:直接参考已经验证过的架构
  • 想理解"记忆"到底怎么实现的研究者:源码级拆解,不是概念堆砌
  • 想在 LangGraph / LangChain / 自研框架中做上下文管理的开发者:每个框架都有复刻指南

完整文档 + 架构图 + 代码分析,全部开源:

👉 GitHub 仓库:https://github.com/breath57/how-ai-agents-remember

如果觉得对你有帮助,给个 ⭐ 吧。我们还在持续更新。


十、总结

OpenClaw 3.7 的 ContextEngine 接口,核心价值用一句话概括:

以后换个上下文处理算法,像换插件一样简单,不用再担心改一处崩全程。

它不是一个"多了个功能"的小更新,而是一次架构层面的升级——把 AI Agent 中最头疼的上下文管理问题,从"硬编码在核心代码里"变成了"可插拔的标准接口"。

7 个生命周期钩子、绞杀者模式的向后兼容、全局注册表 + Slot 机制的引擎管理——这些设计模式不仅适用于 OpenClaw,同样适用于你正在做的任何 AI Agent 系统。

不论你用什么技术栈,上下文管理的核心问题是一样的。理解它、借鉴它、在你的项目中用好它。


本文基于 AI Agent 记忆系统逆向工程项目 中对 OpenClaw 的源码分析撰写。项目持续更新中,欢迎 Star 和 PR。

Read more

论文AI率从60%降到20%以内的完整攻略:亲测有效的3步法

论文AI率从60%降到20%以内的完整攻略:亲测有效的3步法

论文AI率从60%降到20%以内的完整攻略:亲测有效的3步法 上周一个学弟在群里发了一张截图,检测报告上面的AI率是63.4%,他已经修改了两遍,依然没降下来。他当时快崩溃了,说答辩在15天后,导师要求AI率必须低于20%,感觉毫无希望。 这种情况其实很多人都经历过。AI写的论文痕迹很重,换几个词、调整几句语序,根本没用,检测系统识别的是深层语言特征,不是表面文字。今天这篇文章,把我试验过的3步攻略完整写出来,60%能不能降到20%以内,看完你自己判断。 先搞清楚:为什么AI率这么难降 很多人修改了半天还是降不下来,根本原因是搞错了方向。 AIGC检测系统(知网、万方、大雅这些)识别的不是具体的词汇,而是语言模式。AI生成的文本有几个典型特征:句式结构高度规整、逻辑过渡词密集("首先、其次、再次、最后"这套)、段落长度均匀、主动被动句比例异常……这些特征是一个整体,你改几个词根本动不了这个模式。

CherryStudio使用指南——详细教程让你玩懂AI

CherryStudio使用指南——详细教程让你玩懂AI

文章目录 * 为什么使用? * 下载 * 安装 * 使用 * 添加模型 * API 调用 * 本地调用 * 测试使用 * 联网功能 * 添加网络搜索 * 使用网络搜索 * 数据设置 * MCP 使用 * 知识库 * 添加重排模型 * 添加知识库 * 使用知识库 * 迁移配置 * 备份 * 使用备份 为什么使用? CherryStudio 就相当于一个 AI 的合集,能够集合多模型对话,知识库管理,AI 绘画等各种功能的一个集合工具。 而且内容都是本地的,隐私性是拉满了。 当然,主要目的还是为了提升工作效率。 下载 客户端下载 | CherryStudio 直接进入该网站进行下载。 安装 双击下载的 exe 文件。 为所有用户安装,点击下一步。 可以更改一下路径,不用默认安装在 C 盘。

手把手教你开发“AI数据分析师”:利用IPIDEA + 智能体实现全网数据洞察

手把手教你开发“AI数据分析师”:利用IPIDEA + 智能体实现全网数据洞察

前言:为何需要构建一个更智能的数据助手 在当前人工智能的浪潮中,大语言模型(LLM)驱动的智能体(Agent)展现了巨大的潜力。理论上,它们可以自动化执行任务、分析数据,成为我们的得力助手。但在实际开发和使用中,我们常常会遇到一个瓶颈:智能体似乎“不够聪明”,无法获取最新、最真实的数据。这篇将记录并分享如何解决这一核心痛点,通过将智能体与专业的网络数据采集服务(IPIDEA)相结合,从零到一构建一个真正具备全网数据洞察能力的“AI数据分析师”。 第一章 为何我们的智能体“不够聪明” 在着手解决问题之前,首先需要清晰地界定问题本身。智能体在数据获取层面的“不聪明”主要源于两个相互关联的障碍:大模型自身的局限性和传统网络数据抓取的技术壁垒。 1.1 大模型的数据滞后与“幻觉”痛点 大语言模型的能力根植于其庞大的训练数据。然而,这些数据并非实时更新的。绝大多数模型的知识都存在一个“截止日期”,它们无法知晓在该日期之后发生的新闻、发布的财报、变化的商品价格或网络热点。当我们向智能体询问这些实时性要求高的问题时,它可能会坦白自己的知识局限,或者更糟糕地,它会根据已有的模式“

走进脉脉AI创作者xAMA:聊聊智能创作的那些门道!

走进脉脉AI创作者xAMA:聊聊智能创作的那些门道!

声明:本文纯属分享体验,非广告! 文章目录 * 一、为什么说,现在是AI创作者的“黄金窗口期”? * 二、脉脉xAMA:不止是“问答”,更是“AI创作实战指南” * 板块1:大咖开讲——从“技术底层”到“创作顶层”的认知升级 * 板块2:实时AMA——你的困惑,大咖当场拆 * 板块3:案例拆解——从“爆款AI作品”看底层逻辑 * 板块4:资源对接——让创作不止于“兴趣” * 板块5:AI 创作分享:探索智能创作新领域 * 三、谁该来?——所有想“用AI放大创作价值”的人 * 四、写在最后:AI创作的本质,是“人”的创作 在这个AI技术以“