Skip to content

09 - 基础概念解析:从 0 到 1 看懂前 8 章

这一章面向完全没接触过代码索引 / LLM Agent / 知识图谱的读者。每个概念会用两段式讲解:

  1. 比喻/生活实例:先在脑中建立直觉
  2. 技术解释:再补充准确定义

看完这一章后,你重新读 01–08 章会顺畅很多。


0. 全局比喻:把"AI 编程助手"看作一个新来的实习生

整本调研讨论的事情其实可以用一个非常具体的场景描述:

想象你公司新来了一个很会写代码的实习生(这就是 Claude Code / Codex / Cursor 这种 AI 编程助手)。

他每天接到任务的工作流程是:

  1. 不熟悉项目,先翻 README
  2. grep 找一下相关的关键字
  3. 打开几个文件读一读
  4. 然后开始写代码

这个流程在小项目上还行。但如果是一个 几百万行代码的大项目

  • 实习生光是"先翻一遍 README + grep + 读文件" 就要花掉半天
  • 因为不熟悉调用关系,改一行代码可能导致另外 5 个文件出 bug
  • 每次新任务都要重新走一遍这个流程

整个调研讨论的问题就是:

如何不让这个实习生每次都从零开始?

各种方案就像给他配不同的辅助工具:

方案类比
知识图谱派给他一份项目结构图("A 函数调用 B 函数,B 在 X 文件里")
向量 RAG 派给他一个项目专属搜索引擎("按意思找代码")
Grep 加速派把他手里的老式手电筒换成激光雷达(grep 变快 36 倍)
LSP 派直接把 IDE 的能力借给他(鼠标右键就能跳定义)
AST 结构派给他一套代码规则巡查表(自动找出所有不规范的代码)

下面开始详细讲每个概念。


1. Token:大模型的"计费单位"

生活类比

想象寄快递按"重量"算钱。Token 就相当于"快递的克重"。

你给 AI 发一段话 = 寄一个包裹。AI 看这段话的"克重"(token 数)来收费。

技术解释

Token 是大语言模型把文字切成的"最小理解单位"。例如:

"我爱编程" → ["我", "爱", "编", "程"]  → 4 个 token
"Hello World" → ["Hello", " World"] → 2 个 token

不同模型切法略有不同。一般 1 个中文字 ≈ 1–2 token,1 个英文单词 ≈ 1 token。

为什么 token 这么重要

LLM 是按 token 计费的。调用 Claude Sonnet 4 大约每 100 万 token 收 3 美元

举个具体例子:

你让 AI 读完整个 fastapi 仓库(44,751 token)然后回答一个问题

单次成本约 = 44,751 / 1,000,000 × 3 美元 ≈ 0.13 美元

一天问 50 次 = 6.5 美元
一个团队 10 人 = 65 美元/天 ≈ 2 万美元/年

这就是为什么调研里所有项目都在讲"省 token"

  • code-review-graph 省 8.2 倍 → 0.13 美元变 0.016 美元
  • Semble 省 98% → 0.13 美元变 0.0026 美元

省的全是真金白银。


2. MCP(Model Context Protocol):AI 工具的"USB 标准"

生活类比

想象 USB 出现前,每个鼠标、键盘、打印机都有自己的接口(PS/2 圆口、串口、并口、各种奇怪的小针)。买一台新打印机就要重新装一套驱动。

USB 出现后,所有外设都用同一种插口,电脑通过统一协议识别它们。

MCP 就是 AI 工具世界的 USB

技术解释

MCP (Model Context Protocol) 是 Anthropic 在 2024 年推出的开放协议,让 AI 助手(Claude / Codex / Cursor 等)能用同一套接口接入任意"外挂工具"。

       AI 助手(Claude Code)

            │ MCP 协议(统一插口)

   ┌────────┴────────────────────┐
   ▼         ▼          ▼        ▼
 知识图谱    搜索引擎    数据库   浏览器
 (MCP)     (MCP)      (MCP)    (MCP)

每个工具(叫 MCP Server)暴露一些"方法",比如:

gitnexus 暴露:
  - query("关键词")            → 搜代码
  - context("函数名")          → 看函数关系
  - impact("函数名")           → 看爆炸半径
  - rename("旧名", "新名")     → 跨文件重命名

AI 助手通过 MCP 协议自动发现并调用这些方法。

为什么 MCP 重要

在 MCP 出现前,要让 Claude 接入 GitHub,需要专门为 Claude 写一个 GitHub 插件;让 ChatGPT 接入要再写一个;Cursor 也要再写一个。MCP 让一份代码(MCP Server)能被所有支持 MCP 的 AI 同时用

调研中的所有项目都是做成 MCP Server

项目暴露的 MCP 工具数
code-review-graph28 + 5 prompt 模板
GitNexus7 工具 + 多个资源
code-graph-rag-mcp26 方法
Semble少(专注 search)
Serena38+

