NeuG 图数据库:
驱动 wiki 的构建、维护与检索

背景

知识库面临的三个挑战

知识库将分散的信息组织成结构化的概念文档,为团队理解和 AI 辅助开发提供基础。

📄 内部文档 🌐 网上技术资料 💻 代码仓库 💬 聊天记录 📧 邮件
📚 知识库

然而,构建、维护和检索高质量的知识库,始终面临三个核心挑战:

  1. 1

    构建:数据分散且杂乱,概念边界难以自动发现与聚合

  2. 2

    维护:文档持续变化,难以精确定位受影响的 wiki 文章

  3. 3

    检索:文本只能匹配关键词,无法回答结构化关系问题

背景

LLM-Wiki 方案

当前主流做法是让 LLM 阅读全部原始数据并直接生成 wiki 文档。然而,LLM-Wiki 在构建、维护和检索三个环节都存在根本性痛点:

  1. 1

    构建不稳定:概念边界随模型理解漂移,结果不可复现

  2. 2

    更新不精确:难判断间接影响,容易遗漏或过度更新

  3. 3

    检索无结构:Grep定位查询内容,向量找“相似”,但无法查询知识之间的关联关系

一、构建 wiki

直接让 LLM 构建 wiki,三个关键环节都不可靠

NeuG Repo 的1,359 个源文件直接交给 LLM 阅读并生成 wiki,会遇到哪些根本问题?

痛点 01

概念边界不准确

LLM 倾向按目录分章,但目录结构并不等于概念结构

NeuG 方案

Leiden 发现概念边界

依据调用与引用关系聚类,让跨目录的相关文件自然归组

痛点 02

找不到关键文件

依赖文件名启发式选择,容易偏向短名 header 与边缘文件

NeuG 方案

PageRank 识别核心文件

按全局引用度排序,为每个概念组定位真正重要的入口文件

痛点 03

结果不可复现

每次运行的分组边界和文件选择都可能发生漂移

NeuG 方案

确定性算法稳定复现

相同的图得到相同的聚类与排序,结果 100% 可复现

实验结果一:跨目录聚合能力

概念边界由关系决定,而不是由目录决定

典型社区 type-and-value-system 包含 187 个文件、跨 6 个路径前缀;下图用 6 个代表元素呈现两种方案的差异。

原始目录结构

  • compiler/
    • common/
      • types/
        • types.h
        • timestamp_t.h
        • value.h
        • value_vector.h
    • function/
      • cast/
      • comparison/

图方案 · Leiden 聚类

跨目录识别 → 1 个概念
Type System and Value Representation types.h · timestamp_t.h · value.h · value_vector.h
function/cast/ · function/comparison/

LLM 方案 · 按目录推断

同一内容 → 分裂为 2 个章节
common-types types.h · timestamp_t.h
value.h · value_vector.h
按 common/ 目录归类
×
built-in-functions cast/ · comparison/ 误标:值操作被当作函数

实验结果二:文件重要性排序

选对核心文件,才能生成覆盖架构的 wiki

同一 cypher-parser 章节各选 Top-5 文件:PageRank 按全局引用度排序,LLM 按文件名启发式选择,Top-5 重合率为 0%

cypher-parser · 文件引用网络 PageRank Top-5 LLM Top-5 parser.cpp LLM #1 transformer.h 16 个文件引用 · PR #1 transform_expression .cpp · PR #2 ddl.cpp · PR #3 parsed_expression .h · PR #4 transformer.cpp PR #5 statement.h copy.h database_statement .h · LLM #4 use_database.h 2 个引用 · LLM #5
PageRank Top-5 → transformer.h · transform_expression.cpp · transform_ddl.cpp · parsed_expression.h · transformer.cpp

Cypher Parser

Cypher 解析器将查询语句转换为 AST。入口类 Transformer 声明 80+ transform 方法,覆盖完整 Cypher 语法。

