From 421fd3cd61001bedbc7b7285b0b58f0bc0452dc0 Mon Sep 17 00:00:00 2001 From: matevip Date: Mon, 29 Jun 2026 14:48:44 +0800 Subject: [PATCH] fix(llm): stop assuming DeepSeek is vision-capable --- .../llm/service/ModelCapabilityService.java | 9 ++++--- .../service/ModelCapabilityServiceTest.java | 27 ++++++++++++------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/mateclaw-server/src/main/java/vip/mate/llm/service/ModelCapabilityService.java b/mateclaw-server/src/main/java/vip/mate/llm/service/ModelCapabilityService.java index 3eaba40e..ca1ee69c 100644 --- a/mateclaw-server/src/main/java/vip/mate/llm/service/ModelCapabilityService.java +++ b/mateclaw-server/src/main/java/vip/mate/llm/service/ModelCapabilityService.java @@ -97,9 +97,12 @@ public class ModelCapabilityService { m.put("claude-haiku", EnumSet.of(Modality.VISION)); // ===== DeepSeek ===== - // V4 (Apr 2026) is the first DeepSeek line with native multimodal — image + video. - // V3 and earlier are text-only (no entry → defaults to text only). - m.put("deepseek-v4", EnumSet.of(Modality.VISION, Modality.VIDEO)); + // All released DeepSeek chat models (deepseek-chat / deepseek-reasoner / + // deepseek-v3.x) are text-only, so there is no entry and they default to + // text. Do NOT assume a future line is multimodal here: a wrong vision + // assumption makes the router send image_url to a text model, which the + // provider rejects with a 400. A genuinely multimodal model should declare + // its modalities on the model config instead. // ===== ByteDance Doubao / Seed ===== // Seed 2.0 Pro (Feb 2026) handles hour-long videos. Seed1.5-VL also supports video. diff --git a/mateclaw-server/src/test/java/vip/mate/llm/service/ModelCapabilityServiceTest.java b/mateclaw-server/src/test/java/vip/mate/llm/service/ModelCapabilityServiceTest.java index 0c485548..3b231e4a 100644 --- a/mateclaw-server/src/test/java/vip/mate/llm/service/ModelCapabilityServiceTest.java +++ b/mateclaw-server/src/test/java/vip/mate/llm/service/ModelCapabilityServiceTest.java @@ -98,17 +98,24 @@ class ModelCapabilityServiceTest { } @Test - @DisplayName("DeepSeek V4 / V4-Pro → VIDEO; V3 (text-only) gets nothing") - void deepseekV4_supportsVideo() { - // DeepSeek V4 (Apr 2026) introduced native multimodal incl. video to the line. - // V3 and earlier remain text-only and must NOT match the V4 entry. - assertTrue(service.supports("deepseek-v4", null, Modality.VIDEO)); - assertTrue(service.supports("deepseek-v4-pro", null, Modality.VIDEO)); - assertTrue(service.supports("deepseek-v4-flash", null, Modality.VIDEO)); - assertFalse(service.supports("deepseek-v3", null, Modality.VIDEO), - "V3 must NOT inherit V4 capabilities — text-only base differs from V4 entirely"); + @DisplayName("DeepSeek is text-only by default — no speculative vision entry (issue #288)") + void deepseek_textOnlyByDefault() { + // DeepSeek's released chat models (deepseek-chat / deepseek-reasoner / + // deepseek-v3.x) are text-only. A hardcoded deepseek-v4 → vision/video entry + // made the router send image_url to a text model, which DeepSeek rejects with + // a 400 (and it never fell back to the vision sidecar). Default must be + // text-only; a genuinely multimodal model is opted in via the DB modalities + // declaration, not assumed here. + assertFalse(service.supports("deepseek-v4", null, Modality.VISION), + "deepseek must not be assumed vision-capable (issue #288)"); + assertFalse(service.supports("deepseek-v4", null, Modality.VIDEO)); + assertFalse(service.supports("deepseek-chat", null, Modality.VISION)); + assertFalse(service.supports("deepseek-reasoner", null, Modality.VISION)); assertFalse(service.supports("deepseek-v3.2", null, Modality.VIDEO)); - assertFalse(service.supports("deepseek-r1", null, Modality.VIDEO)); + assertEquals(EnumSet.of(Modality.TEXT), service.resolve("deepseek-v4", null)); + // A real multimodal model can still be declared explicitly via DB modalities. + assertTrue(service.supports("deepseek-v4", "[\"vision\"]", Modality.VISION), + "an explicit DB declaration must still grant vision when the model truly has it"); } @Test