2026年Agent上下文管理生态全景:从源码到架构决策

2026年Agent上下文管理生态全景:从源码到架构决策

一项基于源码阅读的实证性技术调研

摘要:本文对2026年4月Agent上下文管理(context management)领域的主要开源项目进行了源码级分析。调研覆盖了10个项目,共阅读约30万行源码,涉及TypeScript、Python、Go三种语言。通过对比各项目的架构设计、核心算法、接口耦合度和工程成熟度,本文得出结论:该领域已进入增量创新阶段,不存在可行的从0到1的独立项目方向。本文所有技术判断均基于对源码的直接阅读,每个关键论断附有文件路径和行号引用。


1 引言

1.1 研究动机

Agent系统在长时运行(long-running)场景中面临上下文窗口管理的核心挑战:对话历史、工具调用结果、任务状态的累积增长与有限的context window之间存在根本矛盾。本研究旨在回答一个实际问题:在2026年4月的技术生态中,是否存在一个值得从0到1构建的独立项目方向?

1.2 方法论

本研究采用源码阅读(source code reading)作为主要调研方法,而非依赖文档、README或博客文章。具体做法:

  1. 克隆目标项目的完整仓库到本地
  2. 从入口文件出发,沿调用链阅读核心实现
  3. 记录关键架构决策的具体文件位置(file:line格式)
  4. 对比不同项目在相同问题域的设计选择

1.3 调研范围

类别 项目 语言 核心代码量 阅读深度
宿主平台 OpenClaw TypeScript 350k+ star主仓库 ContextEngine接口、Registry、压缩管线
ContextEngine插件 lossless-claw TypeScript ~23,000行 全部核心模块
ContextEngine插件 Headroom Python ~211,000行 压缩管线、SmartCrusher、plugin层
工具插件 context-mode TypeScript plugin manifest + benchmark Manifest验证、工具定义
ContextEngine插件 OpenViking TypeScript plugin manifest + examples Manifest验证、能力声明
独立agent Hermes Agent Python ~10,000行(run_agent.py) context_compressor.py全部
记忆框架 Mem0 Python ~2,600行核心 Memory类、MemoryGraph类
记忆框架 Letta/MemGPT Python ~32,000行核心模块 Agent主循环、三层记忆工具、Summarizer
记忆框架 Zep Go ~7,900行legacy代码 全部store/model/graphiti层
MCP工具 ContextVault TypeScript ~1,500行 Server、VaultManager、IndexManager

2 宿主平台分析:OpenClaw ContextEngine接口

OpenClaw是当前最广泛使用的AI编码agent平台(350k+ GitHub stars)。其v2026.3.7版本引入了可插拔的ContextEngine接口,成为上下文管理插件的主要竞争平台。

2.1 ContextEngine接口定义

ContextEngine的完整生命周期合约定义于 src/context-engine/types.ts[^1],包含以下方法:

1
2
3
4
5
6
7
8
9
10
11
interface ContextEngine {
bootstrap(ctx: RuntimeContext): Promise<void>;
ingest(entry: AgentMessage, ctx: RuntimeContext): Promise<IngestResult>;
assemble(ctx: AssembleContext): Promise<AssembleResult>;
compact(ctx: CompactContext): Promise<CompactResult>;
afterTurn?(ctx: RuntimeContext): Promise<void>;
maintain?(ctx: RuntimeContext): Promise<void>;
prepareSubagentSpawn?(ctx: SubagentSpawnContext): Promise<SubagentPrepareResult>;
onSubagentEnded?(ctx: SubagentEndedContext): Promise<void>;
dispose?(): Promise<void>;
}

关键设计决策:

  • ownsCompaction?: booleantypes.ts:51):引擎可以声明自己拥有压缩逻辑,阻止runtime的自动压缩
  • runtimeContext.rewriteTranscriptEntries()types.ts:93-95):提供安全的transcript重写通道
  • systemPromptAddition?: stringAssembleResulttypes.ts:11):允许引擎向system prompt注入内容

2.2 排他性Slot系统

src/plugins/slots.ts[^2] 定义了两个排他性slot:

1
2
3
4
5
6
7
8
9
const SLOT_BY_KIND = {
memory: "memory",
"context-engine": "contextEngine",
}; // slots.ts:12-15

const DEFAULT_SLOT_BY_KEY = {
memory: "memory-core",
contextEngine: "legacy",
}; // slots.ts:17-20

applyExclusiveSlotSelection()slots.ts:76-162)实现winner-takes-all语义:当一个插件占据slot,其他同类插件被自动禁用。

架构含义:这意味着lossless-claw、Headroom和任何其他ContextEngine插件无法同时作为独立插件共存。如果要组合多个引擎的能力,必须构建一个meta-engine占据唯一的contextEngine slot,内部编排子引擎逻辑。

2.3 LegacyContextEngine:默认实现的空壳

src/context-engine/legacy.ts[^3] 实现了默认的LegacyContextEngine:

  • ingest() → 返回 { ingested: false },纯no-op(legacy.ts:~35
  • assemble() → 原样透传消息,estimatedTokens: 0legacy.ts:~45
  • compact() → 委托给 delegateCompactionToRuntime()legacy.ts:~55,调用 delegate.ts:16-63

真正的压缩逻辑在 src/agents/compaction.ts,硬编码了 BASE_CHUNK_RATIO = 0.4MIN_CHUNK_RATIO = 0.15SAFETY_MARGIN = 1.2——不可配置、不可组合。

2.4 五个架构缺陷

缺陷1:压缩是纯reactive的run.ts中的auto-compaction只在API返回context overflow error之后才触发,tool-use循环中没有pre-prompt的context size检查。Issue #24800记录了session从196K涨到200K后永久卡死的案例。

缺陷2:safeguard模式默认开启但静默失败src/config/defaults.ts:368设置 mode: "safeguard"[^4]。180K+ token时产生 "Summary unavailable due to context limits",上下文直接丢失,无警告。

缺陷3:两套hook系统不互通src/hooks/internal-hooks.tstriggerInternalHook()src/plugins/hooks.tshookRunner.runSessionEnd() 是独立系统。session-memory hook只监听 command:newcommand:resetsrc/hooks/bundled/session-memory/handler.ts:55-57[^5]),不监听 session_end

