← 文章 / AI技术
getzep 1小时前 · 2026-09-12 10:18:11 · 3 阅读

我们为什么为 Agent 记忆打造了专属图数据库服务

  • 大规模的受治理 agent 上下文是一种通用图数据库处理不好的工作负载。Konig 是 Zep 专为 agent 记忆打造的图数据库:支撑数百万个知识图谱,每个用户、团队或项目各一个,大部分处于冷存储,且全部具备时间属性和治理能力。
  • 检索延迟随图谱数量增长基本保持恒定:从一千个图谱到数千万个图谱,p95 检索始终低于 100ms;在这个规模下,Zep 完整的端到端检索也低于 200ms。成本跟随实际活动而非容量:热图谱由 RAM 提供服务,闲置图谱则被驱逐到对象存储。
  • 单次查询即可将向量、全文、图和模式信号融合为一个排序结果。通常作为离线批处理任务运行的图分析(如 PageRank)可以在线毫秒级完成。
  • 每个图谱在其快照内部拥有独立的全文索引和向量索引:默认使用 SIMD 内核的精确 kNN,随着图谱增长可切换到采用 SPFresh/LIRE 增量维护的 IVF 索引。无需运维任何共享搜索集群。
  • 治理与安全内置于数据平面:每个节点和边上都有基于属性的访问控制(ABAC),支持图谱级隔离、客户自管密钥(CMEK/BYOK),以及可溯源到原始数据源的双时态事实。

Agent 依赖上下文行动:它们对所服务用户的了解、对所处业务的理解,以及对已完成工作的记录。这些上下文散落在各个来源中:不断变动的账户、未支付的发票、上周那通棘手的电话,其实都属于同一位客户,但每条事实存储在不同的系统里,没有任何一个系统记录它们之间的关联。将这些来源的上下文统一起来,能给 agent 带来工具调用无法提供的洞察和效率。统一后的数据就是实体以及实体之间的关系。

图是这类数据的理想结构。关系是一等公民,遍历可以取代关系型或文档数据库所需的 join。溯源也是内建的:每条事实都是一条边,指向它所提取的源数据,因此要追溯 agent 为什么持有某个信念,只需一次遍历。时间同样契合这个模型——一条边可以同时记录关系在现实世界中成立的时间,以及系统记录它的时间。

图结构非常适合将来自不同来源的业务数据统一建模。

Zep 构建了一种特定类型的图,每个主体一张,这里的主体指 Agent 任务涉及的用户、客户、团队或项目。单个客户可能就拥有数百万张这样的图。

大规模构建和提供图服务极具挑战,这正是我们开发数据库服务的原因。

Konig 的第一版是个假日项目。此前数月,我们在生产环境中的图数据库频繁遭遇宕机和性能瓶颈,因此我在圣诞和新年期间搭建了一个图引擎原型。它基于内存邻接表构建,证明了能满足我们的规模需求。今年年初,团队其他成员加入,凭借他们在图算法、搜索和分布式系统方面的经验,将这个原型打磨成本文描述的这套生产系统。

需求清单

Zep 的客户是大型企业和快速成长的 AI 原生初创公司。单个客户拥有众多 Agent 处理主体,每个主体又有多源数据,以及多类 Agent 在操作这些数据。单个部署需要同时为数千甚至数百万主体维护独立上下文。很多部署运行在受监管行业,错误答案可能直接演变成合规事故。

因此,Konig 的需求包括:

  1. 规模:支持数百万张图,每张图拥有持续演进的记忆,且检索延迟不随图规模或图数量增长而恶化。
  2. 治理:通过策略将访问控制、数据保留、来源追溯和审计能力细化至节点和边。
  3. 安全:图之间的隔离、客户可控的加密,且部署模型需匹配客户的合规要求。
  4. 成本:系统不应为应对罕见峰值,而将数百万张闲置图长期保存在内存或集群存储中。

为何构建图数据库服务

我们初衷并非构建图数据库。Zep 一直使用现有的商业数据库,并运行了很长时间。随着规模扩大,它逐渐不再适用。

