Understand-Anything 深度解析:/understand-explain 技能如何在知识图谱中精准定位并讲解任意组件
/understand-explain 是 Understand-Anything 插件内置的技能之一,用于对代码库中的某个文件、函数或模块给出「有架构上下文」的深度讲解。它不靠凭空阅读代码,而是先查由 /understand 生成的 knowledge-graph.json,从图谱中取出目标节点、邻接边、所属架构层,再结合源码给出解释。读完本文,你将掌握该技能的完整工作流程(数据目录解析、图谱新鲜度校验、节点/边/层定位、源码深读)、知识图谱 JSON 的数据契约,以及每一步在插件源码中的对应实现。
技能定位与输入格式
技能的元数据定义在 SKILL.md 的 frontmatter 中:
---
name: understand-explain
description: Use when you need a deep-dive explanation of a specific file, function, or module in the codebase
argument-hint: "[file-path]"
---
它接收一个可选参数($ARGUMENTS),支持两种写法:
- 文件路径,如
src/auth/login.ts:解释整个文件级组件; - 函数/组件记法
path:funcName,如src/auth/login.ts:verifyToken:解释该文件下的某个具体函数。
插件中还有一套程序化的等价实现 explain-builder.ts,其 buildExplainContext 函数注释明确说明支持这两种格式,并用 lastIndexOf(":") 拆分路径与函数名(同时排除含 :// 的误判),先按 filePath + name 精确匹配函数节点,匹配不到再回退为按 filePath 匹配文件节点。
数据契约:知识图谱 JSON 结构
/understand-explain 的一切查询都发生在 $UA_DIR/knowledge-graph.json 上。SKILL.md 中的 "Graph Structure Reference" 一节给出了该文件的核心结构,必须完整理解它才能高效使用本技能:
project—{name, description, languages, frameworks, analyzedAt, gitCommitHash}nodes[]— 每个节点含{id, type, name, filePath?, summary, tags[], complexity, languageNotes?}- 代码节点类型:
file、function、class、module、concept - 非代码节点类型:
config、document、service、table、endpoint、pipeline、schema、resource - 领域/知识节点类型:
domain、flow、step、article、entity、topic、claim、source - 节点 ID 以类型作前缀,例如
file:path、function:path:name、config:path、article:path
- 代码节点类型:
edges[]— 每条边含{source, target, type, direction, weight}- 常用边类型:
imports、contains、calls、depends_on、configures、documents、deploys、triggers、contains_flow、flow_step、related、cites
- 常用边类型:
layers[]— 每个含{id, name, description, nodeIds[]}tour[]— 每个含{order, title, description, nodeIds[]}
仓库中可以直接查看一份真实样本:仪表盘自带的 knowledge-graph.json(97 个节点、183 条边、7 个架构层、12 个 tour 步骤),其中 project.gitCommitHash 字段正是新鲜度校验的锚点,layers 里的 "Types & Schema Layer" 这类条目就是 /understand-explain 第 6 步要查的内容。
与类型定义的交叉验证
上述 JSON 结构在 core 包中有严格的 TypeScript 类型与运行时校验,可以作为「实现事实」来核对:
- types.ts 定义了完整的枚举:
NodeType共 27 种(5 种代码 + 8 种非代码 + 3 种领域 + 5 种知识 + 6 种设计),EdgeType共 38 种、分 9 个类别(结构、行为、数据流、依赖、语义、基础设施、领域、知识、设计)——SKILL.md 里列出的只是「常用子集」。GraphNode还有lineRange?: [number, number](函数级节点的起止行号)和complexity: "simple" | "moderate" | "complex"三档取值;GraphEdge的direction取forward | backward | bidirectional,weight为 0–1 的数值,另有可选description。 - schema.ts 用 Zod 定义
KnowledgeGraphSchema,validateGraph会做别名归一(如func→function、method→function、uses→depends_on)、缺省值自动修正(边缺weight默认 0.5、节点缺complexity默认moderate)、引用完整性检查(source/target必须指向存在的节点,否则该边被丢弃)。这意味着技能里 Grep 到的节点类型/边类型都可以假定是「已归一化的规范值」。
高效读取策略:先 Grep,不要整图入上下文
SKILL.md 的 "How to Read Efficiently" 一节给出了四条检索纪律,这也是本技能区别于「直接把整个 JSON 丢给模型」的关键设计:
- 读文件之前先用 Grep 在 JSON 中搜索相关条目,定位后再精确读取;
- 只读需要的片段,绝不把整张图谱倾倒进上下文;
name和summary是最有用的字段——summary是分析阶段由 LLM 写成的组件级描述,是快速理解节点语义的第一手材料;- 边告诉你组件如何连接——顺着
imports和calls边追踪依赖链。
完整工作流程:从解析数据目录到输出解释
以下步骤完整继承自 SKILL.md 的 Instructions 一节。
第 1 步:解析数据目录 $UA_DIR
UA_DIR=$([ -d .understand-anything ] && echo .understand-anything || echo .ua)
规则是:旧的 .understand-anything/ 目录已存在时沿用旧目录,否则使用新的 .ua/ 目录。然后确认 $UA_DIR/knowledge-graph.json 存在;若不存在,提示用户先运行 /understand 生成图谱。
这一「双目录」规则与源码一致:persistence/index.ts 中的 resolveUaDirName 实现了同样的逻辑——旧项目无迁移直接原地读写,新项目写入 .ua/。该文件还负责在落盘前把节点 filePath 统一改写为相对项目根的路径(绝对路径转相对、项目外绝对路径只保留文件名),因此图谱里所有 filePath 都是可直接用来读源文件的相对路径——这正是第 7 步「按 filePath 读源码」能成立的前提。
第 2 步:使用图谱上下文前先校验新鲜度
这是本技能中最容易被忽视、但对结论可信度最关键的一步。流程如下:
- 从图谱元数据读取
project.gitCommitHash作为GRAPH_COMMIT_RAW,先把它解析为有效提交,再与HEAD比较,并检查项目范围内的已提交与工作区变更:
GRAPH_COMMIT=$(git rev-parse --verify --end-of-options "${GRAPH_COMMIT_RAW}^{commit}" 2>/dev/null)
git rev-parse HEAD
git diff --name-only "$GRAPH_COMMIT" HEAD -- .
git diff --cached --name-only -- .
git diff --name-only -- .
git ls-files --others --exclude-standard -- .
-- .路径约束是必需的:在 monorepo 中,只触碰兄弟子项目的提交不应让本项目的图谱被判为过期;哈希不一致本身也不构成过期,只有「项目内 diff 为空」时才算新鲜。- 所有命令的输出中都忽略所选数据目录(
.ua/或旧的.understand-anything/),因为里面是生成的图谱产物,不属于项目源码漂移。 - 若已提交 diff 或任一工作区命令报告了项目文件变更,在解释之前先警告:图谱上下文可能遗漏这些变更,并建议运行
/understand刷新图谱。 - 仅当
GRAPH_COMMIT_RAW解析成功时才执行 commit diff;如果图谱提交哈希缺失、非法或不可用,给出简短的尽力而为(best-effort)警告后继续,而不是阻塞流程。
这套 shell 流程与 core 包中的程序化实现 staleness.ts 是同一套语义:其中 PROJECT_PATHSPEC 常量显式排除了 .(understand-anything|ua) 目录(与第 3 点一一对应);getGraphFreshness 返回 fresh / dirty / stale / unknown 四种状态,unknown 与「新鲜」被刻意区分——Git 元数据读不到时应「软警告」而非声称图谱是最新的(对应第 5 点的 best-effort 原则);stale 状态还会给出 behind / ahead / diverged 三种分叉关系和 commitsAhead/commitsBehind 计数。所有 Git 调用带 5 秒超时,超时同样落入 unknown 而不阻塞。
第 3 步:定位目标节点
用 Grep 在知识图谱中搜索 $ARGUMENTS 对应的组件:
- 文件路径(如
src/auth/login.ts):搜索"filePath"字段命中; - 函数记法(如
src/auth/login.ts:verifyToken):在限定文件路径的前提下搜索"name"字段中的函数名。
记下节点的精确 id、type、summary、tags 和 complexity——这几个字段是后续解释的信息骨架。
第 4 步:找出所有相连的边
用 Grep 在 edges 区域搜索目标节点 ID:
"source"命中 → 该节点调用/导入/依赖的对象(出边);"target"命中 → 调用/导入/依赖该节点的对象(入边);- 记下相连节点 ID 与边类型。
第 5 步:读取相连节点,构建「邻域」
对第 4 步拿到的每个相连节点 ID,在 nodes 区域 Grep 出它们的 name、summary、type。这一步组装出目标组件的一跳邻域(neighborhood)——解释时「它和谁交互」的答案全部来自这里。
第 6 步:确定架构层
在 "layers" 区域 Grep 目标节点 ID,找到它属于哪个架构层以及该层的描述。层的 description 直接回答「这个组件在架构中扮演什么角色、为什么存在」。
第 7 步:读取真实源码
打开节点 filePath 指向的源文件,做深度分析。图谱提供结构与关系,但数据流、具体实现细节必须来自源码本身。
第 8 步:在上下文中解释组件
SKILL.md 规定解释必须覆盖五个维度:
- 架构中的角色——属于哪一层、为什么存在;
- 内部结构——它包含的函数/类(来自
contains边); - 外部连接——它导入什么、谁调用它、它依赖什么(来自边);
- 数据流——输入 → 处理 → 输出(来自源码);
- 清晰表达——假设读者可能不熟悉该编程语言,并点出值得理解的模式、惯用法与复杂点。
源码级印证:explain-builder 如何复刻这套流程
explain-builder.ts 是上述工作流的程序化版本,两者逐项对应,可作为「从源码结构看」的权威参照:
buildExplainContext(graph, path):先按path:func格式匹配函数节点,再回退文件匹配(对应第 3 步);通过contains边找出子节点(文件包含的函数/类,对应第 8 步的内部结构);对全部相关 ID 遍历一遍边,收集一跳邻居作为connectedNodes、收集全部相关边作为relevantEdges(对应第 4、5 步);最后在layers中查找包含目标节点 ID 的层(对应第 6 步)。formatExplainPrompt(ctx):把上下文渲染成结构化的 Markdown prompt——# Deep Dive: <name>标题下给出 Type/Complexity/File/Lines 元信息,随后是## Architectural Layer、## Internal Components、## Connected Components、## Relationships(以src --[edgeType]--> tgt形式列出,跳过contains边)和## Language Notes小节,末尾附上与第 8 步一致的 5 条解释指令。目标未找到时则输出 "Component Not Found" 提示,并给出三种可能原因(尚未分析——先跑/understand、路径写法不同、文件已被删除或重命名)。
对应的测试 explain-builder.test.ts 用一份小型样本图谱(auth.ts 文件节点 + login/verify 函数节点 + db.ts 数据库文件节点,含 contains 与 reads_from 边和 "Auth Layer" 层)验证了关键行为:按路径找到文件节点、childNodes 包含两个函数、connectedNodes 包含 file:src/db.ts、layer.name 为 "Auth Layer"、未知路径返回 targetNode: null、src/auth.ts:login 记法命中函数节点,以及渲染结果包含 "Auth Layer" 等内容。该测试同时给出了一个可直接模仿的迷你图谱样本,适合读者本地演练 Grep 定位流程。
使用要点与常见坑
- 前提条件:必须先成功运行过
/understand(其选项如--full、--language <lang>、--exclude <patterns>等定义在 understand/SKILL.md)。没有$UA_DIR/knowledge-graph.json时,本技能只会提示你先生成。 - 过期图谱:第 2 步的警告意味着解释内容可能遗漏未提交或未分析的变更;看到警告后运行
/understand刷新再解释,结论才可靠。core 包中还有mergeGraphUpdate(staleness.ts 末尾)负责增量刷新——删除变更文件的旧节点、清理悬挂边、写入新gitCommitHash与analyzedAt,因此图谱的project.gitCommitHash会随刷新前进。 - monorepo 场景:
-- .路径约束与staleness.ts的PROJECT_PATHSPEC共同保证「兄弟项目变更不误伤本项目图谱新鲜度」,在多包仓库中使用本技能时尤其要保留该约束。 - 字段语义:
complexity只有三档取值(simple/moderate/complex)、weight是 0–1 权重而非次数、边方向由direction字段表达——这些细节在 schema 校验层已被强制归一,解释时可以直接引用。
总结来说,/understand-explain 的设计精髓在于「图谱导航 + 源码实证」的分工:JSON 图谱负责回答「它是什么、属于哪层、和谁相连」,源码负责回答「它具体怎么运作」;而 Grep 优先的读取纪律与 Git 新鲜度校验,则分别保证了上下文成本可控与结论可信。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00