安装一个 MCP Server 长什么样

bash
# 给 Claude Code 加一个 MCP Server
claude mcp add semble -s user -- uvx --from "semble[mcp]" semble

# 给 Codex 加同一个
codex mcp add semble -- uvx --from "semble[mcp]" semble

一行命令搞定,AI 启动后就能调用这个工具。


3. AST(抽象语法树):把代码"翻译"成树结构

生活类比

拿到一句话:"小明吃了一个红苹果"。

在小学语文课上,老师会教你画句子成分分析图

            [整句]
           /      \
    [主语]      [谓语部分]
     小明         /    \
           [动词]    [宾语]
            吃了      /     \
                 [定语]   [中心词]
                 红的       苹果

这棵树就是这句话的 "AST"。它把人类的自然语言变成机器能精确处理的结构。

技术解释

AST (Abstract Syntax Tree, 抽象语法树) 是把代码解析后得到的树形结构。

例如这段 Python 代码:

python
def validate_user(name, password):
    if password == "admin":
        return True
    return False

它的 AST 大致长这样:

FunctionDef (validate_user)
├── Args
│   ├── name
│   └── password
└── Body
    ├── If
    │   ├── Condition: password == "admin"
    │   └── Body: Return(True)
    └── Return(False)

为什么调研里 90% 的项目都用 AST

