Understand Anything Learn Mode 实现解析Tour 生成引擎、Zustand 状态管理与多角色 Persona 系统【免费下载链接】Understand-AnythingGraphs that teach graphs that impress. Turn any code into an interactive knowledge graph you can explore, search, and ask questions about. Works with Claude Code, Codex, Cursor, Copilot, Gemini CLI, and more.项目地址: https://gitcode.com/GitHub_Trending/un/Understand-Anything本文基于 Understand Anything 仓库中 Phase 3Learn Mode实施计划文档系统讲解学习模式这一层的完整落地路径Tour 自动生成引擎LLM 提示词构建 启发式拓扑排序双策略、LearnPanel 与 Zustand tour 状态管理、节点图高亮联动、单节点 Claude 解释、语言课程概念检测以及非技术 / 初级 / 资深三档 Persona 自适应布局。读完后你将掌握如何在core包中实现提示词构建 → 响应解析 → 优雅降级的 LLM 集成模式并能在dashboard包中完成面板状态驱动与图节点高亮的联动。计划背景与总体架构Phase 3 的目标是给 Understand Anything 增加一层Learn Mode——引导式 Tour、上下文解释、语言专属课程language-specific lessons和 Persona 模式非技术 / 初级 / 资深。该计划扩展既有 monorepocore 包负责 Tour 生成与语言课程的提示词构建器dashboard 包负责新增 LearnPanel 组件、Persona 选择器与增强的节点解释原有的 4 面板布局变为随 Persona 自适应的布局。技术栈不引入任何新依赖复用已有的 react-markdown、anthropic-ai/sdk、zustand、xyflow/react、tailwindcss。整个计划拆成 7 个 Task依赖关系如下引自计划文档Task 1 (Tour Gen Core) ──────────────┐ ├─→ Task 3 (Tour Player Highlights) Task 2 (LearnPanel Store) ─────────┘ │ │ Task 4 (Node Explanations) ─── (independent) ───┤ │ Task 5 (Language Lesson Core) ───────────────────┤ ├─→ Task 7 (Persona Modes) Task 6 (Language Lesson Display) ────────────────┘Task 1、2、4、5 可以任意顺序开发Task 3 依赖 Task 2Task 6 依赖 Task 5Task 7 依赖 Task 2 3 6 全部完成。这一依赖图体现了计划的工程考量core 侧的纯函数引擎与 dashboard 侧的 UI 状态层可以并行推进只有图高亮联动和最终 Persona 布局必须在两侧都就绪后收尾。需要注意的一点是计划文档写作时包位于packages/core、packages/dashboard而当前仓库中它们实际位于understand-anything-plugin/插件目录下的 core 包 与 dashboard 包下文引用均以仓库实际路径为准。Task 1Tour 生成引擎core 包Tour 的数据结构在 Phase 1 已经就位TourStep接口定义在 types.ts包含order、title、description、nodeIds和可选的languageLesson字段根结构KnowledgeGraph持有tour: TourStep[]types.ts。示例数据 knowledge-graph.json 中也已带 6 个带语言课程的 tour 步骤。Task 1 要解决的是生成这些 tour 的引擎包含三条导出buildTourGenerationPrompt(graph)构建 LLM 提示词parseTourGenerationResponse(response)解析 LLM 响应带优雅降级generateHeuristicTour(graph)不依赖 LLM、纯图拓扑的启发式生成。LLM 提示词构建提示词的职责是把整张知识图压缩成 LLM 可消化的上下文。构建逻辑分为四段节点清单- [type] name (filePath): summary格式逐行列出、关系清单用slice(0, 50)截断边数量避免提示词过长、层清单每层名称 描述 节点数最后是明确的指令与输出契约。指令部分要求 LLM每个步骤聚焦 1–4 个概念上属于同一组的节点标题要有吸引力Where It All Begins 而不是 Step 1用平实语言解释这些组件做什么、为什么存在遵循自然执行流entry point → routing → business logic → data;对涉及语言专属概念的步骤填写languageLesson字段middleware、generics、async/await、decorators 等简单解释并约定返回 4–8 个步骤的严格 JSON 格式要求使用真实节点 ID。这个截断 严格 schema 字段级说明的提示词设计是该项目的通用模式——语言课程提示词Task 5同样要求Respond ONLY with the JSON object。响应解析与降级parseTourGenerationResponse的关键在于防御式解析这正是 LLM 集成的工程难点。实现顺序为代码围栏提取用正则/(?:json)?\s*\n?([\s\S]*?)\n?/匹配 markdown 代码块命中则取内部内容JSON.parse兼容裸 JSON 与带围栏 JSON 两种返回形状兼容既接受parsed.steps数组也接受顶层即数组的返回字段级过滤order必须是 numbertitle/description必须是非空 stringnodeIds必须是非空数组缺任何一个字段的步骤直接丢弃languageLesson仅在存在时附加全程 try/catch解析失败返回空数组[]绝不抛异常。对应的测试tour-generator.test.ts覆盖了四个场景解析合法 JSON、从 markdown 代码块中提取 JSON、对不可解析的响应返回空数组、过滤掉缺必填字段的步骤3 步输入只保留 1 步有效输出。启发式 Tour入口检测 Kahn 拓扑排序generateHeuristicTour是不需要 LLM 的兜底路径其策略在实现文件的头部注释里写得很清楚tour-generator.ts将 concept 节点与代码节点分离仅对代码节点建立邻接表与入度表边若任一端不是代码节点则跳过;找出入度为 0 的节点作为入口点用Kahn 算法做拓扑排序有层时按层分组层的顺序由拓扑序中首次出现决定无层时按每 3 个节点一批切分concept 节点追加为最后一个 Key Concepts 步骤最后统一顺序编号实现上先以order: 0占位循环结束后steps[i].order i 1统一赋值。从源码结构看实际实现比计划草案做了两处性能优化且留有注释说明动机队列出队改用头指针head index代替queue.shift()因为shift()是 O(n) 的重新索引整个 BFS 会退化为 O(n²)未访问节点的补集判断也从逐个includes()改成Set成员检测tour-generator.ts。这类环路与孤立节点的兜底拓扑排序没覆盖到的节点直接追加保证了对含环、断连图的鲁棒性——测试中 handles graph with no edges gracefully 和 handles graph with no layers 两个用例正是为这两类退化输入而设。测试侧对启发式生成的断言包括首步必须包含入口节点index.ts无入边 → 入口点、拓扑顺序index routes service、concept 节点独立成步、order 连续编号、有层时步骤数不少于层数。这一组断言把生成出来的 tour 是否符合图拓扑语义变成了可回归验证的契约。落地与验证命令计划中 Task 1 采用 TDD 节奏核心命令为cd packages/core pnpm test -- --reporter verbose src/__tests__/tour-generator.test.ts cd packages/core pnpm build实际在插件目录下执行时对应understand-anything-plugin/packages/core。最后一步是把三个函数从index.ts导出——当前仓库的 core/index.ts 中已可看到tour-generator与language-lesson两个模块的导出块。Task 2LearnPanel 组件与 tour 状态dashboard 包计划基线是 dashboard 的 4 面板布局GraphView左上、CodeViewer右上、ChatPanel左下、NodeInfo右下。Task 2 在 Zustand store 中引入 tour 状态并把右下角面板改造为 NodeInfo / LearnPanel 的双 tab 视图。tour 状态与动作计划要求在DashboardStore接口中新增tourActive: boolean; currentTourStep: number; tourHighlightedNodeIds: string[]; startTour: () void; stopTour: () void; setTourStep: (step: number) void; nextTourStep: () void; prevTourStep: () void;动作实现有两个关键防御startTour在graph.tour为空时直接返回并重置selectedNodeId开始导览即取消手动选中避免两种高亮语义冲突setTourStep对越界索引做 clampstep 0 || step graph.tour.length时不动作。每个导航动作都同步把tourHighlightedNodeIds指向当前步骤的nodeIds——这个字段就是 Task 3 图高亮的唯一数据源。当前仓库的 store.ts 已确认包含tourActive、currentTourStep与persona状态初始值tourActive: false、currentTourStep: 0、persona: junior合理默认默认面向学习模式用户。可以推断实际实现在此基础上还扩展了按层排序的步骤遍历逻辑nextTourStep/prevTourStep会结合nodeIdToLayerId与activeLayerId计算相邻步骤属于 Phase 3 之后迭代的结果。LearnPanel 组件LearnPanel.tsx 有三个渲染状态无 tour 数据居中提示 No tour available for this project未开始tourActive false显示 Project Tour 标题、步骤数摘要N steps to understand this codebase、Start Tour 按钮以及全部步骤的编号预览列表导览进行中顶部进度头{current 1} / {total} Exit 按钮、动画进度条宽度 (step1)/total * 100%、正文区步骤标题 ReactMarkdown渲染的 description自定义p/strong/code/ul/ol组件样式、可选的 Language Concept 高亮卡indigo 底 边框对应step.languageLesson、Referenced Components 节点胶囊列表底部为步骤圆点导航当前步 blue-500、已过步 blue-800、未到达 gray-600加 Prev/Next 按钮首步禁 Prev、末步禁 Next。所有状态读取都通过细粒度 selectoruseDashboardStore((s) s.tourActive)等完成——计划文档特别注明App 层 tab 切换示例代码里用了getState()只是草图实现时必须改用响应式 selector否则 tab 不会随 store 变化重渲染。这一点是 zustand 使用者的常见陷阱getState()是命令式读取不建立订阅。Task 3Tour Player——图高亮与节点聚焦Tour 激活期间GraphView 必须在视觉上区分当前步骤引用的节点。做法分两处CustomNode 侧在CustomNodeData接口新增isTourHighlighted: boolean字段环ring样式优先级为——选中态白环 Tour 高亮蓝色脉冲环ring-blue-400 animate-pulse 搜索高亮按searchScore分档的黄环≤0.1 用 yellow-300、≤0.3 用 yellow-400、其余 yellow-500/60。这个搜索黄、Tour蓝的配色区分是刻意为之两种高亮可能同时存在导览中用户仍可能搜索蓝脉冲的动效让 Tour 焦点明显可辨。GraphView 侧const tourHighlightedNodeIds useDashboardStore((s) s.tourHighlightedNodeIds); // useMemo 依赖数组加入 tourHighlightedNodeIdsflowNodes 映射中加入 // isTourHighlighted: tourHighlightedNodeIds.includes(node.id),数据链路即storestartTour/setTourStep写入→ GraphView selector 订阅 → 节点 data 注入 → CustomNode 环样式全链路单向。Task 4单节点上下文解释Claude API用户点击任意节点的 Explain 按钮可获取一段由 Claude 生成的通俗解释覆盖节点做什么、为什么存在、如何嵌入整体架构、值得注意的模式。实现要点store 状态nodeExplanation: string | null、nodeExplanationLoading: boolean、nodeExplanationCache: Recordstring, string按节点 ID 缓存避免重复调用 API、explainNode: (nodeId) Promisevoid。explainNode动作的调用链先查缓存命中即返回 → 收集该节点的全部关联边以-/-标注方向如- [calls] routes.ts→ 查找节点所属 Layer → 拼接提示词Component/Type/File/Summary/Complexity/Tags/Layer/Connections 七段上下文 四问做什么与为何存在、架构定位、关键关系、值得理解的模式要求 2–4 段 markdown→ 调new Anthropic({ apiKey, dangerouslyAllowBrowser: true })的client.messages.create计划中指定模型claude-sonnet-4-20250514、max_tokens: 512→ 取response.content[0]的文本写入 state 并回填缓存异常分支把错误信息直接作为nodeExplanation展示Error: ...不让 UI 悬停在 loading 态。NodeInfo 侧 UI仅当apiKey存在时显示 Explain This 按钮loading 时显示 pulse 动画的 Generating explanation...结果用ReactMarkdown自定义p/strong/code样式渲染在灰色卡片中。另一个细节selectNode动作切换节点时清空nodeExplanation防止上一节点的解释残留在新节点信息卡上。Task 5语言课程 Prompt Buildercore 包这是 Learn Mode 的独特卖点读者在自己的项目里学 Go / Rust / TypeScript 概念。数据面依赖两个既有字段GraphNode.languageNotes与TourStep.languageLesson。Task 5 提供三个函数language-lesson.tsdetectLanguageConcepts(node, language)把node.tags 小写化 summary 小写化 languageNotes 拼成文本对照一张概念-关键词映射表做子串检测。基础模式表覆盖 12 类概念async/awaitasync, await, promise...、middleware patternmiddleware, interceptor, pipe、genericsgeneric, type parameter, template、decorators、dependency injectioninject, provider, container, di、observer pattern、singleton、type guardstype guard, narrowing, discriminated union、higher-order functionscallback, factory, closure、error handlingtry/catch, exception, Result type、streamsstream, pipe, transform, readable, writable、concurrencygoroutine, channel, thread, worker, mutex。从源码结构看实际实现比计划草案更进一步基础表被重命名为BASE_CONCEPT_PATTERNS新增buildConceptPatterns(langConfig)合并函数——可传入LanguageConfig把语言专属概念并入检测表未预定义关键词的概念以其名称小写形式自举为关键词匹配也统一做了toLowerCase()双向归一化。这与仓库后续语言配置注册表方向core 包 languages/ 下 40 余种语言配置演进一致。buildLanguageLessonPrompt(node, edges, language)以编程教师身份提示 LLM——假设读者不懂这门语言像第一次教一样解释概念但必须结合 THIS 段代码不许抽象讲解。提示词包含组件五元组Name/Type/File/Summary/Tags、关系上下文每条边以- / - [type] other表达、Detected concepts (explain these)列表或自行识别该语言模式的兜底指令并要求返回languageNotesconcepts[{name, explanation}]结构的 JSON。parseLanguageLessonResponse(response)与 tour 解析同款防御链路——代码围栏提取 → JSON.parse → 字段类型过滤 → 失败返回{ languageNotes: , concepts: [] }安全默认值。对应测试 language-lesson.test.ts 断言提示词包含节点名/summary/目标语言/关系类型并要求 JSON解析器处理合法响应、代码块包裹与非法输入detectLanguageConcepts能从 tags[auth,jwt,async] 检出 async/await、从 tags[middleware,express] 检出 middleware pattern。Task 6语言课程展示增强数据languageNotes/languageLesson在前序任务已就位Task 6 只改展示层NodeInfo原蓝底纯文本的languageNotes升级为可折叠 Language Concepts 区块——indigo 色小标题 右向箭头 SVG展开时rotate-90旋转动画useState(true)默认展开内容仍是bg-indigo-900/30底 indigo 边框圆角卡LearnPanel确认 Task 2 中 Language Concept 卡片样式indigo-900/30 底、indigo-300 小标题、indigo-200 正文符合增强标准无需改动。Task 7Persona Mode 系统Phase 3 体量最大的任务三种 Persona 改变布局、节点过滤与面板可见性。设计意图引自计划文档Persona布局目标用户说明non-technicalOverview2 列GraphView 右侧 LearnPanel/ChatPanel 竖排隐藏 CodeViewer图内只保留 concept / module / file 级节点PM、设计师、干系人高级架构视图juniorLearn完整 4 面板右下为 LearnPanel 而非 NodeInfo全节点 复杂度指示学习代码库的开发者默认 PersonaexperiencedDeep Dive完整 4 面板CodeViewer 与 ChatPanel 突出右下为 NodeInfo深度挖掘的资深开发者代码优先store 侧persona: non-technical | junior | experienced默认juniorsetPersona直接 set。当前 store.ts 已确认persona: Persona状态与setPersona动作实现上收敛为独立的Persona类型别名。PersonaSelector.tsxheader 中项目信息与搜索栏之间的分段按钮组三个选项带title描述High-level architecture view / Full dashboard with guided learning / Code-focused with chat选中态bg-blue-600 text-white。布局自适应App.tsx 核心逻辑{persona non-technical ? ( div classNameflex-1 grid grid-cols-2 gap-1 p-1 min-h-0 GraphView / div classNameflex flex-col gap-1 LearnPanel / {/* flex-1 */} ChatPanel / {/* flex-1 */} /div /div ) : ( div classNameflex-1 grid grid-cols-2 grid-rows-2 gap-1 p-1 min-h-0 GraphView /CodeViewer / ChatPanel / {persona junior || tourActive ? LearnPanel / : NodeInfo /} /div )}注意右下面板的判定是persona junior || tourActive——资深开发者一旦手动开启 Tour也会被切到 LearnPanelTour 的优先级高于 Persona 默认。GraphView 节点过滤persona non-technical时只保留concept / module / file类型节点跳过 function/class且边过滤为两端都在过滤后集合内的边——保证非技术视图里不出现悬空边。整体验证清单计划末尾的 Verification Checklist 是验收基准全部任务完成后应满足cd packages/core pnpm build pnpm test— 全部测试通过计划时点既有 92 新增约 20 条覆盖 tour-generator.test.ts 与 language-lesson.test.tscd packages/dashboard pnpm build— 无错误编译pnpm dev:dashboard— 用示例数据端到端走查Start Tour 按钮出现在右下、Prev/Next 可导航、图节点按步骤高亮、语言课程在步骤内展示Persona 选择器切换布局正确non-technical 为 2 列无 CodeViewer 且仅高级节点junior/Learn 为带 LearnPanel 的 4 面板experienced/Deep Dive 为带 NodeInfo 的 4 面板NodeInfo 上 Explain This 按钮可通过 Claude API 生成上下文解释Phase 1 Phase 2 既有功能搜索、聊天、分层、dagre 布局不回归。小结计划文档到落地代码的可对照点Phase 3 计划的价值不仅在于功能拆解更在于它给出了LLM 功能 确定性兜底的完整实现范式且与当前仓库代码可逐点对照提示词构建截断上下文50 条边 严格 JSON 契约 字段级说明见 tour-generator.ts响应解析围栏提取 → 形状兼容 → 字段过滤 → 空值降级两条解析器tour / lesson实现同一防御链路启发式兜底Kahn 拓扑排序 入口点检测 层分组 环/孤立节点补集保证无 LLM 时仍有可用 tourtour-generator.ts状态驱动 UItour 状态全部收敛在 zustand storeLearnPanel 与 GraphView 只经 selector 订阅图高亮、进度、tab 切换均由单一数据源驱动store.tsPersona 自适应布局、节点过滤、面板可见性三处随persona联动Tour 激活时对资深模式有覆盖优先级。适用前提提醒Task 4 的节点解释依赖浏览器端Anthropic客户端与apiKey无 key 时 UI 自动隐藏按钮模型与max_tokens以计划中的claude-sonnet-4-20250514/ 512 为基准实际部署可按模型可用性调整。【免费下载链接】Understand-AnythingGraphs that teach graphs that impress. Turn any code into an interactive knowledge graph you can explore, search, and ask questions about. Works with Claude Code, Codex, Cursor, Copilot, Gemini CLI, and more.项目地址: https://gitcode.com/GitHub_Trending/un/Understand-Anything创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
