Files
llm-wiki/docs/spark/2026-06-19-sigma-global-graph-renderer-design.md
2026-07-12 21:26:08 +08:00

361 lines
20 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Sigma/Graphology Global Graph Renderer Design
日期:2026-06-19
状态:待用户复核
当前分支:`codex/pr52-sigma-global-renderer-design`
## 目的
这份设计确定 Sigma/Graphology 如何正式接入 llm-wiki 的全局图谱视角。
前一轮性能计划已经选择 Sigma/Graphology 作为未来全局大图渲染路线,但它只完成了路线选择和试验验证,没有切换生产图谱。当前任务不是继续做隐藏试验,也不是重新评估 Sigma、vis-network、聚合方案,而是把 Sigma/Graphology 作为首选正式全局路线接入的产品和工程边界定清楚,方便后续直接写实施计划。
这里的 Phase 0 是“正式接入前的最后开工门槛”,不是重新开启选型。如果 Phase 0 发现 Sigma 存在硬阻塞,本实施方向应停止并记录 blocker,再另开技术路线决策;不要在同一份落地计划里临时转向 vis-network。
本设计延续 2026-06-18 的大图体验结论:
**全局图谱负责看结构,社区聚焦负责读内容。**
## 设计结论
采用“全局统一 Sigma,社区继续阅读”的首选正式路线。
1. 所有全局视角统一使用 Sigma/Graphology,不按节点数量分成大小图两套全局渲染主路径。
2. 全局视角只承担地图级结构浏览:社区分布、节点点位、关键标签、搜索命中、Pin、选中和高亮。
3. 社区阅读、离线详情、内容阅读和富信息卡片继续使用现有 DOM/SVG 阅读路径,不在本次强行改成 Sigma。
4. Sigma/Graphology 是首选正式全局路线,不是隐藏开关或实验入口;Phase 0 只决定是否允许进入正式接入,不在本计划内改选其它渲染路线。
5. 旧 DOM/SVG 全局图不再作为用户可选的第二套主路径,只保留为小图异常兜底和社区/详情阅读能力。
6. 如果 WebGL 不可用、Sigma 初始化失败或画布异常,系统按规模进入明确兜底:小图退回现有 DOM/SVG,全局大图进入最低可用的聚合安全视图,并记录可排查原因。
一句话:
**全局统一成一张高性能地图;社区继续承担阅读和理解。**
## 为什么不选“大图才用 Sigma”
只让大图走 Sigma、小图继续走当前全局 DOM/SVG,短期改动较小,但长期会留下两套全局图。
同样是全局视角,搜索、高亮、Pin、选中、筛选、社区摘要、返回全局等行为就必须在两条渲染路径里持续对齐。后续任何体验调整都容易变成双份维护,也容易让小图和大图出现细节不一致。
本次不以 MVP 思维处理,因此选择长期边界更清楚的方案:只要是全局视角,就统一走 Sigma/Graphology。
## 为什么不把社区也改成 Sigma
社区阅读不是单纯画更多点。社区内需要完整节点在场、核心节点卡片、摘要、阅读抽屉、节点内容、上下文动作和更高信息密度。
Sigma/Graphology 适合承担全局地图的高性能绘制和视口交互;社区阅读更适合继续使用现有富交互 DOM/SVG 路径。把全局和社区一次性全改成 Sigma 会扩大风险,也会偏离已经确定的“全局看结构,社区读内容”。
## 用户体验边界
### 全局视角
全局视角是地图,不是阅读界面。
显示:
- 节点点位。
- 社区颜色和社区边界。
- 少量关键节点标签。
- 重要边或社区间骨架关系。
- 搜索命中。
- 当前选中对象。
- Pin 提示。
- 社区图例和筛选结果。
降级或不显示:
- 普通节点卡片。
- 大段正文。
- 全量标签。
- 全量弱边。
- 会导致大图卡顿的复杂阴影、动画和富组件。
### 社区阅读和详情
社区阅读继续承担内容理解。
进入社区后:
- 社区内节点完整在场。
- 核心、选中、搜索命中和 Pin 节点可以升级为更高信息密度。
- 继续使用现有阅读抽屉、节点详情和社区摘要能力。
- 社区阅读路径不被 Sigma 的内部状态接管。
## 责任边界
### 图谱引擎负责什么
`packages/graph-engine/` 继续作为图谱语义和产品规则的唯一来源。
它负责:
- 节点、边和社区身份。
- 搜索结果。
- 筛选状态。
- Pin 状态。
- 选择状态。
- 社区聚焦。
- 聚合标记。
- 全局摘要、节点摘要、社区摘要和不可见对象提示。
- 抽屉命令,例如进入社区、打开详情、显示对象、清除选择。
- 大图预算,例如标签、边、卡片和聚合容器显示规则。
### Sigma/Graphology 负责什么
Sigma/Graphology 只负责全局地图绘制和视口层交互。
它负责:
- 全局节点点位绘制。
- 全局边绘制。
- 社区颜色和必要的视觉分组表达。
- 搜索命中、选中、Pin 等状态的视觉表达。
- 拖动、缩放和画布命中。
- 把用户点到的渲染对象投射回图谱引擎能识别的对象。
它不负责:
- 决定搜索命中是谁。
- 决定抽屉显示什么。
- 决定进入哪个社区。
- 保存真实图谱状态。
- 成为新的业务数据源。
### 适配层
正式接入需要清晰的 Sigma 全局适配层,但这一层不从零搭建。`packages/graph-engine/src/render/adapter.ts` 已经有渲染器无关契约(`GraphRendererAdapterData` / `GraphRendererBehaviorContract`),Sigma 试验也已经消费过其中的语义状态,例如选择、搜索命中、Pin、社区和聚合行为。
不过,试验代码仍直接遍历原始 `data.nodes` / `data.edges` 生成 Sigma 点线,因此不能把“数据出向”视为生产就绪。生产 Sigma 必须画适配层输出的受控渲染数据,尤其要使用图谱引擎已经算好的预算、过滤、聚合、标签可见性和语义状态;不能在 Sigma 路径里重新决定画哪些节点、边和标签。
本次主要补两块:第一,把“数据出向”从试验可用推进到生产可用;第二,把 Sigma 的点击、悬停和视口事件转回图谱引擎命令(“命令入向”),以及渲染器生命周期和失败兜底。
适配层必须遵守:
- `GraphData` 不为了 Sigma 改形状。
- Graphology 只保存渲染用图结构,不保存另一份真实业务状态。
- 抽屉永远通过图谱引擎摘要结果渲染,不读取 Sigma 内部状态。
- 如果未来更换渲染库,搜索、Pin、社区、抽屉和选择规则不需要重写。
- 社区区域命中由图谱引擎或适配层根据节点位置、社区 hull / 聚合区域和空间索引计算;Sigma 只上报画布坐标或渲染对象 id,不自己决定“点到了哪个社区”。命中优先级保持为节点、聚合/社区区域、空白。
## 交互规则
### 点击节点
点击全局节点时:
- 全局视角不自动跳转。
- 选中该节点。
- 高亮该节点和少量直接相关节点。
- 右侧打开节点轻量摘要。
- 不自动进入社区。
- 不自动打开完整阅读内容。
用户在轻量摘要里选择“打开详情 / 阅读”后,进入所属社区并选中该节点。
### 点击社区
点击社区区域或社区图例时:
- 全局视角不自动跳转。
- 选中该社区。
- 高亮该社区和少量跨社区关系。
- 右侧打开社区摘要。
- 不自动进入社区。
用户点击“进入社区”后,才进入社区阅读路径。
### 搜索
搜索只改变当前视图的高亮、淡化、列表和摘要,不重排整张图。
搜索命中很多时:
- 命中节点保持可见提示。
- Pin 节点保持可见提示。
- 已选对象保持上下文。
- 普通弱边和普通标签可以降级。
### 筛选
筛选不自动清空当前选择。
如果当前选中对象被筛选排除:
- 右侧抽屉保留该对象。
- 明确提示它不在当前结果中。
- 提供清除选择或显示该对象的动作。
### Pin
Pin 是持久标记,不等于当前选中。
大图降级时,Pin 节点仍要尽量保留可见提示。Pin 可以影响重要性排序,但不能成为唯一排序规则。
### 缩放和拖动
缩放只改变信息密度,不自动切换到社区阅读。
拖动和缩放过程中可以临时降级:
- 隐藏普通标签。
- 隐藏弱边。
- 减少复杂视觉效果。
交互停止后补回当前预算允许显示的信息。核心锚点、搜索命中、Pin 和选中对象不能在交互中突然消失。
### 返回全局
从社区返回全局后:
- 正常情况下回到 Sigma 全局图。
- 如果当前环境已判定 Sigma 不可用,则回到对应规模的兜底全局视图,不能再次尝试进入一个已知失败的 Sigma 实例。
- 保留合理上下文,例如刚刚所在社区轻微高亮。
- 不把用户带到用户可选的另一套全局主路径;兜底只在异常状态下自动发生。
### 失败兜底
如果 Sigma 无法启动(WebGL 不可用、初始化失败、画布异常):
- 按规模分层兜底,而不是一律退回 DOM/SVG:小图退回现有 DOM/SVG 全局图;大图退回最低可用的聚合安全视图。因为 DOM/SVG 在 10000 节点本就约 8836ms、36.8 FPS、近乎拖不动,把大图退给它等于把用户丢进一张已知卡死的图。
- “小图 / 大图”的具体阈值由实施计划用历史基线和真实机器验证确定,初始建议用节点数、边数和社区规模共同判断,而不是只看节点数。
- 大图聚合安全视图只保证不空白、不卡死、能说明当前图谱结构和下一步动作;它不是完整替代图谱。它只显示社区容器、少量骨架边、选中 / 搜索 / Pin 标记,以及右侧抽屉中的溢出列表入口。
- 聚合安全视图下的可用动作限定为:查看社区摘要、查看搜索 / Pin / 选中对象列表、进入社区阅读、清除选择或重试 Sigma。节点级自由点选、完整边浏览、完整标签显示不在兜底目标内。
- 用户要看到轻提示,说明当前处于“图谱安全显示”而不是正常高性能全局图;提示不能打断使用。
- 用户既不看到空白死图,也不被丢进卡死的大图。
- 系统记录失败原因,供后续排查。
- 兜底不是用户主路径,不提供“新旧图谱切换”作为常规入口。这里的聚合降级只是兜底形态,不是第二套全局主产品。
## 性能和验收标准
正式接入不是“Sigma 能画出来”就算完成,而是全局图从小到大都统一、顺滑、可恢复、行为不变。
收益锚点要先说清楚:Sigma 的主要价值不是伺候极端的 10000 节点,而是让数百到数千节点的常见知识库从明显卡顿变丝滑。当前 DOM/SVG 在 1000 节点已要约 900ms、5000 节点约 4615ms 首屏,Sigma 试验把它们压到约 146ms / 175ms。因此验收中心是“真实规模显著变快 + 大图不崩溃”;10000 节点是压力上界,只用来保证不崩,不是产品叙事中心,也不值得为它过度设计(例如为 90000 条弱边堆复杂边预算,而真实库根本到不了那个量级)。
最低验收:
1. 所有全局视角统一走 Sigma/Graphology。
2. 社区阅读和详情继续使用现有阅读体验。
3. 点击节点、点击社区、搜索、筛选、Pin、进入社区、返回全局、不可见对象提示语义保持一致。
4. 1000 节点全局图接近无感。
5. 5000 节点全局图拖动、缩放、搜索和抽屉打开明显流畅。
6. 10000 节点全局图不能出现拖不动、缩放卡住、搜索迟迟不亮、抽屉慢开或画面大跳变。
7. 大图拖动和缩放目标稳定在 45 FPS 以上。
8. 10000 节点首次进入全局图时必须有明确加载状态,不能长时间空白。
9. Sigma 初始化失败、WebGL 不可用或画布异常时能自动兜底。
10. 现有图谱引擎测试、前端图谱行为测试和大图性能测试都必须通过。
## 必测图谱形状
后续实施计划必须跑完整 11 类图谱形状,而不是只复用早期 5 类试验结果。
必须覆盖:
1. 真实图谱快照代理。
2. 1000 节点稀疏图。
3. 1000 节点密集图。
4. 5000 节点稀疏图。
5. 5000 节点密集图。
6. 10000 节点聚合图。
7. 10000 节点高边图。
8. 超大社区。
9. 很多小社区。
10. 很多搜索命中。
11. 很多 Pin 节点。
每类至少验证:
- 首次渲染。
- 拖动。
- 缩放。
- 搜索高亮。
- 点选节点。
- 点选社区或聚合容器。
- 打开抽屉。
- 进入社区。
- 返回全局。
- 重复交互后的内存和稳定性。
## 实施前置门禁(Phase 0
写任何生产渲染代码之前,必须先过一道“允许开工”的性能门禁。当前选择 Sigma 的方向成立,但接入前的证据还不够硬:
- 现有 Sigma 试验数据(10000 节点约 289ms、60.9 FPS)是“历史隔离基线”,由第一版未硬化的试验脚本产出。决策文档自己也要求“锁定 Sigma 前必须重跑硬化试验”。
- 关键缺口:5000 / 10000 节点的重复交互内存测试此前是 not run,只有 1000 节点测过内存增长——大图反复交互是否泄漏,目前没有任何数据。
- 试验用的是极简 drawer 和简单视觉更新模型,不是 workbench 真实的抽屉 / 阅读器 / overlay 负载。
因此 Phase 0 分两层,不把所有发布回归都压到开工前。
开工门禁必须完成:
1. 先升级 harness 判定标准,确保它真的能按本文档验收,而不是继续用过低阈值或极简 drawer 得出虚假通过。
2. 重跑完整 11 类形状的核心动作:首次渲染、拖动、缩放、搜索高亮、点选节点、点选社区/聚合、打开抽屉。
3. 补齐大图(5000 / 10000)重复交互内存周期。
4. 补一个接近真实 drawer / overlay 负载的延迟测试。这里不要求先完成生产集成;可以用代表性负载模拟,但必须比早期极简 drawer 更接近 workbench。
发布回归必须完成:
1. 进入社区。
2. 返回全局。
3. 失败兜底。
4. 小图行为回归。
5. 完整 11 类形状的端到端循环。
开工门禁任一项不达标即停下记录 blocker。若 blocker 指向 Sigma 方案本身不可行,停止本实施方向,另开技术路线决策;不要在同一份落地计划里临时改接 vis-network。
开工门禁不通过,下面的生产接入动作不启动;发布回归不通过,不能宣布正式接入完成。
## 工程落点
后续实施计划应围绕以下落点展开(按依赖排序,第 1 条是真正的硬骨头):
1. 先解耦协调层对 DOM/SVG 的隐性依赖。此前的渲染器协调层拆分(已合入 main,对应 `graph-renderer-coordination-split` 计划)已把“决策”(`controller.ts`)和“画图”(`render-pipeline.ts`)分到不同文件,但 controller 仍有多处直接操作具体 DOM(如 `context.dom.nodeElements.get(id)?.focus()``.classList.add("is-dragging")`;见 `render-context.ts``nodeElements: Map<…, HTMLButtonElement>``edgeElements: Map<…, SVGPathElement>`)。这些假设“每节点是可单独 focus / 加 class 的 DOM、每边是 SVG path”,对 Sigma 的 WebGL 画布全不成立。必须先把已知 DOM 附着点限定在当前渲染层命令里(如 `setNodeFocused` / `setNodeDragging` / `setSearchState`),不要把它扩成泛化渲染框架。
2. 拆清 renderer root、pipeline、controls 的边界。当前生产入口会固定创建 DOM/SVG 根、节点按钮、SVG 边、搜索框、图例和小地图;只抽象 controller 还不够。实施计划需要明确哪些 UI 控件仍由 DOM 外壳承载,哪些图形内容交给 Sigma canvas,哪些能力保留在社区/详情 DOM/SVG 路径。
3. 复用已有的 `render/adapter.ts` 契约,但要把“数据出向”补成生产可用:Sigma 画适配层输出的受控渲染数据,不直接遍历原始全量 `GraphData` 自己决定预算。
4. 补“命令入向”:把 Sigma 的点击、悬停、视口事件转回图谱引擎命令,不在 Sigma 回调里重算语义。
5. 把现有试验用 Sigma 代码收敛成生产路径,而不是直接复制测试 harness。
6. 明确全局 Sigma 与社区 DOM/SVG 的路由点。当前 `createGraphFacade` 只创建一个 renderer`focusCommunity` 只是让同一个 renderer 重新聚焦;正式接入必须决定是双 renderer 切换、单 facade 内部切换,还是 renderer host 管理两种 view,并写清共享状态、销毁、回调、返回全局和兜底如何走。
7. 保持现有 workbench 的 `GraphPanel` 对外能力不大改:数据加载、Pin 持久化、选择回调、打开详情、可见状态通知继续通过当前边界通信。复杂度定位要摆正——真正动手术的是 `graph-engine/render` 和 facade 内部,不是 workbench/GraphPanel;后者只调 facade 高层 API,本就不碰渲染细节。
8. 把 Graphology 和 Sigma 从试验依赖提升为正式运行依赖时,要明确包边界和构建产物影响。
9. 给 WebGL/Sigma 初始化失败增加可测试兜底路径(分层方案见“失败兜底”)。
10. 加一个开发期内部开关(env / config 级,不暴露为用户功能)用于新旧渲染对比与快速回退。它默认不进入正式用户路径;如果未来要作为线上应急开关,必须另行写明触发条件、谁能开启、用户会看到什么、何时关闭。它和“不给用户新旧切换按钮”不矛盾,一个是开发/运维工具,一个是产品形态。
11. 把性能 harness 从“试验记录”升级为正式验收门禁(即 Phase 0 门禁)。
## 不在本次范围
本次不包含:
- 在本实施计划内重新评估或改接 vis-network。若 Phase 0 发现 Sigma 硬阻塞,应停止并另开技术路线决策。
- 做聚合方案作为第二套全局主产品(聚合仅作为大图失败兜底的降级形态,见“失败兜底”,不作为可选主产品)。
- 把社区阅读也改成 Sigma。
- 新增旧图/新图用户切换按钮(开发期内部对比开关不属此列,见“工程落点”第 10 条)。
- 新增 Agent 提问入口。
- 新增边点击关系详情。
- 移动端专项体验。
- 桌面壳专项实现。
- 完整键盘漫游。
- 类型、来源、时间等多套备用组织视角。
## 残余风险
1. Sigma 在生产环境和试验 harness 中的表现可能不同,因此实施前必须通过开工门禁,发布前必须完成完整 11 类形状回归。
2. WebGL 在不同电脑和未来桌面壳里的可用性不同,因此兜底路径必须是真实可测的。
3. 全局统一 Sigma 会触碰小图全局体验,因此小图行为回归也必须测,不能只测大图。
4. 如果适配层边界不够硬,后续容易把搜索、选择、抽屉逻辑写进 Sigma 回调,导致返工。
5. controller、renderer root、pipeline 和 controls 现仍有 DOM/SVG 假设,若不先收敛成清晰渲染边界就接 Sigma,会在回调里重造一套交互附着,造成双份维护——这是本次最大的隐性工作量。
6. 大图聚合安全视图必须严格保持兜底定位;一旦把它扩成完整可选图谱产品,就会重新引入第二套全局路线。
## 后续动作
用户复核通过后,再把这份设计转换成实施计划。
实施计划应按阶段推进:
1. 先过 Phase 0 开工门禁(升级 harness 判定标准、重跑核心动作、补大图内存周期、补代表性 drawer / overlay 负载);不达标即停,不进入生产接入。
2. 解耦 controller、renderer root、pipeline 和 controls 对 DOM/SVG 的隐性依赖,把已知交互附着收敛成渲染器边界命令。
3. 复用 adapter.ts,把 Sigma 数据出向补到生产可用,并补齐命令入向。
4. 明确全局 Sigma 与社区 DOM/SVG 的路由点、共享状态、销毁、回调、返回全局和兜底。
5. 落地生产级 Sigma 全局路径和分层兜底边界。
6. 补齐交互语义和抽屉联动。
7. 全程用 11 类形状持续回归,发布前完成完整端到端循环。
8. 最后把旧 DOM/SVG 从全局主路径移除;它仍可作为小图异常兜底、社区阅读和详情能力保留并测试。