grep 把代码当字符串搜索:

  • 想找"所有函数定义" → 写正则 def \w+\(,但只能找到 def 形式的,匹配不到 lambda、装饰器函数
  • 想找"所有 if 里嵌套 if" → 几乎做不到

AST 把代码当结构搜索

  • "所有函数定义" = 找树里所有 FunctionDef 节点
  • "if 嵌套 if" = 找 If 节点下还有 If 节点的

调研中:

  • code-review-graph、GitNexus、code-graph-rag-mcp:解析 AST → 抽出节点和边 → 建图
  • Semble:解析 AST → 按函数/类粒度切代码 chunk → 做嵌入
  • ast-grep:直接用 AST 模式匹配代码

4. Tree-sitter:业界最常用的"AST 解析器"

生活类比

如果 AST 是"句子成分分析图"Tree-sitter 就是那位画分析图的语文老师——而且这位老师同时会 50 多种语言(Python、Java、Rust……)。

技术解释

Tree-sitter 是 GitHub 在 2018 年开源的一款通用 AST 解析器:

  • 极快:用 C 实现,毫秒级解析千行代码
  • 支持几十种语言:每种语言只需写一份 grammar 文件
  • 增量解析:改一行只重新解析这一行附近,不重做整个文件
  • 容错:代码有语法错误也能解析出"尽量正确的树"(IDE 里语法报错时不影响补全就是靠它)

调研里几乎每个图谱派项目都用 Tree-sitter

项目Tree-sitter 用途
code-review-graph23 种语言的解析全靠它
GitNexus11 种语言解析
code-graph-rag-mcp多 Agent 共享一个 Tree-sitter parser
Semble按 AST 边界切代码 chunk
ProbeAST 感知搜索

它已经是事实标准。


5. LSP(Language Server Protocol):复用 IDE 的智能

生活类比

每个语言(中文 / 英文 / 日文)都有一个专门的"翻译官",懂这个语言的所有细节

你的 VS Code 编辑器不直接懂代码,它通过和翻译官对话来获得智能:

  • VS Code 问翻译官:"validate_user 定义在哪?"
  • 翻译官(Python 的 Pyright)回答:"在 auth.py 第 42 行"
  • VS Code 在屏幕上画一个跳转链接

这个"问答协议"就是 LSP。每种语言的"翻译官"叫一个 Language Server

技术解释

LSP (Language Server Protocol) 是微软为 VS Code 设计、后来成为业界标准的协议。

你的编辑器                       Language Server
(VS Code / Cursor)              (按语言不同:
                                 Python → Pyright
        │  LSP                   TypeScript → tsserver
        │ ←─→                    Rust → rust-analyzer
        │                        Java → jdtls
                                 ……)
        编辑器只管 UI,
        所有"懂代码"的事
        交给 Language Server

LSP 提供的能力:

  • 跳到定义(Go to Definition)
  • 查找所有引用(Find References)
  • 自动补全(Completion)
  • 类型推断与悬浮提示(Hover)
  • 错误诊断(Diagnostics)
  • 跨文件重命名(Rename)
  • 调用层次(Call Hierarchy)

Serena 的核心创新就是"借用 LSP"

调研中的其他项目都在自己重新发明轮子

  • code-review-graph:自己用 Tree-sitter 解析每种语言
  • GitNexus:同样

Serena 的思路不一样:

既然每种语言的 Language Server 已经存在十几年了(VS Code/Vim/Emacs 都用),而且做得比我自己写的好得多——那我直接用 LSP 不就完了?

这让 Serena 一次性支持 52 种语言,且每种语言的 rename / find references 质量与 VS Code 一致


6. 向量嵌入(Embedding):把"意思"变成数字

生活类比

想象给每个词分配一个 GPS 坐标

苹果 → (39.9, 116.4)    ← 跟"水果"和"手机"都近
水果 → (40.0, 116.5)    ← 跟"苹果"很近
手机 → (39.8, 116.3)    ← 跟"苹果"也近(科技语境)
汽车 → (22.5, 113.9)    ← 离"苹果"远

意思接近的词,坐标也接近。 这种"坐标"就是向量嵌入

技术解释

Embedding(向量嵌入) 是把一段文字(单词、句子、代码块)映射到一个高维向量(通常是 384、768、1536 维的浮点数数组)。

python
embed("用户登录")        → [0.12, -0.45, 0.78, ..., 0.33]  (1536 维)
embed("authenticate")    → [0.11, -0.43, 0.80, ..., 0.31]  ← 跟"用户登录"很接近
embed("calculate price") → [-0.55, 0.22, ..., 0.18]        ← 离"用户登录"

衡量"离得近不近"用余弦相似度

similarity(A, B) = (A · B) / (|A| × |B|)

值在 -1 到 1 之间,越接近 1 越像。

为什么这能"按意思搜代码"

用户搜:    "用户认证逻辑"
                ↓ embed
            向量 V_query

代码库每个函数都已经嵌入过:
  validateUser:    V_1 ← 与 V_query 余弦相似度 0.89
  loginHandler:    V_2 ← 与 V_query 余弦相似度 0.85
  calculatePrice:  V_3 ← 与 V_query 余弦相似度 0.12

返回相似度最高的 K 个 → 命中正确答案

即使函数名叫 verifySignature(和"用户认证"字面上没关系),向量空间里它们仍然相近——这就是语义搜索的魔力

调研里的嵌入模型

项目默认嵌入备注
SembleModel2Vec(potion-code-16M)CPU 静态查表,超快
code-review-graphall-MiniLM-L6-v2通用小模型
Claude ContextOpenAI / VoyageAI / Gemini / Ollama云 API 为主
GitNexustransformers.js浏览器内跑

7. Model2Vec / 静态嵌入:让 CPU 也能跑得飞快

生活类比

传统嵌入 = 每次找一个词的 GPS 都重新算一遍卫星定位(要 GPU、要几秒)

静态嵌入 = 预先做好一份"全国地址电话本",每次查只是翻字典(CPU 毫秒级)

技术解释

传统嵌入模型(如 BERT、CodeBERT):

  • 是个 Transformer 神经网络
  • 每生成一条嵌入要跑一次完整推理
  • CPU 上几百毫秒到几秒一条

Model2Vec / 静态嵌入

  • 离线训练一次:用 Transformer 算所有 token 的嵌入
  • 蒸馏成一张大查找表(token → 向量)
  • 推理时只做"查表 + 平均池化",CPU 上每秒上万条

精度损失

  • 传统 BERT:NDCG@10 = 0.862
  • Semble (Model2Vec):NDCG@10 = 0.854
  • 仅差 0.008,但速度快 10–200 倍

这是 Semble 能在普通笔记本上 250ms 索引整个项目的核心原因。


8. BM25:经典的"按关键词找文章"

生活类比

BM25 就像图书馆的目录卡:你说"我要找包含'爆炸半径'这个词的书",图书管理员去翻目录,按"这本书出现这个词多少次 + 这本书有多厚"算个评分,把最相关的几本给你。

它不懂"爆炸半径"和"影响分析"的语义关系,但找精确字符串特别快。

技术解释

BM25 (Best Matching 25) 是 1994 年提出的经典词法检索算法,至今仍是搜索引擎主力。核心思想:

score(doc, query) = Σ over terms in query:
    IDF(term) × (term_freq × (k+1)) / (term_freq + k × (1 - b + b × |doc|/avgdoc))

简单来说:

  • 文档里出现查询词次数越多 → 分数越高
  • 但同时文档不能太长(长文档天然命中多)
  • 查询词在整个语料库越罕见 → 分数加成越多

调研里 BM25 的角色

几乎所有混合检索方案都把 BM25 当"词法路"

项目双路
Semble语义(Model2Vec)+ 词法(BM25)
Claude Context语义(向量)+ 词法(BM25)
GitNexus语义(嵌入)+ 词法(BM25)
code-memory语义(密集向量)+ 词法(BM25)

为什么不能只用语义检索?

因为语义检索找不到"精确名字":

  • 用户搜 MAX_RETRY_COUNT → BM25 一发就中;向量绕远
  • 用户搜 validateUser → BM25 直接命中;向量可能输给"做认证的其他函数"

两路结合才能既"找意图"又"找名字"。


9. RRF(Reciprocal Rank Fusion):怎么合并两个搜索结果?

生活类比

你同时让两个朋友推荐餐厅

  • 朋友 A 列出前 5 名:[海底捞、外婆家、必胜客、汉堡王、麦当劳]
  • 朋友 B 列出前 5 名:[海底捞、肯德基、外婆家、星巴克、必胜客]

你怎么决定最终去哪?最简单的方法:

海底捞:A 排第 1,B 排第 1 → 综合分 (1/1 + 1/1) = 2.0
外婆家:A 排第 2,B 排第 3 → (1/2 + 1/3) = 0.83
必胜客:A 排第 3,B 排第 5 → (1/3 + 1/5) = 0.53
肯德基:A 没排上,B 排第 2 → (0 + 1/2) = 0.50
麦当劳:A 排第 5 → (1/5 + 0) = 0.20

最终结果:海底捞 > 外婆家 > 必胜客 > 肯德基 > ……

这就是 RRF 的核心:每个排名贡献 1/(k+rank) 分,加起来排序。

技术解释

RRF (Reciprocal Rank Fusion) 公式:

RRF_score(doc) = Σ over runs (1 / (k + rank_in_run(doc)))

其中 k 通常取 60(一个经验值,平滑用)。

为什么 RRF 比"加权平均"好

直接对两路分数加权平均的问题:

  • 向量分数范围 0–1
  • BM25 分数范围 0–几十
  • 量纲不同,加权很难调

RRF 只看排名,不看分数,天然解决了"量纲对不齐"的问题。

调研里 Semble、Claude Context、code-graph-rag-mcp 都用了 RRF 思路。


10. Trigram 倒排索引:flashgrep 加速 36 倍的秘密

生活类比

想象你在新华字典里找"葡萄"这个词

笨办法:从第一页翻到最后一页,看每一页有没有"葡萄"。100 万字的字典要翻好几小时。

聪明办法:字典背面有索引表——

"葡" → 第 128, 567, 891 页
"萄" → 第 128, 234, 891 页

"葡萄"的页 = "葡"的页 ∩ "萄"的页 = {128, 891}。直接翻这两页就好

技术解释

Trigram(三字组) = 文件里所有连续 3 字节的窗口:

"fetchRates" 的 trigram = {fet, etc, tch, chR, hRa, Rat, ate, tes}

倒排索引 = 反过来:trigram → 包含它的文件列表

"fet" → [file_12, file_47, file_88, file_92, ...]
"etc" → [file_12, file_23, file_47, file_88, ...]
"tch" → [file_12, file_47, file_88, file_135, ...]

搜索 fetchRates = 把每个 trigram 的文件列表取交集 → 候选文件(少则几个,多则几十个)→ 在候选文件里跑精确匹配。

为什么提速 36 倍

普通 grep 在 Chromium(4GB 代码)上要顺序扫所有文件 = 137 秒。

flashgrep 用 trigram 索引:

  • 候选文件可能只剩几十个
  • 在这几十个文件里跑精确匹配 = 7.82 秒

用空间换时间:索引占 2.5GB,但单次查询时间从分钟级降到秒级。

为什么是 trigram,不是 bigram 或 4-gram

选择问题
Unigram(1 字节)posting list 太长(几乎每个文件都有每个字节)
Bigram(2 字节)区分度不够
Trigram(3 字节)平衡点:区分度好 + 索引体积可控
4-gram+posting list 太短易丢命中 + 索引膨胀

这套方法是 Google Code Search、Zoekt、csearch 等业界产品的通用方案。


11. 知识图谱:把代码变成"人际关系网"

生活类比

把一个公司的关系画成网

     [张总]
      /  \
  汇报     汇报
   /         \
 [李经理]   [王经理]
  /    \         \
汇报   汇报      汇报
 /       \        \
[小明]  [小红]   [小刚]
         |
       合作
         |
       [外包]

节点 = 人,边 = 关系(汇报、合作、协同)

想知道"如果张总辞职会影响谁?"——从张总出发 BFS 遍历整张图,结果一目了然。

技术解释

知识图谱(Knowledge Graph) 是一种 节点 + 边 的数据结构。

对代码而言:

节点(Node)边(Edge)
函数调用关系(A 调用 B)
继承关系(A extends B)
文件引用关系(A imports B)
测试覆盖关系(test_X 覆盖 X)
变量引用关系

图数据库 = 专为图设计的存储

调研里:

  • code-review-graph:用 SQLite 模拟图存储
  • GitNexus:用 KuzuDB(原生图数据库,支持 Cypher 语言)
  • code-graph-rag-mcp:用 better-sqlite3 + sqlite-vec

Cypher 是图数据库的"SQL",例如:

cypher
// 找出所有调用 validateUser 的函数
MATCH (caller:Function)-[:CALLS]->(target:Function {name: "validateUser"})
RETURN caller.name, caller.file

比用 SQL 写多次 JOIN 简洁得多。


12. 爆炸半径(Blast Radius):改一个函数会炸到哪?

生活类比

想象你要换办公室门口的咖啡机

  • 直接影响(半径 1):每天用这台机器的所有人(约 50 人)
  • 间接影响(半径 2):用这些人冲的咖啡的人(来访客户、隔壁部门)
  • 三度影响(半径 3):依赖这些人工作产出的下游团队

半径越小,改动越安全;半径越大,越要小心。

技术解释

代码里的爆炸半径分析

你要改 calculatePrice 函数
  ↓ 在图上找它
图节点:calculatePrice
  ↓ BFS 上游(谁调用它)
深度 1:checkoutHandler, invoiceGenerator   ← 直接会崩溃
深度 2:reportService, taxCalculator         ← 可能受影响
深度 3:dashboardService, exportApi          ← 传递性影响
  ↓ 同时找测试覆盖
覆盖测试:test_checkout, test_invoice
  ↓ 汇总
"改这个函数有 8 个文件可能受影响,但只有 2 个测试覆盖"

风险评分矩阵(GitNexus 用的):

影响范围风险
<5 个符号,少量执行流LOW
5–15 个符号,2–5 个执行流MEDIUM
>15 个符号或大量执行流HIGH
关键路径(认证、支付)CRITICAL

code-review-graph 和 GitNexus 都把这个能力作为核心卖点——传统 grep 完全做不到。


13. 社区检测(Community Detection):自动发现"功能模块"

生活类比

看一张 100 人的关系图

张三 ── 李四 ── 王五         (这三个常聚餐 = 朋友群 A)
  │       │
  │       │
赵六 ── 钱七 ── 孙八         (这三个常打球 = 朋友群 B)

  │(弱连接)
周九 ── 吴十                 (这两个是夫妻 = 家庭群 C)

算法自动把"内部紧密连接"的人圈一起 → 三个社群

技术解释

社区检测算法(如 Leiden、Louvain) 在图上自动找"内部连接稠密、外部连接稀疏"的子图。

应用到代码:

项目 ── 自动检测 ──→
  社区 A:所有认证相关函数
  社区 B:所有支付相关函数
  社区 C:所有数据库 ORM 函数
  ……

为什么这很有用

  • 帮 AI 理解项目的自然边界(即使你没明确分文件夹)
  • 重构时,"把这个函数从社区 A 搬到社区 B"是个明确信号
  • 文档自动生成(每个社区一个章节)
  • code-review-graph 的 generate_wiki_tool 就是基于社区结构

中心度(Centrality)和"桥"节点

继续上面的关系图比喻:

  • Hub 节点(中心度高)= 在派对里认识所有人的"社交达人"。代码里就是"被调用次数最多的函数",往往是架构热点
  • Bridge 节点(介数中心性高)= 连接两个不同朋友群的"中间人"。代码里就是"两个模块间的桥梁函数",改它风险最高

code-review-graph 的 get_hub_nodes_toolget_bridge_nodes_tool 就是干这个的。


14. RAG(检索增强生成):让 AI 现学现卖

生活类比

闭卷考试:你只能用脑子里记得的知识。

开卷考试:你可以查教科书,先查到相关章节,再回答问题

RAG = 给 AI 开卷考试

流程:

  1. AI 收到问题
  2. 系统先从你的资料库里找出几段最相关的内容
  3. 把这几段塞进 AI 的提示词
  4. AI 基于这些内容回答

技术解释

RAG (Retrieval-Augmented Generation, 检索增强生成)

用户问:"这个项目的认证逻辑怎么走?"

        ┌───────────────┐
        │  Retrieval     │   ← 从代码库检索相关 chunk
        │  (BM25/向量/   │
        │   图查询)      │
        └───────┬───────┘

       Top-K 相关代码片段

        ┌───────────────┐
        │  Augmented     │   ← 把这些片段拼到提示词
        │  Prompt        │
        └───────┬───────┘

        ┌───────────────┐
        │  Generation    │   ← LLM 基于片段回答
        │  (LLM)         │
        └───────┬───────┘

            最终答案

调研里所有"语义检索 + 喂给 LLM"的项目都是 RAG

  • Semble = 代码 RAG(极简版)
  • Claude Context = 企业级代码 RAG(Milvus 后端)
  • code-graph-rag-mcp = 图 + RAG 混合

RAG 的核心优势:LLM 不需要把整个仓库塞进上下文,只需要相关的几段就够了 → 省 token、降延迟、不爆 context window。


15. Chunking:怎么把长代码切成"喂得下"的小块

生活类比

写读书笔记:你不会把一本 500 页的书一句话总结。会按章节切,每章一段笔记。

切得太碎(每页一段)→ 上下文丢失 切得太粗(整本一段)→ 不利于检索

Chunking 就是找平衡点。

技术解释

Chunking(分块) 是 RAG 的关键预处理步骤。把代码切成 chunk 的策略:

策略说明优劣
按行数固定切每 200 行一段简单,但可能在函数中间切断
按字符数切每 1500 字符一段同上
AST 感知切(推荐)沿函数 / 类边界切保留语义单元完整性
Overlap(重叠)相邻 chunk 有 100 行重叠避免"刚好切在关键点"

调研里:

  • Semble:AST 感知(按函数)
  • Claude Context:默认 2500 行 chunk + 300 行 overlap
  • code-graph-rag-mcp:AST 感知(按节点)

16. Merkle DAG:Claude Context 的"智能增量"

生活类比

快递公司每天清点仓库

笨办法:逐个货架数所有箱子,10 万箱要数一整天。

聪明办法:

  • 每个货架贴一个总签收码(汇总该货架所有箱子的编号)
  • 每个区域贴一个区域签收码(汇总该区域所有货架)
  • 整个仓库贴一个顶层签收码

清点:只对比顶层签收码与昨天的。

  • 一样 → 整个仓库没动,结束
  • 不一样 → 看哪个区域签收码变了 → 再看哪个货架 → 最后定位到具体箱子

几秒钟就能完成全仓盘点

技术解释

Merkle DAG (有向无环图) 把目录树每一级都做 hash:

顶层 hash = hash(目录 A 的 hash + 目录 B 的 hash + ...)
目录 A 的 hash = hash(文件 a1 的 hash + 文件 a2 的 hash + ...)
文件 a1 的 hash = hash(文件内容)

任何一个文件改了,所有它的祖先节点 hash 都会变

增量同步只需:

比对:当前顶层 hash vs 上次顶层 hash
  ↓ 不同
比对每个子目录 hash
  ↓ 锁定变化的子目录
逐级下钻

找到所有变更的文件

复杂度从 O(N)(逐文件比)降到 O(log N)。

Claude Context 把它存在 ~/.context/merkle/ 里,所以索引几十万文件的项目也能秒级判断"哪些文件变了"。

这与简单的 git status 比对的优势是:

  • 即使不在 git 仓库也能用
  • 跨多个目录联合也能用
  • .gitignore 不感知的场景也能用

17. mmap:让磁盘文件"伪装成"内存

生活类比

图书馆借书 vs 自己买书

借书:每次要看就跑去图书馆找(等同于每次 read 文件),耗时。

买书:摆在自己书架上(等同于读进内存),但占空间。

mmap = 图书馆开了个"租用书架"在你家:书还在图书馆(磁盘),但你查阅时操作系统假装它就在你的书架上(虚拟内存)。

技术解释

mmap (Memory-Mapped File) 是操作系统提供的能力,让程序"假装"一个磁盘文件就在内存里访问:

传统 IO:
  程序 → read() → 内核拷贝磁盘数据 → 程序缓冲区
       (每次 IO 都要拷贝)

mmap:
  程序 → 直接访问内存地址 X

  内核透明地把 X 对应的磁盘页加载进 PageCache

  返回数据

优势

  • 启动 0 拷贝(指针直接指向磁盘)
  • 多进程共享同一份缓存(操作系统级 PageCache)
  • 只加载实际访问的页(懒加载)

flashgrep 用 mmap 的好处

flashgrep 的 trigram 索引有 2.5GB(Chromium 场景):

  • 不 mmap:每次启动加载 2.5GB → 几秒
  • mmap:启动 0 延迟,访问到哪页才加载哪页
  • 多个 flashgrep 进程并行查询时,共享同一份 PageCache,互不重复加载

18. Hooks:在 AI 工具调用前后"插一脚"

生活类比

门铃 = 普通调用:客人按门铃 → 你开门,结束。

门铃 + 提前接待 + 事后送客 = Hooks

  • 客人按门铃前,你的"前台"先扫一眼监控(PreToolUse
  • 客人离开门铃后,"前台"做最后的安全检查(PostToolUse

技术解释

Claude Code 的 Hooks 系统允许在 AI 调用工具的前后自动执行自定义脚本

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Grep|Glob|Bash",
        "hooks": [
          {
            "type": "command",
            "command": "node /path/to/gitnexus-hook.cjs",
            "timeout": 10
          }
        ]
      }
    ]
  }
}
  • PreToolUse:AI 调用 Grep / Glob / Bash 之前,先跑 gitnexus-hook.cjs
  • PostToolUse:AI 调用完 之后,再跑一次