缺陷4:compaction后token计数归零clearStaleAssistantUsageOnSessionMessages()src/agents/pi-embedded-subscribe.handlers.compaction.ts:115-132[^6])清除所有assistant message的usage数据,而非只清除compaction之前的。

缺陷5:Registry是God Objectsrc/plugins/registry.ts 管理20+种注册类型(工具、hooks、CLI、HTTP路由、speech、媒体、channel、gateway、memory、contextEngine等),单文件混合认证、slot分配、provider冲突解决。


3 ContextEngine插件生态

3.1 lossless-claw:DAG无损压缩

仓库Martian-Engineering/lossless-claw
代码量:~23,000行TypeScript
核心架构:DAG-based conversation summarization with incremental compaction

3.1.1 依赖注入设计

LcmContextEngine 类(src/engine.ts:1199[^7])通过 LcmDependencies 接口(src/types.ts:105-165[^8])获取所有外部能力:

1
2
3
4
5
6
7
8
9
10
11
12
13
export interface LcmDependencies {
config: LcmConfig;
complete: CompleteFn; // LLM调用
callGateway: CallGatewayFn; // Gateway RPC
resolveModel: ResolveModelFn; // 模型解析
getApiKey: GetApiKeyFn; // 密钥获取
requireApiKey: RequireApiKeyFn;
parseAgentSessionKey: ParseAgentSessionKeyFn;
isSubagentSessionKey: IsSubagentSessionKeyFn;
normalizeAgentId: (id?: string) => string;
log: { info, warn, error, debug };
// ... 更多
}

engine.ts零OpenClaw import——核心逻辑链完全独立:

模块 文件 职责 OpenClaw耦合
存储层 conversation-store.ts, summary-store.ts 纯SQLite读写
压缩引擎 compaction.ts 摘要生成与DAG构建 仅通过CompleteFn类型
组装器 assembler.ts 上下文装配 仅type推导
检索 retrieval.ts FTS5全文搜索
插件胶水 plugin/index.ts 390行注册逻辑 完全耦合

3.1.2 上下文组装算法

ContextAssembler.assemble()src/assembler.ts:886-1059[^9])的核心流程:

  1. 从SQLite获取所有context items(消息 + 摘要),按ordinal排序
  2. 将每个item解析为 AgentMessage(获取底层消息或摘要记录)
  3. 将items分为可驱逐前缀受保护的fresh tail(默认64条消息,src/db/config.ts:255[^10])
  4. 如果超出token budget,从最旧的非fresh items开始丢弃
  5. 当prompt可用时,使用BM25-lite相关性评分决定保留优先级
  6. 摘要格式化为XML:<summary id="..." kind="leaf" depth="0">...

返回结果包含 messagesestimatedTokenssystemPromptAddition和详细统计。

3.1.3 压缩配置

CompactionConfigsrc/compaction.ts:33[^11])提供精细的压缩参数:

1
2
3
4
5
6
7
8
9
export interface CompactionConfig {
contextThreshold: number; // 默认0.75(budget的75%触发压缩)
freshTailCount: number; // 默认64(保护的最新消息数)
leafMinFanout: number; // depth-0摘要最少数量才触发condensation
condensedMinFanout: number; // depth>=1摘要condensation最少数量
leafChunkTokens: number; // 叶节点chunk的目标token数
leafTargetTokens: number; // 叶节点摘要目标长度
condensedTargetTokens: number; // 聚合摘要目标长度
}

支持四种压缩级别:"normal" | "aggressive" | "fallback" | "capped"

3.1.4 插件注册

src/plugin/index.ts[^12] 执行以下注册:

  • api.registerContextEngine("lossless-claw", ...)api.registerContextEngine("default", ...)——同时注册为命名引擎和默认引擎
  • api.registerTool() × 4:describe(查看摘要树)、expand(展开摘要为原始消息)、expand-query(按查询展开)、grep(全文搜索)
  • api.on("before_reset")api.on("session_end"):生命周期事件监听
  • api.registerCommand():CLI命令注册

工程判断:lossless-claw是调研范围内架构最干净的项目。其核心可以通过约100-150行adapter代码独立于OpenClaw使用,只需构造满足LcmDependencies接口的依赖对象。


3.2 Headroom:内容感知压缩管线

仓库chopratejas/headroom
代码量:~211,000行Python(465个.py文件)
核心架构:内容类型路由 + 统计驱动的压缩策略

3.2.1 压缩管线

headroom/transforms/pipeline.py:70-125[^13] 定义了默认的三级管线:

1
CacheAligner → ContentRouter → IntelligentContextManager
  • CacheAligner:prompt cache前缀稳定化,确保缓存字节前缀在turn间保持不变
  • ContentRouter:基于内容类型的智能路由(pipeline.py:81-89):
    • JSON数组 → SmartCrusher
    • 纯文本 → Kompress(ML-based)
    • 代码 → CodeCompressor(AST-aware)
    • 日志 → LogCompressor
    • 搜索结果 → SearchCompressor
    • HTML → HTMLExtractor
  • IntelligentContextManager:语义感知的上下文管理,策略链为 COMPRESS_FIRST → SUMMARIZE → DROP_BY_SCOREpipeline.py:116-119

降级路径(pipeline.py:91-123):

1
2
3
ContentRouter 不可用 → SmartCrusher(仅JSON)
SmartCrusher 不可用 → ToolCrusher(固定规则)
IntelligentContextManager 不可用 → RollingWindow(基于位置的滚动窗口)

3.2.2 SmartCrusher:统计驱动的JSON压缩

headroom/transforms/smart_crusher.py[^14](3,657行)是Headroom的核心创新:

文件头部的docstring明确了scope(smart_crusher.py:1-46):

“SCOPE: SmartCrusher handles JSON arrays of ANY type — dicts, strings, numbers, mixed types, and nested arrays. Non-JSON content (plain text, search results, logs, code, diffs) passes through UNCHANGED.”

“SCHEMA-PRESERVING: Output contains only items from the original array. No wrappers, no generated text, no metadata keys.”

