mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-15 11:58:34 +08:00
fix(llm): pre-filter non-chat DashScope modalities + quieter probe logging
This commit is contained in:
parent
adfe23cd2c
commit
c4883e108c
@ -36,8 +36,9 @@ public class ModelDiscoveryService {
|
|||||||
// Virtual-thread executor for parallel model probing (lightweight, short-lived)
|
// Virtual-thread executor for parallel model probing (lightweight, short-lived)
|
||||||
private static final ExecutorService PROBE_EXECUTOR = Executors.newVirtualThreadPerTaskExecutor();
|
private static final ExecutorService PROBE_EXECUTOR = Executors.newVirtualThreadPerTaskExecutor();
|
||||||
|
|
||||||
// Probe concurrency cap — avoid flooding the provider with concurrent ping requests
|
// Probe concurrency cap — reduced from 5 to 3 because higher parallelism
|
||||||
private static final int MAX_PROBE_CONCURRENCY = 5;
|
// triggered 429 Throttling.RateQuota on DashScope during bulk refresh
|
||||||
|
private static final int MAX_PROBE_CONCURRENCY = 3;
|
||||||
|
|
||||||
// Per-model probe timeout (short; we only need to know "yes/no usable")
|
// Per-model probe timeout (short; we only need to know "yes/no usable")
|
||||||
private static final long PROBE_TIMEOUT_SECONDS = 12;
|
private static final long PROBE_TIMEOUT_SECONDS = 12;
|
||||||
@ -60,19 +61,57 @@ public class ModelDiscoveryService {
|
|||||||
private static final java.util.regex.Pattern DASHSCOPE_NATIVE_UNSUPPORTED_PATTERN =
|
private static final java.util.regex.Pattern DASHSCOPE_NATIVE_UNSUPPORTED_PATTERN =
|
||||||
java.util.regex.Pattern.compile("^qwen\\d+\\.\\d+.*", java.util.regex.Pattern.CASE_INSENSITIVE);
|
java.util.regex.Pattern.compile("^qwen\\d+\\.\\d+.*", java.util.regex.Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameter-size suffixes used by DashScope open-source base models (e.g.
|
||||||
|
* {@code qwen3-0.6b}, {@code qwen3-8b}, {@code qwen3-32b}, {@code qwen3-30b-a3b}).
|
||||||
|
* These are catalog entries, not DashScope-hosted chat endpoints, and the native
|
||||||
|
* protocol returns {@code InvalidParameter: parameter.enable_thinking ...} for
|
||||||
|
* any attempt to invoke them. Pre-filter them out of discovery.
|
||||||
|
*/
|
||||||
|
private static final java.util.regex.Pattern DASHSCOPE_OPEN_SOURCE_SIZE_PATTERN =
|
||||||
|
java.util.regex.Pattern.compile("^qwen\\d+-\\d+(?:\\.\\d+)?b(?:-.*)?$", java.util.regex.Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prefixes that identify non-chat modalities (image generation, vision understanding,
|
||||||
|
* TTS, ASR, omni/multimodal bases, realtime speech, live translation, OCR, speech-to-
|
||||||
|
* speech, voice-clone). They are catalog-visible but have different endpoints than
|
||||||
|
* the native chat-generation API, so probing them via chat always fails with
|
||||||
|
* "url error". Blocking them up-front cuts discovery time and log noise dramatically.
|
||||||
|
*/
|
||||||
|
private static final Set<String> DASHSCOPE_NON_CHAT_PREFIXES = Set.of(
|
||||||
|
// Vision understanding / OCR
|
||||||
|
"qwen-vl-",
|
||||||
|
"qwen3-vl-",
|
||||||
|
// Image generation / edit
|
||||||
|
"qwen-image-",
|
||||||
|
"qwen3-image-",
|
||||||
|
// TTS / ASR / speech-to-speech / voice
|
||||||
|
"qwen-tts-",
|
||||||
|
"qwen3-tts-",
|
||||||
|
"qwen-asr-",
|
||||||
|
"qwen3-asr-",
|
||||||
|
"qwen-s2s-",
|
||||||
|
"qwen3-s2s-",
|
||||||
|
// Omni multimodal bases
|
||||||
|
"qwen-omni-",
|
||||||
|
"qwen3-omni-",
|
||||||
|
// Audio understanding
|
||||||
|
"qwen-audio-",
|
||||||
|
// Live translation
|
||||||
|
"qwen-livetranslate-",
|
||||||
|
"qwen3-livetranslate-"
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow-list prefixes for DashScope models that are known to work on the native
|
* Allow-list prefixes for DashScope models that are known to work on the native
|
||||||
* protocol. An empty set means "no prefix filter" (we still apply DENY).
|
* chat protocol. An empty set means "no prefix filter" (we still apply DENY).
|
||||||
* Extend conservatively as we verify additional families.
|
* Extend conservatively as new families are verified.
|
||||||
*/
|
*/
|
||||||
private static final Set<String> DASHSCOPE_NATIVE_ALLOW_PREFIXES = Set.of(
|
private static final Set<String> DASHSCOPE_NATIVE_ALLOW_PREFIXES = Set.of(
|
||||||
"qwen-", // qwen-max / qwen-plus / qwen-turbo / qwen-coder-* / qwen-long
|
"qwen-", // qwen-max / qwen-plus / qwen-turbo / qwen-coder-* / qwen-long
|
||||||
"qwen2-", // qwen2 series
|
"qwen2-", // qwen2 series
|
||||||
"qwen3-", // qwen3-max / qwen3-plus / qwen3-coder / qwen3-235b-*
|
"qwen3-", // qwen3-max / qwen3-plus / qwen3-coder / qwen3-235b-*
|
||||||
"qwen-vl-", // vision-language
|
"deepseek-", // deepseek-v3.x / deepseek-r1*
|
||||||
"qwen-audio-",
|
|
||||||
"qwen-omni-",
|
|
||||||
"deepseek-", // deepseek-v3.x
|
|
||||||
"baichuan",
|
"baichuan",
|
||||||
"yi-",
|
"yi-",
|
||||||
"llama"
|
"llama"
|
||||||
@ -139,15 +178,21 @@ public class ModelDiscoveryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if a DashScope model id is allowed on the native protocol:
|
* Return true if a DashScope model id is allowed on the native chat protocol.
|
||||||
* not in the explicit DENY set, doesn't match the dot-version unsupported
|
* Rejection rules (in order):
|
||||||
* pattern, and matches at least one ALLOW prefix (or the allow list is empty).
|
* 1. Explicit DENY set (e.g. qwen3.5-max)
|
||||||
|
* 2. Dot-version family pattern (qwen3.5-*, qwen3.6-*, ...)
|
||||||
|
* 3. Non-chat modality prefix (vl, image, tts, asr, omni, audio, s2s, ocr, livetranslate)
|
||||||
|
* 4. Open-source parameter-size suffix (qwen3-8b, qwen3-32b, qwen3-30b-a3b, qwen3-0.6b ...)
|
||||||
|
* 5. Must start with a known ALLOW prefix (qwen-, qwen2-, qwen3-, deepseek-, ...)
|
||||||
*/
|
*/
|
||||||
private static boolean isDashScopeModelIdAcceptable(String modelId) {
|
private static boolean isDashScopeModelIdAcceptable(String modelId) {
|
||||||
if (modelId == null || modelId.isBlank()) return false;
|
if (modelId == null || modelId.isBlank()) return false;
|
||||||
String lower = modelId.toLowerCase();
|
String lower = modelId.toLowerCase();
|
||||||
if (DASHSCOPE_NATIVE_DENY.contains(lower)) return false;
|
if (DASHSCOPE_NATIVE_DENY.contains(lower)) return false;
|
||||||
if (DASHSCOPE_NATIVE_UNSUPPORTED_PATTERN.matcher(lower).matches()) return false;
|
if (DASHSCOPE_NATIVE_UNSUPPORTED_PATTERN.matcher(lower).matches()) return false;
|
||||||
|
if (DASHSCOPE_NON_CHAT_PREFIXES.stream().anyMatch(lower::startsWith)) return false;
|
||||||
|
if (DASHSCOPE_OPEN_SOURCE_SIZE_PATTERN.matcher(lower).matches()) return false;
|
||||||
if (DASHSCOPE_NATIVE_ALLOW_PREFIXES.isEmpty()) return true;
|
if (DASHSCOPE_NATIVE_ALLOW_PREFIXES.isEmpty()) return true;
|
||||||
return DASHSCOPE_NATIVE_ALLOW_PREFIXES.stream().anyMatch(lower::startsWith);
|
return DASHSCOPE_NATIVE_ALLOW_PREFIXES.stream().anyMatch(lower::startsWith);
|
||||||
}
|
}
|
||||||
@ -196,7 +241,12 @@ public class ModelDiscoveryService {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
dto.setProbeOk(false);
|
dto.setProbeOk(false);
|
||||||
dto.setProbeError(shortError(e));
|
dto.setProbeError(shortError(e));
|
||||||
log.info("[ModelDiscovery] Probe failed for model={}: {}", dto.getId(), dto.getProbeError());
|
// DEBUG level — per-model probe failures are an expected part of bulk
|
||||||
|
// discovery (DashScope lists many deprecated/restricted models). The
|
||||||
|
// aggregate "Probe results: X passed, Y failed" summary below is
|
||||||
|
// sufficient for normal operations. Enable DEBUG for ModelDiscovery
|
||||||
|
// if you need to inspect individual reasons.
|
||||||
|
log.debug("[ModelDiscovery] Probe failed for model={}: {}", dto.getId(), dto.getProbeError());
|
||||||
} finally {
|
} finally {
|
||||||
sem.release();
|
sem.release();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user