可用于高效检索和管理文档信息,支持向量相似度与BM25全文混合检索,能按Markdown标题结构分块并保留层级信息,兼容OpenAI及Silra等嵌入服务,支持元数据过滤。【此简介由AI生成】
ContextEngine: CLI Agent 的
上下文生命周期引擎
贯穿 Agent 循环的每一个阶段,管理什么进入上下文窗口、什么被保留、什么被淘汰、以及什么能够被重新召回。 七类上下文。三级缓存层次。一个虚拟文件系统。 降低 token 消耗。保持信号密度。跨越会话边界。
English | 中文
问题:Token 预算是瓶颈
每个 CLI Agent 运行在固定的 token 预算上。上下文窗口既是最昂贵的,也是最稀缺的资源。
| 症状 | 根因 | 缺失的生命周期阶段 |
|---|---|---|
| Agent 会遗忘对话早期的内容 | 窗口占满后旧内容被淘汰,没有持久化 | ④ afterTurn — 缺少抽取 + 持久化机制 |
| 跨会话重复犯同样的错误 | 没有跨会话传递经验的机制 | ⑥ session_end — 无归档 + ② bootstrap — 无冷启动注入 |
| 一次本该花 $0.05 的查询花了 $0.50 | 扁平检索加载整篇文档,摘要就够了 | ② assemble — 缺少 L0/L1/L2 分层检索 |
| 多 Agent 协作失效 | Agent 之间看不到彼此的工作上下文 | ④ afterTurn — 无跨会话共享 + 多租户隔离 |
| 长会话中上下文不断膨胀 | 没有系统化压缩 — Agent 淹没在自己的历史中 | ⑤ compact — 缺少信号评分 + 摘要链 |
这不是模型的问题。这是基础设施问题。
ContextEngine 提供的正是缺失的那层基础设施:一个全栈上下文生命周期管理系统,在 Agent 循环的六个明确定义阶段拦截,把上下文窗口当作受管资源来管理 — 而不是无界缓冲区。
设计哲学
核心洞察:上下文有生命周期
当前 RAG 系统把检索当作单一操作 — 向量化查询、搜索向量库、返回结果。这忽略了一个基本事实:Agent 系统中的上下文有完整的生命周期,就像数据库中的数据一样。
诞生 结构化 存储 索引 召回 压缩 归档
(从对话中 (按类型分类, (原子写入, (向量化 + (向量搜索, (摘要化, (会话结束,
抽取) 按策略路由) 有顺序保证) 写入 L0/L1/L2 分层展开, 去重, 归档,
IndexRecords) 按预算加载) 压缩) 状态快照)
每个阶段有不同的约束。抽取必须增量(不重复处理旧消息)。存储必须原子(不完整写入可检测)。索引必须异步(不阻塞 Agent 响应)。检索必须感知预算(只加载放得下的)。压缩必须保留信号(保护重要上下文)。
只处理其中一两个阶段的系统 — 比如只做检索 — 把其余阶段留给了偶然。ContextEngine 覆盖完整生命周期。
六个拦截点
Agent 循环不是黑盒。它有明确的执行阶段。每个阶段提供不同的上下文读/写/变换机会。
┌──────────────────────────────────────────────────────────────────────┐
│ Agent Loop(无限循环) │
│ │
│ ┌─────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
│ │ ① │ │ ② │ │ ③ │ │ ④ │ │
│ │ 消息 │────▶│ 推理准备 │────▶│ 工具调用 │────▶│ 轮次结束 │ │
│ │ 到达 │ │ │ │ │ │ │ │
│ └──┬──┘ └──────────┘ └──────────┘ └────┬────┘ │
│ ▲ │ │
│ │ ┌──────────┐ ┌─────────┐ │ │
│ │ │ ⑤ │ │ ⑥ │ │ │
│ └─────────│ 压缩管理 │◀────────│ 会话关闭 │◀────┘ │
│ └──────────┘ └─────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────┘
关键设计选择:在循环边界拦截,而不是在模型推理内部拦截。 阶段 ①–⑥ 全部在 LLM 调用之外。这意味着对模型推理本身零延迟影响 — 所有上下文操作发生在推理前后,绝不在推理过程中。
上下文类型不平等
七类上下文,各有根本不同的生命周期行为。这不是随意分类 — 由信息本身的语义决定。
| 类型 | 为什么是这个生命周期? | 写入策略 |
|---|---|---|
| Profile | 用户状态会变化 — "我住在北京"可能变成"我搬到了东京" | Merge — 冲突时新覆盖旧 |
| Preference | 偏好按主题累积,每个主题只有一个当前视图 | 按 slug 归并 — 合并同主题 |
| Entity | 实体累积事实,但"项目 Alpha"仍然是"项目 Alpha" | 按 slug 归并 — 合并同实体 |
| Event | 历史不可变 — "3月15日完成迁移"永远不会改变 | 仅追加 — 永不覆盖 |
| Case | 问题解决轨迹是历史记录 | 仅追加 — 永不覆盖 |
| Pattern | 模式从反复观察中涌现并随时间演化 | 按 slug 归并 — 逐步精炼 |
| Skill | 工具专长累积增长 — 经验越多知识越好 | 累积追加 — 知识持续积累 |
四种截然不同的写入策略,每种由信息的生命周期语义决定。单一的"用同一种方式存储一切"方案,要么丢失可变状态(如果仅追加),要么破坏不可变历史(如果覆盖写入)。
除 7 类用户面向类型外,还有 3 类系统内部 Schema(tool、session_archive、session_summary)— 它们由分块和压缩管线以编程方式创建,不由 LLM ReAct 循环抽取。
关键架构决策
为什么用 YAML 驱动 Schema?
问题:在 Python 中硬编码抽取 Schema,每新增一个上下文类型都要改代码、测试、部署。
方案:YAML Schema 声明式定义要抽取什么、如何分类。SchemaRegistry、PolicyRouter 和 URIResolver 都在运行时消费这些 Schema。新增类型 — 比如"Decision"或"Handoff" — 只需添加一个 YAML 文件,不需要改抽取管线。
不用这个方案会怎样:每个新类型都变成一次跨抽取、提交路由、URI 解析三个包的代码变更,必须协同发布。实际上团队会跳过添加新类型,所有东西都被塞进泛化的"notes"。
为什么用 Outbox 模式做异步索引?
问题:向量化 + 写入向量索引需要 100–500ms。如果同步执行,每次 afterTurn 都会阻塞那么久,增加 Agent 响应延迟。
方案:Outbox 模式将写入(快,~50ms)和索引(慢,异步)解耦。每次写入投递一个 OutboxEvent。后台 Worker 消费事件,提供至少一次投递保证和死信队列。写入路径立即返回;索引在几秒内追上。
不用这个方案会怎样:Agent 感知的响应时间膨胀 2–10 倍。更糟的是,如果向量库暂时不可用,写入失败、上下文丢失 — 系统对基础设施瞬时故障变得脆弱。
为什么用 L0/L1/L2 三级检索?
问题:内容越长,向量相似度反而可能越低 — 而非越高。一个 5000 token 的文档 embedding 必须表示其中每一个概念,导致任何单一主题的信号被稀释。
方案:每个上下文节点按三种粒度索引。L0 摘要(~100 token)产生聚焦 embedding — 精准的主题路标。L1 概述(~500 token)信号居中。L2 完整内容(~5000 token)信息最全但 embedding 弥散。检索引擎对三个层级做一次统一的向量搜索,然后把 L0/L1 命中作为目录入口点进行递归树展开:当 L0 摘要匹配时,搜索器展开其子节点,发现扁平搜索会遗漏的 L2 内容。分数传播(final = α·child + (1-α)·parent)让强匹配父节点下的边缘 L2 结果获得加成。热度混合(blended = (1-α_hotness)·semantic + α_hotness·h_score)在树展开过程中应用。
┌─────────────┐ ┌─────────────┐ ┌──────────────┐
│ L0 摘要 │ │ L1 概述 │ │ L2 完整内容 │
│ ~100 token │ │ ~500 token │ │ ~5000 token │
│ 聚焦 │ │ 平衡信号 │ │ 信息全面 │
│ embedding │ │ │ │ 但弥散 │
│ → 路标定位 │ │ → 决策参考 │ │ → 完整细节 │
└──────┬───────┘ └──────┬───────┘ └──────┬────────┘
│ │ │
▼ ▼ ▼
.abstract.md .overview.md content.md
召回优势:仅对 L2 做扁平向量搜索,会遗漏那些因细节稀释导致向量分数低于阈值的相关内容。L0/L1 路标引导搜索器定位到正确的目录,然后树展开发现其下的完整内容 — 包括原始向量分数不高但父主题强匹配的 chunk。
为什么用文件系统抽象?
问题:上下文操作 — 创建、读取、更新、关联、删除 — 需要可组合、原子、多租户安全。每一样都作为独立 API 构建意味着要为每个操作重新实现并发、权限和一致性。
方案:ContextFS 将每个上下文操作映射为 ctx:// URI 上的类文件操作。多租户隔离在文件系统层面强制执行(通过路径中的 account_id + owner_space),即使调用方有 bug 也无法绕过。ContextFS 协议提供以下操作:
| 协议方法 | 上下文操作 |
|---|---|
write_node(node, ctx) |
原子写入,4 步顺序(content → relations → abstract/overview → meta.json) |
read_node(uri, ctx) |
加载完整节点(content + meta + relations) |
delete_node(uri, ctx) |
永久删除 |
archive_node(uri, ctx) |
软删除(status → ARCHIVED) |
move_node(from, to, ctx) |
重定位节点 |
list_children(uri, ctx) |
枚举子 URI |
exists(uri, ctx) |
仅 ACTIVE 时为 True(PENDING 不可见) |
关系通过独立的 RelationStore 协议管理,不属于 ContextFS 本身。两个后端实现了 ContextFS:AGFS 适配器(Go 文件服务器,默认)和 SQL 适配器(PostgreSQL)。
不用这个方案会怎样:租户隔离变成"每个调用方都必须记得检查权限"。原子写入变成"每个调用方都必须正确实现 4 步写入协议"。每个新功能都重新解决相同的基础设施问题。
为什么用乐观锁做并发写入?
问题:Profile 节点会被用户的所有会话同时写入。两个会话可能同时抽取冲突的 profile 更新。
方案:乐观锁 — 读取当前 .meta.json 版本,仅在版本未变时写入。常见场景(无竞争)零基础设施开销。罕见场景(并发写入),第二个写入者用新状态重试。
不用这个方案会怎样:分布式锁需要协调服务(etcd/ZooKeeper)— 为罕见问题增加基础设施复杂度。不加锁则后写覆盖,静默丢失第一个写入者的更新。
为什么用 ReAct 循环做抽取?
问题:抽取质量取决于已知内容。如果系统已经知道"Alice 是后端工程师",再次抽取浪费 LLM token 并创建后续必须去重的重复条目。
方案:LLM 被赋予工具访问 — read(uri)、list(uri)、get_relations(uri)、get_access_stats(uri),以及 extract_* 动作 — 然后在循环中运行。每一轮:先读取已有记忆节点(Reason),判断哪些是真正新的,再调用对应的 extract_* 工具(Act)。如果不确定,就读更多节点继续循环。这是真正的 ReAct:推理和工具调用交替进行,不是单次盲目抽取。
迭代 1: read(profile_uri) → "Alice, 后端工程师, 伦敦"
→ 无新信息,跳过
迭代 2: read(entities/go) → "Go 专家,偏好错误处理模式 X"
→ 新增: "Alice 现在也在用 Rust 做副项目"
→ extract_entity(slug="rust", ...)
不用这个方案会怎样:每轮重复抽取相同事实。100 轮后,"Alice 是后端工程师"被抽取 100 次,产生 100 次 Profile 合并操作 — 每次都在已有内容上浪费 LLM token。抽取成本随对话长度线性增长,而不是随信息密度增长。
架构
总体架构
CLI Agent (Claude Code / OpenClaw / SDK)
│ HTTP REST (端口 8090) 或 Python SDK
▼
┌─ HTTP 层 ──── Flask REST · 认证/RBAC · 会话管理 ─┐
└──────────────────────┬─────────────────────────────┘
┌─ Service 层 ── MemoryWriteAPI · MemoryService ────┐
└──────────────────────┬─────────────────────────────┘
┌──────────────────┴──────────────────┐
│ 写入链路 │ 读取链路 │
│ ReAct 抽取循环 │ QueryPlanner │
│ PolicyRouter │ SeedRetriever│
│ ContextWriter │ (+BM25 融合) │
│ OutboxStore │ HierSearcher │
│ │ ResultRanker │
└──────────────────────┬───────────────┘
┌─ ContextFS ── AGFS 适配器 · SQL 适配器 ───────────┐
└──────────────────────┬─────────────────────────────┘
┌─ 异步索引 ── OutboxWorker · DirSummarizer · RepairJob ─┐
└──────────────────────┬─────────────────────────────────┘
┌─────────────▼─────────────┐
│ AGFS · PostgreSQL · ChromaDB/pgvector│
└───────────────────────────┘
开发模式:ChromaDB 向量 + AGFS 文件存储 — 零外部依赖(默认)。
SQL 模式:ChromaDB/pgvector + PostgreSQL — 安装 postgresql 和 pgvector 扩展。
生产模式:pgvector + PostgreSQL RLS — 行级租户隔离,水平可扩展。
写入路径:对话到持久化记忆
Agent 轮次结束
│
▼
┌─────────────────────────────────────────────────┐
│ ReAct 抽取循环 │
│ │
│ LLM 拥有工具: read(uri), list(uri), │
│ get_relations(uri), get_access_stats(uri), │
│ extract_*() │
└────────────────────┬────────────────────────────┘
│ CandidateMemory[]
▼
┌──────────────────┐ ┌──────────────────┐
│ PolicyRouter │ │ ContextWriter │
│ (Schema 驱动) │────▶│ │
│ Profile→Merge │ │ Plan → Build │
│ Entity→Aggregate │ │ → Write (4步) │
│ Event→Append │ │ → Outbox │
│ Skill→SkillTool │ │ → DirSummary │
└──────────────────┘ └────────┬─────────┘
│
┌─────────▼─────────┐
│ Outbox Event │
│ (异步, 持久化) │
└─────────┬─────────┘
│
┌───────────────▼───────────────┐
│ Index Worker (后台) │
│ embed(abstract) → L0 upsert │
│ embed(overview) → L1 upsert │
│ embed(content) → L2 upsert │
│ DirectorySummarizer (L0/L1 │
│ 为父节点生成摘要) │
└───────────────────────────────┘
4 步原子写入(content.md → .relations → abstract+overview → .meta.json)是 AGFS 适配器的物理文件协议。ContextWriter 在更高层编排:Plan → Build → Write → Outbox → Directory Summary(5 个逻辑步骤)。
读取路径:查询到组装上下文
用户消息到达
│
▼
┌───────────────────┐ ┌──────────────────────────────────────────┐
│ QueryPlanner │ │ SeedRetriever │
│ │ │ │
│ 类型分类: │────▶│ 向量搜索 L0+L1+L2 │
│ 正则 → MEMORY/ │ │ + BM25 关键词融合 (alpha 加权) │
│ SKILL/RESOURCE │ │ → L0/L1 命中 = 目录路标 │
│ 意图分类: │ │ → L2 命中 = 直接内容匹配 │
│ RetrievalIntent │ └────────────────────┬─────────────────────┘
└───────────────────┘ │
┌──────▼──────┐
│ 有 L0/L1 │
│ 命中? │
└──────┬──────┘
是 │ 否
┌──────▼──────▼──────┐
│ 分层搜索 │ 直接使用
│ │ L2 结果
│ search_children() │
│ 按目录节点展开 │
│ 分数传播 │
│ + 热度混合 │
└────────┬───────────┘
│
┌────────▼─────────┐
│ ResultRanker │
│ 按 URI 去重 │
│ 按分数排序 │
│ 截断至 top_k │
│ 填充内容 │
└──────────────────┘
一次向量搜索,不是三次逐层扫描。BM25 融合在 SeedRetriever 内部完成(不是独立的管线阶段),使用 Vector-Anchored Fusion:final = α·vec + (1-α)·sat_bm25。热度混合在 HierarchicalSearcher 展开过程中应用,不在 ResultRanker。去重按精确 URI 匹配,不是余弦相似度。
命名空间隔离: 查询按意图类型限定搜索范围。MEMORY 查询同时搜索 users/{user}/memories/ 和 agents/{agent}/memories/。SKILL 查询只搜索 agents/{agent}/skills/。owner_space 过滤由 QueryPlanner 根据 context_type 和 visible_owner_spaces 设置,在向量索引层面强制执行 — 调用方无法覆盖。
Agent 上下文生命周期
六个阶段形成一条管线,每个阶段的输出馈入下一个。设计原则:永远不阻塞模型推理。所有上下文操作发生在循环边界 — LLM 思考前或行动后,绝不在推理过程中。
| 阶段 | 时机 | 做什么 | 关键不变量 |
|---|---|---|---|
| ① 消息到达 | Agent 推理前 | 解析意图,从 L0 预取候选 | 永不阻塞;超时静默失败 |
| ② bootstrap + ingest + assemble | 构建提示前 | 冷启动 profile 注入,预算感知 L0→L1→L2 加载,去重,技能注入 | 永不超过 token 预算 |
| ③ before_tool_call + tool_result_persist | 工具执行前后 | 注入已知失败模式,压缩过大结果,抽取即时事实 | 工具参数有历史经验指导 |
| ④ afterTurn | Agent 完成响应后 | 增量抽取差量,策略路由写入,关系构建,异步索引 | 只抽取新内容 |
| ⑤ before_compaction + compact | 上下文填满时 | 信号打分,保护关键节点,压缩冗余 | 永不丢失 Profile 或活跃任务 |
| ⑥ session_end + dispose | 会话关闭 | 归档已完成任务,为下个会话快照状态,完整性审计 | 下个会话无缝衔接 |
生命周期是循环的:阶段 ⑥ 的任务快照变成阶段 ② 的交接注入。阶段 ④ 诞生的上下文在阶段 ① 被召回。跨越会话持久化的内容使系统学习,而不仅仅是记忆。
数据流:端到端追踪
会话 1 — 写入路径: "我叫 Alice,是一名后端工程师,住在伦敦"
────────────────────────────────────────────────────────────────
用户消息 → 阶段 ④ afterTurn
→ 增量抽取 (name, role, location)
→ CandidateMemory(category="profile")
→ PolicyRouter → ProfilePolicy (merge)
→ ContextWriter (Plan → Build → Write → Outbox → DirSummary)
→ OutboxEvent → 异步 IndexRecordBuilder (L0 + L1 + L2 embed + upsert)
会话 2 — 读取路径: "Alice 是做什么工作的?"
────────────────────────────────────────────────────────────────
用户消息 → 阶段 ① message_received
→ QueryPlanner → type=MEMORY, intent=BACKGROUND_SUPPLEMENT
→ SeedRetriever → 向量搜索 + BM25 → L0 命中 (profile 匹配)
→ HierarchicalSearcher → 从 L0 展开 → 发现 L2 内容
→ ResultRanker → 按 URI 去重,排序,截断
→ 注入 "Alice 是一名后端工程师"
→ Agent 正确响应
写入耗时 ~50ms(同步)+ ~100ms(异步索引)。读取耗时 ~50ms。成本在写入时支付一次,在读取时多次分摊。
与典型方案的区别
ContextEngine 不是"多了几步的向量 RAG"。根本区别在于生命周期覆盖、写入策略和检索粒度。
| 维度 | ContextEngine | 标准向量 RAG | Mem0 |
|---|---|---|---|
| 生命周期覆盖 | 6 阶段:抽取 → 存储 → 索引 → 召回 → 压缩 → 归档 | 1 阶段:检索 | 2 阶段:写入 + 检索 |
| 写入策略 | 4 种策略(merge / aggregate / append / cumulative),按信息语义选择 | 单一:upsert | 单一:upsert with memory_id |
| 检索粒度 | L0/L1 目录路标 → 分层树展开 → L2 内容发现,BM25 融合,分数传播 + 热度 | 扁平 top-k 相似搜索 | 扁平 top-k + 图展开 |
| 上下文类型 | 7 类,每类独立生命周期行为(+ 3 类系统内部 Schema) | 1 类:"document chunk" | 1 类:"memory" + scope 标签 |
| 多租户隔离 | 文件系统层面强制(路径中 account_id + owner_space),调用方无法绕过 | 应用层过滤(依赖调用方) | 应用层过滤 |
| 并发写入 | 乐观锁 + 版本检查 | 后写覆盖(或外部锁) | 后写覆盖 |
| 原子性 | 4 步顺序写入,不完整状态可检测 | 尽力而为 | 尽力而为 |
| 压缩 | 信号评分 + 受保护节点 + 摘要链(Phase 2,进行中) | 无 | 无 |
核心区别:ContextEngine 把上下文当作受管生命周期来处理,不是存取问题。写入策略不是配置 — 它们是源自信息语义的架构决策。检索不是单一操作 — 它是带预算感知的多阶段决策过程。系统设计为跨会话持续运行,而不仅是响应查询。
Roadmap
已完成
| 里程碑 | 核心交付 |
|---|---|
| 核心基础 | 领域模型、ContextFS 抽象(AGFS + SQL 适配器)、ctx:// URI 方案、4 步原子写入 |
| 抽取管线 | YAML SchemaRegistry(10 个 Schema:7 用户面向 + 3 系统)、ReAct 抽取循环、Schema 驱动 PolicyRouter、4 种合并策略 |
| 分层检索 | L0/L1/L2 IndexRecords、SeedRetriever(含 BM25 融合)、HierarchicalSearcher(树展开 + 分数传播 + 热度)、QueryPlanner、IntentClassifier |
| L0 结构化摘要 | 双模板抽取(每节点 L0 abstract + L1 overview)、overview-first 检索、session summary 生成 |
| 会话生命周期 | SessionManager、TopicBuffer、session commit(archive + extract)、session context assembly、RollingCompressor |
| 多租户认证 | RBAC(ROOT/ADMIN/MEMBER)、API key 认证、IP 白名单 + 代理信任、agent sharing(off/whitelist/all)、审计日志 |
| Agent 集成 | Claude Code hooks 插件、OpenClaw TypeScript 桥接、ogmem 统一 CLI(onboard/start/stop/check/config/status/logs/eval) |
| 多 Agent 交接 | 子 Agent spawn/ended 生命周期、Agent 间上下文交接、结果合并回父 Agent |
| 边界检测 | 基于 LLM 的对话分块、消息边界检测、可配置分段大小 |
基准测试进展(LoCoMo10)
| Run | 准确率 | 关键改进 |
|---|---|---|
| Run76 | 88.2% (1358/1540) | L0 结构化摘要 + BM25 混合搜索 + 抽取 prompt 优化 |
| Run69 | 88.2% | L0 摘要注入 + prompt 优化(比 run68 +6.6%) |
| Run68 | 81.6% | session_time 修复(基线) |
基于 LoCoMo 长上下文对话记忆基准评测(10 个会话,4 个类别,1540 道题)。
进行中
| 里程碑 | 描述 |
|---|---|
| 上下文压缩(⑤ compact) | 信号评分、受保护节点(Profile、活跃任务)、摘要链、预算感知截断 |
| 图检索 | 实体-关系图遍历用于多跳查询,关系加权展开 |
计划中
| 里程碑 | 描述 |
|---|---|
| 工具上下文注入(③) | 工具调用前后 hook — 注入已知失败模式,压缩过大工具结果 |
| 会话恢复(⑥) | 跨会话状态交接 — 会话结束时快照,新会话冷启动注入 |
| 图聚类 | 社区检测用于实体分组 — 自动将关联实体聚类为话题 |
| 自适应规划 | 查询感知的检索策略选择 — 复杂查询路由到更深的管线 |
| 可观测性 | OpenTelemetry 追踪、token 使用面板、检索质量指标 |
| AI Functions | 工具增强的检索动作 — 上下文感知的工具选择和参数建议 |
快速开始
前置条件
- Python 3.11+
- PostgreSQL 14+ 及 pgvector 扩展(PostgreSQL 模式需要)
- Docker(可选,用于容器化部署)
安装
git clone https://gitcode.com/opengauss/oG-Memory.git
cd oG-Memory
python3 -m venv .venv && source .venv/bin/activate
方式 A:AGFS 模式(默认)
pip install -e .
# 交互式配置向导(引导 LLM + Embedding + 向量库 + 存储配置)
ogmem onboard
# 一键启动(AGFS + ContextEngine)
ogmem start local
非交互模式(CI / 自动化)
ogmem onboard --non-interactive --mode headless \
--provider openai --api-key sk-xxx \
--embedding-model text-embedding-ada-002 --vector-db chroma \
--storage-backend sql
方式 B:PostgreSQL 模式(直连 SQL 存储)
1. 安装并配置 PostgreSQL
# Ubuntu / Debian
sudo apt-get install postgresql postgresql-contrib
sudo apt-get install postgresql-16-pgvector # 版本号按实际 PG 调整
# macOS
brew install postgresql@16
brew install pgvector
# 启动 PostgreSQL
sudo service postgresql start # Ubuntu
brew services start postgresql # macOS
# 创建数据库并启用 pgvector
sudo -u postgres createdb ogmemory
sudo -u postgres psql -d ogmemory -c "CREATE EXTENSION IF NOT EXISTS vector;"
2. 安装 ContextEngine(含 SQL 扩展)
pip install -e ".[dev,sql]"
3. 配置连接
cp config/ogmem.reference.yaml config/ogmem.yaml
# 编辑 storage.connection_string 指向你的 PostgreSQL 实例
使用
HTTP 服务(推荐)
AGFS 模式:
ogmem start local # 启动 AGFS + ContextEngine,端口 1833 + 8090
PostgreSQL 模式:
cp config/ogmem.reference.yaml config/ogmem.yaml
# 编辑 ogmem.yaml: 设置 storage.backend 为 sql,storage.connection_string 为 PostgreSQL DSN
python server/app.py
写入对话轮次
curl -X POST http://localhost:8090/api/v1/after_turn
-H "Content-Type: application/json"
-d '{"userId":"user-1","sessionId":"session-1",
"messages":[{"role":"user","content":"I am Alice, a backend engineer"},
{"role":"assistant","content":"Nice to meet you!"}]}'
搜索记忆
curl -X POST http://localhost:8090/api/v1/compose
-H "Content-Type: application/json"
-d '{"userId":"user-1","sessionId":"session-2","query":"what is alice job"}'
</details>
<details>
<summary><strong>Python SDK</strong></summary>
```python
from service.api import MemoryWriteAPI
from core.models import RequestContext
from fs.sql_adapter import SQLContextFS
from providers.config import ProviderConfig
config = ProviderConfig.from_env()
fs = SQLContextFS(connection_string="host=127.0.0.1 port=5432 dbname=ogmemory user=postgres password=postgres")
write_api = MemoryWriteAPI(fs=fs, llm=config.create_llm())
ctx = RequestContext(account_id="acct", user_id="u1", agent_id="a1", session_id="s1", trace_id="t1")
result = write_api.commit_session([
{"role": "user", "content": "I'm Alice, backend engineer, London"},
{"role": "assistant", "content": "Nice to meet you, Alice!"},
], ctx)
Docker / HTTP API 参考
docker compose up # 服务端口 8090,PostgreSQL 端口 5432
| 端点 | 方法 | 说明 |
|---|---|---|
/api/v1/compose |
POST | 搜索记忆,返回当前轮次上下文 |
/api/v1/after_turn |
POST | 从对话中抽取并持久化记忆 |
/api/v1/ingest |
POST | 单条消息写入 |
/api/v1/ingest_batch |
POST | 批量消息写入 |
/api/v1/bootstrap |
POST | 冷启动会话(profile + preferences 注入) |
/api/v1/compact |
POST | 触发上下文压缩 |
/api/v1/prepare_compaction |
POST | 准备压缩令牌(预压缩规划) |
/api/v1/dispose |
POST | 会话处置 — 归档 + 清理 |
/api/v1/prepare_subagent_spawn |
POST | 子 Agent 上下文交接(多 Agent) |
/api/v1/on_subagent_ended |
POST | 子 Agent 结果合并回父 Agent |
/api/v1/token_stats |
GET/POST | LLM & embedding token 用量(POST 带 reset 清除) |
/api/v1/sessions/{id}/messages |
POST | 向会话缓冲区添加消息 |
/api/v1/sessions/{id} |
GET | 获取会话元数据 + 待处理 token |
/api/v1/sessions/{id}/commit |
POST | 提交会话:archive + extract |
/api/v1/sessions/{id}/context |
GET | 获取组装后的会话上下文 |
/api/v1/call/<method> |
POST | 通用方法分发(前向兼容) |
/api/v1/health |
GET | 健康检查(storage + LLM + vector DB) |
/api/v1/admin/accounts |
GET | 列出账户 |
/api/v1/admin/accounts/{id} |
GET | 获取账户 |
/api/v1/admin/accounts/{id}/users |
GET/POST | 列出 / 创建用户 |
/api/v1/admin/accounts/{id}/users/{uid} |
DELETE | 删除用户 |
/api/v1/admin/accounts/{id}/users/{uid}/role |
PATCH | 设置用户角色(ROOT/ADMIN/MEMBER) |
/api/v1/admin/accounts/{id}/roles |
GET | 列出角色 |
/api/v1/admin/accounts/{id}/agents |
GET/POST | 列出 / 注册 Agent |
/api/v1/admin/accounts/{id}/agents/{aid} |
GET/PATCH | 获取 / 更新 Agent |
/api/v1/admin/accounts/{id}/audit-logs |
GET | 列出审计日志 |
/api/v1/admin/accounts/{id}/audit-logs/{log_id} |
GET | 获取单条审计日志 |
/api/v1/admin/config/agent-sharing |
GET | Agent 共享配置 |
配置
主要环境变量(完整参考见 ENV.md)。 配置优先级:YAML 值 > 环境变量 > 硬编码默认值。
| 变量 | 默认值 | 说明 |
|---|---|---|
OGMEM_API_KEY |
— | LLM API 密钥(OpenAI 兼容) |
OGMEM_BASE_URL |
— | 自定义 LLM API 基础 URL |
OGMEM_LLM_MODEL |
gpt-4o-mini |
抽取 + 分类使用的 LLM 模型 |
OGMEM_EMBEDDING_MODEL |
text-embedding-ada-002 |
向量索引使用的嵌入模型 |
OGMEM_EMBEDDING_API_KEY |
— | 嵌入 API 独立密钥(缺省回退 OGMEM_API_KEY) |
EMBEDDING_PROVIDER |
— | 独立嵌入提供商(openai / volcengine / st / mock) |
VECTOR_DB_TYPE |
chroma |
向量后端:chroma / opengauss(pgvector)/ memory |
STORAGE_BACKEND |
agfs |
存储后端:agfs(AGFS 文件服务器)/ sql(PostgreSQL) |
SQL_CONNECTION_STRING |
— | PostgreSQL DSN(STORAGE_BACKEND=sql 时必填) |
AGFS_BASE_URL |
http://127.0.0.1:1833 |
AGFS 服务器 URL(STORAGE_BACKEND=agfs 时使用) |
OGMEM_HTTP_PORT |
8090 |
HTTP 服务监听端口 |
OGMEM_CONFIG |
config/ogmem.yaml |
YAML 配置文件路径 |
OG_ACCOUNT_ID |
acct-demo |
默认账户 ID |
OG_USER_ID |
u-alice |
默认用户 ID |
OG_AGENT_ID |
main |
默认 Agent ID |
OG_ROLE_CONTROL_ENABLED |
false |
启用 RBAC 认证 |
OG_ROOT_API_KEY |
— | Root API key 用于管理员访问 |
OG_AGENT_SHARED_MODE |
off |
Agent 记忆共享:off / whitelist / all |
OGMEM_AFTER_TURN_THRESHOLD |
200 |
触发抽取的最小消息长度 |
OGMEM_CACHE_ENABLED |
true |
启用检索缓存 |
CHUNKING_ENABLED |
false |
启用边界检测 + 分块 |
INDEX_INTERVAL |
30 |
索引 Worker 轮询间隔(秒) |
仓库结构
ContextEngine/
├── core/ # 领域模型、Protocol 接口、枚举、错误类型
├── fs/ # ContextFS 抽象(上下文操作的文件系统隐喻)
│ ├── agfs_adapter/ # AGFS-backed ContextFS(Go 文件服务器,默认后端)
│ └── sql_adapter/ # PostgreSQL-backed ContextFS(原子 upsert、RLS 租户隔离)
├── extraction/ # CandidateExtractor(ReAct 循环 + YAML SchemaRegistry)
│ ├── prompts/ # LLM 提示模板(Jinja2)
│ └── schemas/ # Schema 注册 + 各类别 YAML 定义
│ └── definitions/ # 10 个 YAML 文件:profile, entity, event, skill, tool 等
├── commit/ # 写入链路:PolicyRouter → MergePolicy → ContextWriter → OutboxStore
├── index/ # 异步索引:OutboxWorker → IndexRecordBuilder → DirectorySummarizer
├── retrieval/ # 读取链路:QueryPlanner → IntentClassifier → SeedRetriever (+BM25)
│ # → HierarchicalSearcher → ResultRanker
├── providers/ # 外部适配:LLM、Embedder、VectorIndex、RelationStore
│ ├── llm/ # OpenAI 兼容 LLM(支持 OpenAI/Volcengine/DashScope/Zhipu)
│ ├── embedder/ # 4 种后端(OpenAI、Volcengine、SentenceTransformers、Mock)
│ ├── vector_index/ # InMemory / ChromaDB / pgvector (OpenGauss)
│ └── relation_store/ # SQL + AGFS 关系存储
├── service/ # API 层:MemoryWriteAPI、MemoryService、IndexService
├── server/ # HTTP REST 服务(Flask)、认证/RBAC、IP 白名单、会话管理
├── session/ # SessionManager、TopicBuffer、RollingCompressor、ArchiveStore
├── tests/
│ ├── contract/ # 跨团队契约测试(不变量检查)
│ ├── unit/ # 各包单元测试
│ ├── integration/ # 端到端集成测试
│ ├── e2e/ # LoCoMo 基准评测框架
│ ├── benchmark/ # 性能和质量基准
│ ├── ab/ # A/B 对比测试
│ └── fixtures/ # 共享测试数据
├── docs/ # 架构、部署、快速上手指南
├── examples/ # 使用示例(SDK、Agent 集成)
├── cli/ # 统一管理 CLI(ogmem 命令)
│ └── commands/ # onboard, start, stop, check, config, status, logs, eval
├── claude-plugin/ # Claude Code hooks 集成(hooks, scripts, skills)
├── openclaw_context_engine_plugin/ # OpenClaw 插件(TypeScript 桥接)
├── agfs/ # AGFS Go 服务器源码(cmd/, pkg/, sdk/)
├── config/ # 配置文件(ogmem.yaml, .env, AGFS 配置)
├── deploy/ # Docker 部署脚本和配置
├── docker/ # Docker Compose 文件
└── scripts/ # 辅助脚本(索引服务等)
Agent 集成
Claude Code
ContextEngine 提供原生 Claude Code hooks 实现零配置记忆:
ogmem onboard # 交互式:选择 "Agent Plugin" → "Claude Code"
ogmem start plugin # 启动 CE 服务 + 安装 hooks
OpenClaw
cd openclaw_context_engine_plugin && openclaw plugins install -l .
| 工具 | 阶段 | 操作 |
|---|---|---|
og_memory_write |
④ 轮次结束 | 提取 + 持久化新上下文 |
og_memory_search |
① 消息到达 | 预取相关上下文 |
og_memory_read |
② 推理准备 | 按 URI 加载完整上下文 |
自动行为(无需 Agent 代码修改):新消息触发预取,轮次结束触发抽取,上下文填满触发压缩,会话关闭触发归档。
实现状态
Phase 0 + 1(生产质量): 详见 Roadmap 里程碑分解。
核心模型、ContextFS 抽象(AGFS + PostgreSQL 适配器)、抽取管线(YAML SchemaRegistry + ReAct 循环)、写入链路(4 种合并策略 + OutboxStore)、分层检索(L0/L1/L2)含 BM25 混合搜索、异步索引含死信队列、提供商(OpenAI/Volcengine/DashScope/Zhipu LLM、4 种嵌入器、InMemory/ChromaDB/pgvector)、HTTP REST API 含 RBAC 认证、会话管理、L0 结构化摘要生成、多 Agent 交接、边界检测/分块。100+ 测试文件(contract + unit + integration + e2e + benchmark)。
已覆盖生命周期阶段: ① message_received, ② bootstrap + ingest + assemble, ④ afterTurn
Phase 2(进行中): 上下文压缩管线、图检索。Phase 3(计划中): 工具上下文注入、会话恢复、图聚类、自适应规划、可观测性、AI Functions。
待覆盖生命周期阶段: ③ before_tool_call + tool_result_persist, ⑤ compression, ⑥ session_end + dispose
文档: CLAUDE.md(完整技术规范)| ENV.md(环境配置)| 快速开始 | 部署指南 | Claude 插件 | OpenClaw 插件 | 基准测试(LoCoMo 评测)
测试: pytest tests/contract/ -v(核心不变量)| pytest tests/ -v(全部测试)| pytest tests/ --cov=core --cov=fs --cov=service --cov-report=html
参考文献
基准测试与评估
- LoCoMo: Evaluating Long-Context Conversational Memory — Maharana et al., 2024 — 长上下文对话记忆基准
LLM Agent 记忆架构
- MemoryBank: Enhancing LLMs with Long-Term Memory — Zhong et al., 2023 — 情感驱动的记忆处理机制
- A-MEM: Agentic Memory for LLM Agents — 2025 — 动态记忆组织与索引
- Mem0: Production-Ready AI Agents with Scalable Long-Term Memory — 2025 — user/session/agent 三级作用域记忆
- SeCom: Memory Construction and Retrieval for Personalized Conversational Agents — 2025 — 段级记忆库与对话分割
分层检索与多粒度
- ReadAgent: Gist Memory of Very Long Contexts — Lee et al., 2024 — gist 记忆,有效上下文长度提升 20 倍
- MemoRAG: Memory-Augmented Retrieval — Qian et al., 2024 — 双系统架构
- LATTICE: LLM-guided Hierarchical Retrieval — Gupta et al., 2025 — 层次化检索框架
上下文压缩
- LLMLingua-2: Task-Agnostic Prompt Compression — Pan et al., 2024 — 高效 prompt 压缩,最高 20 倍
- LongLLMLingua: Question-Aware Compression for Long Context — Jiang et al., 2024, ACL — 粗到细压缩策略
- Prompt Compression for Large Language Models: A Survey — 2024 — 综述
推理与行动
- ReAct: Synergizing Reasoning and Acting in Language Models — Yao et al., 2023, ICLR
多 Agent 与治理
- Governed Memory — Taheri, 2026 — 记忆治理与访问控制
- Collaborative Memory — 多用户记忆共享 + 动态 ACL
- Multi-Agent Memory Systems for Production — Mem0, 2026
- Cemri et al. — Multi-Agent 协调失败分析
基础设施
- OpenViking — AGFS 文件存储层与核心设计灵感来源
- AI Agent Memory Architectures — Zylos Research, 2026