489 lines
15 KiB
Markdown
489 lines
15 KiB
Markdown
# 浏览器端代码知识图谱引擎
|
||
|
||
`代码分析` `知识图谱` `WebAssembly` `语义搜索` `静态分析` `AI问答`
|
||
|
||
# GitNexus V2
|
||
|
||
**零服务器、基于图的代码智能分析引擎**
|
||
完全在浏览器内通过 WebAssembly 运行。(数据库引擎、嵌入模型、AST 解析,全部在浏览器中完成)
|
||
|
||
https://github.com/user-attachments/assets/2fb7c522-20d1-48f6-9583-36c3969aa4dc
|
||
|
||
https://gitnexus.vercel.app
|
||
由于是纯客户端运行,部署成本为零,你可以免费使用 :-) (当然,点个 ⭐ 就更好了)
|
||
|
||
> *像 DeepWiki,但更深入。* 😉
|
||
|
||
DeepWiki 帮助你*理解*代码,GitNexus 让你*分析*代码——因为知识图谱追踪每一个依赖、调用链和关系。
|
||
|
||
这就是以下两者的区别:
|
||
- "这个函数是做什么的?" → *理解*
|
||
- "如果我修改这个函数,什么会崩溃?" → *分析*
|
||
|
||
**一些技术术语:**
|
||
- **增强搜索**:BM25 + 语义搜索 + 通过 Cypher 进行一跳图扩展
|
||
- **完整 WASM 栈**:Tree-sitter 解析 + KuzuDB 图数据库,全在浏览器内
|
||
- **仓库地图**:包含 CALLS、IMPORTS、EXTENDS 关系的完整代码知识图谱
|
||
- **向量索引**:用于语义相似度搜索的 HNSW 嵌入
|
||
- **Cypher 查询**:用于精准上下文检索的关系分析
|
||
- **有据可查的 AI**:每个答案都以 `[[文件:行号]]` 作为证据引用
|
||
|
||
**你可以做什么:**
|
||
|
||
| 能力 | 描述 |
|
||
|------|------|
|
||
| **全代码库审计** | 发现层级违规、禁止的依赖 |
|
||
| **爆炸半径分析** | 查看某次修改影响到的每个函数 |
|
||
| **死代码检测** | 识别零入调用的孤立节点 |
|
||
| **依赖追踪** | 跨整个代码库追踪导入链 |
|
||
| **带引用的 AI 分析** | 提问、分析,获得带 `[[文件:行号]]` 证明的答案 |
|
||
|
||
**100% 客户端运行。** 你的代码永远不会离开浏览器。
|
||
|
||
**支持语言:** TypeScript、JavaScript、Python(Go、Java、C 开发中)
|
||
|
||
<img width="2550" height="1343" alt="gitnexus_img" src="https://github.com/user-attachments/assets/cc5d637d-e0e5-48e6-93ff-5bcfdb929285" />
|
||
|
||
---
|
||
|
||
## 🔍 AI 编码工具的问题所在
|
||
|
||
**Cursor**、**Claude Code**、**Cline**、**Roo Code** 和 **Windsurf** 等工具很强大——但它们有一个共同的根本局限:**它们并不真正了解你的代码库结构**。
|
||
|
||
| 工具 | 上下文策略 | 缺口 |
|
||
|------|------------|------|
|
||
| **Cursor** | 标签页中的文件 + 嵌入 | 无调用图,无法追踪"谁调用了这个?" |
|
||
| **Claude Code** | 文件搜索 + grep | 基于文本,遗漏语义连接 |
|
||
| **Cline/Roo Code** | 仓库地图 + tree-sitter | 静态结构,未追踪运行时依赖 |
|
||
| **Windsurf** | Cascade 上下文 | 依赖深度有限 |
|
||
|
||
**会发生什么:**
|
||
1. AI 编辑 `UserService.validate()`
|
||
2. 不知道有 47 个函数依赖其返回类型
|
||
3. **破坏性变更上线** 💥
|
||
|
||
### 解决方案:图覆盖
|
||
|
||
知识图谱追踪**实际关系**,而不只是文件内容:
|
||
|
||
```mermaid
|
||
graph LR
|
||
EDIT[AI 想编辑 UserService.validate] --> QUERY[图查询:什么依赖于此?]
|
||
QUERY --> DEPS["12个文件中的47个调用者"]
|
||
DEPS --> SAFE[AI 先看到完整爆炸半径]
|
||
```
|
||
|
||
**当前状态:** GitNexus 是一个独立工具——一个更好的 DeepWiki,100% 客户端运行,带图驱动分析。
|
||
|
||
**未来目标(MCP):** 将 GitNexus 作为 MCP 服务器暴露,让 Cursor、Claude Code 等工具可以查询它以获取精准上下文。它们问"什么调用了 X?",GitNexus 返回实际调用图,不再靠猜测。
|
||
|
||
---
|
||
|
||
## 🚀 快速开始
|
||
|
||
```bash
|
||
git clone <仓库地址>
|
||
cd gitnexus
|
||
npm install
|
||
npm run dev
|
||
```
|
||
|
||
打开 http://localhost:5173,将代码库的 ZIP 文件拖放进去,开始探索。
|
||
|
||
---
|
||
|
||
## 🏗️ 索引架构
|
||
|
||
两阶段索引:**知识图谱**(阻塞式)→ **嵌入**(后台)。
|
||
|
||
### 第 1-5 阶段:知识图谱构建
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
subgraph P1["第1阶段:提取 (0-15%)"]
|
||
E1[解压 ZIP] --> E2[收集文件路径]
|
||
end
|
||
|
||
subgraph P2["第2阶段:结构 (15-30%)"]
|
||
S1[构建目录树] --> S2[创建 CONTAINS 边]
|
||
end
|
||
|
||
subgraph P3["第3阶段:解析 (30-70%)"]
|
||
PA1[加载 Tree-sitter WASM] --> PA2[生成 AST]
|
||
PA2 --> PA3[提取符号]
|
||
PA3 --> PA4[填充符号表]
|
||
end
|
||
|
||
subgraph P4["第4阶段:导入 (70-82%)"]
|
||
I1[查找导入语句] --> I2[解析路径]
|
||
I2 --> I3[创建 IMPORTS 边]
|
||
end
|
||
|
||
subgraph P5["第5阶段:调用 + 继承 (82-100%)"]
|
||
C1[查找函数调用] --> C2[通过符号表解析]
|
||
C2 --> C3[创建 CALLS 边]
|
||
C3 --> H1[查找 extends/implements]
|
||
H1 --> H2[创建 EXTENDS/IMPLEMENTS 边]
|
||
end
|
||
|
||
P1 --> P2 --> P3 --> P4 --> P5
|
||
P5 --> DB[(KuzuDB WASM)]
|
||
DB --> READY[图就绪!]
|
||
```
|
||
|
||
### 符号表:双哈希映射
|
||
|
||
函数调用的解析策略:
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
CALL[发现调用:validateUser] --> CHECK1{在导入映射中?}
|
||
CHECK1 -->|是| FOUND1[使用导入的定义]
|
||
CHECK1 -->|否| CHECK2{在当前文件中?}
|
||
CHECK2 -->|是| FOUND2[使用本地定义]
|
||
CHECK2 -->|否| CHECK3{全局搜索}
|
||
CHECK3 -->|找到| FOUND3[使用第一个匹配]
|
||
CHECK3 -->|未找到| SKIP[跳过 - 未解析]
|
||
|
||
FOUND1 --> EDGE[创建 CALLS 边]
|
||
FOUND2 --> EDGE
|
||
FOUND3 --> EDGE
|
||
```
|
||
|
||
**数据结构:**
|
||
```
|
||
文件范围:Map<FilePath, Map<SymbolName, NodeID>>
|
||
全局: Map<SymbolName, SymbolDefinition[]>
|
||
```
|
||
|
||
### 第 6+ 阶段:后台嵌入
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
subgraph BG["后台(非阻塞)"]
|
||
M1[加载 snowflake-arctic-embed-xs] --> M2[初始化 WebGPU/WASM]
|
||
M2 --> E1[批量嵌入节点]
|
||
E1 --> E2[INSERT 到 CodeEmbedding 表]
|
||
E2 --> V1[创建 HNSW 向量索引]
|
||
V1 --> B1[构建 BM25 索引]
|
||
end
|
||
|
||
BG --> AI[AI 搜索就绪!]
|
||
```
|
||
|
||
嵌入期间用户可以探索图,嵌入完成后 AI 功能解锁。
|
||
|
||
---
|
||
|
||
## 📊 图模式
|
||
|
||
### 节点类型
|
||
|
||
| 标签 | 描述 | 属性 |
|
||
|------|------|------|
|
||
| `Folder` | 目录 | `name`, `filePath` |
|
||
| `File` | 源文件 | `name`, `filePath`, `language` |
|
||
| `Function` | 函数定义 | `name`, `filePath`, `startLine`, `endLine`, `isExported` |
|
||
| `Class` | 类定义 | `name`, `filePath`, `startLine`, `endLine` |
|
||
| `Interface` | 接口定义 | `name`, `filePath`, `startLine`, `endLine` |
|
||
| `Method` | 类方法 | `name`, `filePath`, `startLine`, `endLine` |
|
||
| `CodeElement` | 通用符号 | `name`, `filePath` |
|
||
|
||
### 关系表:`CodeRelation`
|
||
|
||
带 `type` 属性的单一边表:
|
||
|
||
| 类型 | 起点 | 终点 | 描述 |
|
||
|------|------|------|------|
|
||
| `CONTAINS` | Folder | File/Folder | 目录结构 |
|
||
| `DEFINES` | File | Function/Class/等 | 代码定义 |
|
||
| `IMPORTS` | File | File | 模块依赖 |
|
||
| `CALLS` | Function/Method | Function/Method | 调用图 |
|
||
| `EXTENDS` | Class | Class | 继承 |
|
||
| `IMPLEMENTS` | Class | Interface | 接口实现 |
|
||
|
||
---
|
||
|
||
## 🛠️ Agent 工具架构
|
||
|
||
LangChain ReAct Agent 有 **5 个工具**用于代码探索,这些工具**使用索引期间构建的图**。
|
||
|
||
### 工具 1:`search` — 带图上下文的混合搜索
|
||
|
||
结合 **BM25**(关键词)+ **语义**(向量)+ **一跳扩展**:
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Q[查询:auth middleware] --> BM25[BM25 关键词搜索]
|
||
Q --> SEM[语义向量搜索]
|
||
|
||
BM25 --> RRF[倒数排名融合]
|
||
SEM --> RRF
|
||
|
||
RRF --> TOP[Top K 结果]
|
||
TOP --> HOP[一跳图扩展]
|
||
|
||
HOP --> OUT["每个结果包含:
|
||
• ID、文件、分数
|
||
• 入向连接(谁调用了这个)
|
||
• 出向连接(这个调用了什么)"]
|
||
```
|
||
|
||
**一跳扩展原理:**
|
||
```cypher
|
||
MATCH (n {id: $nodeId})
|
||
OPTIONAL MATCH (n)-[r1:CodeRelation]->(dst)
|
||
OPTIONAL MATCH (src)-[r2:CodeRelation]->(n)
|
||
RETURN collect(dst.name), collect(src.name)
|
||
```
|
||
|
||
Agent 不仅看到*什么匹配*,还看到*什么与之相连*。
|
||
|
||
---
|
||
|
||
### 工具 2:`cypher` — 带自动嵌入的原生图查询
|
||
|
||
直接执行 Cypher。如果包含 `{{QUERY_VECTOR}}`,会自动嵌入:
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
CQ[带占位符的 Cypher] --> CHECK{包含 QUERY_VECTOR?}
|
||
CHECK -->|是| EMBED[嵌入查询文本]
|
||
EMBED --> REPLACE[替换占位符为向量]
|
||
CHECK -->|否| EXEC
|
||
REPLACE --> EXEC[执行 Cypher]
|
||
EXEC --> RES[返回结果]
|
||
```
|
||
|
||
**带自动嵌入的示例:**
|
||
```cypher
|
||
CALL QUERY_VECTOR_INDEX('CodeEmbedding', 'idx', {{QUERY_VECTOR}}, 10)
|
||
YIELD node, distance
|
||
WHERE distance < 0.4
|
||
MATCH (caller:Function)-[:CodeRelation {type: 'CALLS'}]->(n:Function {id: node.nodeId})
|
||
RETURN caller.name, n.name
|
||
```
|
||
|
||
Agent 提供 `query: "authentication"` → 系统嵌入 → 注入向量。
|
||
|
||
---
|
||
|
||
### 工具 3:`grep` — 正则表达式模式匹配
|
||
|
||
用于精确字符串、错误码、TODO:
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
PAT["模式:TODO|FIXME"] --> REGEX[编译正则]
|
||
REGEX --> SCAN[扫描所有文件]
|
||
SCAN --> MATCH[按行匹配]
|
||
MATCH --> RES["文件:行号: 内容"]
|
||
```
|
||
|
||
---
|
||
|
||
### 工具 4:`read` — 智能文件读取
|
||
|
||
带建议的模糊路径匹配:
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
REQ[请求:src/utils.ts] --> EXACT{精确匹配?}
|
||
EXACT -->|是| RET[返回内容]
|
||
EXACT -->|否| FUZZY[按段模糊匹配]
|
||
FUZZY --> FOUND{找到?}
|
||
FOUND -->|是| RET
|
||
FOUND -->|否| SUGGEST[建议相似文件]
|
||
```
|
||
|
||
---
|
||
|
||
### 工具 5:`highlight` — 可视化图反馈
|
||
|
||
发出 UI 解析的标记以高亮节点:
|
||
```
|
||
[HIGHLIGHT_NODES:Function:src/auth.ts:validate,Class:src/user.ts:UserService]
|
||
```
|
||
|
||
---
|
||
|
||
## 💡 关键发现:统一向量 + 图
|
||
|
||
大多数 Graph RAG 系统使用**独立数据库**——向量数据库用于语义搜索,图数据库用于遍历。
|
||
|
||
KuzuDB 支持**原生向量索引(HNSW)**,因此我们在**单个 Cypher 查询**中同时完成两者:
|
||
|
||
```cypher
|
||
-- 语义搜索 + 图遍历在一个查询中完成
|
||
CALL QUERY_VECTOR_INDEX('CodeEmbedding', 'code_embedding_idx', $queryVector, 20)
|
||
YIELD node AS emb, distance
|
||
WITH emb, distance WHERE distance < 0.4
|
||
MATCH (n:Function {id: emb.nodeId})<-[:CodeRelation {type: 'CALLS'}]-(caller:Function)
|
||
RETURN n.name, caller.name, distance
|
||
ORDER BY distance
|
||
```
|
||
|
||
**为什么重要:**
|
||
- 🎯 **单次查询执行** — 系统间无往返
|
||
- 📊 **内置相关性排序** — 距离即分数
|
||
- ⚡ **无需独立向量数据库** — 一个数据库,一种查询语言
|
||
- 🌳 **LLM 友好** — Agent 写一条 Cypher,获得语义 + 结构双重结果
|
||
|
||
---
|
||
|
||
## 🔬 深度剖析:写时复制内存问题
|
||
|
||
遇到了一个值得记录的嵌入存储问题。
|
||
|
||
**场景:** 将 384 维嵌入与代码节点一起存储。
|
||
```cypher
|
||
MATCH (n:CodeNode {id: $id}) SET n.embedding = $vec
|
||
```
|
||
|
||
**问题:** 约 20 个节点时正常,约 1000 个时崩溃:
|
||
```
|
||
Buffer manager exception: Unable to allocate memory!
|
||
```
|
||
|
||
**根本原因:写时复制(Copy-on-Write)。** 每次 `UPDATE` 都会复制整条记录(约 2KB 的代码内容)。1000 次更新 = 在 WASM 中大量内存复制。
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
subgraph COW["写时复制效果"]
|
||
OLD[旧:2KB] --> NEW[新:3.5KB]
|
||
end
|
||
COW -->|"× 1000 个节点"| BOOM[💥 缓冲区耗尽]
|
||
```
|
||
|
||
**解决方案:** 单独建立仅 `INSERT` 的 `CodeEmbedding` 表:
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
subgraph Old["❌ 单表"]
|
||
CN1[带嵌入的 CodeNode<br/>UPDATE 触发 COW]
|
||
end
|
||
|
||
subgraph New["✅ 分离表"]
|
||
CN2[CodeNode<br/>id, name, content]
|
||
CE[CodeEmbedding<br/>nodeId, embedding<br/>仅 INSERT]
|
||
end
|
||
|
||
Old -->|"内存爆炸"| FAIL
|
||
New -->|"大规模可用"| WIN
|
||
```
|
||
|
||
**经验:** 内存中的 WASM 数据库有硬性限制。在规模下做性能分析,而非只测试理想路径。
|
||
|
||
---
|
||
|
||
## ⚡ V2 技术改进
|
||
|
||
### Sigma.js + WebGL
|
||
- V1:D3.js,约 3k 节点时卡顿
|
||
- V2:Sigma.js + GPU 渲染,10k+ 节点流畅运行
|
||
|
||
### 双哈希映射符号表
|
||
- V1:前缀树(Trie)——聪明但慢
|
||
- V2:文件范围 + 全局哈希映射——**约 2 倍提速**
|
||
|
||
### LRU AST 缓存
|
||
- Tree-sitter AST 存储在 WASM 内存中
|
||
- LRU 缓存(50 个槽位)配合 `tree.delete()` 清理
|
||
- 即使对超大代码库,内存也保持有界
|
||
|
||
### ForceAtlas2 在 Web Worker 中运行
|
||
- 布局算法在主线程外运行
|
||
- 图定位期间 UI 保持响应
|
||
|
||
---
|
||
|
||
## 🚧 路线图
|
||
|
||
### 积极开发中
|
||
|
||
- [ ] **MCP 支持** — 用于工具扩展的模型上下文协议
|
||
- [ ] **外部数据库支持** — 连接 Neo4j(托管或 Docker)
|
||
- [ ] **爆炸半径分析工具** — 专用影响分析 UI
|
||
- [ ] **多 Worker 池** — 跨 Web Worker 并行解析
|
||
- [ ] **Ollama 支持** — 本地 LLM 集成
|
||
- [ ] **CSV 导出** — 导出节点/关系表
|
||
|
||
### 🎯 愿景:基于浏览器的 MCP 服务器
|
||
|
||
**目标:** 直接从浏览器将 GitNexus 暴露为本地 MCP 服务器。
|
||
|
||
这将允许 **Cursor**、**Claude Code**、**Windsurf** 等 AI 编码工具连接到你运行的 GitNexus 实例,并使用其知识图谱:
|
||
- 🔍 **可靠的上下文获取** — AI 获得实际依赖,而非 grep 猜测
|
||
- 💥 **爆炸半径检测** — 修改前查询什么会被破坏
|
||
- 🔐 **全代码库审计** — 发现违规、死代码、循环依赖
|
||
- 🧠 **有据可查的答案** — 每个响应由图遍历支撑,而非幻觉
|
||
|
||
```mermaid
|
||
graph LR
|
||
subgraph Browser["GitNexus(浏览器)"]
|
||
KG[知识图谱]
|
||
MCP[MCP 服务器]
|
||
end
|
||
|
||
subgraph Tools["AI 编码工具"]
|
||
CURSOR[Cursor]
|
||
CLAUDE[Claude Code]
|
||
WIND[Windsurf]
|
||
end
|
||
|
||
KG --> MCP
|
||
MCP <-->|localhost| CURSOR
|
||
MCP <-->|localhost| CLAUDE
|
||
MCP <-->|localhost| WIND
|
||
```
|
||
|
||
**为什么重要:** 当前 AI 编码工具对真实依赖是盲目的。它们使用 grep 或嵌入——聊胜于无,但不足以防止破坏性变更。知识图谱 MCP 将为它们提供所需的精准结构化上下文。
|
||
|
||
### 近期已完成 ✅
|
||
|
||
- [x] 带 5 个工具的图 RAG Agent(search、cypher、grep、read、highlight)
|
||
- [x] 浏览器嵌入(snowflake-arctic-embed-xs,2200 万参数)
|
||
- [x] KuzuDB 中带 HNSW 的向量索引
|
||
- [x] 混合搜索(BM25 + 语义 + RRF)
|
||
- [x] 带工具可见性的流式 AI 对话
|
||
- [x] 有据可查的引用(`[[文件:行号]]` 格式)
|
||
- [x] 多 LLM 提供商(OpenAI、Azure、Gemini、Anthropic)
|
||
|
||
---
|
||
|
||
## 🛠 技术栈
|
||
|
||
| 层级 | 技术 |
|
||
|------|------|
|
||
| **前端** | React 18、TypeScript、Vite、Tailwind v4 |
|
||
| **可视化** | Sigma.js、Graphology、ForceAtlas2(WebGL)|
|
||
| **解析** | Tree-sitter WASM(TS、JS、Python)|
|
||
| **数据库** | KuzuDB WASM(图 + 向量 HNSW)|
|
||
| **嵌入** | transformers.js、snowflake-arctic-embed-xs(22M)|
|
||
| **AI** | LangChain ReAct Agent、流式输出 |
|
||
| **并发** | Web Workers + Comlink |
|
||
|
||
---
|
||
|
||
## 🔐 安全与隐私
|
||
|
||
- 所有处理均在你的浏览器中进行
|
||
- 无代码上传至任何服务器
|
||
- API 密钥仅存储在 localStorage 中
|
||
- 开源——自行审计代码
|
||
|
||
---
|
||
|
||
## 📝 许可证
|
||
|
||
MIT 许可证
|
||
|
||
---
|
||
|
||
## 🙏 致谢
|
||
|
||
- [Tree-sitter](https://tree-sitter.github.io/) — AST 解析
|
||
- [KuzuDB](https://kuzudb.com/) — 带向量支持的嵌入式图数据库
|
||
- [Sigma.js](https://www.sigmajs.org/) — WebGL 图渲染
|
||
- [transformers.js](https://huggingface.co/docs/transformers.js) — 浏览器机器学习
|
||
- [LangChain](https://langchain.com/) — Agent 编排 |