关键安全保证:

  • First K + Last K items始终保留(K是自适应的,基于Kneedle算法,非硬编码)
  • 错误条目(包含’error’、’exception’、’failed’、’critical’)永远不丢弃
  • 异常数值(>2 std)始终保留
  • 变化点(change points)附近的items被保护
  • 基于RelevanceScorer的高相关性items保留(ML-powered或BM25-based)

支持的JSON类型(smart_crusher.py:25-31):

类型 压缩策略
dict数组 完整统计分析 + 自适应K(Kneedle)
字符串数组 去重 + 自适应采样 + 错误保留
数值数组 统计摘要 + 异常/变化点保留
混合类型数组 按类型分组,各组独立压缩
扁平对象(多key) Key级别自适应采样
嵌套对象 递归压缩内部数组/对象

3.2.3 OpenClaw集成

plugins/openclaw/src/engine.ts(240行)实现了 HeadroomContextEngine

  • 声明 ownsCompaction: true
  • assemble()AgentMessage 转为OpenAI格式 → 调用 compress() → 转回
  • compact() 本质上是no-op(”applies on next assemble()”)
  • 通过 import { compress } from "headroom-ai" 调用Python库(HTTP proxy方式)

engine.ts同样零OpenClaw import——核心压缩逻辑完全在Python库中。


3.3 context-mode:MCP工具方案

仓库mksglu/context-mode

关键发现:context-mode的manifest(openclaw.plugin.json)声明 "kind": "tool"[^15]——它不是ContextEngine插件。它通过MCP tools(ctx_execute_filectx_indexctx_search)提供功能,不参与ContextEngine的assemble/compact生命周期。

BENCHMARK.md声明整体节省率为96%[^16](非98%),主要针对tool output场景。

3.4 OpenViking:长期记忆

仓库volcengine/OpenViking(字节跳动)

manifest(examples/openclaw-plugin/openclaw.plugin.json)确认 "kind": "context-engine"[^17]。声明了完整的assemble/afterTurn/compact生命周期实现。功能包括:autoCapture、autoRecall、bypassSessionPatterns、commitTokenThreshold。


4 记忆框架:源码级分析

4.1 Mem0:LLM-in-the-loop的记忆CRUD

仓库mem0ai/mem0(48k stars)
核心文件mem0/memory/main.py(2,597行)、mem0/memory/graph_memory.py(744行)

4.1.1 架构概述

Mem0的核心类 Memorymain.py:258[^18])包含一个vector store和一个可选的graph store(Neo4j),两条路径通过 ThreadPoolExecutor 并行执行。

4.1.2 add() 方法调用链

Memory.add()main.py:383[^19])的真实执行流程:

  1. LLM提取facts:发送一次LLM调用(tool call模式),让模型从输入文本中抽取结构化记忆条目
  2. 搜索已有记忆:对每个抽取的fact做vector search,找到相似的已有记忆
  3. LLM决策:再发一次LLM调用,让模型对每条记忆做ADD/UPDATE/DELETE决策
  4. 执行存储操作:根据决策写入vector store

如果启用了graph store,步骤4还会并行执行 _add_to_graph()

1
2
3
4
# main.py - Memory.add() 内部
with concurrent.futures.ThreadPoolExecutor() as executor:
future1 = executor.submit(self._add_to_vector_store, ...)
future2 = executor.submit(self._add_to_graph, ...)

一次 memory.add() 最少需要2次LLM调用(fact提取 + 决策),启用graph后增加到5次。

4.1.3 Graph Memory实现

MemoryGraph类(graph_memory.py:29[^20])使用 langchain_neo4j.Neo4jGraph 做图存储。

add()方法(graph_memory.py:76[^21])的调用链:

  1. _retrieve_nodes_from_data()graph_memory.py:219)— LLM tool call提取实体和类型
  2. _establish_nodes_relations_from_data()graph_memory.py:252)— LLM tool call建立实体间关系
  3. _search_graph_db()graph_memory.py:294)— 对每个实体做embedding cosine相似度搜索:
1
2
3
4
5
6
7
8
# graph_memory.py:312
cypher_query = f"""
MATCH (n {self.node_label} {{{node_props_str}}})
WHERE n.embedding IS NOT NULL
WITH n, round(2 * vector.similarity.cosine(n.embedding, $n_embedding) - 1, 4) AS similarity
WHERE similarity >= $threshold
...
"""
  1. _get_delete_entities_from_search_output()graph_memory.py:347)— LLM tool call决定删除
  2. 执行删除和新增

图的删除是软删除graph_memory.py:423-428[^22]):

1
SET r.valid = false, r.invalidated_at = datetime()

这保留了关系的时间线,支持temporal reasoning。

搜索实现graph_memory.py:96-130[^23])使用BM25重排序:

1
2
3
4
from rank_bm25 import BM25Okapi
bm25 = BM25Okapi(search_outputs_sequence)
tokenized_query = query.split(" ")
reranked_results = bm25.get_top_n(tokenized_query, search_outputs_sequence, n=5)

4.1.4 架构局限

Mem0是一个”记忆数据库”,不是”上下文引擎”。它不感知token budget、不做context压缩、不参与prompt组装。开发者需要自己将Mem0的检索结果手动塞进prompt。这与OpenClaw的ContextEngine插件、lossless-claw的assembler是完全不同的抽象层次。


4.2 Letta/MemGPT:Agent-as-OS的三层记忆

仓库letta-ai/letta
核心文件letta/agents/letta_agent.py(1,983行)、letta/functions/function_sets/base.pyletta/schemas/block.pyletta/schemas/memory.pyletta/services/summarizer/summarizer.py

4.2.1 设计哲学

Letta的架构思想是把Agent当OS、把记忆当文件系统。三层记忆是三种不同的”内存地址空间”,Agent通过function calling(tool call)自主决策何时读写哪一层。

4.2.2 第一层:Core Memory(Block系统)

Block类(schemas/block.py:67[^24])是LLM上下文窗口内的一块可写区域:

