OpenClaw项目缓存架构与缓存数据流分析
OpenClaw缓存子系统是一个多级架构,针对多Agent并发场景设计了四大模块:1)启动缓存加速Agent初始化;2)上下文压缩机制动态控制对话Token量;3)长期记忆系统结合向量缓存和混合检索;4)Prompt缓存追踪分析大模型接口命中率。系统采用内存Map、SQLite缓存、异步日志等技术,实现了API限流防护、Token成本控制和状态监控三大核心目标。该架构通过分层缓存策略,有效解决了L
OpenClaw 的缓存子系统是一个多级、多维度的复杂架构,旨在解决多 Agent 并发场景下的性能瓶颈、大模型 Token 成本控制,以及长期记忆的快速召回问题,个人觉得项目的成功该模块的贡献占一半。
一、缓存架构概览
整个缓存系统由以下四个相对独立但互相配合的子系统构成:
- Bootstrap 启动缓存 (
Bootstrap Cache):负责极速加载 Agent 环境与初始化配置,避免重复的文件系统 IO。 - 上下文摘要与状态压缩 (
Token Compaction):在 Agent 对话轮次叠加时,动态控制上下文窗口大小,并丢弃/压缩历史对话。 - 长期记忆与向量缓存 (
Memory & Embedding Operations):负责知识库或高价值历史的持久化混合检索,同时对第三方 Embedding 接口(如 OpenAI/Gemini)提供防刷接口的向量哈希缓存。 - 大模型 Prompt 缓存追踪 (
Cache Tracing):专门用于对接 Anthropic、OpenAI 等支持 Prompt Caching (提示词缓存) 的大模型,分析缓存命中命中率、提供日志级诊断追踪。
二、四大缓存流程与实现细节
2.1 Agent 启动缓存数据流 (src/agents/bootstrap-cache.ts)
业务场景:每当一个用户在群聊或私聊唤醒 Agent 时,引擎需要加载该 Agent 的工作空间(Workspace)配置文件(如 HEARTBEAT.md、INSTRUCTIONS.md)。
工作流程:
- 触发挂载:外部调用 getOrLoadBootstrapFiles(config, sessionKey, workspaceDir, agentId)。
- 命中内存:由于使用了全局的
Map<string, WorkspaceBootstrapFile[]>,引擎直接以sessionKey查询内存。若命中,则直接跳过磁盘读取步骤。 - 未命中回退 (Cache Miss):
- 走
loadWorkspaceBootstrapFiles访问底层文件系统。 - 读取后经过 Hook (如 applyBootstrapHookOverrides在 bootstrap-hooks.ts 中拦截调整文件结构)。
- 最后将结果推入全局
Map中供下一次极速启动。
- 走
2.2 上下文摘要压缩流 (src/agents/compaction.ts)
业务场景:对话越来越长,达到大模型 32K 或 128K 阈值边界。
工作流程:
- Token 估算器:利用 estimateMessagesTokens 和
estimateAdaptiveTokenLength来预测消息流占用的 Token。 - 动态滑动窗口计算:通过 computeAdaptiveChunkRatio 和大模型自身的
contextWindow,计算出本次留给历史消息的安全边际(SAFETY_MARGIN)。 - 超量切分与大块替换:
- 若某条单独的日志/消息超大,核心库会触发分块:chunkMessagesByMaxTokens。
- 系统调用 summarizeWithFallback,尝试用轻量级 LLM 将一段冗长的对话压缩为简短总结。
- 若总结失败或触及更底层的防线,它会执行冷酷截断,并用诸如
[Large message (~10K tokens) omitted]的占位符替换原本的巨量文本。
- 不可丢失参数锁定 (Identifier Preservation):即使处于严重压缩抛弃阶段,OpenClaw 通过独特的声明 (
IDENTIFIER_PRESERVATION_INSTRUCTIONS) 强势保护会话中出现的 URL、IP地址、哈希值、文件路径,防止 Agent 变“失忆”但依然看似接得上话的伪状态。
2.3 记忆混合检索与 Embedded 向量缓存机制
负责模块:src/memory/manager.ts, src/memory/manager-embedding-ops.ts, src/memory/qmd-manager.ts
底座设施:具有原生向量和全文引擎的 SQLite 数据库 (chunks_vec, chunks_fts)
业务场景:用户问:“三个月前关于重构支付网关的讨论细节是什么?”。此时 Agent 需要通过向量在海量归档对话中捞出关键片段。
工作流程:
- 内容重组与分块 (Indexing):
- indexFile 被触发。大文本首先被
chunkMarkdown细切。 - 每个小 Chunk 开始过 embedChunksInBatches 队列流程。
- indexFile 被触发。大文本首先被
- 向量接口级防刷层 (
EMBEDDING_CACHE_TABLE):- OpenClaw 为了避免昂贵的远程 Embedding 调用(如向 Voyage 或 OpenAI POST 数据),通过
hashText计算 Chunk 文本的哈希(结合provider.model+providerKey防止换模型产生脏命中)。 - 使用 loadEmbeddingCache 到 SQLite 的
embedding_cache表去查是否已经为相同的字符串生成过向量。 - 如果全部命中,根本不会发送网络请求,直接内存补齐向量数组。
- OpenClaw 为了避免昂贵的远程 Embedding 调用(如向 Voyage 或 OpenAI POST 数据),通过
- 并发调用与后置更新:
- 遭遇未命中的缺口 (
missing) 时,组装成 Batch Requests(例如runOpenAiEmbeddingBatches或runGeminiEmbeddingBatches)。 - 成功后,通过 upsertEmbeddingCache 回写缓存表。同时系统具备清理机制 (pruneEmbeddingCacheIfNeeded) 保证体积不超标。
- 遭遇未命中的缺口 (
- 混合召回策略 (Hybrid Search):
- Agent 请求回忆时,调用 search。首先执行纯降级 FTS(基于关键字)。然后同时进行 searchVector(Cosine 向量逼近)。
- 调用 mergeHybridResults 去重归并分数,然后组装好并注入到 System Prompt 提供给 LLM。
2.4 Prompt Cache 追踪落盘体系 (src/agents/cache-trace.ts 与 queued-file-writer.ts)
业务场景:开发者想要度量目前 Agent 是否有效地命中了例如 Anthropic 的原生 Context Caching。
工作流程:
- 埋点拦截:通过包装原生推流入口
CacheTrace.wrapStreamFn获取底层的元数据拦截点。 - 阶段指纹计算:
- record() 方法按照四个生命周期:
session:loaded、session:sanitized、prompt:before、stream:context运行。 - 将每一次发送给 LLM 的系统级和对话级 prompt 进行分段 Hash (主要是
messagesDigest和messageFingerprints)。
- record() 方法按照四个生命周期:
- 队列落盘无阻塞:
- 采集到的指纹对象被传入底层的 getQueuedFileWriter (基于 Promise 链安全实现的单线异步队列落盘) 写入本地物理日志中。供外部监控系统抽检 Prompt Hit 的状态跳变情况。
总结
OpenClaw 并非采用暴力的 Redis 或者简单的全文全局变量来进行缓存,而是深刻根据 LLM Agent 的底层链路(从初始化 -> Token 超限应对 -> 长期记忆向量化 -> Prompt 追踪)构建了多层防护池:
- 短期热点:通过内存
Map拦截 (Bootstrap)。 - 账单与速率防护:防撞库般的 Embedding SQLite 缓存拦截与重试退避。
- 对话臃肿防御:极具策略性的 fallback Token 截断与总结机制。
- 状态追踪:非侵入式的 Trace 排队写入,用于监控大模型后端的缓存表现。
这套架构高度聚焦于“防 API 限流、防 Token 超量、防重入计算”,是大型 Agent 基座典型的标准打法。
更多推荐


所有评论(0)