GitNexus 用 Hooks 干什么

AI: "我要 grep 一下 calculatePrice"
       ↓ 触发 PreToolUse
GitNexus hook:
  - 注意到 AI 在搜索代码
  - 从图谱里取出 calculatePrice 的相关上下文
  - 把这些信息**注入**到 Grep 工具的结果里

AI 收到的是: grep 结果 + 图谱补充的"这个函数的 callers/callees/测试覆盖"

AI 直接拿到更丰富的上下文,省去再次 MCP 调用

这是 GitNexus 与 code-review-graph 的关键差异:前者用 Hooks 自动增强 AI 工具,后者主要靠 AI 主动调 MCP


19. Skills:Claude Code 的"工作流模板"

生活类比

新同事入职拿到的"操作手册"

  • 接客户电话怎么做(按 SOP 一步步)
  • PR 审查怎么做
  • 部署上线怎么做

Skills 就是给 AI 装的一套 SOP,每个 Skill 是一个具体场景的工作流模板。

技术解释

Claude Code 的 Skills 是放在 ~/.claude/skills/ 目录的 markdown 文件,每个 Skill 描述:

  • 触发场景("调试 bug"、"审查 PR")
  • 推荐工作流(先调哪个 MCP 工具,再调哪个)
  • 输出格式