1
2
3
4
5
class Block(BaseBlock):
value: str = Field(..., description="Value of the block.")
limit: int = Field(CORE_MEMORY_BLOCK_CHAR_LIMIT, ...)
label: Optional[str] = Field(None, description="Label of the block")
read_only: bool = Field(False)

预置两个Block:Humanblock.py:117,label=”human”)和 Persona(label=”persona”)。

Agent通过以下tool call修改Block:

  • core_memory_append(agent_state, label, content)base.py:246[^25]):
1
2
3
current_value = str(agent_state.memory.get_block(label).value)
new_value = current_value + "\n" + str(content)
agent_state.memory.update_block_value(label=label, value=new_value)
  • core_memory_replace(agent_state, label, old_content, new_content)base.py:263[^26]):
1
2
3
4
current_value = str(agent_state.memory.get_block(label).value)
if old_content not in current_value:
raise ValueError(f"Old content '{old_content}' not found in memory block '{label}'")
new_value = current_value.replace(str(old_content), str(new_content))
  • rethink_memory(agent_state, new_memory, target_block_label)base.py:283):整体重写Block

  • memory(agent_state, command, ...)base.py:10[^27]):类文件系统操作(create/str_replace/insert/delete/rename)。函数体是 raise NotImplementedError——实际路由在server端。

关键区别:这些是tool定义,Agent通过function calling自主决策写什么。不是自动提取,是Agent-driven的记忆管理。

4.2.3 第二层:Archival Memory(向量搜索)

archival_memory_insert(self, content, tags)base.py:164[^28])和 archival_memory_search(self, query, tags, tag_match_mode, top_k, start_datetime, end_datetime)base.py:194[^29])。

两个函数体都是 raise NotImplementedError("This should never be invoked directly.")——实际执行由Agent框架在tool call时路由到Passage store(PostgreSQL + 向量索引)。函数签名和docstring是给LLM看的,真正的存储逻辑在server端。

4.2.4 第三层:Recall Memory(消息搜索)

conversation_search(self, query, roles, limit, start_date, end_date)base.py:87[^30])是真正实现的:

1
2
3
4
5
6
messages = self.message_manager.list_messages_for_agent(
agent_id=self.agent_state.id,
actor=self.user,
query_text=query,
roles=roles, limit=limit,
)

使用hybrid search(文本 + 语义),支持按role、时间范围过滤。

4.2.5 Agent主循环

LettaAgent.step()letta_agent.py:174[^31])→ _step() → 循环(最多max_steps轮):

  1. _build_and_request_from_llm()letta_agent.py:328)— 组装上下文 + LLM调用
  2. 解析response的tool call
  3. _handle_ai_response()letta_agent.py:1714)— 执行tool call

Agent通过强制tool calling驱动(letta_agent.py:360-362[^32]):

1
2
3
if not response.choices[0].message.tool_calls:
stop_reason = LettaStopReason(stop_reason=StopReasonType.no_tool_call.value)
raise ValueError("No tool calls found in response, model must make a tool call")

每轮必须产出tool call,否则报错。这意味着每一轮交互都是一次完整的LLM调用,即使只是写一条记忆。

4.2.6 Summarization实现

Summarizer类(summarizer/summarizer.py:36[^33])支持两种模式(enums.py[^34]):

模式一:STATIC_MESSAGE_BUFFERsummarizer.py:244-300[^35])

固定buffer。当 len(all_in_context_messages) > message_buffer_limit 时,丢弃最旧消息,保留最近 message_buffer_min 条。如果有summarizer agent,异步触发背景摘要。

模式二:PARTIAL_EVICT_MESSAGE_BUFFERsummarizer.py:136-242[^36])

原始MemGPT方案。按比例(默认30%,partial_evict_summarizer_percentagesummarizer.py:49)驱逐最旧消息,用一次LLM调用生成摘要(simple_summary()summarizer.py:188),插入到 context[1] 位置(system_message后的第一条)。

1
2
3
# summarizer.py:241-242
updated_in_context_messages = all_in_context_messages[assistant_message_index:]
return [all_in_context_messages[0], summary_message_obj, *updated_in_context_messages], True

关键观察:摘要触发是message数量驱动的(message_buffer_limit),不是token数量驱动的。这与现代大模型的context window管理方式脱节——不同消息的token数差异可达100x(一条简单回复 vs 一个大型tool output)。

4.2.7 ContextWindowOverview

schemas/memory.py[^37] 定义了 ContextWindowOverview,包含四种记忆的统计:

  • core_memory:当前Block内容和token数
  • archival_memory:passages总数
  • recall_memory:messages总数
  • summary_memory:最近的摘要(如有)

4.2.8 架构评价

  • 概念完整度最高(三层 + Agent自主管理),但每层都需要LLM调用,延迟和成本累积很快
  • Core Memory的”Agent自主写”模式对system prompt的prompt engineering要求极高
  • Summarizer按message数量触发,不感知实际token使用
  • Archival和Recall的存储实现在server端(ORM + PostgreSQL),client SDK拿到的是间接接口

4.3 Zep:从Go服务器到Graphiti HTTP壳

仓库getzep/zep(25k stars)
核心文件legacy/src/store/memory_ce.golegacy/src/lib/graphiti/service_ce.go(300行)、legacy/src/store/memory_common.golegacy/src/store/message_common.go(547行)

4.3.1 项目现状

Zep分为两个阶段:

  • 阶段一(开源Go服务器):包含消息存储、NER、摘要、嵌入、搜索的完整记忆服务
  • 阶段二(当前):开源代码移入 legacy/ 目录,核心产品变为Zep Cloud(闭源SaaS)。当前仓库的README(README.md:56-58[^38])明确说明:

“Note: This repository is currently a work in progress. This repository contains examples, integrations, and tools…”

4.3.2 CE版核心:Graphiti HTTP Client

读了legacy代码后的关键发现:即使是”完整的”Go服务器,CE版的记忆逻辑也只是一个Graphiti HTTP客户端

memory_ce.go[^39] 的 _get() 方法(第15-57行):

