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或博客文章。具体做法:
- 克隆目标项目的完整仓库到本地
- 从入口文件出发,沿调用链阅读核心实现
- 记录关键架构决策的具体文件位置(
file:line格式) - 对比不同项目在相同问题域的设计选择
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 | interface ContextEngine { |
关键设计决策:
ownsCompaction?: boolean(types.ts:51):引擎可以声明自己拥有压缩逻辑,阻止runtime的自动压缩runtimeContext.rewriteTranscriptEntries()(types.ts:93-95):提供安全的transcript重写通道systemPromptAddition?: string(AssembleResult,types.ts:11):允许引擎向system prompt注入内容
2.2 排他性Slot系统
src/plugins/slots.ts[^2] 定义了两个排他性slot:
1 | const SLOT_BY_KIND = { |
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: 0(legacy.ts:~45)compact()→ 委托给delegateCompactionToRuntime()(legacy.ts:~55,调用delegate.ts:16-63)
真正的压缩逻辑在 src/agents/compaction.ts,硬编码了 BASE_CHUNK_RATIO = 0.4、MIN_CHUNK_RATIO = 0.15、SAFETY_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.ts 的 triggerInternalHook() 和 src/plugins/hooks.ts 的 hookRunner.runSessionEnd() 是独立系统。session-memory hook只监听 command:new 和 command:reset(src/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 Object。src/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 | export interface LcmDependencies { |
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])的核心流程:
- 从SQLite获取所有context items(消息 + 摘要),按ordinal排序
- 将每个item解析为
AgentMessage(获取底层消息或摘要记录) - 将items分为可驱逐前缀和受保护的fresh tail(默认64条消息,
src/db/config.ts:255[^10]) - 如果超出token budget,从最旧的非fresh items开始丢弃
- 当prompt可用时,使用BM25-lite相关性评分决定保留优先级
- 摘要格式化为XML:
<summary id="..." kind="leaf" depth="0">...
返回结果包含 messages、estimatedTokens、systemPromptAddition和详细统计。
3.1.3 压缩配置
CompactionConfig(src/compaction.ts:33[^11])提供精细的压缩参数:
1 | export interface CompactionConfig { |
支持四种压缩级别:"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_SCORE(pipeline.py:116-119)
降级路径(pipeline.py:91-123):
1 | ContentRouter 不可用 → SmartCrusher(仅JSON) |
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_file、ctx_index、ctx_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的核心类 Memory(main.py:258[^18])包含一个vector store和一个可选的graph store(Neo4j),两条路径通过 ThreadPoolExecutor 并行执行。
4.1.2 add() 方法调用链
Memory.add()(main.py:383[^19])的真实执行流程:
- LLM提取facts:发送一次LLM调用(tool call模式),让模型从输入文本中抽取结构化记忆条目
- 搜索已有记忆:对每个抽取的fact做vector search,找到相似的已有记忆
- LLM决策:再发一次LLM调用,让模型对每条记忆做ADD/UPDATE/DELETE决策
- 执行存储操作:根据决策写入vector store
如果启用了graph store,步骤4还会并行执行 _add_to_graph():
1 | # main.py - Memory.add() 内部 |
一次 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])的调用链:
_retrieve_nodes_from_data()(graph_memory.py:219)— LLM tool call提取实体和类型_establish_nodes_relations_from_data()(graph_memory.py:252)— LLM tool call建立实体间关系_search_graph_db()(graph_memory.py:294)— 对每个实体做embedding cosine相似度搜索:
1 | # graph_memory.py:312 |
_get_delete_entities_from_search_output()(graph_memory.py:347)— LLM tool call决定删除- 执行删除和新增
图的删除是软删除(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 | from rank_bm25 import BM25Okapi |
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.py、letta/schemas/block.py、letta/schemas/memory.py、letta/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 | class Block(BaseBlock): |
预置两个Block:Human(block.py:117,label=”human”)和 Persona(label=”persona”)。
Agent通过以下tool call修改Block:
core_memory_append(agent_state, label, content)(base.py:246[^25]):
1 | current_value = str(agent_state.memory.get_block(label).value) |
core_memory_replace(agent_state, label, old_content, new_content)(base.py:263[^26]):
1 | current_value = str(agent_state.memory.get_block(label).value) |
rethink_memory(agent_state, new_memory, target_block_label)(base.py:283):整体重写Blockmemory(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 | messages = self.message_manager.list_messages_for_agent( |
使用hybrid search(文本 + 语义),支持按role、时间范围过滤。
4.2.5 Agent主循环
LettaAgent.step()(letta_agent.py:174[^31])→ _step() → 循环(最多max_steps轮):
_build_and_request_from_llm()(letta_agent.py:328)— 组装上下文 + LLM调用- 解析response的tool call
_handle_ai_response()(letta_agent.py:1714)— 执行tool call
Agent通过强制tool calling驱动(letta_agent.py:360-362[^32]):
1 | if not response.choices[0].message.tool_calls: |
每轮必须产出tool call,否则报错。这意味着每一轮交互都是一次完整的LLM调用,即使只是写一条记忆。
4.2.6 Summarization实现
Summarizer类(summarizer/summarizer.py:36[^33])支持两种模式(enums.py[^34]):
模式一:STATIC_MESSAGE_BUFFER(summarizer.py:244-300[^35])
固定buffer。当 len(all_in_context_messages) > message_buffer_limit 时,丢弃最旧消息,保留最近 message_buffer_min 条。如果有summarizer agent,异步触发背景摘要。
模式二:PARTIAL_EVICT_MESSAGE_BUFFER(summarizer.py:136-242[^36])
原始MemGPT方案。按比例(默认30%,partial_evict_summarizer_percentage,summarizer.py:49)驱逐最旧消息,用一次LLM调用生成摘要(simple_summary(),summarizer.py:188),插入到 context[1] 位置(system_message后的第一条)。
1 | # summarizer.py:241-242 |
关键观察:摘要触发是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.go、legacy/src/lib/graphiti/service_ce.go(300行)、legacy/src/store/memory_common.go、legacy/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 | func (dao *memoryDAO) _get(ctx context.Context, session *models.Session, |
_initializeProcessingMemory()(memory_ce.go:59-72[^40])同样只是HTTP POST:
1 | func (dao *memoryDAO) _initializeProcessingMemory(...) error { |
4.3.3 Graphiti服务接口
graphiti/service_ce.go[^41] 定义的 Service 接口(第80行)全是HTTP调用:
1 | type Service interface { |
每个方法内部都是 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 数据模型
Memory(models/memory_common.go:86-92[^43]):
1 | type MemoryCommon struct { |
Fact(models/fact_common.go[^44]):只有UUID、CreatedAt、Fact(字符串)、Rating(可选浮点)。
Session(models/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 存储模型
VaultSettings(types.ts:3-12[^46]):
1 | export interface VaultSettings { |
两个tier:global(~/.contextvault/)和project(./.contextvault/)。每个tier有一个 index.md(markdown表格做索引)和若干 P001_*.md / G001_*.md 文件。
VaultManager(manager.ts[^47])核心操作都是 fs.readFileSync / fs.writeFileSync。没有数据库、没有向量索引、没有embedding。
4.4.3 搜索实现
IndexManager.search()(index-manager.ts:346-363[^48]):
1 | search(query: string): IndexEntry[] { |
搜索范围是index.md中每条entry的topic和summary(各15个词以内)。不搜索文档正文。这是纯关键词匹配,不是语义搜索。
4.4.4 Enforcement机制
VaultManager跟踪agent的编辑次数和探索范围(manager.ts:195-372[^49])。当编辑超过阈值(balanced模式:8次编辑 + 2个文件),在tool response末尾追加reminder:
1 | getEnforcementReminder(): string | 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
通过 ContextVaultServer(server.ts:35[^51])注册:ctx_init、ctx_doc、ctx_error、ctx_decision、ctx_search、ctx_read、ctx_plan、ctx_handoff、ctx_bootstrap、ctx_changelog、ctx_quiz、ctx_review、ctx_share、ctx_archive、ctx_import、ctx_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])的流程:
- 修剪旧的tool results(保留结构但截断内容)
- 确定压缩边界(哪些消息需要摘要)
- 生成摘要——仅1次LLM调用(
_generate_summary()内部,context_compressor.py:404) - 组装压缩后的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行代码:
- 占据OpenClaw的contextEngine slot
- 内部实例化lossless-claw的
LcmContextEngine(需要构造LcmDependencies) - 在
assemble()的输出上运行Headroom的compress()管线 - 将lossless-claw的结构化摘要(XML格式)与Headroom的tool output压缩组合
7.3 价值分析
lossless-claw的assembler输出包含两类内容:
- 摘要(
<summary>XML节点)——已经是压缩后的文本,Headroom再压缩的边际收益极低 - 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: 0,compact()委托给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-132 — clearStaleAssistantUsageOnSessionMessages()清除所有assistant message的usage数据。
[^7]: lossless-claw src/engine.ts:1199 — LcmContextEngine implements ContextEngine,构造函数接受LcmDependencies + DatabaseSync。全文4,306行。
[^8]: lossless-claw src/types.ts:105-165 — LcmDependencies接口定义,包含config、complete、callGateway、resolveModel、getApiKey、requireApiKey、parseAgentSessionKey、isSubagentSessionKey、normalizeAgentId、log等字段。
[^9]: lossless-claw src/assembler.ts:886-1059 — ContextAssembler.assemble()方法。包含context items获取(SQLite)、fresh tail分割(默认64条)、token budget感知的选择、BM25-lite相关性评分、XML格式摘要输出。
[^10]: lossless-claw src/db/config.ts:255 — freshTailCount默认值为64。
[^11]: lossless-claw src/compaction.ts:33 — CompactionConfig接口,包含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_reset和session_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:258 — Memory类定义。包含vector_store(必选)和graph store(可选,Neo4j)。同文件还有AsyncMemory类。全文2,597行。
[^19]: Mem0 mem0/memory/main.py:383 — Memory.add()方法。LLM调用提取facts → vector search找相似记忆 → LLM决策ADD/UPDATE/DELETE → 写入存储。graph路径通过ThreadPoolExecutor并行。
[^20]: Mem0 mem0/memory/graph_memory.py:29 — MemoryGraph类定义。使用langchain_neo4j.Neo4jGraph。初始化时创建Neo4j索引(entity_single和entity_composite)。
[^21]: Mem0 mem0/memory/graph_memory.py:76 — MemoryGraph.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-130 — MemoryGraph.search()方法。使用rank_bm25.BM25Okapi对graph查询结果做BM25重排序。
[^24]: Letta letta/schemas/block.py:67 — Block类定义。字段包含value(str)、limit(CORE_MEMORY_BLOCK_CHAR_LIMIT)、label(如’human’、’persona’)、read_only。Human子类位于第117行。
[^25]: Letta letta/functions/function_sets/base.py:246 — core_memory_append()实现:new_value = current_value + "\n" + str(content)。
[^26]: Letta letta/functions/function_sets/base.py:263 — core_memory_replace()实现:精确字符串替换,找不到old_content时抛ValueError。
[^27]: Letta letta/functions/function_sets/base.py:10 — memory()函数,类文件系统操作(create/str_replace/insert/delete/rename)。函数体为raise NotImplementedError。
[^28]: Letta letta/functions/function_sets/base.py:164 — archival_memory_insert()。函数体为raise NotImplementedError("This should never be invoked directly."),实际路由在server端。
[^29]: Letta letta/functions/function_sets/base.py:194 — archival_memory_search()。支持query、tags、tag_match_mode(any/all)、top_k、start/end datetime。同为NotImplementedError。
[^30]: Letta letta/functions/function_sets/base.py:87 — conversation_search()。调用self.message_manager.list_messages_for_agent(),使用hybrid search,支持role和时间范围过滤。
[^31]: Letta letta/agents/letta_agent.py:174 — LettaAgent.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:36 — Summarizer类定义。接受SummarizationMode、summarizer_agent、message_buffer_limit(默认10)、message_buffer_min(默认3)、partial_evict_summarizer_percentage(默认0.30)。
[^34]: Letta letta/services/summarizer/enums.py — SummarizationMode枚举。两个值:STATIC_MESSAGE_BUFFER和PARTIAL_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.py — ContextWindowOverview定义。包含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-57 — memoryDAO._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-92 — MemoryCommon结构体定义。包含Messages、RelevantFacts、Metadata三个字段。
[^44]: Zep legacy/src/models/fact_common.go — Fact结构体。字段:UUID、CreatedAt、Fact(string)、Rating(*float64)。
[^45]: Zep legacy/src/models/session_common.go:10-22 — SessionCommon结构体。字段:UUID、ID、CreatedAt、UpdatedAt、DeletedAt、EndedAt、SessionID、Metadata、UserID、ProjectUUID。
[^46]: ContextVault contextvault-mcp/src/vault/types.ts:3-12 — VaultSettings接口。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.ts — VaultManager类。核心方法:readDocument()(fs.readFileSync)、writeDocument()(fs.writeFileSync)、search()(委托IndexManager)、getEnforcementReminder()(编辑计数nudge)。全文493行。
[^48]: ContextVault contextvault-mcp/src/vault/index-manager.ts:346-363 — IndexManager.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-440 — generateDocContent()。根据type(doc/error/decision/plan/snippet/intel/handoff/explain)生成不同的markdown模板。
[^51]: ContextVault contextvault-mcp/src/server.ts:35 — ContextVaultServer类。注册20+个MCP tools,通过withTracking()包装enforcement和reminder逻辑。
[^52]: Hermes Agent agent/context_compressor.py:612-745 — ContextCompressor.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月。各项目代码可能在此后发生变化。