mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
fix(llm): skip chat-style probe for embedding-prefix models in DashScope discovery
This commit is contained in:
parent
58c53687e5
commit
3340885da3
@ -139,6 +139,17 @@ public class ModelDiscoveryService {
|
||||
"qwen3-livetranslate-"
|
||||
);
|
||||
|
||||
/**
|
||||
* Model-id prefixes that mark an embedding model. These pass the chat-focused
|
||||
* acceptable-id check (so the manual "Add model" form works) but must be
|
||||
* excluded from chat-style runtime probes and from "new chat models" auto
|
||||
* suggestions — they only speak the embeddings protocol, not chat completion.
|
||||
*/
|
||||
private static final Set<String> EMBEDDING_MODEL_PREFIXES = Set.of(
|
||||
"text-embedding-",
|
||||
"embedding-"
|
||||
);
|
||||
|
||||
/**
|
||||
* Allow-list prefixes for DashScope models that are known to work on the native
|
||||
* protocol (chat or embedding). An empty set means "no prefix filter" (we still
|
||||
@ -183,10 +194,13 @@ public class ModelDiscoveryService {
|
||||
.map(ModelConfigEntity::getModelName)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// Only propose models that passed the probe (or were not probed) as "new"
|
||||
// Only propose models that passed the probe (or were not probed) as "new".
|
||||
// Embedding models are catalog-visible but excluded from the chat-discovery
|
||||
// suggestion bucket — adding them as chat models would 400 at runtime.
|
||||
List<ModelInfoDTO> newModels = discovered.stream()
|
||||
.filter(m -> !existingIds.contains(m.getId()))
|
||||
.filter(m -> !Boolean.FALSE.equals(m.getProbeOk()))
|
||||
.filter(m -> !isEmbeddingModelId(m.getId()))
|
||||
.toList();
|
||||
|
||||
return new DiscoverResult(discovered, newModels, discovered.size(), newModels.size());
|
||||
@ -235,6 +249,18 @@ public class ModelDiscoveryService {
|
||||
return DASHSCOPE_NATIVE_ALLOW_PREFIXES.stream().anyMatch(lower::startsWith);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when a model id looks like an embedding model (e.g.
|
||||
* {@code text-embedding-v3}). Used to skip chat-style probes and to keep
|
||||
* embedding entries out of the "new chat models to add" auto-suggestion.
|
||||
* Package-private for unit tests.
|
||||
*/
|
||||
static boolean isEmbeddingModelId(String modelId) {
|
||||
if (modelId == null) return false;
|
||||
String lower = modelId.toLowerCase();
|
||||
return EMBEDDING_MODEL_PREFIXES.stream().anyMatch(lower::startsWith);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defensive guard for code paths that persist a model id without going through
|
||||
* discovery (e.g. the manual "Add model" form). Throws a MateClawException with
|
||||
@ -270,6 +296,13 @@ public class ModelDiscoveryService {
|
||||
Semaphore sem = new Semaphore(MAX_PROBE_CONCURRENCY);
|
||||
List<CompletableFuture<Void>> futures = new ArrayList<>(discovered.size());
|
||||
for (ModelInfoDTO dto : discovered) {
|
||||
if (isEmbeddingModelId(dto.getId())) {
|
||||
// Embedding models don't speak chat completion — sendTestPrompt would
|
||||
// 400 with InvalidParameter. Leave probeOk null (no warning badge)
|
||||
// and surface a clear, non-error reason in probeError.
|
||||
dto.setProbeError("Embedding model — not chat-probeable");
|
||||
continue;
|
||||
}
|
||||
futures.add(CompletableFuture.runAsync(() -> {
|
||||
try { sem.acquire(); }
|
||||
catch (InterruptedException ie) { Thread.currentThread().interrupt(); return; }
|
||||
|
||||
@ -0,0 +1,61 @@
|
||||
package vip.mate.llm.service;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Coverage for {@link ModelDiscoveryService#isEmbeddingModelId(String)} —
|
||||
* the predicate that keeps embedding models out of the chat-style probe and
|
||||
* out of the chat-discovery "new models" suggestion bucket.
|
||||
*/
|
||||
class ModelDiscoveryEmbeddingDetectionTest {
|
||||
|
||||
@Test
|
||||
void dashscopeEmbeddingVariants_recognised() {
|
||||
assertTrue(ModelDiscoveryService.isEmbeddingModelId("text-embedding-v1"));
|
||||
assertTrue(ModelDiscoveryService.isEmbeddingModelId("text-embedding-v3"));
|
||||
assertTrue(ModelDiscoveryService.isEmbeddingModelId("text-embedding-v4"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void openAiEmbeddingVariants_recognised() {
|
||||
assertTrue(ModelDiscoveryService.isEmbeddingModelId("text-embedding-ada-002"));
|
||||
assertTrue(ModelDiscoveryService.isEmbeddingModelId("text-embedding-3-small"));
|
||||
assertTrue(ModelDiscoveryService.isEmbeddingModelId("text-embedding-3-large"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void genericEmbeddingPrefix_recognised() {
|
||||
// Some providers ship just "embedding-..." without the "text-" prefix.
|
||||
assertTrue(ModelDiscoveryService.isEmbeddingModelId("embedding-001"));
|
||||
assertTrue(ModelDiscoveryService.isEmbeddingModelId("embedding-large"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void chatModels_notRecognisedAsEmbedding() {
|
||||
assertFalse(ModelDiscoveryService.isEmbeddingModelId("qwen-plus"));
|
||||
assertFalse(ModelDiscoveryService.isEmbeddingModelId("gpt-4o"));
|
||||
assertFalse(ModelDiscoveryService.isEmbeddingModelId("claude-sonnet-4-6"));
|
||||
assertFalse(ModelDiscoveryService.isEmbeddingModelId("deepseek-r1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void detectionIsCaseInsensitive() {
|
||||
assertTrue(ModelDiscoveryService.isEmbeddingModelId("Text-Embedding-V4"));
|
||||
assertTrue(ModelDiscoveryService.isEmbeddingModelId("TEXT-EMBEDDING-3-SMALL"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullAndBlank_notEmbedding() {
|
||||
assertFalse(ModelDiscoveryService.isEmbeddingModelId(null));
|
||||
assertFalse(ModelDiscoveryService.isEmbeddingModelId(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
void stringContainingEmbeddingMidway_notDetected() {
|
||||
// Only prefix-anchored matches count; arbitrary mentions don't.
|
||||
assertFalse(ModelDiscoveryService.isEmbeddingModelId("qwen-embedding-experimental"));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user