1
2
3
4
5
6
7
8
9
10
11
12
13
func (dao *memoryDAO) _get(ctx context.Context, session *models.Session,
messages []models.Message, _ models.MemoryFilterOptions) (*models.Memory, error) {
mForRetrieval := messages
if len(messages) > maxMessagesForFactRetrieval { // maxMessagesForFactRetrieval = 4
mForRetrieval = messages[len(messages)-maxMessagesForFactRetrieval:]
}
memory, err := graphiti.I().GetMemory(ctx, graphiti.GetMemoryRequest{
GroupID: groupID,
MaxFacts: 5,
Messages: mForRetrieval,
})
// ...转换Graphiti返回的facts为本地Fact结构
}

_initializeProcessingMemory()memory_ce.go:59-72[^40])同样只是HTTP POST:

1
2
3
4
5
6
7
func (dao *memoryDAO) _initializeProcessingMemory(...) error {
err := graphiti.I().PutMemory(ctx, session.SessionID, memoryMessages.Messages, true)
if session.UserID != nil {
err = graphiti.I().PutMemory(ctx, *session.UserID, memoryMessages.Messages, true)
}
return err
}

4.3.3 Graphiti服务接口

graphiti/service_ce.go[^41] 定义的 Service 接口(第80行)全是HTTP调用:

1
2
3
4
5
6
7
8
9
10
type Service interface {
GetMemory(ctx context.Context, payload GetMemoryRequest) (*GetMemoryResponse, error)
PutMemory(ctx context.Context, groupID string, messages []models.Message, ...) error
Search(ctx context.Context, payload SearchRequest) (*SearchResponse, error)
AddNode(ctx context.Context, payload AddNodeRequest) error
GetFact(ctx context.Context, factUUID uuid.UUID) (*Fact, error)
DeleteFact(ctx context.Context, factUUID uuid.UUID) error
DeleteGroup(ctx context.Context, groupID string) error
DeleteMessage(ctx context.Context, messageUUID uuid.UUID) error
}

每个方法内部都是 s.newRequest(ctx, method, path, body) + s.doRequest(req, &resp)——标准HTTP client模式(service_ce.go:118-165)。

Graphiti本身是一个独立的Python temporal knowledge graph框架(同为Zep团队的开源项目),支持valid_at/invalid_at时间戳的关系管理。Zep CE只是它的一个Go包装层。

4.3.4 消息存储

message_common.go[^42] 使用PostgreSQL(bun ORM)。GetLastN()message_common.go:135-184)按ID倒序取N条消息。metadata更新支持JSON merge + advisory lock防并发(message_common.go:394-451)。

4.3.5 数据模型

Memorymodels/memory_common.go:86-92[^43]):

1
2
3
4
5
type MemoryCommon struct {
Messages []Message `json:"messages"`
RelevantFacts []Fact `json:"relevant_facts"`
Metadata map[string]any `json:"metadata,omitempty"`
}

Factmodels/fact_common.go[^44]):只有UUID、CreatedAt、Fact(字符串)、Rating(可选浮点)。

Sessionmodels/session_common.go:10-22[^45]):标准会话模型,含SessionID、UserID、Metadata、时间戳。

4.3.6 架构评价

能力 实现情况
知识图谱 ❌ 无自有实现,全部委托外部Graphiti服务
会话摘要 ❌ GetMemory只返回最后N条消息 + 最多5个facts
Token budget管理 ❌ 完全不存在
Context压缩 ❌ 完全不存在
消息搜索 ❌ 无embedding、无FTS,只有Graphiti代理搜索
消息存储 ✅ PostgreSQL CRUD

结论:评估Zep的真实能力边界需要去读 getzep/graphiti 仓库的Python代码,不是这个Go服务器。Go服务器只是一个REST API壳 + PostgreSQL消息CRUD + Graphiti HTTP client。


4.4 ContextVault:Markdown文件系统 + MCP工具

仓库ahmadzein/ContextVault
核心文件contextvault-mcp/src/vault/manager.ts(493行)、contextvault-mcp/src/vault/index-manager.ts(452行)、contextvault-mcp/src/vault/types.ts

4.4.1 本质

ContextVault不是context压缩框架或记忆管理系统。它是一个MCP server,把知识存在本地markdown文件里,通过MCP tools让AI助手读写这些文件。

4.4.2 存储模型

VaultSettingstypes.ts:3-12[^46]):

1
2
3
4
5
6
7
8
9
10
export interface VaultSettings {
mode: 'local' | 'global' | 'full';
enforcement: 'light' | 'balanced' | 'strict';
limits: {
max_global_docs: number; // 默认50
max_project_docs: number; // 默认50
max_doc_lines: number; // 默认100
max_summary_words: number; // 默认15
};
}

两个tier:global(~/.contextvault/)和project(./.contextvault/)。每个tier有一个 index.md(markdown表格做索引)和若干 P001_*.md / G001_*.md 文件。

VaultManagermanager.ts[^47])核心操作都是 fs.readFileSync / fs.writeFileSync。没有数据库、没有向量索引、没有embedding。

4.4.3 搜索实现

IndexManager.search()index-manager.ts:346-363[^48]):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
search(query: string): IndexEntry[] {
const entries = this.parseEntries();
const queryTerms = queryLower.split(/\s+/);
return entries
.map(entry => {
const text = `${entry.id} ${entry.topic} ${entry.summary}`.toLowerCase();
let score = 0;
for (const term of queryTerms) {
if (text.includes(term)) score++;
}
return { entry, score };
})
.filter(r => r.score > 0)
.sort((a, b) => b.score - a.score)
.map(r => r.entry);
}

搜索范围是index.md中每条entry的topic和summary(各15个词以内)。不搜索文档正文。这是纯关键词匹配,不是语义搜索。

4.4.4 Enforcement机制

VaultManager跟踪agent的编辑次数和探索范围(manager.ts:195-372[^49])。当编辑超过阈值(balanced模式:8次编辑 + 2个文件),在tool response末尾追加reminder:

1
2
3
4
5
6
7
getEnforcementReminder(): string | null {
if (editCount >= editThreshold && filesEdited.size >= fileThreshold) {
return `\n\n---\n**ContextVault Reminder:** You've made ${editCount} edits
across ${filesEdited.size} files without documenting...`;
}
return null;
}