数据库在负载下失效,而增加硬件也无法改善,因为故障源于架构本身。在我们的访问模式下,性能瓶颈无法通过调优消除。它无法满足客户的实际需求:多图管理、按图隔离、由客户持有加密密钥,以及基于实际活动量而非预分配集群容量的计费模式。

这套技术本身很优秀,但它是为另一类问题设计的。通用图数据库通常假设只有一个大图:大部分数据常驻内存,通过复杂查询遍历,且基于预先固定的模式。Agent 上下文恰好相反:包含数百万个小图,任意时刻大多处于冷数据状态,且每个图都需独立进行时间序列管理和治理。图数据库一直被认为慢且难以扩展。在我们看来,问题根源在于数据库与该工作负载不匹配,而非图模型本身。

试图对抗一个为不同工作负载设计的数据库不如直接构建一个契合自身负载的系统,因此我们开发了 Konig。它是 Graphiti 及其他 Zep 服务组件运行的数据平面。

Zep 架构:Konig 是 Zep 服务的数据平面。

为何窄范围更容易构建

构建通用数据库是一项耗时多年的工程。而针对单一工作负载定制的引擎,在开发和维护成本上都要小得多,因为它无需兼容所有用例。

查询接口是最典型的例子。Konig 暴露 gRPC API,支持变更、搜索、遍历及少量查询操作。它没有 Cypher 等通用查询语言。这消除了构建数据库过程中的一大难点:无需解析语法,也无需为任意查询维护高性能的查询优化器。在通用数据库里耗费大量精力的解析与规划层,在 Konig 中并不存在。

我们在基础设施上也做了同样的取舍。Konig 运行在云厂商的托管服务上,而不是自己实现存储和故障转移的底层机制:快照存放在对象存储,write-ahead log 和元数据则使用托管的多可用区数据存储。这些东西自研的话工程量巨大,直接用托管基础设施大大缩短了上线时间。

数百万个小图,而不是一个大图

Konig 不会把一个大图分片给多个租户共用,而是给每个主体(比如用户、项目或团队)分配独立的一个图。这个图就是存储、访问控制、加密和保留策略的基本单元。

一个主体对应一个图,隔离就成了结构性保证:一个租户的上下文不可能出现在另一个租户的查询结果里。治理、加密和保留策略都附着在这个天然存在的边界上,完全不需要 SaaS 产品里常见的按租户过滤查询。

把每次查询限定在单个图内,让一些原本只能离线运行的算法可以实时执行。PageRank 查询能在几毫秒内返回。把记忆拆分成每个主体一个图,限制了每次查询和算法需要触碰的工作集大小。这些算法按请求内联执行,而随着图数量的增长,延迟保持平稳。

这个设计的代价是放弃了全局排序和跨所有图的遍历。但在实时检索路径上我们并不需要它们:单次检索只针对一个图,agent 需要跨多个图推理时通过多次独立调用完成。有些客户确实需要跨图分析,我们正在把它作为一个单独的、非实时的负载来构建,与低延迟检索路径分开。

Konig 架构:多层分级的图存储

热、温、冷三层存储

大部分图在大部分时间都处于闲置状态。Konig 把这一点作为成本模型的基础,让每个图处于三种层级之一。

热图存放在 RAM 中,以微秒级延迟响应绝大多数查询。快照会定期写入本地临时 NVMe 和对象存储。因长期不活跃而从 RAM 中被逐出的图进入温状态,其快照仍保留在本地 NVMe 上,可在几毫秒内重新加载。闲置更久之后,本地副本会被清理,图转为冷状态,只在对象存储中保留快照。

冷图谱几乎不需要保留成本,下一次请求时从对象存储重新加载即可。优化对云厂商对象存储的使用方式后,冷加载时间已降至数百毫秒的低两位数区间。晋升为热状态的过程是惰性的;没有后台进程去预热那些未被使用的图谱。

成本取决于活跃图谱的数量,而非图谱总数。一个部署百万图谱且热占比仅 1% 的系统,只需为 1% 的内存付费;其余部分以对象存储的价格存储在对象存储中。这是数据湖模式在 Agent 上下文中的应用:工作集保留在高速存储中,长尾部分成本极低。