例如 GitNexus 安装的 7 个 Skill 之一 gitnexus-pr-review

markdown
触发: "审查这个 PR" / "PR #42 改了什么?"

工作流:
1. gh pr diff <number>                  → 获取 diff
2. gitnexus_detect_changes              → 映射到流
3. 对每个变更符号: gitnexus_impact      → 爆炸半径
4. 汇总发现并评估风险

输出模板:
## PR Review: <标题>
**风险: LOW / MEDIUM / HIGH / CRITICAL**
...

Claude Code 看到用户说"审查这个 PR"就自动加载这个 Skill 走流程。


20. NDCG@10:怎么衡量"搜索结果好不好"

生活类比

百度搜"附近的火锅店",给你 10 个结果。

  • 第 1 名是真好的店 → 加分多
  • 第 10 名是真好的店 → 加分少(用户根本不会翻到)
  • 完全无关的店排在前面 → 减分多

NDCG = "搜索结果的综合考分",分数越高越好。

技术解释

NDCG@10 (Normalized Discounted Cumulative Gain at 10) 是信息检索领域的标准指标:

  • 看前 10 个结果
  • 第 K 个位置的"贡献" = (相关度) / log(K+1)
  • 把这 10 个加起来得到 DCG
  • 再除以"理想排序下的 DCG"(IDCG)得到 NDCG,范围 0–1