核心流程

  • parser.cpp → ANTLR4 生成解析树
  • Transformer::transform() 遍历解析树并分发
  • transform*() 将 ANTLR context 转为 AST 节点

关键组件

  • 表达式transformExpression() 运算符优先级链 (OR→XOR→AND→NOT→比较→算术),返回 ParsedExpression
  • DDLtransformCreateNodeTable() / transformCreateRelTable()
  • 查询transformQuery() → RegularQuery → SingleQuery (MATCH/RETURN/WITH)
  • 图模式transformPattern() → 节点-关系-节点模式
  • COPYtransformCopyFrom() / transformCopyTemp()
LLM 启发式 Top-5 → parser.cpp · statement.h · copy.h · database_statement.h · use_database.h

Cypher Parser

Cypher 解析器将查询语句解析为内部表示,使用 ANTLR4 作为语法分析工具。parser.cpp 是解析入口,接收 Cypher 文本并生成解析树。

语句类型

解析器支持多种语句类型(statement.h 定义),包括查询、DDL、数据库管理、数据导入等。

数据库管理

  • UseDatabase — 切换当前数据库,继承 DatabaseStatement
  • DatabaseStatement — 数据库操作基类

Copy 操作

COPY FROM 从文件导入数据,COPY TO 导出数据。

查询与表达式

支持 MATCH、RETURN、WITH 等查询子句和表达式运算,具体实现分布在多个 transform 源文件中。

⚠ 缺少 Transformer 类 80+ 方法分发架构、运算符优先级链、图模式解析细节

实验结果三:可复现性与效率

确定性图算法稳定复现,LLM 大纲随运行漂移

同一份 NeuG 代码库(1,359 文件、71 个社区 → 23 个章节)连续生成两次大纲:图方案逐字一致,LLM 的章节数量与分组边界均发生变化。

图方案 · 两次运行

23/23
Run 1 = Run 2 · 章节标题、社区编号、成员归属与 PageRank 排序逐字一致
  1. 01Type System and Value Representation
  2. 02Cypher Parser
  3. 03Query Binder
  4. 04Execution Engine
  5. 05Graph Storage Engine
  6. 06GDS Graph Algorithm Extension
  7. 07Python Client Binding
  8. ......
大纲生成:秒级 API 成本低
LLM · 第一次运行 21
类型系统 Common Types & Utilities:合并 common/ 与 utils/
执行引擎 拆成 Execution Operators + Columns & Expressions
存储 Graph Storage:包含 checkpoint
Pattern Matching 未单独成章
内置函数 Built-in Functions 独立一章
分钟级 · API 成本高
LLM · 第二次运行 24
类型系统 Type System:仅含 common/types/
执行引擎 合并为 Execution Engine 一章
存储 拆成 Storage Layer + Checkpoint & Recovery
Pattern Matching 单独列为一章
内置函数 并入 Type System
分钟级 · API 成本高

二、维护 wiki

让 LLM 判断增量影响,更新范围依然不可控

当源文件持续新增、修改和删除,直接让 LLM 阅读 git diff 并更新 wiki,会遇到哪些问题?

痛点 01

影响范围不精确

可能漏掉间接影响,也会把无关的小改动误判为需要更新

NeuG 方案

精确计算变更社区

Cypher group by 识别 stable、changed、new 与 dissolved

痛点 02

概念编号漂移

重新归组后旧章节编号变化,可能触发大量无意义重写

NeuG 方案

freeze-assign 保持稳定

冻结旧节点与概念组,只为新增节点分配社区

痛点 03

文件选择不准确

继续依赖文件名启发式,容易遗漏真正受影响的核心文件

NeuG 方案

按社区重跑 PageRank

只对受影响社区排序,定位最重要的更新依据

痛点 04

结果不可复现

每次推断的影响范围和文件选择都可能发生变化

NeuG 方案

确定性增量更新

相同的图变更得到相同的增量结果与文件排序