通过增加分片进行扩展

图谱通过聚会哈希(rendezvous hashing)分布在各个分片上。每个图谱会通过哈希其键与分片 ID 对所有分片进行评分,得分最高的分片拥有该图谱。因此,添加或删除分片只会导致大约 1/N 的图谱迁移,其余保持位置不变。没有再分片步骤,没有再平衡窗口,也没有协调器分配所有权。

哈希评分决定哪个分片拥有图谱。

新分片几乎能立即就绪。启动时,它不会批量加载分配的图谱或重放日志。它注册心跳,标记自身就绪,并从空的内存映射开始。每个图谱在首次请求时按需加载:König 先加载快照,然后重放自那以来写入的预写日志。增加容量意味着添加节点,并让它在请求到来时加载其图谱。

这解决了最初的失败问题,即增加硬件不再有帮助。即使集群化,旧数据库仍在每个节点上保留完整数据集,无法将工作负载分片到不同节点,因此扩展意味着更大的机器。König 支持水平扩展。无需预先设计集群拓扑,也无需针对峰值负载进行容量规划。

查询仅针对单个图,因此其延迟与图的总数无关。在生产环境中,随着图数量的增长,p95 搜索延迟基本保持稳定。即便从一千个图扩展到数千万个,p50 检索时间保持不变,p95 始终低于 100 毫秒,且随着数量进一步增加仅有微小上升。Zep 的端到端延迟低于 200 毫秒,系统每秒可处理数千次变更和查询。

查询执行方式

读取请求通过类型化 API 进入,并针对内存中的图执行。实体和边存储在与紧凑的整数索引数组及邻接列表中,因此追踪关系只需指针解引用,而非索引查找。在该表示之上,Konig 将所有相关性信号合并为单一的排序结果。

Konig 提供多种从图中获取上下文的方法,包括通过 BM25 实现的词法相关性以及用于语义匹配的向量相似度。这两者均源自下一节描述的每图搜索索引。

Konig 执行搜索策略的示例。

这些词法和语义搜索结果可作为图结构查询的种子,例如 BFS(广度优先搜索)和个性化 PageRank。这样做将操作范围缩小到子图,从而优化了这些过程。

在许多搜索操作中,Konig 运行上述所有策略的流水线,通过倒数排名融合(RRF)将它们合并,随后进行可选的多样性重排或低延迟 LLM 重排,最终生成一个有序结果。无需 Elastic 或 OpenSearch 等独立的搜索集群。

搜索索引

每个图拥有独立的一组全文和向量索引,作为伴随结构存储在其快照中。没有共享的搜索集群,也没有需要单独管理的独立索引工件。这些索引采用分层设计,随其服务的图一起进行快照、复制和删除。BM25 在每图全文索引上运行;向量搜索则在每图向量索引上运行,每个嵌入模型对应一个索引。

向量搜索默认采用精确 k 近邻。在规模有限的图上,精确扫描速度很快,且每次都能返回正确结果。我们通过支持 fp32、bf16 和 int8 的 AVX-512 SIMD 距离计算内核来保持其性能。在大多数图上,精确搜索可在个位数低毫秒内完成。

Konig 在大型图上使用 ANN,索引由 SPFresh/LIRE 维护。

在最大的图上,精确扫描变慢了,因为完整遍历受限于内存带宽。我们首先尝试用近似最近邻(ANN)索引 DiskANN 来提升性能,但对这个场景来说它是错误的选择。DiskANN 会在向量之上构建自己的邻近图,每个节点的索引条目里内嵌了其邻居向量的副本,这样搜索时每跳只需一次读取即可在图上游走。由于每个节点有几十个邻居,索引把向量数据复制了好多份,数据库体积膨胀了一个数量级,内存和存储开销也随之大增。索引构建时间也从每个图几十分钟延长到数小时。

随后我们尝试了 IVF 索引,实现成本低得多。IVF 会把向量聚类成一个个 cell,查询时只扫描离它最近的几个 cell,收益随图规模增长而呈亚线性提升。cell 的成员关系只存储行引用而非向量本身,因此每个向量可以同时属于多个邻近的 cell。

