technical architecture plugins contextengine

ContextEngine 深度解析:OpenClaw 2026.3.7 如何把上下文管理變成外掛

OpenClaws.io Team

OpenClaws.io Team

@openclaws

March 9, 2026

10 分鐘

ContextEngine 深度解析:OpenClaw 2026.3.7 如何把上下文管理變成外掛

AI agent 好不好用,很大程度取決於一件你看不見的事:上下文管理。對話歷史、工具呼叫的結果、外部知識——這些東西怎麼塞進模型那個有限的窗口,決定了 agent 是真能幫上忙,還是一本正經地胡說八道。在 OpenClaw 2026.3.7 之前,這套邏輯是寫死在核心裡的。現在,它是一個外掛。

原來有什麼問題

OpenClaw 之前用的是滑動視窗壓縮:對話太長了,就把舊訊息摘要一下,給新訊息讓路。能跑,但很多人不滿意:

  • 壓縮必然丟資訊。寫程式的 agent 要引用 50 輪前寫的函式?摘要裡早就沒了。
  • 關了就忘。對話一結束,上下文清零。agent 沒有跨對話的記憶。
  • 想換策略沒門。你想用 RAG、想做對話分支、想自己管 token 預算——沒有正經的擴充口,只能 hack。

社群的解決辦法五花八門:monkey-patch 內部模組、fork 核心程式碼、在外面套一層編排。折騰是折騰了,都不是長久之計。

ContextEngine:把上下文管理變成可替換的外掛

2026.3.7 做了一件乾脆的事:把上下文的整個生命週期抽成介面,開放為外掛槽位(slot)。你寫一個外掛,實作這套介面,就能完全接管 agent 的上下文邏輯。

怎麼接入

外掛透過 API 註冊自己的 ContextEngine:

typescript
// In your plugin's bootstrap
export default function myContextPlugin(api: PluginAPI) {
  api.registerContextEngine('my-engine', (config) => {
    return new MyCustomContextEngine(config);
  });
}

使用者在設定裡選一下就行:

yaml
plugins:
  slots:
    contextEngine: my-engine

什麼都不設定?照常用。OpenClaw 會套上 LegacyContextEngine,滑動視窗該怎麼跑還怎麼跑,老使用者完全無感。

七個鉤子,管住上下文的一生

ContextEngine 介面給了你七個鉤子,從引擎啟動到子 agent 收工,每個關鍵節點都能插手:

1. `bootstrap()`

引擎初始化時跑一次。連資料庫、建圖結構、載入上次存下來的狀態,都在這兒幹。

typescript
async bootstrap(): Promise<void> {
  this.vectorStore = await connectToVectorDB(this.config.dbUrl);
  this.sessionGraph = new DAG();
}

2. `ingest(message: Message)`

每來一條新訊息就觸發——不管是使用者說的、agent 回的、還是工具吐出來的。你在這裡決定怎麼存、怎麼建索引。

typescript
async ingest(message: Message): Promise<void> {
  // Add to the DAG
  const node = this.sessionGraph.addNode(message);
  // Index for retrieval
  const embedding = await embed(message.content);
  await this.vectorStore.upsert(node.id, embedding, message);
}

3. `assemble(budget: TokenBudget): AssembledContext`

最核心的一個。每次要調模型之前,OpenClaw 會帶著 token 預算來問你:給我組裝上下文。你回傳什麼,模型就看到什麼。

不同的引擎在這裡可以玩出完全不同的花樣:

typescript
async assemble(budget: TokenBudget): AssembledContext {
  const recentMessages = this.sessionGraph.getRecent(budget.soft * 0.6);
  const relevantHistory = await this.vectorStore.query(
    this.currentQuery,
    budget.soft * 0.3
  );
  const systemContext = this.buildSystemPrompt(budget.soft * 0.1);

  return {
    system: systemContext,
    messages: [...relevantHistory, ...recentMessages],
    tokenEstimate: this.estimateTokens([systemContext, ...relevantHistory, ...recentMessages]),
  };
}

4. `compact()`

上下文撐破硬上限了,OpenClaw 喊你來瘦身。預設引擎會摘要舊訊息;你的外掛可以砍掉圖裡不相關的節點,可以往向量庫裡挪,也可以什麼都不做——如果你在 assemble() 裡就已經控制住了。

5. `afterTurn(turn: Turn)`

一輪對話結束(使用者說完、agent 答完)。存個狀態、寫個持久化、跑個背景索引,都適合放這兒。

6. `prepareSubagentSpawn(parentContext: Context): SubagentContext`

