This commit is contained in:
2026-07-12 21:26:08 +08:00
commit 9dd41afd48
502 changed files with 129901 additions and 0 deletions
@@ -0,0 +1,360 @@
# 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 从全局主路径移除;它仍可作为小图异常兜底、社区阅读和详情能力保留并测试。