Graph SDK 架构
Graph 模块本身就是一个完整的 Graph SDK。它向应用提供图数据模型、Space 和 Schema 管理、数据写入与导入、统一查询语言、事务、能力检查、结果处理以及后端连接管理等能力。
Neo4j 和 Nebula 不是 Graph 模块之外的“适配器产品”,而是 Graph SDK 内部面向不同图数据库的后端实现。应用依赖的是 Graph SDK 定义的公共契约,通常不需要直接接触数据库客户端、连接池或数据库方言。
总体架构
Graph SDK 处在业务应用与具体图数据库之间,内部由公共契约、统一语义层和后端实现共同组成:
┌─────────────────────────────────────────────────────────────┐
│ 业务应用 │
│ 知识库服务 / 推荐服务 / 风控服务 / 数据管道 / 自定义管理后台 │
└──────────────────────────────┬──────────────────────────────┘
│ 使用 Graph SDK 公共契约
┌──────────────────────────────▼──────────────────────────────┐
│ Graph SDK │
│ │
│ 连接与生命周期 │
│ Space / Schema / Capability 管理 │
│ 节点与边写入、批量导入、异步任务 │
│ 统一查询语言与 AST │
│ TraversalQuery / Union / Optional / Native Query │
│ 分页、游标、Explain、事务、结果模型和错误分类 │
└───────────────┬───────────────────────────┬─────────────────┘
│ 统一后端执行契约 │ 可选扩展层
┌───────────────▼──────────────┐ ┌─────────▼────────────────┐
│ Graph SDK 后端实现 │ │ Graph Extractor │
│ Neo4j 实现 / Nebula 实现 │ │ 文档分段、实体关系抽取、 │
│ 方言编译、连接、结果转换 │ │ 校验、归一化和增量入图 │
└───────────────┬──────────────┘ └───────────────────────────┘
│
┌───────────────▼──────────────────────────────────────────────┐
│ Neo4j / Nebula 等真实图数据库 │
└───────────────────────────────────────────────────────────────┘其中,Graph Extractor 是面向知识图谱场景的可选组成部分,负责把非结构化内容转换为候选节点和边;Graph SDK 负责这些结构化数据的存储、维护和查询。两者可以独立使用,也可以通过导入流程组合。
工程模块组成
Graph SDK 由多个协作模块组成,但对应用仍表现为一套统一的 SDK:
| 模块 | 定位 | 主要职责 |
|---|---|---|
agents-flex-graph-api | SDK 公共核心 | 公共模型、接口、查询语言、AST、能力声明、错误和结果契约 |
agents-flex-graph-neo4j | SDK 的 Neo4j 后端实现 | Neo4j 连接、Cypher 编译执行、事务、游标、Schema 和结果转换 |
agents-flex-graph-nebula | SDK 的 Nebula 后端实现 | Nebula 连接、nGQL 编译执行、Space、Schema/索引和结果转换 |
agents-flex-graph-extractor | 可选知识抽取扩展 | 文档内容到节点/边候选的抽取、校验、实体归一和增量入图编排 |
agents-flex-graph-testkit | 测试支持模块 | 面向实现方的内存替身、契约测试和导入/任务行为验证 |
其中,agents-flex-graph-api 是公共语义的中心;后端模块依赖它并实现具体数据库能力;Extractor 不属于数据库驱动,而是面向知识图谱数据生产的上层扩展;Testkit 不参与生产运行时。
Graph SDK 的内部层次
公共模型与契约层
这一层定义跨后端稳定的业务对象和服务接口,是应用编程的主要依赖:
- 图数据模型:节点、标签、属性、边、边类型、方向、边 rank 和稳定业务 ID;
- Space 与 Schema 模型:图空间、节点类型、边类型、属性、索引、Schema 检查和迁移信息;
- 写入与导入模型:upsert、删除、批量请求、导入报告、异步任务、checkpoint 和恢复点;
- 查询与结果模型:查询、过滤、投影、聚合、分页、游标、执行计划、记录和子图结果;
- 运行时契约:连接健康、事务、能力矩阵、统一错误码和资源关闭规则。
这一层不包含 Neo4j Driver、Nebula SessionPool 或具体数据库语句,因此公共模型可以被多个后端实现共同使用。
控制面能力
控制面负责“图的结构和运行环境”,通常在应用启动、租户初始化、Schema 发布或管理操作中使用:
- 注册和管理多个图数据库连接;
- 检查连接健康状态和后端版本能力;
- 创建、删除、列出和选择 Graph Space;
- 定义、应用、反查和比较 Schema;
- 创建索引并获取迁移预览;
- 查询后端能力矩阵,判断统一功能是否可用。
Graph Space 是 SDK 的逻辑隔离概念。Neo4j 通常映射到 database,Nebula 通常映射到 Space;上层可以把它用于租户、项目、知识库或环境隔离。
数据面能力
数据面负责“图中的内容和查询”,通常被业务请求、数据管道和知识抽取流程调用:
- 节点和边的新增、更新、删除与幂等 upsert;
- 节点优先、边随后写入的批量导入;
- 进程内异步导入任务、状态、报告和恢复信息;
- 统一查询、原生查询、分页、游标和执行计划;
- 在支持的后端上执行事务中的读写;
- 对结果数量、超时、只读模式和资源释放进行保护。
控制面和数据面共享同一个 Graph SDK 连接和能力模型,但职责不同。只执行查询的服务可以只依赖查询能力,不必获得 Schema 或写入权限。
统一查询语言架构
统一查询语言是 Graph SDK 的核心组成部分,不是对 Neo4j Cypher 或 Nebula nGQL 的简单转发。它为应用提供一套独立于后端的查询表达方式,并把字符串查询和程序化查询统一到同一个语义模型。
两种公共查询入口
Graph SDK 支持两种表达同一类 Portable Query 的方式:
- 程序化查询:通过节点模式、边模式、过滤器、投影、排序、聚合和分页对象构建查询;
- 字符串查询语言:使用 Graph 自己定义的
MATCH、WHERE、RETURN、OPTIONAL MATCH、UNION、聚合、排序和分页语法。
两种入口都不直接生成数据库语句,而是先形成统一的查询表示。这样可以让业务代码、配置文件、管理后台或自然语言转查询的上层组件共享同一套查询语义和校验规则。
查询处理流水线
字符串查询 / 程序化查询
│
▼
词法分析与语法解析
│
▼
统一查询 AST
│
├── 标识符、别名、投影、跳数和参数校验
├── 查询结构校验与语义约束
└── 参数快照与模板绑定
│
▼
目标后端编译器
│
├── Neo4j:参数化 Cypher
└── Nebula:参数化 nGQL
│
▼
后端执行器
│
▼
统一 GraphResult / GraphRecord / GraphSubgraphResult值通过参数绑定传给后端,避免把用户输入直接拼接到语句中。标签、边类型、属性名和别名属于查询结构,必须经过标识符校验,不能用普通参数替换。
Portable Query 与 Native Query
Portable Query 表达多个后端都可以实现的共同语义,例如线性节点遍历、边方向、属性过滤、路径投影、聚合、排序和分页。后端编译器负责把统一 AST 转换为目标数据库方言;如果后端无法保持语义一致,SDK 应明确抛出能力异常。
Native Query 用于最短路径、数据库专属函数、管理语句、复杂子查询或其他后端专属能力。它绕过统一 AST,直接使用 Cypher、nGQL 等原生语句,因此应被限制在明确的后端边界内。
后端实现层
每一种后端实现都需要完成相同的 SDK 契约,但可以保留自身的连接和执行方式。以当前实现为例:
- Neo4j 实现:负责 Bolt 连接、Cypher 编译与执行、事务、流式游标、执行计划和结果转换;
- Nebula 实现:负责 GraphD/SessionPool 连接、nGQL 编译与执行、Space 切换、Schema/索引传播和 Nebula 结果转换。
后端实现主要包含以下职责:
- 将公共模型编译为目标数据库语句;
- 绑定参数并执行数据库操作;
- 将数据库结果转换为统一结果模型;
- 把后端错误映射为统一错误码和异常;
- 声明事务、索引、分页、聚合、游标等能力差异;
- 对后端特有的连接、重试、资源和 Schema 生命周期负责。
后端实现不应把数据库方言泄漏到公共模型,也不应在不支持某项语义时静默改变结果。新的后端应优先实现公共契约,再通过能力矩阵明确其限制。
能力声明与统一失败语义
不同图数据库的功能并不完全相同。Graph SDK 通过能力矩阵描述每个后端支持的功能、限制、支持模式和参数上限,例如:
- 是否支持事务和事务中的查询;
- 是否支持流式游标、分页和单查询超时;
- 是否支持聚合、分组、可选遍历和 UNION;
- 是否需要索引才能执行某些属性过滤;
- 是否支持唯一索引、多标签、变长路径或特定 Schema 反查。
应用可以据此在运行前选择 Portable 或 Native 路径,也可以在管理后台展示能力提示。执行不支持的功能时,SDK 应返回明确的 UnsupportedGraphFeatureException 或统一错误码,而不是让业务依赖数据库原始错误文本。
连接、生命周期与并发模型
GraphStore 代表一个长期复用的 Graph SDK 后端连接实例,通常由应用容器、连接注册表或 Spring Bean 创建和关闭。高并发请求不应为每次查询重复创建和关闭 GraphStore,而应共享已经初始化的连接池和后端资源。
请求级对象应保持轻量和无状态:查询条件、写入请求和 GraphOptions 可以按请求创建;连接、SessionPool、Driver 和后台导入执行器由 Store 或连接注册表统一管理。应用关闭时,再由生命周期拥有者关闭 Store、任务执行器和游标等资源。
多个后端或多个 Space 可以通过连接注册表和 GraphOptions 路由,但具体的动态 Space 切换能力仍受目标数据库连接模型和权限限制影响。
知识抽取架构
在知识图谱场景中,Graph SDK 通常位于“抽取结果”和“图数据库”之间:
文档 / 文件 / 业务事件
│
▼
解析、分段和内容预处理
│
▼
模型抽取实体与关系候选
│
▼
Schema 校验、实体归一和冲突处理
│
▼
Graph SDK 写入与导入
│
▼
Space 中的节点、边和可查询图谱抽取层决定“文本中可能有什么”,Graph SDK 决定“如何可靠地保存、更新和查询”。同一个 Space 可以在首次全量导入后继续接收新的文件和事件;上层通过稳定的文档 ID、实体 ID、版本或来源信息实现幂等、追踪和回滚。
扩展点
Graph SDK 的扩展应围绕稳定契约进行,而不是修改公共查询语义来适配单个产品:
- 新增图数据库:实现 Store、Manager、Writer、Query、Transaction 等后端能力,并提供方言编译器;
- 新增查询能力:先扩展统一 AST、解析校验和能力声明,再由各后端决定是否支持;
- 新增导入方式:实现数据源、监听器、任务存储或 checkpoint 持久化;
- 新增连接管理:使用连接注册表或应用容器托管 Store 生命周期;
- 新增知识抽取流程:在 Graph Extractor 或业务管道中完成,不把模型调用耦合进数据库执行器。
明确不属于 Graph SDK 的部分
Graph SDK 不负责以下产品和基础设施职责:
- Web 管理后台、Schema 设计器、图可视化和查询编辑器;
- 用户、租户、角色、权限、凭据加密和审计策略;
- 文件上传、OCR、文档解析、分段和大模型提示词编排;
- 分布式任务调度、消息队列、跨服务一致性和业务级去重;
- 图数据库部署、备份、高可用、扩缩容和运维监控平台。
这些系统可以使用 Graph SDK 的能力矩阵、Schema 反查、任务状态、结果元数据和统一错误码构建自己的控制面,但不应把控制面逻辑反向塞入 Graph SDK。
架构设计原则
Graph SDK 的整体设计遵循以下原则:
- 公共语义优先:先定义稳定的图数据和查询语义,再实现数据库方言;
- 统一入口、能力透明:尽量统一调用方式,但不隐藏后端限制;
- 查询结构与参数分离:结构经过校验,值通过参数绑定;
- 控制面与数据面分离:Schema、Space 和连接治理不与业务查询混为一谈;
- 资源长期复用:Store、Driver 和连接池由生命周期容器管理,请求只创建轻量操作对象;
- 失败可诊断:使用能力异常、错误码、警告和结果元数据表达问题;
- 后端可替换:业务依赖 Graph SDK,而不是依赖某个数据库的客户端实现。