典型值参考

NDCG@10含义
0.95+接近完美
0.85–0.95商业级搜索引擎水平(Semble: 0.854)
0.70–0.85良好
<0.70还不够好

调研里:

  • Semble: NDCG@10 = 0.854 ← 跟专业 Transformer 模型相当
  • 专业 Transformer: NDCG@10 = 0.862

仅差 0.008,但 Semble 速度快 10–200 倍。


21. F1 / Precision / Recall:影响分析的准确性指标

生活类比

机场安检:找出所有真正带违禁品的人。

  • Recall (召回率):所有真正带违禁品的 100 人里,安检抓到了几个?(抓到 100 个 = 100% 召回)
  • Precision (精确率):所有被安检拦下的 200 人里,真正带违禁品的有几个?(50 个 = 25% 精确率)
  • F1:召回率和精确率的"折中分数"

技术解释

            真实情况
              是    否
预测  是    [TP]   [FP]
      否    [FN]   [TN]
  • Precision = TP / (TP + FP):预测为"是"的里面,真正"是"的比例
  • Recall = TP / (TP + FN):真正"是"的里面,被预测为"是"的比例
  • F1 = 2 × Precision × Recall / (Precision + Recall)

code-review-graph 的影响分析为什么"故意保守"

官方 benchmark:

  • Recall = 100%(不会漏报)
  • Precision = 0.38(多报很多)
  • F1 = 0.54