实验:图增量 vs LLM 增量扫描

增量更新:freeze-assign vs LLM 全量扫描

47 文件变更后,图方案冻结旧章节 + 归类新文件,LLM 方案读全部 diff + 对比全部章节。

已有 Wiki + 新增文件 实验输入

已有 Wiki(23 章节)

  1. 01 Type System and Value Representation
  2. 02 Cypher Parser
  3. 03 Query Binder
  4. 04 Execution Engine
  5. 05 Graph Storage Engine
  6. 06 GDS Graph Algorithm Extension
  7. ...

新增文件(git diff,35 个)

  • pattern_matching_functions.h
  • pattern_matching_data_graph_meta.h
  • pattern_matching_data_graph_meta.cpp
  • graph_interface.h (+1行 #include)
  • ... 等 35 个变更文件
输入:已有 Wiki(23 章节)+ 新增文件(git diff,35 个)
图方案(freeze-assign Leiden) freeze-assign:旧章节冻结不动,新文件自动归类
✓ 21 个章节冻结 — wiki 无需任何修改
⚡ 01 Type System and Value Representation +2 成员 新增文件: type_node.h, type_cast.h wiki 更新 → §类型系统:新增 TypeNode 类型定义(枚举值 + 校验逻辑)
+06 GDS Graph Algorithm Extension 3 文件: pm_functions.h, pm_data_graph_meta.h/cpp wiki 新建:DataGraphMeta 数据结构 + PatternFunction API
旧章节编号不变 → wiki 章节稳定,仅增量补充
→ 21 个章节直接复用,仅 2 个需更新(97.3%)
LLM 方案(全量对比) 读全部 35 个 diff → 逐个对比全部 23 个章节 → 判断分到哪里 / 是否新章节
✗ §类型系统 — 误报 graph_interface.h 仅 +1 行 #include → 误标为“类型定义变更”,实际无影响
✗ §存储引擎 — 误报 pm_data_graph_meta.cpp 变更 → 误判为存储层改动,实际是 GDS 数据
✗ §GDS算法扩展 — 文件选错 选中 extension.cpp(90 行注册代码) → 遗漏 data_graph_meta.h(304 行核心数据结构)
✗ 重跑结果不一致 第一次:标记 4 个章节需更新 → 第二次:标记 3 个章节,且归属不同
→ 可能更新 4 个章节(2 误报 + 1 文件选错 + 结果不稳定)

三、检索 wiki

传统检索能找到文本,却回答不了代码结构

当开发者询问“Leiden 在哪里实现、哪些模块依赖 GDS 扩展”,传统搜索为什么仍需要多轮拼接?

痛点 01

grep 只能匹配文本关键词

精确匹配字符串,但搜不到语义相关的代码

NeuG 方案

全文索引 + 向量索引

全文索引快速匹配符号,向量索引支持语义相似检索

痛点 02

无法查询结构关系

“谁调用 Leiden?”“GDS 依赖了哪些模块?“grep 和向量 DB 都回答不了

NeuG 方案

Cypher 图查询

直接返回调用路径、依赖关系和影响范围

痛点 03

多轮搜索效率低

AI 助手平均需要 4.8 次 grep 与文件读取才能拼出答案

NeuG 方案

单次查询返回完整上下文

1 次 context_query 返回符号定位、调用路径与依赖关系

检索实验:三类查询的端到端对比

一次图查询返回完整上下文,传统搜索需要多轮拼接

在 NeuG 代码库上使用 GPT-5.6 完成 100 个查询 case;以下三个代表性 use case 覆盖全文、向量和结构查询。

全文检索 精确符号定位
01

“Leiden::local_moving_phase 在哪实现?”

with NeuG 1 次调用 · 94.9s · 41.6k tokens
without NeuG 4 次调用 · 168.2s · 172.5k tokens

返回结果:精确定位 leiden_impl.cc:157,并返回入口、主流程、refinement、sink 等 9 个相关符号。

1 次查询完成符号定位与完整拓扑返回
向量检索 语义实现发现
02

“哪些代码实现了社区发现?”

with NeuG 1 次调用 · 79.7s · 41.5k tokens
without NeuG 5 次调用 · 169.7s · 223.9k tokens

返回结果:定位 Leiden 和 Louvain 两个算法,包含核心实现、结果结构和查询集成入口。

不依赖关键词,也能发现两套社区算法实现
结构查询 跨模块依赖分析
03

“GDS模块依赖哪些其他模块?”

with NeuG 1 次调用 · 59.1s · 41.2k tokens
without NeuG 5 次调用 · 186.9s · 207.5k tokens

返回结果:直接返回 4 个子模块,以及具体函数调用和源文件路径。

grep 与向量 DB 无法直接回答结构依赖

检索实验总结

图检索降低多轮搜索成本,并补齐结构查询能力

100个查询 case 的聚合数据表明:NeuG 不只减少调用、延迟和 token,更提供 grep 与向量 DB 无法完成的结构查询。

聚合性能对比 with NeuG vs without NeuG · 100 个查询 case
平均工具调用数 1.0 vs 4.8
79.3%降幅
平均延迟 74.1s vs 176.2s
58.0%降幅
平均 token 46,196 vs 207,485
77.7%降幅
平均成本 $0.065 vs $0.340
81.0%降幅
with NeuG 在全部 6 个 case 中均只调用 1 次 context_query,没有执行额外搜索
整体功能对比 grep / 文件搜索 · 向量 DB · NeuG 图检索
方案关键词搜索结构查询工具调用数信息深度token 成本
grep / 文件搜索✓ 搜文本4.8 次平均只能搜到文本内容高(多轮搜索)
向量 DB✓ 搜语义同上可以搜到语义相关内容同上
NeuG 图检索全文索引 + 向量索引Cypher 路径、依赖、影响分析1 次图结构信息(调用路径、依赖关系、枢纽节点)低(单次查询返回完整结果)
关键区别:图检索不只是搜文本,而是查结构

额外能力

远程数据直连,并覆盖端侧到云端的运行形态

除 wiki 的构建、维护与检索外,NeuG 还支持远程数据读写,以及 AP/TP 访问、嵌入式和服务器部署方式。

远程数据能力 COPY FROM / EXPORT TO · OSS / S3
对象存储可直接作为数据入口与出口

通过统一 SQL 从 OSS/S3 导入节点与关系,或将查询和 wiki 结果直接导出到远程存储。

从 OSS / S3 导入 COPY node FROM 's3://bucket/nodes.csv'
(header=true, delim=',');
导出查询结果 EXPORT 's3://bucket/wiki_result.csv'
FROM ...;
数据导入导出无需本地 staging,减少中间搬运步骤
端云能力 AP + TP 访问 · Embedded + Server 部署
访问模式
AP 访问

面向图分析、批量计算和复杂关系查询。

TP 访问

面向在线读写、持续更新和事务型访问。

运行形态
嵌入式执行

随应用进程运行,适合本地和端侧集成。

服务器部署

作为独立服务运行,支持共享访问与集中管理。

同一引擎覆盖端侧、服务端与云端,按业务场景组合访问和部署方式

总结

NeuG 与大模型,不是替代,而是各司其职

图数据库负责结构化、确定性的部分;大模型负责语义理解与内容生成。

NeuG 图数据库

结构化、确定性的部分
· 概念发现(Leiden 聚类)
· 变更检测(freeze-assign)
· 结构查询(Cypher)
· 文件选择(PageRank)

大模型(LLM)

语义理解与内容生成
· wiki 章节内容撰写
· 自然语言交互与问答
· 代码摘要与解释

图提供结构骨架,大模型填充语义血肉 —— 二者结合,才能构建、维护和检索高质量的知识库。