这是一个行为nudge系统,不是自动化的context管理。

4.4.5 文档模板

generateDocContent()manager.ts:376-440[^50])根据类型生成不同的markdown结构:

类型 模板结构
error Error / Root Cause / Solution / Prevention
decision Decision / Options Considered / Reasoning / Trade-offs
plan Goal / Steps / Status
handoff Completed / In Progress / Next Steps
intel Area Explored / Findings
explain Concept / Explanation

4.4.6 20+ MCP Tools

通过 ContextVaultServerserver.ts:35[^51])注册:ctx_initctx_docctx_errorctx_decisionctx_searchctx_readctx_planctx_handoffctx_bootstrapctx_changelogctx_quizctx_reviewctx_sharectx_archivectx_importctx_upgrade等。

4.4.7 架构评价

ContextVault解决的是”session间知识持久化”问题——确保AI在新会话中能访问到之前积累的知识。它不应被归类为”上下文管理”或”记忆框架”,更准确的定位是AI笔记本工具。其真正价值在于结构化的文档模板和行为nudge机制,而非技术上的context management创新。


5 独立Agent分析

5.1 Hermes Agent:单次LLM调用的上下文压缩

仓库NousResearch/hermes-agent
核心文件agent/context_compressor.py(745行)、run_agent.py(9,660行)

ContextCompressor.compress()context_compressor.py:612-745[^52])的流程:

  1. 修剪旧的tool results(保留结构但截断内容)
  2. 确定压缩边界(哪些消息需要摘要)
  3. 生成摘要——仅1次LLM调用_generate_summary()内部,context_compressor.py:404
  4. 组装压缩后的context

工程特征run_agent.py是一个9,660行的单文件脚本,不是模块化的类结构。这使得复用或集成Hermes的上下文管理逻辑非常困难。


6 跨项目比较与分析

6.1 分类学

本文调研的项目可以按问题域分为四类:

类别 解决什么 代表项目
上下文引擎 管理LLM context window的完整生命周期(ingest/assemble/compact) lossless-claw, Headroom, OpenViking
记忆数据库 存储和检索跨session的记忆/知识 Mem0, Letta/MemGPT
记忆服务 提供hosted的记忆/知识图谱API Zep (Cloud)
知识持久化 在session间保存结构化文档 ContextVault

这四类解决的是上下文管理栈的不同层次,不是竞品关系

6.2 LLM调用开销对比

项目 一次记忆写入的LLM调用数 说明
lossless-claw 1 compact时一次summarization call
Headroom 0 纯算法压缩(ML模型是本地的,非LLM API)
Mem0 2-5 2次(vector path) + 3次(graph path额外)
Letta/MemGPT 1+ 每次tool call是一轮LLM交互
Hermes Agent 1 单次summary call
ContextVault 0 纯文件读写

6.3 token budget感知

项目 感知token budget 主动压缩 压缩触发方式
lossless-claw contextThreshold: 0.75 ✅ budget 75%时自动触发 Token比例
Headroom ✅ IntelligentContextManager ✅ 管线自动执行 Token数量
OpenClaw默认 ❌ 仅在API overflow后reactive 错误触发
Mem0 N/A(不参与context组装)
Letta/MemGPT 部分 Message数量(非token)
Zep CE N/A
ContextVault N/A

6.4 耦合度与可复用性

项目 与宿主平台耦合度 独立复用所需adapter代码量
lossless-claw engine.ts 零import ~100-150行(构造LcmDependencies)
Headroom核心 零import ~50行(Python库直接import)
Letta三层记忆 深度耦合(server端ORM) 不可行(需要整个server)
Mem0 Memory类 松耦合 ~20行(直接pip install)
Zep CE 依赖外部Graphiti服务 不可行(需要部署Graphiti)
ContextVault MCP标准接口 ~10行(MCP client配置)

7 Meta-Engine可行性分析

7.1 动机

既然lossless-claw和Headroom的核心逻辑都可以独立于OpenClaw使用,是否可以构建一个meta-engine组合两者的能力?

7.2 技术可行性

可行。预计~500行代码:

  1. 占据OpenClaw的contextEngine slot
  2. 内部实例化lossless-claw的 LcmContextEngine(需要构造 LcmDependencies
  3. assemble() 的输出上运行Headroom的 compress() 管线
  4. 将lossless-claw的结构化摘要(XML格式)与Headroom的tool output压缩组合

7.3 价值分析

lossless-claw的assembler输出包含两类内容:

  1. 摘要<summary> XML节点)——已经是压缩后的文本,Headroom再压缩的边际收益极低
  2. Fresh tail原始消息(默认64条)——其中tool output部分可以被Headroom的SmartCrusher有效压缩

因此组合价值仅限于fresh tail中的tool output部分——对tool-heavy的编码场景有意义,但对纯对话、写作等场景价值有限。

7.4 战略结论

技术上可行,但战略上不成立:

  • 目标用户群窄(仅tool-heavy场景受益)
  • 两个上游项目都在活跃开发,维护成本高
  • OpenClaw自身也在改进默认压缩(reactive → proactive的issue已被讨论)

8 为什么最终放弃找独立项目方向

8.1 排除矩阵

方向 排除原因 源码证据
通用压缩中间件 Headroom已做(211k行Python,Apache 2.0) headroom/transforms/pipeline.py
记忆存储框架 Mem0(48k星,AWS集成)、Letta(三层架构)已做 mem0/memory/main.py, letta/functions/function_sets/base.py
独立任务状态管理 天生与agent框架深度耦合 OpenClaw src/tasks/task-registry.ts内存Map
OpenClaw ContextEngine实现 lossless-claw/Headroom/OpenViking/context-mode已做 各项目manifest和engine.ts
Memory OS Letta概念完整,MemOS/MemoryOS学术实现已有 letta/schemas/memory.py
编码agent特化 Claude Code/Cursor/Windsurf定义了体验天花板 N/A(市场判断)
Meta-engine 仅对tool-heavy场景有价值(§7) lossless-claw assembler + Headroom SmartCrusher分析
知识持久化工具 ContextVault已做(MCP标准接口) contextvault-mcp/src/vault/manager.ts