意思是:它会报很多"可能受影响"的文件(一部分其实不会受影响),但不会漏掉任何真正受影响的文件

设计哲学:改代码时宁多报勿漏报。多检查几个文件无所谓,漏掉一个调用方导致线上 bug 才严重。


22. 调用图 vs. 依赖图 vs. 模块图:别搞混

很多调研项目里都提到"图",但其实不止一种:

图的类型节点用途
调用图(Call Graph)函数A 调用 B"改 A 影响谁"
依赖图(Dependency Graph)模块 / 包A 依赖 B"升级这个包会影响哪些项目"
继承图(Inheritance Graph)A 继承 B"这个父类有哪些子类"
数据流图(Data Flow Graph)变量A 的值流向 B"敏感数据有没有泄露"
执行流(Execution Flow)入口函数A 经过 B 最后到 C"登录请求走过哪些函数"

调研里

  • code-review-graph:所有都覆盖
  • GitNexus:调用图 + 模块图 + 执行流
  • code-graph-rag-mcp:调用图 + 模块图 + 跨语言依赖

23. 概念全景速查表

概念一句话理解对应章节 / 项目
TokenLLM 的计费单位全部
MCPAI 工具的 USB 标准全部(核心协议)
AST代码的"句子成分分析图"02 / 03 / 04 / 05 / 08
Tree-sitter通用 AST 解析器同上
LSPIDE 的"语言翻译官协议"08 (Serena)
Embedding把意思变 GPS 坐标04 / 05 / 08
Model2VecCPU 上跑得飞快的嵌入05 (Semble)
BM25经典关键词搜索04 / 05 / 08
RRF合并多路检索的方法05 / 08
Trigram 倒排索引flashgrep 的核心06
知识图谱代码的"人际关系网"02 / 03 / 04
爆炸半径"改这个会炸到哪"02 / 03
社区检测自动发现功能模块02
RAG让 AI 开卷考试04 / 05 / 08
Chunking切代码喂给 LLM04 / 05 / 08
Merkle DAG智能增量同步08 (Claude Context)
mmap磁盘文件伪装成内存06 (flashgrep)
HooksAI 工具调用前后插一脚03 (GitNexus)
SkillsAI 的工作流 SOP 模板03 (GitNexus)
NDCG@10搜索结果好不好的考分05
F1 / Precision / Recall准确性指标02

