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

20 KiB
Raw Permalink Blame History

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.tsnodeElements: 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 只创建一个 rendererfocusCommunity 只是让同一个 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 从全局主路径移除;它仍可作为小图异常兜底、社区阅读和详情能力保留并测试。