agent 要派子 agent 出去幹活了。給多少上下文?全給會撐爆 token,不給又兩眼一抹黑。這個鉤子讓你精確控制子 agent 帶走哪些資訊。

typescript
prepareSubagentSpawn(parentContext: Context): SubagentContext {
  // Give the subagent a focused slice of context
  const relevantNodes = this.sessionGraph.getSubtree(parentContext.taskId);
  return {
    messages: relevantNodes.map(n => n.message),
    metadata: { parentSessionId: this.sessionId },
  };
}

7. `onSubagentEnded(result: SubagentResult)`

子 agent 幹完活回來了。它帶回來的結果怎麼合進父級上下文?全收、摘要、還是挑著要?你說了算。

架構細節:slot 不是 hook

ContextEngine 在外掛體系裡是個槽位,不是鉤子。區別在哪?鉤子是疊加的,十個外掛可以同時監聽 onMessage;槽位是排他的,同一時間只能有一個 ContextEngine 在跑。

┌─────────────────────────────────────┐
│           Plugin Registry           │
│                                     │
│  Hooks(可疊加):                    │
│    onMessage  → [plugin1, plugin2]  │
│    onTool     → [plugin3]           │
│                                     │
│  Slots(只能選一個):                │
│    contextEngine → my-engine        │
│    (預設: LegacyContextEngine)      │
└─────────────────────────────────────┘

啟動時 OpenClaw 讀 plugins.slots.contextEngine 的設定值,找到對應的工廠方法,實例化。找不到?直接報錯退出,不會偷偷回退到預設引擎——這是刻意的設計,避免你以為在用自訂引擎其實跑的是預設的。

子 agent 之間的隔離靠 AsyncLocalStorage:每個子 agent 有自己的執行時作用域,外掛狀態不會串台。

已經有人在用了

Lossless-Claw

GitHub · Martian Engineering 出品

第一個有份量的 ContextEngine 外掛。用基於 DAG 的摘要系統替掉了滑動視窗,做到了在 token 上限內保留每一條原始訊息。

  • 每條訊息變成有向無環圖裡的一個節點
  • 按話題相關性自動分組成「片段」
  • 預算超了,舊片段會被摘要——但原始訊息還留在圖裡
  • 後面如果又聊到了舊內容,引擎直接取回原文,不用將就摘要

寫程式的人應該能體會:100 輪前定義的函式,突然又要用了,滑動視窗早就把它壓沒了,Lossless-Claw 還能翻出來。

MemOS Cloud Plugin

GitHub · MemTensor 出品

一個很輕的外掛,就幹一件事:讓 agent 記住你

  • 啟動時從 MemOS Cloud 召回跟當前話題相關的記憶
  • 每輪對話結束後把新內容存回去
  • 組裝上下文時把記憶注入進來

效果就是:上週聊過的事、你的偏好、你正在做的專案——agent 都記得,不用你每次重複交代。

接下來會冒出什麼

翻翻 GitHub issue 和 Discord,社群已經在搞這些:

  • RAG 原生組裝:不再拼訊息歷史,直接用檢索到的文件片段組裝上下文。OpenClaw 秒變對話式搜尋引擎。
  • 多 agent 共享記憶:幾個 agent 共用一張知識圖譜,協作幹活時不用重複同步資訊。
  • Token 預算自動調配:根據你用的模型貴不貴、快不快,動態調整上下文怎麼分配。
  • 對話分支:樹狀結構,一條對話岔出去探索不同方向,隨時切回來,歷史不丟。

這件事為什麼重要

OpenClaw 之前能加頻道、加模型、加工具,但上下文這一層——說白了就是 agent 的「腦子怎麼運轉」——一直是個碰不得的黑盒。

ContextEngine 把這個盒子撬開了。往後的事情會一環扣一環:

  1. 1.外掛開發者終於能在 agent 體驗裡最難也最值錢的地方發力了——上下文品質。
  2. 2.企業使用者可以做合規:資料到模型之前先脫敏、留存策略強制執行、每個 prompt 輸入了什麼全程可稽核。
  3. 3.研究者驗證新的上下文策略,再也不用 fork 整個專案。
  4. 4.模型廠商可以出官方外掛,針對自家架構最佳化上下文組裝——長視窗模型和短視窗模型,策略本來就該不一樣。

這就是從框架變成平台的樣子。不靠改名,不靠發公告,靠的是一個實實在在的架構改動,讓生態開始自己轉起來。外掛越多 → 使用者越多 → 開發者越多 → 外掛更多。飛輪一旦轉起來,就很難停下了。

龍蝦又長出了一隻新鉗子。

訂閱更新

第一時間收到新功能和整合資訊。不會發垃圾信,隨時可以退訂。