24. 从 0 到 1 的推荐学习路径

如果你完全零基础,建议这样读:

第一阶段(理解大图景)
  本章 §0 全局比喻

  本章 §1 Token + §2 MCP        ← 看完知道为什么需要本地索引

  README + 01 章                ← 全景图 + 三大流派

第二阶段(理解核心技术)
  本章 §3 AST + §4 Tree-sitter   ← 解析代码的基础

  本章 §6 Embedding + §8 BM25   ← 检索的两条路

  本章 §14 RAG                   ← 整个 RAG 思想

第三阶段(按兴趣深入)
  对图谱感兴趣 → §11 知识图谱 + §12 爆炸半径 + §13 社区检测 → 02 / 03 章
  对检索感兴趣 → §7 Model2Vec + §9 RRF + §15 Chunking → 05 / 08 章
  对速度感兴趣 → §10 Trigram + §17 mmap → 06 章
  对 IDE 集成感兴趣 → §5 LSP → 08 章 (Serena)

第四阶段(动手实战)
  选 02–08 中任一项目按教程跑起来

  07 章对比与选型 → 决定团队最终方案

25. 常见问题(FAQ)

Q: "MCP" 和 "API" 有什么区别?

A:API 是泛指任何"程序对外暴露的接口"。MCP 是 API 的一种特定形式——专门为 AI 助手设计,规定了如何描述工具能力、如何调用、如何返回。可以理解为"AI 助手用的 REST API"。

Q: "向量数据库"和"普通数据库"有什么区别?

A:普通数据库(MySQL)擅长"精确查找"(user_id = 123)。向量数据库(Milvus)擅长"相似度查找"("找跟这个向量最像的 10 个")。前者用 B-tree 索引,后者用 HNSW / IVF 等向量索引。

Q: 为什么"语义检索"不能取代"关键字检索"?

A:因为语义检索擅长"按意思找",但找精确名字时反而绕远。例如搜常量 MAX_RETRY_COUNT,BM25 一发命中,向量可能输给"做重试的其他函数"。所以业界普遍 BM25 + 向量混合

Q: 我要装哪些工具才能在 Claude Code 里用上代码索引?

A:最简单的:

bash
# 一个语义搜索
claude mcp add semble -s user -- uvx --from "semble[mcp]" semble
# 一个图谱分析
pip install code-review-graph && code-review-graph install
# 重启 Claude Code

然后随便问:"找一下处理认证的代码" / "改这个函数会影响什么?",AI 会自动调用合适的工具。

Q: 这些索引数据会上传到云端吗?

A:默认全部本地。但有几个项目可选用云嵌入:

  • code-graph-rag-mcp、code-review-graph 默认本地嵌入(sentence-transformers),可切到 OpenAI/Gemini
  • Claude Context 默认 OpenAI 云嵌入,可切到本地 Ollama
  • Semble、BitFun、Serena 完全本地

数据敏感的话,记得选全本地路径

Q: 索引会占多大空间?

A:粗略对照:

项目索引体积(相对源码)
Semble<5%
code-review-graph~10%
GitNexus~10–15%
code-graph-rag-mcp~15–20%(含向量)
BitFun (flashgrep)~58%(用空间换速度)

26. 推荐扩展阅读

读完本章 + 推荐阅读,你基本就能加入业界关于"AI 代码助手"的所有技术讨论了。