【Understand Anything】核心架构与设计原理深度解析:把任意代码库变成可探索的知识图谱
【Understand Anything】核心架构与设计原理深度解析
一、引子:从「200,000 行代码从哪看起」到「一张图读懂整个仓库」
一个新人加入团队,仓库 20 万行代码,文档缺位,README 只有一行”This is the monolith”。最痛苦的时刻不是”看不懂一段函数”,而是”不知道整个系统在做什么、各模块如何咬合、改一行会不会塌一片”。
传统做法是逐文件读、画脑图、问 ChatGPT 一段一段喂。但这种”线性串行”模式有三个致命问题:
- 视野碎片化:单文件读懂后,看不到上下游依赖
- 语义丢失:抽象成脑图后,关键设计决策被简化掉了
- 不可探索:一旦脑图做完就是静态的,代码一改就过时
Egonex-AI/Understand Anything(⭐80,883,2026-08-29 数据,MIT)走了一条完全不同的路:把整个代码库交给一个多 Agent 流水线,每个 Agent 负责一个职责(扫描/解析/分层/总结),最终产出一张结构化知识图谱(Knowledge Graph) + 一个交互式 Dashboard + 一组Graph RAG 工具。它不是另一个”读代码的 IDE 插件”,而是一个把”代码理解”做成可计算、可缓存、可增量更新的工程化系统。
本文从源码层(核心 13 个 TS 文件,共 589 个节点)深度剖析其架构:
- 核心抽象:KnowledgeGraph 14 节点类型 × 5 边类型 × 5 阶段处理流水线
- 多 Agent 协同:4 个 sub-agent(scanner / architecture-analyzer / file-analyzer / tour-builder)× 11 个 prompt-only agent
- 增量更新决策:SKIP / PARTIAL_UPDATE / ARCHITECTURE_UPDATE / FULL_UPDATE 四档
- Graph RAG 双轨搜索:Fuse.js 模糊匹配 + Cosine 语义向量
- 多平台适配:Claude Code / Codex / Cursor / Copilot / Gemini CLI / OpenCode / OpenClaw / Antigravity / Hermes / Cline / Kiro / Pi Agent / Vibe CLI / Nanobot / KIMI CLI / Trae 共 16 个 Coding Agent 的统一安装接口
仓库地址:https://github.com/Egonex-AI/Understand-Anything
二、项目定位与核心价值
2.1 一句话定义
Understand Anything 是一个跨 16 个 Coding Agent 的代码库知识图谱引擎:把任意 git 仓库(GitHub / GitLab / Azure / 本地 / ZIP)扫描 → 解析 → 抽取 → 摘要 → 装配 → 增量更新 → 输出为可视化图谱 + Graph RAG 数据源。
2.2 能力矩阵
| 能力 | 描述 | 技术实现 |
|---|---|---|
| 多语言解析 | 13 种编程语言 | Tree-sitter(TypeScript/Python/Rust/Go/Java/Kotlin/C/C++/C#/PHP/Ruby/Scala/JavaScript) |
| 结构指纹 | 函数/类/导入/导出指纹 + SHA-256 | crypto.createHash('sha256') + 自研 FunctionFingerprint / ClassFingerprint / ImportFingerprint |
| 知识图谱 | 14 节点类型 + 5 边类型 | Graphology + graphology-communities-louvain |
| 架构分层 | 自动识别 3-10 个分层 | LLM 语义识别 + 启发式目录匹配 |
| 增量更新 | 4 档决策 + 增量指纹 | classifyUpdate() + git commit hash 对比 |
| 模糊搜索 | 4 字段加权(Fuse.js) | name 0.4 / tags 0.3 / summary 0.2 / languageNotes 0.1 |
| 语义搜索 | Cosine Similarity + 预计算 embedding | cosineSimilarityWithQueryMag() 优化(queryMag 提到循环外) |
| Diff 影响 | 改动前看影响范围 | ChangeAnalysis + mergeGraphUpdate() |
| 引导 Tour | 新人按依赖顺序遍历 | LLM 生成 + 启发式后备(generateHeuristicTour()) |
| Graph RAG | “auth 在哪里”的问答 | 语义搜索 + 邻居拓展 + LLM 重答 |
| 跨 Agent 适配 | 16 个 Coding Agent 同一命令 | 统一 .ua/ 数据目录 + 各平台 invocation prefix 适配 |
2.3 仓库统计
- Stars: 80,883(2026-08-29)
- License: MIT
- Language: TypeScript (94.7%) + Shell + PowerShell
- Monorepo 结构:
pnpm-workspace.yaml编排,2 个包(@understand-anything/core+@understand-anything/skill) - 测试: Vitest,30+ 测试文件,覆盖 graph-builder / embedding-search / fingerprint / staleness / layer-detector / normalize-graph / search / plugin-registry / plugin-discovery 等核心模块
- 最近推送: 2026-08-26(持续活跃)
三、整体架构
3.1 顶层架构图
flowchart TB
subgraph CLI["Coding Agent CLI (Claude Code / Codex / Cursor / ...)"]
CMD["/understand<br/>$understand<br/>kiro-cli chat --agent understand"]
end
subgraph ENTRY["入口层 (skill invocation)"]
HOOK["hooks/post-tool-use-auto-update.mjs"]
AGT["agents/<br/>project-scanner.md<br/>architecture-analyzer.md<br/>file-analyzer.md<br/>tour-builder.md"]
end
subgraph SCAN["扫描层 (Deterministic)"]
SP["scan-project.mjs<br/>file enumeration<br/>+ .understandignore filter"]
IM["extract-import-map.mjs<br/>tree-sitter parse<br/>+ import resolution"]
end
subgraph ANALYZE["分析层 (LLM-driven)"]
LLM1["buildFileAnalysisPrompt()<br/>fileSummary / tags / complexity"]
LLM2["buildProjectSummaryPrompt()<br/>description / frameworks / layers"]
LLM3["buildLayerDetectionPrompt()<br/>3-10 layers assignment"]
LLM4["buildTourGenerationPrompt()<br/>guided tour steps"]
end
subgraph CORE["核心层 (@understand-anything/core)"]
GB["GraphBuilder<br/>assemble nodes/edges<br/>+ dedup by nodeIds"]
FP["fingerprint.ts<br/>SHA-256 + FunctionFingerprint"]
CC["change-classifier.ts<br/>SKIP/PARTIAL/ARCH/FULL"]
NG["normalize-graph.ts<br/>stripToValidPrefix<br/>id canonicalization"]
LD["layer-detector.ts<br/>10 layer patterns<br/>+ LLM fallback"]
EMB["SemanticSearchEngine<br/>cosineSimilarityWithQueryMag"]
SR["SearchEngine<br/>Fuse.js 4-key weighted"]
TG["tour-generator.ts<br/>buildTourGenerationPrompt"]
ST["staleness.ts<br/>getGraphFreshness<br/>git HEAD vs graphCommitHash"]
end
subgraph OUTPUT["输出层"]
KG[".ua/knowledge-graph.json"]
FP2[".ua/fingerprints.json"]
DASHDATA["Dashboard data<br/>graph + layers + tour + embeddings"]
RAG["Graph RAG Tool<br/>search_by_name / search_by_meaning<br/>get_neighbors / explain_node"]
end
CMD --> AGT
HOOK --> CC
AGT --> SP
AGT --> IM
SP --> GB
IM --> GB
AGT --> LLM1
AGT --> LLM2
AGT --> LLM3
AGT --> LLM4
LLM1 --> GB
LLM2 --> GB
LLM3 --> LD
LLM4 --> TG
GB --> NG
GB --> KG
FP --> CC
CC --> ST
NG --> KG
LD --> KG
TG --> KG
EMB --> DASHDATA
SR --> DASHDATA
KG --> DASHDATA
FP2 --> CC
DASHDATA --> RAG
RAG --> CMD3.2 包结构(pnpm workspace)
1 | # pnpm-workspace.yaml |
1 | // understand-anything-plugin/package.json (excerpt) |
包拆分原则:core 不依赖任何 LLM SDK(pure data + 算法),skill 只负责平台对接与 prompt 编排(依赖 core 但反过来 core 不知道 skill 存在)。这种”内圈纯算法、外圈 LLM 适配”的分层是 Understand Anything 能跨 16 个 Coding Agent 的关键。
四、多 Agent 流水线
4.1 四个核心 Agent
sequenceDiagram
participant User
participant Scanner as project-scanner
participant Arch as architecture-analyzer
participant File as file-analyzer (per-file)
participant Tour as tour-builder
participant Graph as GraphBuilder
participant LLM
User->>Scanner: /understand [path]
activate Scanner
Scanner->>Scanner: scan-project.mjs (deterministic)<br/>file enumeration + .understandignore
Scanner->>Scanner: extract-import-map.mjs (deterministic)<br/>tree-sitter parse 13 langs
Scanner->>LLM: read README + manifests → JSON inventory
LLM-->>Scanner: {name, description, languages, frameworks, layers}
Scanner->>Scanner: persist inventory to .ua/
deactivate Scanner
activate Arch
Arch->>Arch: load all file nodes + import edges
Arch->>Arch: Phase 1: write Node.js script<br/>compute structural patterns<br/>(fan-in/fan-out/peripheral)
Arch->>LLM: Phase 2: layers semantic assignment<br/>3-10 layers + every file → 1 layer
LLM-->>Arch: {layers: [{name, description, filePatterns}]}
Arch-->>Graph: applyLLMLayers()
deactivate Arch
activate File
loop for each non-cosmetic-changed file
File->>LLM: buildFileAnalysisPrompt(path, content, context)
LLM-->>File: LLMFileAnalysis<br/>{fileSummary, tags, complexity,<br/>functionSummaries, classSummaries}
end
File-->>Graph: GraphBuilder.addFile(path, meta)
deactivate File
activate Tour
Tour->>Tour: load graph + nodes + edges + layers
alt LLM available
Tour->>LLM: buildTourGenerationPrompt(graph)
LLM-->>Tour: {steps: [{order, title, description, nodeIds}]}
else fallback
Tour->>Tour: generateHeuristicTour()<br/>topological sort by dependencies
end
Tour-->>Graph: tour steps persisted
deactivate Tour
Graph->>Graph: validateGraph() + autoFixGraph()
Graph-->>User: /understand-dashboard opens .ua/knowledge-graph.json4.2 阶段 1:Project Scanner(确定性扫描 + LLM 叙事)
agents/project-scanner.md 把工作切成两部分:
- 确定性(mjs 脚本跑):file 枚举、语言检测、分类、行数、复杂度、
.understandignore过滤、import 解析 —— 这些都 不许 LLM 重做 - LLM(唯一一段):读 README + manifests,合成叙事性
name/description/frameworks
1 | // 来自 agents/project-scanner.md: Phase 1 Step A |
关键设计:”Subagent boundary: Do not delegate work or create subagents, including via the Agent tool. Complete this task directly.” —— 这是给 LLM 的硬约束,禁止递归 Agent 调用,避免”Agent 调用 Agent 调用 Agent”的失控。
4.3 阶段 2:Architecture Analyzer(双阶段脚本+语义)
1 | // 来自 agents/architecture-analyzer.md: Phase 1 |
设计哲学:让 LLM 写脚本算确定性图指标(避免 LLM 算错),只把语义判断留给 LLM(layer 命名、layer 描述、file → layer 归属)。这是”工具调用范式”的极致体现。
4.4 阶段 3:File Analyzer(per-file 并行 prompt)
1 | // 来自 packages/core/src/analyzer/llm-analyzer.ts:28-58 |
关键点:
- 强约束 JSON 输出(”Respond ONLY with the JSON object”)—— 避免 LLM 加废话导致 JSON.parse 失败
- 每文件独立 prompt —— 可并行(16 Coding Agent 通常并发 ≥ 4 个文件)
- projectContext 注入 —— 把阶段 1 的 project summary 作为上下文,让 LLM 知道”这个文件在整个项目里算什么角色”
4.5 阶段 4:Tour Builder(LLM 主路径 + 启发式回退)
1 | // 来自 packages/core/src/analyzer/tour-generator.ts:6-40 |
回退机制(关键工程细节):
1 | // 来自 tour-generator.ts: parseTourGenerationResponse |
generateHeuristicTour() 是基于拓扑排序的后备方案:LLM 不可用 / 解析失败 → 仍能给用户一个按依赖顺序排列的 tour。
五、核心数据结构:KnowledgeGraph 与指纹
5.1 节点类型(14 种)
1 | // 来自 packages/core/src/analyzer/normalize-graph.ts:1-22 |
每种 nodeType 对应一个 prefix,保证 ID 格式全局一致:
| nodeType | ID 格式 | 例子 |
|---|---|---|
file | file:src/auth/login.ts | file:src/auth/login.ts |
function | func:login | func:src/auth/login.ts:login |
class | class:UserService | class:src/auth/UserService.ts:UserService |
service | service:auth | service:auth-svc |
endpoint | endpoint:POST /api/login | endpoint:POST /api/login |
table | table:users | table:users |
domain | domain:payment | domain:payment |
flow | flow:checkout | flow:checkout |
step | step:checkout:validate-cart | step:checkout:src/checkout.ts:validate-cart |
5.2 边类型(5 种)
| edge type | 含义 | 示例 |
|---|---|---|
imports | 文件 A import 文件 B | file:A.ts → file:B.ts |
calls | 函数 A 调用函数 B | func:A → func:B |
belongs_to_layer | 文件归属某分层 | file:X.ts → layer:api |
part_of_domain | 文件/服务归属某业务域 | service:auth → domain:identity |
depends_on | 通用依赖(语义层) | flow:checkout → service:payment |
5.3 GraphBuilder:装配 + 去重
1 | // 来自 packages/core/src/analyzer/graph-builder.ts:60-78 |
两条 Set 索引是关键工程决策:
nodeIds—— addFile 时先去重,避免同一文件被多个 agent 各加一次edgeKeys—— 加 edge 时先去重(source:target:type 三元组)
1 | // addFile 简化版(来自 graph-builder.ts:80-130) |
5.4 文件结构指纹:Fingerprint + SHA-256
1 | // 来自 packages/core/src/fingerprint.ts:1-50 |
指纹的精髓:不只是文件哈希(SHA-256 已经够了用于判断”是否改动”),而是结构级指纹(函数签名、类成员、import 列表)—— 用于判断”改动是否影响知识图谱”。
1 | // 来自 fingerprint.ts: SHA-256 内容哈希 |
三档变化级别:
NONE—— 文件无改动COSMETIC—— 仅注释/空行/格式化改动(functions/classes/imports指纹完全一致)STRUCTURAL—— 函数签名变、类成员变、import 列表变
ChangeAnalysis 把所有文件归类到 5 个桶:newFiles / deletedFiles / structurallyChangedFiles / cosmeticOnlyFiles / unchangedFiles —— 直接喂给下游 classifyUpdate()。
六、增量更新决策:四档矩阵
6.1 决策流程图
flowchart TB
Start([git diff HEAD vs graphCommitHash]) --> FP["FileFingerprint 对比<br/>生成 ChangeAnalysis"]
FP --> CC{"structuralCount<br/>(new+deleted+changed)?"}
CC -->|"= 0"| SKIP["SKIP<br/>无需 LLM<br/>只更新元数据"]
CC -->|"≤ 10<br/>+ 无目录变化"| PARTIAL["PARTIAL_UPDATE<br/>只重跑 file-analyzer<br/>对变更文件"]
CC -->|"11-30<br/>或目录结构变化"| ARCH["ARCHITECTURE_UPDATE<br/>重跑 file-analyzer<br/>+ architecture-analyzer<br/>+ tour-builder"]
CC -->|"> 30<br/>或 > 50% 总文件"| FULL["FULL_UPDATE<br/>完全重建<br/>适合大重构"]
SKIP --> Cost1["成本: ~0 token"]
PARTIAL --> Cost2["成本: 文件数 × ~2k token"]
ARCH --> Cost3["成本: ~50% 全量"]
FULL --> Cost4["成本: 100% 全量"]6.2 源码:决策矩阵
1 | // 来自 packages/core/src/change-classifier.ts:14-79 |
6.3 目录变化检测
1 | // 来自 change-classifier.ts: detectDirectoryChanges |
为什么目录变化触发 ARCHITECTURE_UPDATE?因为 layer-detector.ts 的 LAYER_PATTERNS 是按目录关键词匹配的(service/、controller/、middleware/、util/ 等),新目录可能需要重新划分 layer。
6.4 与 Git HEAD 对比:staleness.ts
1 | // 来自 packages/core/src/staleness.ts:26-48 |
三态判定:
fresh—— graphCommitHash == headCommitHash 且无未提交改动dirty—— 工作区有改动(未提交)stale—— 已落后 N 个 commit 或有分叉unknown—— git 命令超时(> 5s)、graph commit 缺失、HEAD 不可达
关键防护:
GIT_TIMEOUT_MS = 5_000—— 防 git 命令卡死整个流水线GIT_MAX_BUFFER_BYTES = 4 * 1024 * 1024—— 防大仓库 diff 输出爆内存PROJECT_PATHSPEC用 git pathspec 排除.ua/和.understand-anything/—— 避免自我递归(自己改自己的图谱不算”仓库变化”)
七、知识图谱规范化:normalize-graph.ts
7.1 双前缀修复
LLM 输出节点 ID 时偶尔会”叠前缀”(file:file:src/foo.ts),normalize-graph 必须容错:
1 | // 来自 packages/core/src/analyzer/normalize-graph.ts:24-52 |
算法:
- 从左往右找第一个
:,取前缀 - 如果是 valid prefix → 检查剩余部分是否又是 valid prefix
- 如果是双前缀 → 丢掉外层,从内层重新开始
- 如果不是 → 返回当前 prefix + path
7.2 step 节点的特殊处理
1 | // 来自 normalize-graph.ts: ~60-80 |
step 节点特殊原因:两个 flow(checkout 和 refund)里都有名为 validate-cart 的 step,同一文件路径。保留 flowSlug 作 discriminator 才能全局唯一。
7.3 schema 自动修复
1 | // 来自 packages/core/src/schema.ts (top-level export) |
autoFixGraph 把常见 LLM 输出错误自动归一化:
COMPLEXITY_ALIASES:'easy' / 'simple' / 'trivial'→'simple'DIRECTION_ALIASES:'upstream' / 'incoming' / 'in'→'in'
LLM 输出不一致是常态,让 schema 容忍 + 自动修复比 prompt 里要求 LLM “一定要输出 simple/moderate/complex” 更鲁棒。
八、Graph RAG 双轨搜索
8.1 模糊搜索:Fuse.js 4-key 加权
1 | // 来自 packages/core/src/search.ts |
关键设计:
name权重 0.4 —— 用户最常搜的是文件名/函数名threshold: 0.4—— 容忍拼写错误(auth命中authoriz)useExtendedSearch+' | 'join —— 多 token 用 OR 而非 AND(避免 “auth contrl” 因为没有同时完全匹配而空结果)
8.2 语义搜索:Cosine Similarity 优化
1 | // 来自 packages/core/src/embedding-search.ts:9-110 |
优化关键:每次搜索时 queryEmbedding 的模长是常量,提到循环外只算一次,省 N 次平方+开方。注释明确写出 “Same arithmetic, same order → bit-identical results” —— 这是数值等价性优先于微优化的工程哲学。
8.3 双轨融合策略
flowchart LR
Q["用户 query<br/>'where is auth handled?'"] --> FUSE["Fuse.js 模糊<br/>name/tags/summary"]
Q --> EMB["语义 embedding<br/>(调用 LLM embed)"]
FUSE --> SCORE1["score1<br/>(0=best)"]
EMB --> SCORE2["score2<br/>(1-cosine)"]
SCORE1 --> RRF["Reciprocal Rank Fusion<br/>1/(k+rank1) + 1/(k+rank2)"]
SCORE2 --> RRF
RRF --> TOP["Top K 节点 + 邻居展开"]
TOP --> LLM["LLM 重答<br/>with node context"]
LLM --> ANS["回答 + 节点引用"]九、跨平台适配层
9.1 16 个 Coding Agent 的统一接口
1 | // 概念:每个平台一个 invocation prefix,但语义相同 |
关键观察:15 个用 / 前缀,只有 Codex 用 $ 前缀(OpenAI Codex CLI 的设计约定)。Kiro 用的是 kiro-cli chat --agent <name> "..." 命令行形式(最特殊)。
9.2 安装脚本设计
1 | # install.sh 简化版 |
设计哲学:不复制代码,全用 symlink。升级时 git pull 即可,16 个平台同步更新。
9.3 Plugin Manifest 三件套
1 | // .claude-plugin/marketplace.json (Claude Code) |
1 | // .cursor-plugin/plugin.json (Cursor) |
1 | // .copilot-plugin/plugin.json (GitHub Copilot) |
十、Hooks 体系:post-tool-use-auto-update
10.1 Hook 注册
1 | // understand-anything-plugin/hooks/hooks.json |
触发时机:Agent 调用 Edit / Write / MultiEdit 工具后,异步触发更新检查。不阻塞主对话流。
10.2 更新检查逻辑
1 | // post-tool-use-auto-update.mjs 简化版 |
设计哲学:Hook 不直接修改图谱(避免 race condition + LLM 工作流被中断),只追加 additionalContext 告诉 Agent “嘿你刚改了文件,要不要增量更新图谱”。由 Agent 决定是否调用 /understand --incremental。
十一、Layer Detector:启发式 + LLM 兜底
11.1 启发式优先(10 模式)
1 | // 来自 packages/core/src/analyzer/layer-detector.ts:12-95 |
Order matters:第一个匹配获胜。例如 controllers/api/users.ts 会匹配 controller → API Layer,而非 api → 也匹配到 API Layer,结果一致。
11.2 LLM 兜底
1 | // layer-detector.ts: detectLayers |
启发式 vs LLM 的成本取舍:
- 启发式:0 token,~1ms,但漏掉非典型命名
- LLM:
5k token / 项目(一次),10s,但能识别domain/、feature/、module/、hexagonal/等非标准分层
80% 阈值 是经验值:典型项目 80% 文件落在 10 个标准模式里,剩下 20% 让 LLM 处理”项目特殊分层”。
十二、端到端数据流
sequenceDiagram
participant User
participant Cursor as Cursor IDE
participant Hook as post-tool-use.mjs
participant Claude as Claude Code Agent
participant Scanner as project-scanner
participant Arch as architecture-analyzer
participant File as file-analyzer
participant Builder as GraphBuilder
participant LLM as LLM Provider
participant Storage as .ua/
User->>Cursor: Edit src/auth/login.ts (add OAuth)
Cursor->>Hook: PostToolUse event
Hook->>Hook: check .ua/ exists? git dirty?
Hook-->>Claude: additionalContext<br/>"Run /understand --incremental"
Claude->>Claude: parse suggestion
Claude->>Scanner: dispatch
Scanner->>Scanner: getChangedFiles() (git diff)
Scanner->>Scanner: extract-import-map.mjs (tree-sitter src/auth/login.ts)
Scanner->>File: dispatch for src/auth/login.ts
File->>LLM: buildFileAnalysisPrompt(content)
LLM-->>File: {fileSummary, tags, complexity,<br/>functionSummaries: {loginOAuth:...}}
File-->>Builder: addFile(src/auth/login.ts, meta)
Builder->>Builder: nodes +=, edges += (imports)
Builder->>Builder: validateGraph() + autoFixGraph()
Builder->>Storage: write .ua/knowledge-graph.json
Storage-->>Cursor: Dashboard auto-reloads
Cursor-->>User: graph updated, OAuth node visible关键节点:
- Hook 不直接写图谱 —— 避免 race condition
- Agent 调度 Scanner 而非全自动 —— 用户可中断
- GraphBuilder 是同步单例 —— 所有 agent 写入顺序可控
- validateGraph() 每次写入前跑 —— 防 LLM 输出污染整个图
十三、与同类项目对比
13.1 四维度横向对比
| 项目 | 形态 | 图抽象 | 增量更新 | 跨 Agent | 评测依据 |
|---|---|---|---|---|---|
| Understand Anything | Plugin + Dashboard | KnowledgeGraph 14 types + 5 edges | 4 档决策矩阵 + git HEAD | 16 个 Coding Agent | MIT, ⭐80k, 生产活跃 |
| GitNexus | VSCode 扩展 | Client-side knowledge graph (browser) | 仅增量 fingerprint | 仅 VSCode 系 | NOASSERTION, ⭐46k, 客户端 |
| mcp-server-code-graph | MCP server | 简单 RAG 索引 | 无增量 | MCP 协议 | 各家实现差异大 |
| Sourcegraph | SaaS / 自托管 | Code intelligence (LSIF) | 索引同步 | 通用 | 商业, ⭐~10k |
13.2 设计差异分析
13.2.1 图抽象的”节点粒度”
- Understand Anything:14 节点类型,含
domain/flow/step等业务层抽象(不只文件/函数) - GitNexus:以
file/function/class为主,无业务抽象 - Sourcegraph:LSIF 索引是
document/definition/reference三层
差异:UA 把”代码”和”业务”在同一个图里 —— 你能同时看到 service:auth 节点和 domain:identity 节点以及它们的 part_of_domain 边。这是 Graph RAG 真正的差异化。
13.2.2 增量更新的”决策粒度”
- UA:4 档(SKIP / PARTIAL / ARCH / FULL),基于结构指纹
- GitNexus:2 档(full rebuild / skip),简单粗暴
- 传统:基本无增量,每次全量重建
差异:UA 的 4 档矩阵让 token 成本随改动线性而非全量变化。一个 1000 文件的仓库改 1 个文件:
- UA PARTIAL_UPDATE:1 个 file-analyzer 调用 ≈ 2k token
- 朴素全量:1000 个 file-analyzer ≈ 2M token(1000 倍差距)
13.2.3 跨 Agent 适配策略
- UA:统一
.ua/数据目录 + 各平台 invocation prefix 适配(/vs$) - GitNexus:VSCode 平台绑定
- MCP servers:协议绑定(任何支持 MCP 的 Agent 都能用),但牺牲 IDE 集成
差异:UA 是 “插件即源码” 模式(symlink + manifest)—— 加一个新 Agent 平台只需写一个 install.sh 入口。
13.2.4 Graph RAG 的数据源
- UA:本地
.ua/knowledge-graph.json(precomputed embedding) - GitNexus:浏览器内 in-memory graph(每次重启丢失)
- MCP code-graph servers:动态查询(每次重新 embed)
差异:UA 是 “build once, query fast” —— 适合”反复查询同一仓库”的场景(如 onboarding、新人 ramp-up)。
十四、优缺点分析
| 维度 | 优势 | 代价 |
|---|---|---|
| 架构简洁性 | 4 个 Agent 职责清晰、core 包零 LLM 依赖 | 14 节点类型 + 5 边类型对小型项目过重 |
| 扩展性 | 16 个 Coding Agent 统一接口、新平台只需 install.sh | Plugin manifest 三件套(Claude/Cursor/Copilot)需各自维护 |
| 易用性 | /understand 一键全图、/understand-diff 看影响、/understand-chat 问答 | 首次扫描大型仓库 token 消耗大(README 警告”用 token plan 或本地模型”) |
| 性能 | 增量更新 + Git HEAD 对比 + 结构指纹去重 | 每次增量也需重跑 file-analyzer(token 成本非零) |
| 复杂度 | 多 Agent 流水线 + 双轨搜索 + 自动 schema 修复 | 调试链路长(Hook → Agent → Scanner → File Analyzer → GraphBuilder) |
| 维护性 | 30+ Vitest 测试 + MIT + 单体仓库 | Tree-sitter 13 语言版本同步 + LLM 输出漂移监控 |
14.1 架构简洁性 vs 复杂度的权衡
UA 的核心矛盾:节点类型多(14 种)+ Agent 多(4 + 11 prompt-only)= 灵活性强但入门曲线陡。
解决办法:
- 默认只暴露 3 个命令:
/understand//understand-dashboard//understand-chat - 高级命令(
--incremental/--language zh/--auto-update)通过--help发现 - 每个 Agent 的 prompt 是 markdown 文件(
agents/*.md),用户可直接编辑改 prompt
14.2 性能 vs 维护性的权衡
UA 的 token 优化(4 档决策矩阵)减少了 运行成本,但增加了 决策代码复杂度(change-classifier.ts 80 行 vs 朴素 5 行 if-else)。
这是正确选择:
- 大仓库(1000+ 文件)日常增量 1-5 个文件 → PARTIAL_UPDATE 节省 ~95% token
- 决策代码虽然复杂,但有完整单元测试 + 文档注释(
reason字段直接给出触发原因)
十五、实践:本地运行 + 接入 Coding Agent
15.1 一键安装
1 | # macOS / Linux |
15.2 在 Claude Code 中使用
1 | # 1. 安装 plugin |
15.3 自定义 LLM Provider
1 | // .ua/config.json |
支持的 provider:
openai/anthropic/azure-openai(标准 API)ollama/vllm/lm-studio(本地推理)- 自定义 HTTP 端点
15.4 Hook 自动接入
1 | # 启用 auto-update |
开启后,每次 commit 后 5 秒内 Hook 会检测变化并提示 Agent 调用增量更新。
15.5 跨平台命令对照表
| 平台 | 安装 | 调用 | 数据目录 |
|---|---|---|---|
| Claude Code | /plugin install | /understand | .ua/ |
| Codex | install.sh codex | $understand | .ua/ |
| Cursor | 自动发现 | /understand | .ua/ |
| VSCode Copilot | 自动发现 | /understand | .ua/ |
| Gemini CLI | install.sh gemini | /understand | .ua/ |
| OpenCode | install.sh opencode | /understand | .ua/ |
| OpenClaw | install.sh openclaw | /understand | .ua/ |
| Antigravity | install.sh antigravity | /understand | .ua/ |
| Vibe CLI | install.sh vibe | /understand | .ua/ |
| Hermes | install.sh hermes | /understand | .ua/ |
| Cline | install.sh cline | /understand | .ua/ |
| KIMI CLI | install.sh kimi | /understand | .ua/ |
| Trae | install.sh trae | /understand | .ua/ |
| Nanobot | install.sh nanobot | /understand | .ua/ |
| Pi Agent | install.sh pi | /understand | .ua/ |
| Kiro | install.sh kiro | kiro-cli chat --agent understand "..." | .ua/ |
数据目录统一为 .ua/(向后兼容 .understand-anything/)—— 切换 Agent 不丢数据。
十六、趋势与工程经验总结
16.1 三个核心趋势判断
趋势 1:代码理解从”IDE 内嵌”走向”跨 Agent 插件化”
2026 年代码理解工具的形态正在发生根本变化:
- 2020-2024 时代:Sourcegraph / LGTM 等是 IDE 内嵌(Codeium Tab、Warp、Cursor Built-in)—— 强 IDE 绑定
- 2025-2026 时代:Understand Anything / Context7 等是 Coding Agent 插件 —— 解耦 IDE,通过 LLM 调用层提供
- 未来 12 个月:会进一步抽象为 “代码理解即 MCP 服务”(类似 chrome-devtools-mcp),任何 Agent 通过 MCP 协议调用
趋势 2:增量更新从”全量重建”走向”4 档决策矩阵”
传统代码索引工具(ctags / LSP / Sourcegraph)几乎都是”全量重建 + 后台异步”。UA 的 4 档决策矩阵(SKIP / PARTIAL / ARCH / FULL)是 精细化的代表 —— token 成本与改动幅度线性而非全量变化。这套模式会扩散到文档索引、API 索引、测试索引等其他场景。
趋势 3:Graph RAG 从”向量召回”走向”图结构推理”
传统 RAG:query → embedding → top-K 文档 → LLM 重答。问题:丢失了文档间结构关系。
Graph RAG(UA / Microsoft GraphRAG):query → embedding → top-K 节点 → 邻居展开(1-2 跳)→ 子图序列化 → LLM 重答。优势:能回答”X 和 Y 的关系是什么”这种结构性问题。
UA 的 14 节点类型 + 5 边类型相当于给代码库预定义了一套 ontology,让 Graph RAG 不只是”找相似”,而是”推理关联”。
16.2 工程经验提炼
经验 1:把 LLM 当”工具调用者”,不是”全能助手”
UA 的 project-scanner.md 明确说:”Deterministic (file enumeration, language detection, category assignment, line counting, complexity estimation, .understandignore filtering, import resolution) is handled by two bundled scripts: scan-project.mjs and extract-import-map.mjs. Do NOT re-implement any of this logic.”
核心原则:
- 凡是 deterministic 的工作(计数、解析、过滤)→ 用 mjs 脚本
- 凡是语义判断的工作(layer 命名、文件摘要)→ 才让 LLM 做
反例:很多 Agent prompt 让 LLM “数一下这个文件有多少行” —— 浪费 token 且容易数错。
经验 2:给 LLM 输出做”自动修复”,别只让 LLM “更守规矩”
UA 的 autoFixGraph() + COMPLEXITY_ALIASES + DIRECTION_ALIASES 是这一思想的极致体现:
- LLM 输出
'simple' / 'easy' / 'trivial'都接受 → 内部归一为'simple' - LLM 输出
'upstream' / 'incoming' / 'in'都接受 → 内部归一为'in'
不要花 50 行 prompt 让 LLM “一定要输出 exactly these values”。让 schema 容忍 + 自动修复比 prompt 约束更鲁棒。
经验 3:Hook 设计哲学 —— “告知而非干预”
UA 的 post-tool-use-auto-update.mjs 关键设计:
1 | // 不是直接更新图谱(会 race condition) |
为什么不让 Hook 直接做:
- race condition —— Hook 和主 Agent 可能同时写
.ua/ - 工作流被打断 —— Agent 正在写代码,Hook 突然启动 LLM 调用 → 主对话流卡顿
- 用户意图缺失 —— 改文件不一定想更新图谱(可能只是 explore)
正确做法:Hook 只做”告知”,让主 Agent 决定。
经验 4:跨平台适配的”零代码接管”哲学
UA 的 16 平台统一接口核心:
- 数据目录统一
.ua/ - 各平台只需写一个
install.sh <platform>入口(创建 symlink + manifest) - 加新平台 = 加一个 case 分支,不改 core
反例:很多框架的”跨平台”是”每个平台一份配置”,加一个平台要改 5 个文件。UA 是”数据驱动 + symlink”模式 —— 加新平台边际成本极低。
经验 5:LLM 输出的”双层 schema 校验”
UA 的 schema 体系:
- 第一层:每个 Agent prompt 内置 JSON 格式约束(”Respond ONLY with the JSON object”)
- 第二层:全局
validateGraph()+autoFixGraph()兜底
不要只依赖第一层(LLM 会偶尔”放飞自我”加废话)。也不要只依赖第二层(错误发现太晚,回滚成本高)。双层校验才是工程化方案。
16.3 适用场景与不适用场景
适合用 UA 的场景
✅ 200+ 文件的中大型仓库
✅ 需要新人快速 onboard
✅ 跨多个 Coding Agent 协作(团队用不同 IDE)
✅ 长期维护的项目(需要持续追踪代码演进)
✅ 业务领域复杂(domain / flow / step 需要显式建模)
不适合用 UA 的场景
❌ 小型脚本(< 50 文件)—— LLM 成本不划算
❌ 一次性原型 —— 没有”持续追踪”的需求
❌ 闭源 SaaS 项目的纯消费者 —— UA 是源码分析工具
❌ 嵌入式 / 单文件项目 —— 没有”图”的概念
16.4 与已有文章项目的差异化定位
| 已写主题 | 与 UA 的关系 |
|---|---|
| Cognee / Mem0 / Memori | Memory/RAG 类(用户级记忆)—— UA 是 codebase 知识图谱(项目级图谱) |
| Composio / Chrome-devtools-mcp | 工具/MCP 协议 —— UA 不做工具,做”代码理解工具链” |
| RagaAI Catalyst / Logfire | LLM 可观测性 —— UA 是 LLM 应用场景(代码理解) |
| Pipecat / OpenMontage / Parlant | Voice/Video/对话治理 —— UA 是代码理解 |
| claude-code / codex / goose / planning-with-files | Coding Agent Harness —— UA 是 Coding Agent 的能力插件,不替代 Harness |
UA 在生态中的位置:是 “Coding Agent 时代的知识工程” —— 把传统静态文档/脑图变成可计算、可缓存、可增量更新、可 Graph RAG 查询的动态资产。与 Planning-with-Files(持久化规划)互补,与 Cognee(用户记忆)正交。
附录:关键资源
- GitHub: https://github.com/Egonex-AI/Understand-Anything
- 官网 / Live Demo: https://understand-anything.com/demo/
- 主创: Lum1104(GitHub: https://github.com/Lum1104)
- License: MIT
- 版本: v2.9.4(2026-08-26)
- 支持 Coding Agent: Claude Code / Codex / Cursor / GitHub Copilot / Copilot CLI / Gemini CLI / OpenCode / OpenClaw / Antigravity / Vibe CLI / Hermes / Cline / KIMI CLI / Trae / Nanobot / Pi Agent / Kiro(17 个)
- 依赖核心库: tree-sitter (13 语言)、Graphology、graphology-communities-louvain、Fuse.js
- 测试: Vitest(30+ 测试文件)
- 包结构: pnpm workspace,
@understand-anything/core+@understand-anything/skill - 数据目录:
.ua/(向后兼容.understand-anything/) - 默认 LLM Provider: 任意 OpenAI 兼容 API / Anthropic / Ollama / vLLM / LM Studio
写在最后
Understand Anything 不是一个新奇的 AI 项目,而是一个工程化典范。它把”代码理解”这个看似智能的任务拆成:
- 确定性部分(扫描、解析、指纹、对比)→ 用 mjs 脚本 + TypeScript 算法
- 语义部分(摘要、分层、命名)→ 用 LLM agent
- 缓存部分(Git HEAD 对比 + SHA-256 指纹)→ 让 token 成本随改动线性变化
- 跨平台部分(统一数据目录 + symlink + manifest)→ 16 个 Coding Agent 同一接口
这种 “工具调用 + Agent 编排 + 增量缓存 + 平台解耦” 的组合拳,是 2026 年 AI 工程化最值得学习的范式。
它告诉所有 Coding Agent 的开发者:LLM 不是银弹,prompt 工程 + 数据结构 + 增量算法 + 平台适配四件套才是真正的工程答案。
当你下次写 Agent 时,不妨问自己:
- 哪些步骤是 deterministic 的?(用脚本,别用 LLM)
- 哪些步骤是 semantic 的?(用 LLM,但配 schema 兜底)
- 增量更新的决策矩阵是什么?(别朴素全量)
- 数据目录的 canonical path 是什么?(统一,别每个 Agent 各一套)
这四个问题的答案,会让你的 Agent 从”能用”走向”好用 + 可维护 + 可扩展”。
完。