8.2 最终判断

这个领域在2026年4月已进入增量创新(incremental innovation)阶段。

每个子问题域都有至少一个具备工程成熟度的开源解决方案。剩下的工作是:各方案在自己的场景内优化细节(lossless-claw改进BM25评分、Headroom增加新的ContentRouter类型、Letta优化Summarizer触发策略)。没有可以从0到1构建的、既有足够价值又没有人做的独立方向。

方向仍然是harness工程——在特定场景(特定模型、特定任务类型、特定部署约束)内,通过组合现有工具链构建深度优化的agent体验。


附录A:源码引用索引

以下所有引用基于2026年4月10-14日期间从各项目主分支克隆的代码版本。

[^1]: OpenClaw src/context-engine/types.ts — ContextEngine接口定义,含bootstrap/ingest/assemble/compact/afterTurn等生命周期方法。ownsCompaction字段位于第51行,rewriteTranscriptEntries()位于第93-95行,systemPromptAddition位于AssembleResult类型第11行。

[^2]: OpenClaw src/plugins/slots.ts — 排他性slot系统。SLOT_BY_KIND定义于第12-15行,DEFAULT_SLOT_BY_KEY定义于第17-20行,applyExclusiveSlotSelection()实现于第76-162行。

[^3]: OpenClaw src/context-engine/legacy.ts — LegacyContextEngine实现。ingest()返回{ingested: false}assemble()透传且estimatedTokens: 0compact()委托给delegateCompactionToRuntime()。全文约85行。

[^4]: OpenClaw src/config/defaults.ts:368 — 默认compaction模式设为"safeguard"

[^5]: OpenClaw src/hooks/bundled/session-memory/handler.ts:55-57 — session-memory hook仅监听event.type === "command"event.action === "new" || "reset"

[^6]: OpenClaw src/agents/pi-embedded-subscribe.handlers.compaction.ts:115-132clearStaleAssistantUsageOnSessionMessages()清除所有assistant message的usage数据。

[^7]: lossless-claw src/engine.ts:1199LcmContextEngine implements ContextEngine,构造函数接受LcmDependencies + DatabaseSync。全文4,306行。

[^8]: lossless-claw src/types.ts:105-165LcmDependencies接口定义,包含config、complete、callGateway、resolveModel、getApiKey、requireApiKey、parseAgentSessionKey、isSubagentSessionKey、normalizeAgentId、log等字段。

[^9]: lossless-claw src/assembler.ts:886-1059ContextAssembler.assemble()方法。包含context items获取(SQLite)、fresh tail分割(默认64条)、token budget感知的选择、BM25-lite相关性评分、XML格式摘要输出。

[^10]: lossless-claw src/db/config.ts:255freshTailCount默认值为64。

[^11]: lossless-claw src/compaction.ts:33CompactionConfig接口,包含contextThreshold(默认0.75)、freshTailCount、leafMinFanout、condensedMinFanout等参数。CompactionLevel类型为"normal" | "aggressive" | "fallback" | "capped"。全文起始于第1行。

[^12]: lossless-claw src/plugin/index.ts — 插件注册胶水代码,390行。执行api.registerContextEngine("lossless-claw", ...)api.registerContextEngine("default", ...),注册4个工具(describe, expand, expand-query, grep),监听before_resetsession_end事件。

[^13]: Headroom headroom/transforms/pipeline.py:70-125 — 默认管线:CacheAligner → ContentRouter(或SmartCrusher fallback)→ IntelligentContextManager(或RollingWindow fallback)。ContentRouter路由策略定义于第81-89行。全文387行。

[^14]: Headroom headroom/transforms/smart_crusher.py:1-46 — SmartCrusher模块docstring。声明scope为”JSON arrays of ANY type”,safety保证包含first/last K保留、error item永不丢弃、异常值保留、change point保护。全文3,657行。

[^15]: context-mode openclaw.plugin.json — manifest声明"kind": "tool"。通过MCP tools(ctx_execute_file, ctx_index, ctx_search)提供功能。

[^16]: context-mode BENCHMARK.md — 整体节省率为96%(非98%)。

[^17]: OpenViking examples/openclaw-plugin/openclaw.plugin.json — manifest声明"kind": "context-engine"。功能包含autoCapture、autoRecall、bypassSessionPatterns、commitTokenThreshold。

[^18]: Mem0 mem0/memory/main.py:258Memory类定义。包含vector_store(必选)和graph store(可选,Neo4j)。同文件还有AsyncMemory类。全文2,597行。

[^19]: Mem0 mem0/memory/main.py:383Memory.add()方法。LLM调用提取facts → vector search找相似记忆 → LLM决策ADD/UPDATE/DELETE → 写入存储。graph路径通过ThreadPoolExecutor并行。

[^20]: Mem0 mem0/memory/graph_memory.py:29MemoryGraph类定义。使用langchain_neo4j.Neo4jGraph。初始化时创建Neo4j索引(entity_singleentity_composite)。

[^21]: Mem0 mem0/memory/graph_memory.py:76MemoryGraph.add()方法。调用链:_retrieve_nodes_from_data()(LLM实体提取)→ _establish_nodes_relations_from_data()(LLM关系建立)→ _search_graph_db()(embedding搜索)→ _get_delete_entities_from_search_output()(LLM删除决策)→ 执行。

[^22]: Mem0 mem0/memory/graph_memory.py:423-428 — 图关系软删除实现:SET r.valid = false, r.invalidated_at = datetime()

[^23]: Mem0 mem0/memory/graph_memory.py:96-130MemoryGraph.search()方法。使用rank_bm25.BM25Okapi对graph查询结果做BM25重排序。

[^24]: Letta letta/schemas/block.py:67Block类定义。字段包含value(str)、limit(CORE_MEMORY_BLOCK_CHAR_LIMIT)、label(如’human’、’persona’)、read_only。Human子类位于第117行。

[^25]: Letta letta/functions/function_sets/base.py:246core_memory_append()实现:new_value = current_value + "\n" + str(content)

[^26]: Letta letta/functions/function_sets/base.py:263core_memory_replace()实现:精确字符串替换,找不到old_content时抛ValueError。