索引的划分方式与搜索的过滤方式一致。图中的每个 scope 拥有自己的 cell 码本、自己的 postings 和自己的内存导航器,带过滤条件的查询只探测它指定的那个 scope。因此过滤完全不影响召回率:索引不会先产生一个候选列表再由过滤器筛选,所以在小 scope 上搜索的召回率与整图搜索一样。不带过滤的查询则跨 scope 取并集。

这种复制方式把召回率提升到约 0.95,同时只需扫描语料的几个百分点,每个图的代价仅为几兆字节。图在创建时就会注册进 IVF,因此在规模变大之前就已建好索引,无需后续转换。

该索引通过 SPFresh/LIRE 增量维护机制自动保持更新。图数据在数年间持续变化,而对数百万向量图执行全局重新聚类需耗时数小时,因此我们负担不起定期重建的开销。借助 SPFresh,后台进程会对过满的单元格进行拆分,合并过空的单元格,仅重新分配边界附近的向量。索引在原地保持平衡,读写操作全程无阻塞。

邻接表与稀疏矩阵

邻接表是动态图的标准结构。每个节点维护自身的边列表,添加关系只需在某个节点的列表中追加一项,遍历节点时仅需读取其邻居。Konig 以这种方式在 RAM 中存储每个图:使用整数索引的节点数组,每个节点都附带其边列表。由于内存负载持续运行突变和遍历操作,而这两类操作在邻接表下成本极低。

邻接表并不适合 PageRank 和模式查找(motif finding,一种识别图模式的方法)等线性代数负载。这些算法需批量处理所有边,在压缩稀疏行(CSR)矩阵上运行效率最高:所有边被打包进一个连续数组,并通过偏移索引标记每个节点边的起始位置。该布局紧凑,且由于 CPU 按缓存行读取内存,扫描打包数组时取回的每个字节都会被有效利用,整个图按顺序流经 CPU。

邻接表是数据真相来源,而在邻接表性能不佳的场景下使用 CSR 矩阵。

CSR 作为主存储同样存在缺陷,原因正是其扫描速度快的特性。由于数组是紧密打包的,插入一条边意味着移动其后的所有元素并重建偏移量,这几乎等同于重建整个结构。Zep 图通常处于快速变化状态,使得实时维护 CSR 的成本过高。

Konig 两种结构都用。邻接表作为唯一可信数据源承接所有写入;当算法需要矩阵时,Konig 会在几毫秒内按需构建 CSR 矩阵,执行完毕后在闲置一段时间再将其丢弃。由于每个图的规模有限,矩阵生成开销很低。Konig 的图算法常基于 CSR 形态运行,延迟可达微秒至低毫秒级。只要两种表示之间的转换足够廉价,就值得同时维护。

图原生支持双时态事实

Zep 的一项核心创新是引入双时态事实。每条承载事实的边都带有四个时间戳:两个记录世界状态——关系何时生效、何时失效;两个记录系统认知——Zep 何时首次记录该事实、何时得知其已不再成立。真实世界与系统认知是两条独立的时间线,而 Konig 原生支持同时追踪这两条线。

这使得高效的“时间点”查询成为可能:结果反映的是指定日期时的状态,而非被后续写入覆盖后的当前值。当新信息与既有事实矛盾时,Konig 通过 invalid_at 字段标记旧事实为无效,而非直接覆写,从而保留历史以便审计,并能在任意时间点重建 Agent 的认知。基于时间戳的“最新优先”排序与“当前有效”过滤也由此自然导出。这些功能完全建立在数据模型之上,无需额外的逻辑层。

Konig 对 Zep 双时态事实的原生支持,让时间点查询更加高效。

持久性与恢复

Agent 记忆属于权威记录系统(system of record),写路径也按此标准设计。每次变更都会追加到一个已复制、有序的前置写入日志中,只有在追加操作完成持久化后才会确认写入成功。每个图按单调递增的序列号独立排序,确保历史可确定性重放。内存中的图采用写透(write-through)方式同步更新,保证常驻副本与日志始终一致。

