From 685e3ffa8dd0c71189d6440a56e90878513668d9 Mon Sep 17 00:00:00 2001 From: oliver Date: Mon, 10 Aug 2026 22:17:45 +0800 Subject: [PATCH] Align ops UME playbook with MCP camelCase tools and freshness-first triage. Document 14 netx tools, snapshot time windows, severity Top-N, and compact topology path usage for alarm workflows. Co-authored-by: Cursor --- runtime/workspaces/ops/ROLE_SYSTEM.en.md | 9 +- runtime/workspaces/ops/ROLE_SYSTEM.md | 7 +- .../ops/ops-netx-ume-playbook/SKILL.md | 123 ++++++++-------- .../ops/ops-netx-ume-playbook/reference.md | 132 +++++++----------- 4 files changed, 114 insertions(+), 157 deletions(-) diff --git a/runtime/workspaces/ops/ROLE_SYSTEM.en.md b/runtime/workspaces/ops/ROLE_SYSTEM.en.md index 1ce70ff6..514055bb 100644 --- a/runtime/workspaces/ops/ROLE_SYSTEM.en.md +++ b/runtime/workspaces/ops/ROLE_SYSTEM.en.md @@ -26,7 +26,7 @@ You are the ops specialist (network operations expert). ## Alarm and network element display (mandatory) - **Use `host_name` as the primary key for every NE dimension** (first table column, Top-N keys, group-by, and how you refer to an NE in prose). After sync, netx stores it on the alarm row — prefer: - - List/paged alarms: **`host_name`** from `netx_query_ume_alarms` + - List/paged alarms: **`host_name`** from `mcp__netx__queryUmeAlarms` - Raw/SQL: **`alarm_host_name`** (over `ne_host_name` when both exist) - **Never** use `ne_id` / `alarm_ne_id` (UUID) as the user-facing primary key; `ne_id` is for filters and joins only. - If `host_name` is empty, fall back to `user_label` / `ne_name` with a "host_name missing" note — never bare `ne_id`. @@ -48,14 +48,15 @@ You are the ops specialist (network operations expert). ## netx detail and statistics -Each turn may append a **UME alarm runtime anchor** at the end of system context (latest `alarms_current` sync). Still call tools for alarm/NE evidence when answering. +Each turn may append a **UME alarm runtime anchor** at the end of system context (latest `alarms_current` sync). Still call tools for alarm/NE evidence when answering; also check diagnostics/aggregate `meta.last_seen_min/max` for snapshot freshness. - Default UME current alarms only (no Excel import `batch_id`). -- **MCP (12 tools, `server_id=netx`)**: +- **MCP (14 tools, `server_id=netx`)**: - UME alarms: `mcp__netx__queryUmeAlarms`, `mcp__netx__aggregateUmeAlarms`, `mcp__netx__runUmeDiagnostics` - UME NE inventory: `mcp__netx__queryUmeNeInventory`, `mcp__netx__getUmeNe` - UME deep query: `mcp__netx__queryUmeAlarmsRaw`, `mcp__netx__aggregateUmeAlarmsRaw`, `mcp__netx__listUmeAlarmFields`, `mcp__netx__sqlQueryUme` - - Managed NE CLI: `mcp__netx__listManagedNe`, `mcp__netx__getManagedNe`, `mcp__netx__execManagedNe` + - Topology triage: `mcp__netx__findTopologyPaths` (alarm `ne_id` → shortest paths) + - Managed NE CLI: `mcp__netx__listManagedNe`, `mcp__netx__getManagedNe`, `mcp__netx__execManagedNe`, `mcp__netx__listCliTargets` ## netx managed NE (device CLI) diff --git a/runtime/workspaces/ops/ROLE_SYSTEM.md b/runtime/workspaces/ops/ROLE_SYSTEM.md index 71339142..b2382e76 100644 --- a/runtime/workspaces/ops/ROLE_SYSTEM.md +++ b/runtime/workspaces/ops/ROLE_SYSTEM.md @@ -40,14 +40,15 @@ ## netx 明细与统计 -每轮对话 **system 末尾会自动附带当前 UME 告警运行锚点**(最近一次 `alarms_current` 同步状态),用于快速判断数据新鲜度。涉及告警/统计时仍应用工具拉明细。 +每轮对话 **system 末尾会自动附带当前 UME 告警运行锚点**(最近一次 `alarms_current` 同步状态),用于快速判断数据新鲜度。涉及告警/统计时仍应用工具拉明细;并核对 diagnostics/aggregate 的 `meta.last_seen_min/max`。 - 默认 UME 当前告警;不依赖 Excel 导入 `batch_id`。 -- **MCP(12 个工具,`server_id=netx`)**: +- **MCP(14 个工具,`server_id=netx`)**: - UME 告警:`mcp__netx__queryUmeAlarms`、`mcp__netx__aggregateUmeAlarms`、`mcp__netx__runUmeDiagnostics` - UME 网元:`mcp__netx__queryUmeNeInventory`、`mcp__netx__getUmeNe` - UME 深查:`mcp__netx__queryUmeAlarmsRaw`、`mcp__netx__aggregateUmeAlarmsRaw`、`mcp__netx__listUmeAlarmFields`、`mcp__netx__sqlQueryUme` - - 纳管网元 CLI:`mcp__netx__listManagedNe`、`mcp__netx__getManagedNe`、`mcp__netx__execManagedNe` + - 拓扑排障:`mcp__netx__findTopologyPaths`(告警 `ne_id` → 最短路径) + - 纳管网元 CLI:`mcp__netx__listManagedNe`、`mcp__netx__getManagedNe`、`mcp__netx__execManagedNe`、`mcp__netx__listCliTargets` ## netx 纳管网元(登录设备查 CLI) diff --git a/skills/_workspace/ops/ops-netx-ume-playbook/SKILL.md b/skills/_workspace/ops/ops-netx-ume-playbook/SKILL.md index fd0bb931..aef70a95 100644 --- a/skills/_workspace/ops/ops-netx-ume-playbook/SKILL.md +++ b/skills/_workspace/ops/ops-netx-ume-playbook/SKILL.md @@ -1,6 +1,6 @@ --- name: ops-netx-ume-playbook -description: 面向 ops 专家的 netx UME 运维作业手册。覆盖告警查询/聚合/诊断、网元清单与单网元详情、raw 字段过滤与 UME 只读 SQL。 +description: 面向 ops 专家的 netx UME 运维作业手册。覆盖告警查询/聚合/诊断、网元清单与单网元详情、raw 字段过滤、UME 只读 SQL、以及告警关联拓扑路径。 --- # Ops Netx UME 作业手册 @@ -9,88 +9,77 @@ description: 面向 ops 专家的 netx UME 运维作业手册。覆盖告警查 凡是涉及 netx/UME **告警**或 **网元信息** 的 ops 请求,必须优先加载并遵循本技能。 +## MCP 工具名(强制) + +使用 Cursor / oclaw MCP 时,工具名为 **camelCase**(`server_id=netx`): + +| 用途 | MCP 工具 | +|------|----------| +| 告警列表 | `queryUmeAlarms` | +| 告警聚合 | `aggregateUmeAlarms` | +| 诊断摘要 | `runUmeDiagnostics` | +| 网元清单 | `queryUmeNeInventory` | +| 网元详情 | `getUmeNe` | +| 字段清单 | `listUmeAlarmFields` | +| 原始明细 | `queryUmeAlarmsRaw` | +| 动态聚合 | `aggregateUmeAlarmsRaw` | +| SQL | `sqlQueryUme` | +| 拓扑路径 | `findTopologyPaths` | +| 纳管/CLI(另册) | `listManagedNe` / `getManagedNe` / `execManagedNe` / `listCliTargets` | + +旧名 `netx_query_ume_alarms` 等仅在 `OCLAW_NETX_BUILTIN_TOOLS=1` 时可用;**优先 MCP**。 + ## 工具选择顺序 -1. 基础视图(先看整体): - - `netx_query_ume_alarms` - - `netx_aggregate_ume_alarms` - - `netx_run_ume_diagnostics` -2. 字段感知深查(需要细节): - - `netx_list_ume_alarm_fields` - - `netx_query_ume_alarms_raw`(优先使用 `select_fields` 控制返回字段) -3. 自定义聚合(非 SQL): - - `netx_aggregate_ume_alarms_raw`(`group_by`,可选 `group_by2`) -4. 高级分析(SQL): - - `netx_sql_query_ume`(仅 SELECT、仅 UME 表;重查询建议设置 `statement_timeout_ms`) -5. **网元(inventory,与 netx「网元清单」同源)**: - - 列表/搜索:`netx_query_ume_ne_inventory`(`keyword` + 分页) - - 单条详情(含 `raw_json`):`netx_get_ume_ne`(`ne_id` = UUID) +1. **新鲜度(先做)**:`runUmeDiagnostics` 或 `aggregateUmeAlarms` → 看 `meta.last_seen_min` / `last_seen_max`。 + - 若最大值远早于「现在」,按 **快照数据** 处理:时间窗用数据范围内的日期,禁止套 `now()-30 minutes`。 +2. 基础视图:`aggregateUmeAlarms` + `runUmeDiagnostics`;样本用 `queryUmeAlarms`(默认 1 页)。 +3. 证据明细:`listUmeAlarmFields` → `queryUmeAlarmsRaw`(`field_preset=evidence` / `select_fields`)。 +4. 自定义聚合:`aggregateUmeAlarmsRaw`(`group_by=alarm_host_name` 等)。 +5. SQL:`sqlQueryUme`(仅 SELECT;设 `statement_timeout_ms`)。 +6. **告警关联拓扑**:两台相关网元取 `ne_id` → `findTopologyPaths`(最短路径优先)。 +7. **登设备查 CLI**:见 `ops-netx-managed-ne-playbook`(`listCliTargets` / `execManagedNe`)。 -## 快速决策树(强推荐) +## 快速决策树 -- **只需要整体态势 / Top 风险 / 快速简报**: - - 先 `netx_aggregate_ume_alarms` + `netx_run_ume_diagnostics` - - 必要时再用 `netx_query_ume_alarms` 看前 1 页做样本核对 -- **需要“可引用证据”的具体告警明细**: - - 先 `netx_list_ume_alarm_fields` - - 再 `netx_query_ume_alarms_raw`,并用 `select_fields` 只取必要字段 -- **需要按任意字段做统计(但不想写 SQL)**: - - `netx_aggregate_ume_alarms_raw`(`group_by` / `group_by2`) -- **需要复杂条件 / 自定义计算 / 多条件关联**: - - `netx_sql_query_ume`(必须过滤 + `statement_timeout_ms`) -- **查网元是谁、IP/标签、在线状态、或核对告警里的 ne_id**: - - 先 `netx_query_ume_ne_inventory`(`keyword` 可填名称、主机名、标签、IP 或 UUID 片段) - - 需要完整字段与 `raw_json` 时再 `netx_get_ume_ne` +- **整体态势 / Top 风险**:`runUmeDiagnostics` + `aggregateUmeAlarms`(默认已排除 missing host;看 `by_ne_missing`)。 + - 高危 Top-N:`aggregateUmeAlarms(severity=critical, top_ne=10)`,勿只看总量 Top。 +- **时间收敛**:`queryUmeAlarms` / `aggregateUmeAlarms` / raw 均支持 `time_from`/`time_to`(语义=`last_seen_at`)。先看 freshness,再填时间窗。 +- **可引用证据**:`queryUmeAlarmsRaw` + `field_preset=evidence`。 +- **任意字段统计**:`aggregateUmeAlarmsRaw`(按 host 分组时默认排除 missing;看 `by_ne_missing`)。 +- **复杂条件**:`sqlQueryUme`。 +- **critical 口类/光路类告警**:抽 1–2 个 `ne_id` → `findTopologyPaths`(默认 `detail=summary`,看 `paths[].label`)→ 再决定是否 CLI。 +- **查网元身份**:`queryUmeNeInventory(keyword=host_name)`;完整 `raw_json` 用 `getUmeNe`。 ## 约束与护栏 -- 优先使用非 SQL 工具;仅当工具参数无法表达需求时再用 SQL。 -- 默认过滤优先级(先收敛再扩展): - - 首选:`severity`(先把问题缩小到 critical/major 等) - - 其次:`keyword`(网元名/标签/IP/对象名/告警关键字) - - 再次:`time_from/time_to`(按 `last_seen_at` 限定时间窗) - - 最后:`event_type` 或 `ne_id`(当你明确知道要锁定事件类型/网元时) -- 禁止“为了凑全量而无脑翻页”: - - `netx_query_ume_alarms` 默认只看前 1 页(必要时最多 2 页) - - 如需更多数据,必须先明确过滤条件(`severity/ne_id/keyword/time_from/time_to/event_type` 等)或改用聚合/SQL -- 控制响应体积: - - 默认 `page_size=50`(除非明确需要更多,否则不要上来就拉满 500) - - 动态聚合默认 `limit=200` - - 合理设置 `page_size` - - raw 查询尽量传 `select_fields`;或使用 `field_preset=brief/evidence/ne_debug` - - 先加过滤条件,再增大分页范围 -- 时间窗过滤默认基于 `last_seen_at` 语义,除非需求明确要求其它口径。 -- 若数据新鲜度不明确,先查看 runtime 锚点状态,再下结论。 -- SQL 使用规则(`netx_sql_query_ume`): - - 建议总是设置 `statement_timeout_ms`(例如 3000~10000) - - 推荐默认从 `statement_timeout_ms=8000` 开始 - - 除非只是 `count(*)`,否则应包含过滤条件(至少时间窗或 `ne_id`/严重度过滤),避免全表扫描 +- 优先非 SQL;参数表达不了再用 SQL。 +- 过滤优先级:`severity` → `keyword`/`host_name` → `time_from/time_to` → `event_type`/`ne_id`。 +- 禁止无脑翻页:列表默认 ≤2 页;扩大前必须先过滤。 +- 体积:`page_size` 默认 50;聚合 `top_ne` 默认 50;raw 用 preset;动态聚合 `limit≤200`。 +- **Top 网元**:默认忽略 `(host_name missing)`;结论中说明 missing 数量,勿把 UUID/`unknown`/空串当网元名。 +- SQL:建议 `statement_timeout_ms=8000`;非 `count(*)` 应带过滤;时间窗相对 **数据新鲜度**,不是盲目 `now()`。 +- `WITH` CTE 可用;**禁止** `WITH RECURSIVE`。 ## 输出约定 -- 输出必须包含: - - 简明结论 - - 证据依据(工具输出) - - 可执行下一步 -- 没有工具证据时,不得臆测告警事实。 -- **用户用英文提问时(强制)**:回复中**不得出现任何汉字**;工具里的中文告警字段(原因、对象名、描述等)必须先**译成英文**再写入表格或正文,禁止原样粘贴;网元名用 `host_name`,协议类维度用英文类别名(Other/Clock/…)。 +- 结论 + 工具证据 + 可执行下一步。 +- 无工具证据不得臆测告警事实。 +- 英文提问:回复不得含汉字;工具中文字段须译成英文。 ### 网元展示:以 host_name 为主键(强制) -- **告警/统计里标识网元时,主键永远是 `host_name`**(主机名),不是 `ne_id`。表格第一列、Top 网元、分组键、结论里的网元名都用它。 -- **优先数据源**(同步时已写入告警表): - - `netx_query_ume_alarms` → 字段 **`host_name`** - - `netx_query_ume_alarms_raw` → **`alarm_host_name`**(`select_fields` / `brief` / `evidence` 预设已包含) - - 聚合 → `group_by=alarm_host_name` 或 `group_by=ne_host_name` -- **禁止**对用户展示裸 `ne_id` / `alarm_ne_id`;`ne_id` 仅作查询参数。 -- `host_name` 为空时:用 `user_label` / `ne_name` 并注明缺失;仍不得退回 UUID。 -- 仅当列表接口缺 `host_name` 时再 `netx_get_ume_ne` / 网元清单 / SQL JOIN 补全。 +- 表格首列、Top、分组键、结论中的网元名 = **`host_name`**。 +- 来源:`queryUmeAlarms.host_name` / raw `alarm_host_name` / 聚合 `alarm_host_name`。 +- **禁止**对用户展示裸 `ne_id`;`ne_id` 仅作过滤与 `findTopologyPaths` 入参。 +- host 缺失时用 `user_label`,并标注「host_name 缺失」;仍不得退回 UUID。 ## 推荐分析模式 -- 高风险网元:`netx_aggregate_ume_alarms_raw` + `group_by=alarm_host_name`(首选)或 `ne_host_name` + 严重度过滤;勿按 `alarm_ne_id` 分组对外展示。 -- 严重度分布:`group_by=alarm_perceived_severity`。 -- 事件趋势切片:raw 查询中组合 `time_from/time_to` + `event_type`。 +- 高风险网元:`aggregateUmeAlarmsRaw` + `group_by=alarm_host_name` + `severity`。 +- 严重度:`aggregateUmeAlarms` 或 `group_by=alarm_perceived_severity`。 +- 事件类型:看 diagnostics `top_event_types`;真正告警码看 `top_alarm_codes`(UME `alarmCode`)。 +- 关联路径:critical Port down / LOS → `findTopologyPaths(from_ume_ne_id, to_ume_ne_id)`。 ## 参考模板 diff --git a/skills/_workspace/ops/ops-netx-ume-playbook/reference.md b/skills/_workspace/ops/ops-netx-ume-playbook/reference.md index cc6fe016..c229cae9 100644 --- a/skills/_workspace/ops/ops-netx-ume-playbook/reference.md +++ b/skills/_workspace/ops/ops-netx-ume-playbook/reference.md @@ -1,101 +1,67 @@ # Ops Netx UME 快速参考 -## 1) 当前告警明细(轻量入口) +## 0) 数据新鲜度(必做) -- 工具:`netx_query_ume_alarms` -- 常用参数: - - `severity`, `ne_id`, `keyword`, `page`, `page_size` -- 建议: - - 推荐 `page_size=50` - - 默认只看前 1 页(必要时最多 2 页),不要无脑翻页拉全量 +- `runUmeDiagnostics` / `aggregateUmeAlarms` → `meta.last_seen_min` / `last_seen_max` +- 快照数据:时间窗落在 min~max 内;**不要**默认 `now()-30 minutes` -## 2) 原始明细(字段可控,推荐用于证据输出) +## 1) 当前告警明细(轻量) -- 工具:`netx_query_ume_alarms_raw` -- 推荐流程: - - 先调用 `netx_list_ume_alarm_fields` 获取字段清单 - - 再用 `select_fields` 控制返回字段,减少输出体积 -- 字段集预设(推荐优先用 preset,避免手写字段列表): - - `field_preset=brief`:轻量概览(严重度/事件/最近时间/网元显示) - - `field_preset=evidence`:证据输出(含 object/cause/时间/网元状态) - - `field_preset=ne_debug`:定位网元信息缺失或状态异常 -- `select_fields` 示例: - - `alarm_alarm_key` - - `alarm_perceived_severity` - - `alarm_last_seen_at` - - `alarm_host_name`(告警表已冗余的网元主机名,**对外展示主键,放首列**) - - `ne_host_name`(与上同义,优先 `alarm_host_name`) - - `ne_user_label` - - `ne_ip_address` -- **禁止**在用户可见输出中只列 `alarm_ne_id`;需要网元身份时必须带 `ne_host_name` 或先联查网元表。 +- 工具:`queryUmeAlarms` +- 参数:`severity`, `host_name`, `ne_id`(仅过滤), `keyword`, `time_from`, `time_to`, `page`, `page_size` +- 建议:`page_size=50`;默认最多 2 页 -## 3) 动态聚合(非 SQL) +## 2) 原始明细(证据) -- 工具:`netx_aggregate_ume_alarms_raw` -- 常用分组: - - `group_by=alarm_perceived_severity` - - `group_by=alarm_host_name` 或 `group_by=ne_host_name`(网元主键;勿用 `alarm_ne_id` / `ne_ne_id`) - - `group_by=alarm_event_type` - - `group_by=ne_connection_status` - - `group_by=alarm_perceived_severity, group_by2=ne_host_name` -- 建议: - - 推荐 `limit=200` +- 工具:`queryUmeAlarmsRaw` +- 先 `listUmeAlarmFields`(可选) +- `field_preset`:`brief` / `evidence` / `ne_debug` +- 展示主键:`alarm_host_name`(首列) -## 4) 诊断摘要 +## 3) 聚合 -- 工具:`netx_run_ume_diagnostics` -- 用途:在深挖前先快速形成“概览简报”(严重度、Top 网元、Top 事件类型等) +- `aggregateUmeAlarms`:`severity`(可选,如 critical)、`top_ne`(默认50)、`exclude_missing_host`(默认true)、`time_from`/`time_to` + - 高危 Top:`severity=critical`;看 `by_ne_missing`;Top 默认不含 missing +- `aggregateUmeAlarmsRaw`:`group_by=alarm_host_name` 等;按 host 分组时默认排除 missing(`by_ne_missing`) -## 4b) 网元清单与详情 +## 4) 诊断 -- 工具:`netx_query_ume_ne_inventory` — 对应 netx `GET /v1/ume/inventory/ne` - - 参数:`keyword`(可选,匹配 ne_id/ne_name/user_label/ip_address/**host_name**)、`page`、`page_size`(最大 500) -- 工具:`netx_get_ume_ne` — `GET /v1/ume/inventory/ne/{ne_id}` - - 参数:`ne_id`(UUID,与清单字段一致) -- 与告警 raw 中的 `ne_*` 字段互补:需要 UME 原始 JSON 时用 `netx_get_ume_ne` 的 `raw_json`。 +- `runUmeDiagnostics` +- `top_event_types`:事件类型 +- `top_alarm_codes`:UME `alarmCode`(有则) +- `top_ne`:已排除 missing host +- `meta.last_seen_*`:新鲜度 -## 5) SQL 深度分析(受限) +## 4b) 网元清单 -- 工具:`netx_sql_query_ume` -- 约束: - - 仅允许 SELECT - - 仅允许表:`ume_alarms_current` / `ume_inventory_ne` - - 重查询务必设置 `statement_timeout_ms` - - 除非只是 `count(*)`,否则建议带时间窗(例如 `last_seen_at >= now() - interval '30 minutes'`) -- 示例(全量聚合,谨慎使用): +- `queryUmeNeInventory(keyword=…)` +- `getUmeNe(ne_id=UUID)` — 仅内部关联 / raw_json + +## 4c) 拓扑路径(告警关联) + +- `findTopologyPaths` + - `from_ume_ne_id` + `to_ume_ne_id`(来自告警 `ne_id`) + - 或 managed 侧 `from_managed_ne_id` / `to_managed_ne_id` + - 默认 `detail=summary`:看 `paths[].label`(含端口)与精简 nodes/edges;需要 attrs 时再 `detail=full` +- 返回最短路径优先;0 条路径也要说明,再考虑 CLI + +## 5) SQL + +- `sqlQueryUme`;表:`ume_alarms_current` / `ume_inventory_ne` +- `statement_timeout_ms=8000` +- 时间窗相对 `meta.last_seen_max`,示例: ```sql -select - coalesce(nullif(trim(ne.host_name), ''), ne.user_label, ne.ne_name, '(host_name missing)') as ne_name, - count(*) as alarm_count +select coalesce(nullif(trim(a.host_name), ''), '(host_name missing)') as host_name, + count(*) as alarm_count from ume_alarms_current a -left join ume_inventory_ne ne on ne.ne_id = a.ne_id -group by coalesce(nullif(trim(ne.host_name), ''), ne.user_label, ne.ne_name, '(host_name missing)') -order by alarm_count desc -``` - -- 示例(推荐:带时间窗 + 超时): - - `statement_timeout_ms=8000` -```sql -select - coalesce(nullif(trim(ne.host_name), ''), ne.user_label, ne.ne_name, '(host_name missing)') as ne_name, - count(*) as alarm_count -from ume_alarms_current a -left join ume_inventory_ne ne on ne.ne_id = a.ne_id -where a.last_seen_at >= now() - interval '30 minutes' -group by coalesce(nullif(trim(ne.host_name), ''), ne.user_label, ne.ne_name, '(host_name missing)') -order by alarm_count desc -``` - -- 示例(推荐:带时间窗 + 严重度过滤,现场最常用): - - `statement_timeout_ms=8000` -```sql -select - coalesce(nullif(trim(ne.host_name), ''), ne.user_label, ne.ne_name, '(host_name missing)') as ne_name, - count(*) as alarm_count -from ume_alarms_current a -left join ume_inventory_ne ne on ne.ne_id = a.ne_id -where a.last_seen_at >= now() - interval '30 minutes' +where a.last_seen_at >= timestamp '2026-08-07 00:00:00' and lower(coalesce(a.perceived_severity, '')) in ('critical','major') -group by coalesce(nullif(trim(ne.host_name), ''), ne.user_label, ne.ne_name, '(host_name missing)') +group by 1 order by alarm_count desc +limit 50 ``` + +## 6) 登设备 + +- 见 `ops-netx-managed-ne-playbook` +- UME `ne_id` → `listCliTargets` / `execManagedNe(ume_ne_id=…)`(需已配 UME→CLI)