[^27]: Letta letta/functions/function_sets/base.py:10memory()函数,类文件系统操作(create/str_replace/insert/delete/rename)。函数体为raise NotImplementedError

[^28]: Letta letta/functions/function_sets/base.py:164archival_memory_insert()。函数体为raise NotImplementedError("This should never be invoked directly."),实际路由在server端。

[^29]: Letta letta/functions/function_sets/base.py:194archival_memory_search()。支持query、tags、tag_match_mode(any/all)、top_k、start/end datetime。同为NotImplementedError。

[^30]: Letta letta/functions/function_sets/base.py:87conversation_search()。调用self.message_manager.list_messages_for_agent(),使用hybrid search,支持role和时间范围过滤。

[^31]: Letta letta/agents/letta_agent.py:174LettaAgent.step()方法入口。调用_step()执行循环,最多max_steps轮。

[^32]: Letta letta/agents/letta_agent.py:360-362 — 强制tool calling检查。无tool call时抛ValueError("No tool calls found in response, model must make a tool call")

[^33]: Letta letta/services/summarizer/summarizer.py:36Summarizer类定义。接受SummarizationModesummarizer_agentmessage_buffer_limit(默认10)、message_buffer_min(默认3)、partial_evict_summarizer_percentage(默认0.30)。

[^34]: Letta letta/services/summarizer/enums.pySummarizationMode枚举。两个值:STATIC_MESSAGE_BUFFERPARTIAL_EVICT_MESSAGE_BUFFER

[^35]: Letta letta/services/summarizer/summarizer.py:244-300_static_buffer_summarization()。固定buffer模式,超过limit时丢弃旧消息保留最近message_buffer_min条。

[^36]: Letta letta/services/summarizer/summarizer.py:136-242_partial_evict_buffer_summarization()。MemGPT原始方案,按30%比例驱逐最旧消息,生成摘要插入context[1]。

[^37]: Letta letta/schemas/memory.pyContextWindowOverview定义。包含core_memory、archival_memory(passages数量)、recall_memory(messages数量)、summary_memory。

[^38]: Zep README.md:56-58 — “Note: This repository is currently a work in progress. This repository contains examples, integrations, and tools for building intelligent agent context with Zep.”

[^39]: Zep legacy/src/store/memory_ce.go:15-57memoryDAO._get()方法。取最后4条消息用于retrieval,调用graphiti.I().GetMemory()获取最多5个facts。

[^40]: Zep legacy/src/store/memory_ce.go:59-72_initializeProcessingMemory()。两个HTTP POST调用:graphiti.I().PutMemory(ctx, session.SessionID, ...)graphiti.I().PutMemory(ctx, *session.UserID, ...)

[^41]: Zep legacy/src/lib/graphiti/service_ce.go — Graphiti HTTP client。Service接口定义于第80行,包含GetMemory/PutMemory/Search/AddNode/GetFact/DeleteFact/DeleteGroup/DeleteMessage。每个方法内部是HTTP request(s.newRequest() + s.doRequest())。全文300行。

[^42]: Zep legacy/src/store/message_common.go — 消息存储实现。使用PostgreSQL(bun ORM)。GetLastN()位于第135-184行。metadata更新含advisory lock(第394-451行)。全文547行。

[^43]: Zep legacy/src/models/memory_common.go:86-92MemoryCommon结构体定义。包含Messages、RelevantFacts、Metadata三个字段。

[^44]: Zep legacy/src/models/fact_common.goFact结构体。字段:UUID、CreatedAt、Fact(string)、Rating(*float64)。

[^45]: Zep legacy/src/models/session_common.go:10-22SessionCommon结构体。字段:UUID、ID、CreatedAt、UpdatedAt、DeletedAt、EndedAt、SessionID、Metadata、UserID、ProjectUUID。

[^46]: ContextVault contextvault-mcp/src/vault/types.ts:3-12VaultSettings接口。mode(local/global/full)、enforcement(light/balanced/strict)、limits(max docs 50/50, max lines 100, max summary words 15)。

[^47]: ContextVault contextvault-mcp/src/vault/manager.tsVaultManager类。核心方法:readDocument()(fs.readFileSync)、writeDocument()(fs.writeFileSync)、search()(委托IndexManager)、getEnforcementReminder()(编辑计数nudge)。全文493行。

[^48]: ContextVault contextvault-mcp/src/vault/index-manager.ts:346-363IndexManager.search()。对index.md中的entry进行纯关键词匹配(split → includes → 计分)。搜索范围仅限id、topic、summary字段。

[^49]: ContextVault contextvault-mcp/src/vault/manager.ts:195-372 — Enforcement机制。包含trackEdit()trackResearch()getEnforcementReminder()(edit-based)、getResearchReminder()(research-based)。域分类支持frontend/backend/database/testing/config/utils/services/types/docs。

[^50]: ContextVault contextvault-mcp/src/vault/manager.ts:376-440generateDocContent()。根据type(doc/error/decision/plan/snippet/intel/handoff/explain)生成不同的markdown模板。

[^51]: ContextVault contextvault-mcp/src/server.ts:35ContextVaultServer类。注册20+个MCP tools,通过withTracking()包装enforcement和reminder逻辑。

[^52]: Hermes Agent agent/context_compressor.py:612-745ContextCompressor.compress()。流程:修剪旧tool results → 确定边界 → 生成摘要(1次LLM调用,位于_generate_summary()第404行)→ 组装。


附录B:代码量统计

项目 核心模块代码量 计量范围
Headroom 211,243行 Python headroom/**/*.py(465文件)
Letta 31,955行 Python letta/{agents,schemas,services/summarizer,functions}/**/*.py
lossless-claw 22,967行 TypeScript src/**/*.ts
Hermes Agent 9,660行 Python run_agent.py(单文件)
Zep legacy 7,885行 Go legacy/src/**/*.go
Mem0核心 3,341行 Python mem0/memory/{main,graph_memory}.py
ContextVault ~1,500行 TypeScript contextvault-mcp/src/**/*.ts

本文所有技术判断基于对源码的直接阅读,写作时间2026年4月。各项目代码可能在此后发生变化。