快照会周期性压缩日志:合并墓碑记录并压缩结果,附带校验和以检测数据损坏。每个快照持久化到多可用区对象存储,同时保留本地 NVMe 副本以加快预热加载。恢复时先加载最新快照,再重放其后写入的日志,图即为最新状态。如果快照缺失,Konig 也可以仅凭日志完成重建。

Konig 的分片故障切换方案。

故障切换不需要中央协调器。各分片会发送心跳,当选的协调器在心跳停止后将该分片从成员列表中移除,再通过 rendezvous hashing 重新推导出新的数据所有者。gRPC 请求可以打到任意分片,然后被路由到持有该图的分片。存活分片通常是在处理请求时才发现某个分片挂了:转发请求打到了失效节点,连接失败。此时存活分片刷新成员列表,重试后请求到达新所有者,新所有者从对象存储和日志冷加载图数据。数据不会丢失,因为持久性从来不依赖任何单个分片。

Konig 更看重可用性而非强一致性。它在整个集群上是最终一致的,用幂等性代替 exactly-once 语义。上下文检索可以容忍故障切换期间短暂的数据滞后,但无法容忍写入被静默丢失。

安全与治理

安全是重建系统的四大需求之一,也是我们推倒重来的原因之一,因此它被直接内置在 Konig 中。

访问控制采用基于属性的模型(ABAC),在检索时对每个节点和边进行评估。系统没有那种返回整张图、然后指望调用方自行过滤的粗粒度 API 边界。隔离也是结构性的:每个主体一张图,意味着某个图的上下文不可能出现在另一个主体的结果里,因为根本不存在共享的图。

图同时也是加密的单元。客户自管密钥(CMEK/BYOK)通过信封加密绑定在图和租户边界上,数据模型无需任何改动。当合规要求时,Konig 还可以部署在客户自己的云环境内。

治理体系基于同一套基础设施。数据保留策略会根据客户自定义的计划使数据过期,而合规要求触发时,法律保留功能会阻止删除。删除操作先写入墓碑记录,随后永久清除,确保整个生命周期均可审计溯源。数据溯源(Provenance)——即从事实回溯至原始来源的路径——是图中可查询的属性,而非事后重构的日志。

利用智能体构建

Konig 主要是用编码智能体(coding agents)构建的。关键在于如何使用它们,以及我们首先开发了哪些工具来提升效率。

我们以对抗方式使用智能体,从设计和规范阶段便已开始。一个智能体提出设计方案,另一个则负责攻击该方案。我们还要求它们挑战我们的既有假设。这种方式比单个智能体独立运作时,能更快、更全面地暴露出关键的假设。

我们优先构建监控工具,使智能体能够快速开发、测试和迭代。正确性测试套件从一开始便投入运行,同时配有 `graphctl` CLI 和基于 Web 的图形浏览器,供开发者检查图结构。我们还开发了可扩展性和浸泡(soak)测试套件。Datadog CLI 早于 Datadog 的原生 MCP 服务发布,补全了工具链。智能体可以部署变更,运行测试套件,读取回产生的追踪记录和性能分析结果,并修复发现的问题。

从一开始,我们就为智能体和团队编写了详尽的文档和运维手册(runbooks)。`AGENTS.md` 中的规则确保任何功能或架构变更都会同步更新相关文档。

经验教训

被替换的数据库本身技术良好,但它预设了单一大型、热点图(hot graph)的场景。无论如何调优,都无法缩小其与数百万个小规模、冷数据、受治理图之间的差距。本文中的结果——平直的延迟、随活动量波动的成本、通过架构实现隔离——均源于数据库与工作负载形态的匹配。

相比于“我们构建了一个数据库”这一说法,实际构建规模更小,因为我们只开发了问题所需的部分。Konig 没有通用查询语言,也缺少数据库为适应所有工作负载而累积的广阔功能面(surface area)。这一约束使得小团队能够构建并维护该系统。

这次实践为我们如何构建大型复杂服务提供了宝贵的经验,也让我们有信心去接手以前会避开的其他项目。

🔆我们正在招聘!如果您对参与 Konig、Graphiti 等类似项目感兴趣,请通过联系我们
原始来源: getzep

评论 (0)