mirror of
https://github.com/hansjone/netx.git
synced 2026-10-09 20:30:45 +08:00
Ship gated eye polish, fabric levels, and collection UI refresh.
Topology MCP adds pull/compact/bundle/suggest-hubs with a no-template skill path; API gains fabric level and NE collection policy; web list pages get paging and denser collect/network workflows. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
b1aee86701
commit
b81e5869a6
91 changed files with 10395 additions and 1513 deletions
|
|
@ -1,33 +1,184 @@
|
|||
---
|
||||
name: netx-topology
|
||||
description: >-
|
||||
用 netx-topology MCP 查邻接、dual_unit 分批沉入、扫角压交叉(不污染 Fabric)。
|
||||
触发:画拓扑、布图、拖图、LLDP、Fabric、netx-topology。先读本 skill 再调工具。
|
||||
用 netx-topology MCP 查邻接、分类打标;先 dual_unit 一次抽最大核心眼,再换其它算法下沉/布图(不污染 Fabric)。
|
||||
触发:画拓扑、布图、拖图、分类、LLDP、Fabric、netx-topology。先读本 skill 再调工具。
|
||||
---
|
||||
|
||||
# netx 拓扑(通用)
|
||||
|
||||
只用 **`netx-topology`** MCP(包 `netx-topology-mcp`)。安装与 scopes:仓库 [`docs/MCP_TOPOLOGY.md`](../../../docs/MCP_TOPOLOGY.md)。
|
||||
|
||||
**原则**:复杂图先拆 **dual_units** 再拼;交叉少、边短、近轴优先。
|
||||
**原则**:
|
||||
1. **第一步用 dual_units**:从**核心**出发,选**覆盖网元最多**的那一只眼(`prefer_top_eye` + max cover)。
|
||||
2. **`sinkTopologyDualUnits` / `layout_dual_unit` 整图流程只用一次**——只沉这一只最大眼;**禁止**再连抽下一批 dual_unit。
|
||||
3. **后续下沉换算法**:`suggestSinkHubs` → `move_nodes(park)` / `projectTopologyNeighbors`;**不要**再 `sinkTopologyDualUnits`。
|
||||
4. **眼图已定型 → 门控精修**:对该 sink 只用下表「允许」动作;禁止全局拆眼工具。
|
||||
5. 布眼目标:少交叉、眼心空旷、少重叠(椭圆弧带;长链在眼外)。对照人工金标时还要看:**紧凑度、正交边、贴边清开**(见「算法天花板」)。
|
||||
|
||||
**禁止**写临时 py 穷举坐标或直接调 HTTP;验证与压交叉**只调 MCP**。不造 Fabric 边。
|
||||
**勿**把客户网元名、区域名、具体交叉数写进本 skill。
|
||||
**脱敏(硬)**:勿把客户网元名、站点/区域名、具体交叉数、具体 view_id 写进本 skill。角色只用通用词:门户 / 枢纽 / 汇聚 / 接入 / 末梢。**禁止**在 skill 正文写站点缩写或设备角色缩写当专名举例。
|
||||
|
||||
---
|
||||
|
||||
## 完整处理思路(一次大区接入眼)
|
||||
|
||||
按阶段执行;每阶段只调 MCP,读返回再决定下一步。
|
||||
|
||||
```
|
||||
① 认眼
|
||||
analyze(structure) → dual_units 里取覆盖最大的核心门户对
|
||||
② 一次 sink
|
||||
sinkTopologyDualUnits(max_units=1, prefer_top_eye, layout_batch)
|
||||
→ 同一 sink 贯穿全程;眼形不对只 layout_dual_unit 重布同一对门户
|
||||
③ 换算法下沉(禁 dual)
|
||||
循环:suggestSinkHubs(pick:1) → move_nodes(park) → until_limit(crossing)
|
||||
空批次后:orphan_batch / 对根−sink−门户 分批 park;仍禁 dual
|
||||
④ 眼定型精修(门控序列,见下)
|
||||
until_limit(crossing) → until_limit(total)
|
||||
→ clear_edge_hits(portal_ids) → pull_far_chains(portal_ids)
|
||||
→ compact_bbox(portal_ids, outlier_only) → 可选再 clear / total
|
||||
⑤ 停手(算法天花板,**默认无范本**)
|
||||
overlaps=0;until_limit stall;pull/compact/clear 均 moved≈0
|
||||
→ 交付:眼可读 + ov=0 + 交叉可接受;util/正交/贴边缺口 → 手拖或改初布
|
||||
→ 勿再发明无门控全局工具硬挤
|
||||
```
|
||||
|
||||
**范本现实(硬)**:
|
||||
- **日常默认没有范本**;有人工图也几乎不是同一张网 → **禁止**把 `align_reference` / 抄坐标当主路径。
|
||||
- `align_reference` **仅**用于:同网同成员画布的 A/B 对照、调试、回放(共享 `fabric_node_id`)。跨网 ID 对不上,抄了也无意义。
|
||||
- 生产要缩短与人工观感差距 → **改初布配方**(正交/紧凑从 dual 一次就偏地铁风),不是现场找金标对齐。
|
||||
|
||||
**从零重布(无范本算力路径)**:
|
||||
- 眼已在 sink、只需甩掉坏坐标 / 金标残留:对本 sink **`layout_dual_unit`(同一门户对)→ 立刻门控精修**。这**不算**再 sink 一批 dual。
|
||||
- 初布后交叉会先飙高、贴边变差属正常;**不要**因此改走 `polish_crossings` / `fix_overlaps`。
|
||||
- 纯算力压交叉后 util/bbox 常崩(枢纽被 `until_limit` 甩远)→ **必须**接 `pull_far_chains` → `compact_bbox`;缺这两个 action 就先重启 MCP,勿半截交付。
|
||||
- 无范本时:交叉可压到可读,但仍常高于「抄同网坐标」路径;util/正交缺口靠 pull + 初布,**不是**再堆 until_limit。
|
||||
|
||||
**开局核对 catalog(硬)**:
|
||||
- 精修前先 `layoutTopologyView(catalog=true)`:须见 `pull_far_chains`、`compact_bbox`,且 `version`/`rev` 为当前包。
|
||||
- 缺 action 或 `rev` 过旧 → **重启** netx-topology MCP 再干;禁止用旧进程硬跑、禁止改走 HTTP/临时 py。
|
||||
|
||||
**精修硬门控(已写进算法,skill 须遵守)**:
|
||||
- 任何落笔:**全局交叉不得升高**;升高 → 弃该候选。
|
||||
- **最小化展开**(bundle):从小压缩步长试探;步长须清开 footprint(成员互叠也算失败)。
|
||||
- **侵入** = 展开后踏入外人框 / 留下任意 footprint 重叠 → 换 tip,勿硬塞。
|
||||
- `until_limit` 只接受 `overlaps=0`;apply 遇 `overlaps_remain` → 修算法,**勿**对眼 sink 跑 `fix_overlaps`。
|
||||
- `portal_ids` **只钉眼门户**;`freeze_layers=["core"]` 会冻住 sink 上所有核心(含旁路枢纽)——慎用。
|
||||
- 旁路枢纽也要动时:`protect_rigid=off`(仍受 `portal_ids` 约束)。
|
||||
- `clear_edge_hits`:**禁止**放宽交叉(含 `preserve_axis`);交叉升高一律拒。
|
||||
- `pull_far_chains`:相对**门户中点**缩放远走廊/孤立点/远叶(不是朝外圈枢纽);枢纽本身在外围时朝枢纽缩**收不了 bbox**。
|
||||
- `compact_bbox`:默认 **farthest-K**(`outlier_only`);全图/分位均匀缩易叠点 → 拒。
|
||||
- `until_limit`:`stop_reason=max_moves` **≠** stall → **再调**直到 `stall`(可提高 `max_moves`,但仍以 stall 为准)。
|
||||
- 大眼 `max_jump` 用 4k–8k;勿收到 <2k。大图会 background → `job_status`(可数分钟);勿中途改走拆眼工具。
|
||||
|
||||
---
|
||||
|
||||
## 算法天花板(经验固化)
|
||||
|
||||
大区接入眼跑完门控序列后,常见结果:
|
||||
|
||||
| 维度 | 算法能做到 | 再挤会怎样 | 交付策略 |
|
||||
|------|------------|------------|----------|
|
||||
| 交叉 | 从零 dual 后 `until_limit` 可大幅压下;无范本时仍常高于抄坐标路径 | 再挪极值尖端易抬交叉;`max_moves` 停了要续跑到 stall | **停**于 stall;残余当弦交叉可接受 |
|
||||
| 重叠 | 硬零 | — | 必须保持 |
|
||||
| 紧凑 util / bbox | 压交叉常先**炸开** bbox;`pull_far_chains` 多轮收远走廊 | 缺 pull 就半截交付;强缩常 `Δg>0` 拒 | **必跑** pull→compact 到 `moved=0`;其余手拖 |
|
||||
| 贴边 clearance | `clear` + `objective=total` 能降一批 | 与交叉/紧凑拉扯,清到个位数很难 | stall 后手拖擦边点 |
|
||||
| 正交 axis | `total` 略抬;远低于人工地铁风 | `preserve_axis` 清边若放宽交叉会毁掉前面成果(已禁 slack) | 手拖走廊;勿为轴牺牲交叉 |
|
||||
| 直链 / 环穿 | bundle 后仍有折角与穿环 | 全局 straighten 拆眼 | 勿清零;结构优先 |
|
||||
|
||||
**判定「算法到头」**(门控精修,无范本):
|
||||
1. `overlaps=0`
|
||||
2. `until_limit`(crossing 与 total)均 stall
|
||||
3. pull/compact/clear `moved≈0`
|
||||
4. 目视:眼心空、双门户可辨
|
||||
|
||||
**可选对照**(仅评测):对**同网**人工画布与算法 sink 各 `analyze`,只比 `summary`;**勿**因此去 `align_reference` 当交付手段。
|
||||
|
||||
**明确无效 / 禁止再试**(眼 sink):
|
||||
- 再次 `sinkTopologyDualUnits` / `until_empty` / 新块画布抽 dual
|
||||
- `polish_crossings` / `straighten_channels` / `untangle` / `fix_overlaps` / `orbit_sweep(round=true)`
|
||||
- 临时 py 穷举坐标、无门控的整图缩放/平移极值点
|
||||
- 为追 util 关掉交叉门控或给 `clear` 开交叉 slack
|
||||
- **把跨网/他网人工图当范本抄坐标**(含滥用 `align_reference`)
|
||||
|
||||
---
|
||||
|
||||
## 主路径(必循)
|
||||
|
||||
```
|
||||
analyze(structure) → 认 dual_units / shape
|
||||
→ 核心层:手拖或小图 layout(compact|corridor|rings)
|
||||
→ sinkTopologyDualUnits(一批,layout_batch=true)
|
||||
或 move_nodes(park=true) 指定 ids
|
||||
→ orbit_sweep(round) → polish_crossings → clear_edge_hits
|
||||
→ 手拖微调 updateTopologyViewPositions
|
||||
→ 下一批 sink…(禁止 until_empty 日常连抽)
|
||||
analyze(structure) → 读 dual_units(认核心最大眼)
|
||||
→ 有 level:先打标;巨图勿先全量 level_bands
|
||||
→ 【仅一次】sinkTopologyDualUnits(
|
||||
max_units=1, prefer_top_eye=true, prefer_pure=false,
|
||||
sink_layers=[access], keep_layers=[core,agg], layout_batch=true,
|
||||
max_nodes/max_batch_nodes 放行大眼
|
||||
)
|
||||
→ 眼形不对:可对本 sink 重跑 layout_dual_unit(仍算同一只眼;勿再 sink 下一批 dual)
|
||||
→ 【换算法】suggestSinkHubs → move_nodes(park) 分批迁入同一 sink;每批后 until_limit;禁止再 dual
|
||||
→ 【眼定型】门控精修序列(下节);禁止全局拆眼
|
||||
→ 根图可 level_bands(只动根上残留,不动已定型的眼 sink)
|
||||
```
|
||||
|
||||
停手:`overlaps=0` 且 `verdict.total≈70`、cpl 中档、`edge_clearance.status≠fail`、`edge_axis.status≠fail` 方可交付。**勿只看 crossing**——orbit_sweep 的 `improving_n=0` 只代表交叉维度卡壳,须逐项检查 edge_clearance/edge_axis/rings,任一 fail 即继续处理。
|
||||
停手:最大眼可读、眼心空、`overlaps≈0`、门户清晰;其余节点用非 dual 手段靠上去即可。交叉允许来自跨走廊弦边。
|
||||
|
||||
**dual 一次用尽**:`until_empty`、再次 `sinkTopologyDualUnits`、为下一批 dual 新建块画布 —— **一律禁止**(日常)。
|
||||
|
||||
**布眼几何**(仅那一次):嵌套半椭圆;中轴只有双门户;长链/尾巴放眼外禁穿环。眼坏了重跑 `layout_dual_unit`,勿全局拆眼。
|
||||
|
||||
---
|
||||
|
||||
## 眼图定型后的精修(门控序列)
|
||||
|
||||
眼 sink 一经验收,**禁止**再对该画布跑会整图拆眼的工具。
|
||||
|
||||
| 允许 | 禁止(眼 sink 上) |
|
||||
|------|-------------------|
|
||||
| `analyze(detail=hotspots\|both)` 只读 | `polish_crossings` / `straighten_channels` |
|
||||
| `orbit_sweep`:**`until_limit=true`** 或 `node_id` preview→pick | `orbit_sweep(round=true)` 全图轮扫 |
|
||||
| `clear_edge_hits`(**须** `portal_ids`;交叉不升) | `fix_overlaps` / `untangle` 批处理整图 |
|
||||
| `pull_far_chains`(朝**门户中点**收远走廊/孤立点;同上门控) | `layout` / 再次 `sinkTopologyDualUnits` |
|
||||
| `compact_bbox`(farthest-K;交叉不升、ov=0) | 临时 py 穷举坐标 |
|
||||
| `updateTopologyViewPositions` 手拖 1~少数点 | `align_reference` 当无同网范本时的交付手段 |
|
||||
| 眼形整体崩了才 `layout_dual_unit` 重布同一门户对 | |
|
||||
|
||||
**推荐节奏**(一次序列,读返回再决定是否重复某一环):
|
||||
|
||||
```
|
||||
0) catalog=true 核对 pull_far_chains / compact_bbox(缺则重启 MCP)
|
||||
0b) 从零重布时:layout_dual_unit(同一门户对, apply) // 交叉飙高正常
|
||||
1) until_limit + objective=crossing + portal_ids + bundle
|
||||
→ stop_reason=max_moves 则续跑,直到 stall
|
||||
2) until_limit + objective=total // 交叉不升;抬贴边/正交;亦可 max_moves→续跑
|
||||
3) clear_edge_hits(portal_ids, top_n/max_moves 可加大;勿 preserve_axis 除非确认不抬交叉)
|
||||
4) pull_far_chains(portal_ids) // 可 2~3 轮直到 moved=0;压交叉后必做
|
||||
5) compact_bbox(portal_ids, outlier_only) // 常 accepted=false,正常
|
||||
6) 可选:再 clear 或 total;再 stall → 停手
|
||||
```
|
||||
|
||||
`until_limit` 调用模板:
|
||||
|
||||
```
|
||||
layoutTopologyView({
|
||||
action: "orbit_sweep", mode: "apply",
|
||||
params: {
|
||||
until_limit: true,
|
||||
objective: "crossing", // 再一轮改 total
|
||||
portal_ids: [<门户A>, <门户B>],
|
||||
protect_rigid: "off",
|
||||
max_degree: 14,
|
||||
max_jump: 8000, // 大眼用 4k–8k;勿 <2k
|
||||
max_stretch: 32,
|
||||
max_moves: 40, // 触顶只说明配额满,不是算法到头
|
||||
bundle: true
|
||||
}
|
||||
})
|
||||
→ 读 local.op:start/end_crossings、moves[]、stop_reason
|
||||
→ max_moves → 再调;stall → 进入下一步
|
||||
```
|
||||
|
||||
`round=true` ≠ `until_limit`:前者一批 top_n 死拿 pick#1;后者循环到 stall。
|
||||
勿为清零交叉拆弧带;以 `verdict.total` + 目视眼形 +「算法到头」四条为准。
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -35,13 +186,14 @@ analyze(structure) → 认 dual_units / shape
|
|||
|
||||
1. `getTopologyTree` → **`view_id`**(文件夹 physical 画布)。
|
||||
2. 建根/子区域只用 `createTopologyFolder`。
|
||||
3. `analyzeTopologyViewLayout({ view_id, detail: "structure" })` 读 `dual_units` / `shape`。
|
||||
4. `addTopologyViewNodes` / `projectTopologyNeighbors`(区域画布务必 `region_folder_id`)。
|
||||
5. 多余点用 `removeTopologyViewNodes` **移出画布**(不删 Fabric)。`region:…` 幽灵点勿当网元拖。
|
||||
3. 缺层级/区域时:`classifyTopologyFabricNodes`(`match` → `tag(level, dry_run)` → `tag`;或 `unmatched` / `apply_rules`)。**level** 越小越靠外(0 外部 / 1 核心 / 2 汇聚 / 3 接入;可用 1.1、2.1 子层)。**勿**切片建图。
|
||||
4. `analyzeTopologyViewLayout({ view_id, detail: "structure" })` 读 `dual_units` / `shape` / `layers` —— **先认核心最大眼**(`unit_count` / 各 unit `node_count`)。
|
||||
5. `addTopologyViewNodes`(可按 `role` 大档或后续 level)/ `projectTopologyNeighbors`(区域画布务必 `region_folder_id`)。
|
||||
6. 多余点用 `removeTopologyViewNodes` **移出画布**(不删 Fabric)。`region:…` 幽灵点勿当网元拖。
|
||||
|
||||
---
|
||||
|
||||
## 形状与 dual_units
|
||||
## 形状与 dual_units(只服务「第一只眼」)
|
||||
|
||||
```
|
||||
analyzeTopologyViewLayout({ view_id, detail: "structure" })
|
||||
|
|
@ -50,19 +202,85 @@ analyzeTopologyViewLayout({ view_id, detail: "structure" })
|
|||
| 字段 | 用途 |
|
||||
|------|------|
|
||||
| `shape.primary` | `chains` / `star` / `mesh` / `mixed_blocks` |
|
||||
| `dual_units` | 两端门户 + ≥2 条内部不交走廊;成员可重叠 |
|
||||
| `advice.block_plan` | 每块怎么拖 |
|
||||
| `dual_units` | **从核心出发**:core–core → core–agg → …,再取 **node_count 最大**的一只做唯一 sink |
|
||||
| `advice.block_plan` | 其余块怎么靠(非 dual 连抽) |
|
||||
| `gravity.type` | 链图勿当 hub 花瓣 |
|
||||
|
||||
- **链图**:脊柱水平 + stub;小图 preview `corridor`/`compact`(跳过 rings)。
|
||||
- **巨图 / 多门户**:勿全图一把揉;走 **sink 分批 dual_unit**。
|
||||
- **第一步必选最大核心眼**:`prefer_top_eye=true`,`prefer_pure=false`,`max_units=1`;目标是**一块吃进尽量多网元**,不要求交叉=0。
|
||||
- **禁止**把 dual_units 当成「抽干源图」的循环泵;剩余网元见下方「后续下沉」。
|
||||
- **禁止**再用互斥 soft_block 把通路切开。
|
||||
- **链图 / 小图**:可不走 dual;preview `corridor`/`compact`。
|
||||
|
||||
---
|
||||
|
||||
## 根图 → 子区域:第一次(dual,仅一次)
|
||||
|
||||
```
|
||||
sinkTopologyDualUnits({
|
||||
source_view_id: <根图>,
|
||||
sink_view_id: <子区域>, // 同一张接入画布贯穿全程
|
||||
max_units: 1,
|
||||
max_nodes: 300,
|
||||
max_batch_nodes: 400,
|
||||
layout_batch: true,
|
||||
sink_layers: ["access"],
|
||||
keep_layers: ["core", "agg"],
|
||||
prefer_top_eye: true,
|
||||
prefer_pure: false,
|
||||
// 勿 until_empty;勿随后再调本工具
|
||||
})
|
||||
→ 眼形验收 / 手拖;必要时 layout_dual_unit 重布同一眼
|
||||
```
|
||||
|
||||
- **同一 sink**:后续非 dual 迁入也进**同一个** `sink_view_id`;禁止块1/块2/块3。
|
||||
- **眼定型后**:对该 sink **只门控精修**(见上节)。
|
||||
|
||||
---
|
||||
|
||||
## 后续下沉(换算法,禁用 dual)
|
||||
|
||||
源图仍有接入 / 旁路网元时,**不要**再 `sinkTopologyDualUnits`。
|
||||
|
||||
0. **先问算法要批次**(推荐)
|
||||
```
|
||||
suggestSinkHubs({
|
||||
source_view_id: <根图>,
|
||||
sink_view_id: <眼 sink>,
|
||||
pick: 1,
|
||||
})
|
||||
→ batch.fabric_node_ids / move_nodes 可直接套用
|
||||
```
|
||||
排序:剩余领地大优先、agg 优于 core;眼门户不当 batch 头。
|
||||
|
||||
**每批迁完立刻** `until_limit(crossing, portal_ids)`,再取下一批;勿攒多批再一起 polish。
|
||||
|
||||
`suggestSinkHubs` 空了但根上还有孤立末梢/旁路:清掉已在 sink 的重复点,再对 `root−sink−眼门户` 分批 `move_nodes(park)`(每批后 `until_limit`)。也会直接吐 `orphan_batch_*`。勿再 dual。
|
||||
|
||||
1. **指定迁移 + 扫角停靠**
|
||||
```
|
||||
layoutTopologyView({
|
||||
action: "move_nodes",
|
||||
source_view_id: <FROM>, view_id: <TO>,
|
||||
mode: "apply",
|
||||
params: {
|
||||
fabric_node_ids: [...],
|
||||
park: true,
|
||||
remove_from_source: true,
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
2. **投影邻居**:`projectTopologyNeighbors`(区域画布带 `region_folder_id`),再手拖或 `orbit_sweep`。
|
||||
|
||||
3. **根图收尾**:`level_bands` 只钉**根图**上残留的 core/agg;**勿**对已定型眼 sink 跑全局带。
|
||||
|
||||
4. **小连通块**:源上剩余短链/星,可对**源图**或迁入后**单点**处理;勿对眼 sink `layout(recipe=…)`。
|
||||
|
||||
---
|
||||
|
||||
## 分层布局(特殊场景)
|
||||
|
||||
当网络需呈现层级结构(外部→接入→核心→汇聚→客户等)时,优化策略不同于通用 mesh:
|
||||
当网络需呈现层级结构(外部→接入→核心→汇聚→客户等)时:
|
||||
|
||||
### 分层通用规则
|
||||
1. **顶层:外部/对接网络**
|
||||
|
|
@ -73,54 +291,16 @@ analyzeTopologyViewLayout({ view_id, detail: "structure" })
|
|||
|
||||
### 优化流程
|
||||
1. **先手动后算法**:用户手动拖拽保证业务结构,再用算法优化
|
||||
2. **分层约束**:用 `updateTopologyViewPositions` 按层级设定 y 坐标(同层 y 落在区间内可错落,勿跨层);`orbit_sweep` 传 `y_min/y_max` 约束搜索在本层区间内
|
||||
3. **分步迭代**:
|
||||
- `polish_crossings` 减少交叉(可能破坏分层)
|
||||
- 若分层被破坏,**保留 x 坐标,恢复 y 坐标**重新分层
|
||||
- `clear_edge_hits` 消除贴边
|
||||
- `fix_overlaps` 修复重叠
|
||||
2. **分层约束**:`updateTopologyViewPositions` 按层钉 y;`orbit_sweep` 可传 `y_min/y_max`
|
||||
3. **分步(非眼画布 / 根图)**:可贴边、分层钉 y;**已定型眼 sink 除外**——只允许门控精修 / 手拖
|
||||
|
||||
### 冲突处理原则
|
||||
### 冲突处理
|
||||
| 冲突场景 | 处理方式 |
|
||||
|---------|---------|
|
||||
| 交叉 vs 结构 | **结构优先**,接受少量跨层交叉 |
|
||||
| 算法 vs 手动 | **手动优先**,算法辅助 |
|
||||
| polish 破坏分层 | 保留 x 坐标,恢复 y 坐标分层 |
|
||||
|
||||
### 关键经验
|
||||
1. **跨层交叉是结构性的**:跨层连线必然穿越中间层,属正常
|
||||
2. **外层节点必须在外部层**:与 PS/PE 连接的外部网元(RNC、华为设备等)应放在最上方
|
||||
3. **orbit_sweep 卡壳更早**:分层约束下 `improving_n=0` 来得快;改传 `objective=total` 让 orbit_sweep 按 crossing+edge_clearance 综合排序
|
||||
4. **验收以层级清晰为先**:`verdict.total` 次于结构可读性;同层 y 在区间内、层间不串层即可交付
|
||||
|
||||
---
|
||||
|
||||
## 根图 → 子区域排水
|
||||
|
||||
```
|
||||
sinkTopologyDualUnits({
|
||||
source_view_id: <根图>,
|
||||
sink_view_id: <子区域>,
|
||||
max_units: 3,
|
||||
max_batch_nodes: 120,
|
||||
layout_batch: true, // 每单元 layout_dual_unit → 块扫挂 sink
|
||||
})
|
||||
→ orbit_sweep / polish_crossings / clear_edge_hits
|
||||
→ 再调下一批(source_remaining>0)
|
||||
```
|
||||
|
||||
- **一次只沉一批**;勿日常 `until_empty`。
|
||||
- 落点:**块扫**(交叉/重叠/桥长择优),禁止固定往右排。
|
||||
- 指定迁移:
|
||||
```
|
||||
layoutTopologyView({
|
||||
action: "move_nodes",
|
||||
source_view_id: <FROM>, view_id: <TO>,
|
||||
mode: "apply",
|
||||
params: { fabric_node_ids: [...], park: true, remove_from_source: true },
|
||||
})
|
||||
```
|
||||
`park=true` = 扫角停靠;回迁对调两 view_id。
|
||||
| 交叉 vs 结构 | **结构优先**(最大眼 / 分层) |
|
||||
| 算法 vs 手动 | **手动优先** |
|
||||
| polish 拆眼 | **禁止**对 dual 眼走 straighten 主路径 |
|
||||
| 算法 vs 金标观感 | 交叉可赢;紧凑/正交/贴边交给手拖 |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -128,27 +308,20 @@ sinkTopologyDualUnits({
|
|||
|
||||
| action | 用途 |
|
||||
|--------|------|
|
||||
| `layout` | 小图配方:`compact` / `corridor` / `rings` / `unstick` |
|
||||
| `layout_dual_unit` | 双门户眼形;单元内交叉≠0 拒绝 |
|
||||
| `move_nodes` / `sink_nodes` | 指定 ids 双向迁移;`park` 块扫 |
|
||||
| `orbit_sweep` | 压交叉;`round` + 大 `max_jump`(约 1800–2800);`objective=total` 综合 crossing+edge_clearance;`y_min/y_max` 分层约束 |
|
||||
| `polish_crossings` | 一键:straighten→press→untangle |
|
||||
| `clear_edge_hits` | 网元贴非关联边时正交弹开 |
|
||||
| `fix_overlaps` / `resolve_overlaps` | 只拉开重叠 |
|
||||
| `untangle` | 贪心降交叉;默认可冻门户 |
|
||||
| `straighten_channels` | 拉直 deg≤2 走廊 |
|
||||
| `layout` | 小图 / 剩余块:`compact` / `corridor` / `rings` / `unstick` |
|
||||
| `layout_dual_unit` | **仅**重布已沉的那一只眼;椭圆弧带 + 空心眼 |
|
||||
| `move_nodes` / `sink_nodes` | **后续下沉主路径**;`park` 块扫 |
|
||||
| `orbit_sweep` | **眼后精修主工具**:`until_limit` 或 `node_id`;`objective=crossing\|total` |
|
||||
| `clear_edge_hits` | 眼 sink **可**(须 `portal_ids`;交叉不升) |
|
||||
| `pull_far_chains` | 眼 sink **可**:朝门户中点收远走廊/孤立点 |
|
||||
| `align_reference` | **非主路径**:仅同网同成员 A/B 调试;跨网禁用 |
|
||||
| `compact_bbox` | 眼 sink **可**:farthest-K 收 bbox |
|
||||
| `level_bands` | 仅根图/未定型画布;巨图在 dual 一次之后钉根 |
|
||||
| `polish_crossings` | **眼 sink 禁用** |
|
||||
| `fix_overlaps` / `untangle` / `straighten_channels` | **眼 sink 禁用** |
|
||||
| `job_status` / `job_cancel` | 后台 job |
|
||||
|
||||
阶段2是多目标循环,非单向链:
|
||||
|
||||
1. `orbit_sweep` 压交叉 → `polish_crossings`
|
||||
2. **orbit_sweep `improving_n=0` 时勿停**——立即转看 `edge_clearance`(贴边对视觉可读性影响 ≥ 交叉)→ `clear_edge_hits` 正交弹开
|
||||
3. 再看 `edge_axis`(斜边过多)→ `straighten_channels` / 手拖归轴
|
||||
4. 回头复检 crossing 是否因上步变动出现新机会 → 再 `orbit_sweep`
|
||||
|
||||
`orbit_round` 只在全局交叉严格下降时落笔;卡顿加大 `max_jump` / 单点 preview→pick。
|
||||
|
||||
**关键**:单节点 `updateTopologyViewPositions` 拖动时,某节点移动可能增交叉但解多个贴边——以 `verdict.total` 升降为准,勿只盯 crossing 数。`drag_candidates` 可能为空,此时看 `edge_clearance.top` / `crossing.top_nodes` 自行判断拖谁。
|
||||
眼 sink 精修 = 门控序列 + 手拖补观感;不要排全局流水线,也不要在 stall 后继续发明新全局动作。
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -156,20 +329,16 @@ sinkTopologyDualUnits({
|
|||
|
||||
| 块 | 看什么 |
|
||||
|----|--------|
|
||||
| `overlap` | 硬零(权重 0.24,硬门控) |
|
||||
| `crossing` | crossings/cpl;`top_nodes` / `top_edges`(权重 0.18) |
|
||||
| `rings` | 最小环被穿(权重 0.10) |
|
||||
| `edge_clearance` | 贴边 → clear_edge_hits;**权重 0.08 但视觉影响 ≥ crossing,优先处理** |
|
||||
| `edge_axis` | 斜边过多 → straighten_channels / 手拖归轴(权重 0.06) |
|
||||
| `verdict.total` | ≈70 可交付(ov=0);**总分升降为准,勿只盯 crossing** |
|
||||
| `overlap` | 硬零(权重 0.24) |
|
||||
| `crossing` | crossings/cpl;`top_nodes` / `top_edges` |
|
||||
| `sparsity` / `edge_axis` / `edge_clearance` | 对照人工:紧凑、正交、贴边(算法常弱于此) |
|
||||
| `rings` / `chains` | 环被穿、走廊折角 |
|
||||
| `verdict.total` | ≈70 可交付(ov=0);结构可读优先于刷分 |
|
||||
| `score_profile` | `auto`(默认)/ `default` / `eye`;大稀疏斜边画布自动走 eye |
|
||||
|
||||
### 评分优化快速方法
|
||||
1. **消除 overlap** → 硬门控项,必须为 0
|
||||
2. **减少 crossings** → polish_crossings 大幅降低
|
||||
3. **处理 edge_clearance** → clear_edge_hits 消除贴边
|
||||
4. **结构检查** → 分层清晰 > 交叉最少
|
||||
**评分修订(相对旧权)**:util 甜区下限 0.08;贴边分=节点命中∪hits/link;rings 降权;eye 再降 axis、抬 util/clearance;`compactness` 仅诊断不加权。
|
||||
|
||||
图标 25px;推荐中心距 Δx≥200、Δy≥170。交叉 = 无向 NE↔NE 真交叉(共端点不算)。
|
||||
图标 25px;推荐中心距 Δx≥200、Δy≥170。
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -178,59 +347,25 @@ sinkTopologyDualUnits({
|
|||
| 工具 | 作用 |
|
||||
|------|------|
|
||||
| `getTopologyTree` / `getTopologyView` | 树与画布 |
|
||||
| `createTopologyFolder` | 新建根/区域(返回 view_id) |
|
||||
| `createTopologyFolder` | 新建根/区域 |
|
||||
| `add` / `remove` / `updateTopologyViewPositions` | 成员与手拖 |
|
||||
| `sinkTopologyDualUnits` | dual_units 分批沉入 |
|
||||
| `copyTopologyViewNodes` | 克隆沙箱 |
|
||||
| `sinkTopologyDualUnits` | **仅一次**:最大核心眼 → sink |
|
||||
| `suggestSinkHubs` | **后续下沉批次**(含 orphan_batch) |
|
||||
| `move_nodes`(经 layoutTopologyView) | **后续下沉** |
|
||||
| `projectTopologyNeighbors` | 投影邻居 |
|
||||
| `queryTopologyFabricNodes` | 库存(summary\|list\|search) |
|
||||
| `copyTopologyViewNodes` | 克隆沙箱 |
|
||||
| `queryTopologyFabricNodes` | 库存 |
|
||||
| neighborhood / edges | 邻接 |
|
||||
| `layoutTopologyView` | 上表 action |
|
||||
| `analyzeTopologyViewLayout` | structure + 验收 |
|
||||
|
||||
---
|
||||
|
||||
## 通用优化策略(实战经验)
|
||||
|
||||
### 算法与手动的最佳组合
|
||||
```
|
||||
Step 1: 用户手动拖拽 → 保证业务结构和分层
|
||||
Step 2: polish_crossings → 大幅减少交叉(接受可能破坏分层)
|
||||
Step 3: 检查分层 → 若被破坏,保留 x 恢复 y 重新分层
|
||||
Step 4: clear_edge_hits → 处理贴边问题
|
||||
Step 5: fix_overlaps → 修复节点重叠
|
||||
Step 6: 最终验收 → 结构清晰 > 交叉最少
|
||||
```
|
||||
|
||||
### 工具使用优先级
|
||||
| 场景 | 首选工具 | 参数建议 |
|
||||
|-----|---------|---------|
|
||||
| 整体减交叉 | `polish_crossings` | `top_n=10, max_moves=50` |
|
||||
| 单点微调 | `orbit_sweep` | `objective=total, y_min/y_max` |
|
||||
| 处理贴边 | `clear_edge_hits` | `top_n=15, max_moves=30` |
|
||||
| 修复重叠 | `fix_overlaps` | 直接调用 |
|
||||
| 批量调坐标 | `updateTopologyViewPositions` | 保留 x,恢复 y |
|
||||
|
||||
### 常见问题解决方案
|
||||
| 问题 | 原因 | 解决方案 |
|
||||
|-----|------|---------|
|
||||
| polish 破坏分层 | 算法优先减少交叉 | 保留 x 坐标,恢复 y 分层 |
|
||||
| orbit_sweep 无改善 | 位置已优化 | 接受现状或手动调整 |
|
||||
| 节点重叠 | 坐标调整太近 | fix_overlaps 自动修复 |
|
||||
| 交叉突然增加 | clear_edge_hits 移动节点 | 重新 polish_crossings |
|
||||
|
||||
### 关键原则
|
||||
1. **业务结构优先于算法优化**:网络拓扑的分层结构比最少交叉更重要
|
||||
2. **局部微调优于全局重置**:用 `orbit_sweep`/`updateTopologyViewPositions` 单点调整,而非 `layout` 全局布局
|
||||
3. **预览模式优先于应用模式**:先用 `mode=preview` 查看效果,确认后再 `mode=apply`
|
||||
4. **分步迭代优于一次性操作**:polish → clear_edge_hits → fix_overlaps 分步骤执行
|
||||
|
||||
---
|
||||
|
||||
## 代码热更
|
||||
|
||||
1. 本仓 MCP 用 `PYTHONPATH=…/src`,改源码后不必为加载而 pip install。
|
||||
2. **必须重启** stdio 进程;`catalog` 含 `rev`(当前 `NETX_MCP_REV`)。
|
||||
3. `layoutTopologyView(catalog=true)` 核对 action/recipe 清单。
|
||||
1. 本仓 MCP 用 `PYTHONPATH=…/src`(见用户 `~/.cursor/mcp.json`),改源码后不必为加载而 pip install。
|
||||
2. **必须重启** stdio 进程(杀旧 `python -m netx_topology_mcp` 后由 Cursor 拉起;或 MCP 面板禁用/启用)。
|
||||
3. `layoutTopologyView(catalog=true)` 核对:`version` / `rev`(`NETX_MCP_REV`)+ action 含 `pull_far_chains` / `compact_bbox`。
|
||||
4. 机器上常残留多份旧 MCP 进程 → 精修前 catalog 若仍缺 action,**杀光再启**;勿用旧进程半截交付,勿改走 HTTP/临时 py。
|
||||
|
||||
拓扑页开「实时同步」可看落笔。勿用告警/CLI MCP 写拓扑。
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue