From 528486cabd8f2af7de402bb27717405d5bffbded Mon Sep 17 00:00:00 2001 From: ssongliu Date: Mon, 9 Nov 2026 18:20:37 +0800 Subject: [PATCH] fix(ai): unify GPU detection and improve group topology (#14367) --- agent/app/service/vllm_upgrade.go | 5 + agent/utils/ai_tools/vllm/version.go | 5 + .../src/components/layout-content/index.vue | 10 +- frontend/src/lang/modules/en.ts | 28 +- frontend/src/lang/modules/es-es.ts | 28 +- frontend/src/lang/modules/fa.ts | 26 +- frontend/src/lang/modules/ja.ts | 28 +- frontend/src/lang/modules/ko.ts | 28 +- frontend/src/lang/modules/lo.ts | 27 +- frontend/src/lang/modules/ms.ts | 29 +- frontend/src/lang/modules/pt-br.ts | 29 +- frontend/src/lang/modules/ru.ts | 27 +- frontend/src/lang/modules/tr.ts | 28 +- frontend/src/lang/modules/zh-Hant.ts | 23 +- frontend/src/lang/modules/zh.ts | 23 +- frontend/src/routers/modules/ai.ts | 2 +- .../views/ai/components/gpu-config/index.vue | 117 +++- .../ai/components/gpu-topology/index.vue | 45 +- frontend/src/views/ai/gpu/current/index.vue | 82 +-- frontend/src/views/ai/gpu/environment.ts | 18 + frontend/src/views/ai/gpu/groups/index.vue | 358 +++------- frontend/src/views/ai/gpu/groups/topology.vue | 625 ++++++++++++++++++ frontend/src/views/ai/gpu/history/index.vue | 19 +- frontend/src/views/ai/gpu/index.vue | 6 +- 24 files changed, 1204 insertions(+), 412 deletions(-) create mode 100644 frontend/src/views/ai/gpu/environment.ts create mode 100644 frontend/src/views/ai/gpu/groups/topology.vue diff --git a/agent/app/service/vllm_upgrade.go b/agent/app/service/vllm_upgrade.go index 0acc16a99..18a44c380 100644 --- a/agent/app/service/vllm_upgrade.go +++ b/agent/app/service/vllm_upgrade.go @@ -86,6 +86,11 @@ func buildDefaultVllmImageByVersion(version string) string { } func isVllmUpgradeVersionAllowed(currentVersion, targetVersion, currentImage string) bool { + currentRTX := vllm.IsRTXVersion(currentVersion) + targetRTX := vllm.IsRTXVersion(targetVersion) + if currentRTX != targetRTX { + return false + } currentGB10 := vllm.IsGB10Version(currentVersion) targetGB10 := vllm.IsGB10Version(targetVersion) if currentGB10 != targetGB10 { diff --git a/agent/utils/ai_tools/vllm/version.go b/agent/utils/ai_tools/vllm/version.go index 12b1967ee..630ba7568 100644 --- a/agent/utils/ai_tools/vllm/version.go +++ b/agent/utils/ai_tools/vllm/version.go @@ -5,8 +5,13 @@ import "strings" const ( gb10VersionPrefix = "nvidia-" gb10VersionSuffix = "-optimized-for-ds-v4-flash" + rtxVersionSuffix = "-optimized-for-ds-v4.1-flash" ) +func IsRTXVersion(version string) bool { + return strings.HasSuffix(strings.ToLower(strings.TrimSpace(version)), rtxVersionSuffix) +} + func IsGB10Version(version string) bool { normalized := strings.ToLower(strings.TrimSpace(version)) tag := strings.TrimPrefix(normalized, gb10VersionPrefix) diff --git a/frontend/src/components/layout-content/index.vue b/frontend/src/components/layout-content/index.vue index 42d7129c2..fab6f95e9 100644 --- a/frontend/src/components/layout-content/index.vue +++ b/frontend/src/components/layout-content/index.vue @@ -19,7 +19,7 @@
-
+
-
+
@@ -87,12 +87,12 @@ const showBack = computed(() => { const { backPath, backName, backTo, reload } = prop; return backPath || backName || backTo || reload; }); -const hasTitleContent = computed(() => { +const hasTitleContent = () => { return Boolean( slots.title || slots.leftToolBar || slots.rightToolBar || slots.toolbar || prop.divider || showBack.value, ); -}); -const hasMainTopGap = computed(() => hasTitleContent.value || Boolean(slots.prompt)); +}; +const hasMainTopGap = () => hasTitleContent() || Boolean(slots.prompt); diff --git a/frontend/src/views/ai/components/gpu-topology/index.vue b/frontend/src/views/ai/components/gpu-topology/index.vue index b71ea429f..c19fa89e2 100644 --- a/frontend/src/views/ai/components/gpu-topology/index.vue +++ b/frontend/src/views/ai/components/gpu-topology/index.vue @@ -4,9 +4,9 @@ v-for="section in sections" :key="section.id ?? 'unknown'" class="numa-node" - :class="{ unknown: section.id === undefined }" + :class="{ unknown: section.id === undefined, unassigned: cards && section.id === undefined }" > -
+
{{ section.id === undefined ? $t('aiTools.gpuGroup.unknownNode') : `NUMA ${section.id}` }} @@ -87,7 +87,7 @@ const sections = computed(() => { ); const unknown = props.devices.filter((device) => !props.nodes.some((node) => node.id === device.numaNode)); if (unknown.length) result.push({ devices: unknown }); - return result; + return result.filter((section) => !props.selectable || section.devices.length > 0); }); const missingDevices = computed(() => selected.value.filter((id) => !props.devices.some((device) => device.id === id))); const toggleDevice = (id: string, checked: boolean) => { @@ -108,15 +108,19 @@ const toggleNode = (devices: AI.ModelGPUDevice[], checked: boolean) => { gap: 24px; } .topology-cards { - grid-template-columns: repeat(auto-fit, minmax(min(440px, 100%), 1fr)); - gap: 20px; - align-items: stretch; + grid-template-columns: repeat(auto-fill, minmax(min(380px, 100%), 1fr)); + gap: 16px; + align-items: start; } .topology-cards > .numa-node { border: 1px solid var(--el-border-color-lighter); - border-radius: 10px; + border-radius: 8px; padding: 20px; } +.gpu-topology.topology-cards > .numa-node.unassigned { + border: 0; + padding: 0; +} .topology-cards .numa-node-header { margin-bottom: 16px; } @@ -126,6 +130,33 @@ const toggleNode = (devices: AI.ModelGPUDevice[], checked: boolean) => { .topology-cards .topology-device { align-content: start; } +.topology-cards .numa-devices { + grid-template-columns: minmax(0, 1fr); + gap: 0; +} +.topology-cards .topology-device { + background: transparent; + border: 1px solid transparent; + border-radius: 6px; + padding: 10px 12px; +} +.topology-cards .topology-device + .topology-device { + border-top-color: var(--el-border-color-extra-light); +} +.topology-cards .topology-device.selected { + background: var(--el-color-primary-light-9); + border-color: var(--el-color-primary-light-5); +} +.topology-cards.selectable .numa-devices { + gap: 6px; +} +.topology-cards.selectable .unassigned .numa-devices { + grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr)); + gap: 12px; +} +.topology-cards.selectable .unassigned .topology-device:not(.selected) { + border-color: var(--el-border-color-lighter); +} .topology-cards.selectable { grid-template-columns: minmax(0, 1fr); gap: 12px; diff --git a/frontend/src/views/ai/gpu/current/index.vue b/frontend/src/views/ai/gpu/current/index.vue index a2cd6367d..22e286cab 100644 --- a/frontend/src/views/ai/gpu/current/index.vue +++ b/frontend/src/views/ai/gpu/current/index.vue @@ -2,10 +2,10 @@
- -