fix(agent): relax vision model detection for image analysis
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-02-19 02:07:38 +08:00
parent 825da7fd52
commit 0f3b562dc7
2 changed files with 97 additions and 22 deletions

View File

@ -487,8 +487,44 @@ type EnabledModelWithProvider = Awaited<
ReturnType<typeof import("@/lib/db/queries")["getEnabledAiModelsWithProvider"]>
>[number];
function isLikelyVisionCapableModel(item: EnabledModelWithProvider) {
if (!item.model.isEnabled || item.model.isSubModel) return false;
if (item.model.supportsVision) return true;
if (isAiModelMultimodal(item.model)) return true;
const providerType = item.provider.type || "";
const modelText = `${item.model.displayName || ""} ${item.model.modelId || ""}`.toLowerCase();
if (providerType === "volcano-multimodal") return true;
if (
providerType === "zhipu" &&
/(glm[-_.]?4v|glm[-_.]?4\.?6v|vision|多模态)/i.test(modelText)
) {
return true;
}
if (
providerType === "alibaba" &&
/(qwen|vl|vision|通义|多模态)/i.test(modelText)
) {
return true;
}
if (
["custom", "openai", "local"].includes(providerType) &&
/(doubao[-_.]?seed[-_.]?2[-_.]?0|seed[-_.]?2[-_.]?0|qwen[-_.]?vl|glm[-_.]?4v|gpt[-_.]?4o|vision|vl|多模态)/i.test(
modelText,
)
) {
return true;
}
return false;
}
function pickQwenVisionModel(models: EnabledModelWithProvider[]) {
const visionModels = models.filter((item) => item.model.supportsVision && item.model.isEnabled);
const visionModels = models.filter((item) => isLikelyVisionCapableModel(item));
const zhipuVision = visionModels.find(
(item) =>
item.provider.type === "zhipu" ||
@ -514,12 +550,7 @@ function pickAgentVisionModel(
agentModel: EnabledModelWithProvider | undefined,
models: EnabledModelWithProvider[],
) {
if (
agentModel &&
agentModel.model.isEnabled &&
agentModel.model.supportsVision &&
isAiModelMultimodal(agentModel.model)
) {
if (agentModel && isLikelyVisionCapableModel(agentModel)) {
return agentModel;
}

View File

@ -568,6 +568,56 @@ interface HistoryMessage {
content: string;
}
function isLikelyVisionCapableModel(modelWithProvider: {
model: {
isEnabled: boolean;
isSubModel: boolean;
supportsVision?: boolean;
displayName?: string | null;
modelId?: string | null;
capabilities?: unknown;
defaultParams?: unknown;
};
provider: {
type?: string | null;
};
}) {
const model = modelWithProvider.model;
const providerType = String(modelWithProvider.provider?.type || "");
if (!model?.isEnabled || model.isSubModel) return false;
if (model.supportsVision) return true;
if (isAiModelMultimodal(model)) return true;
const modelText = `${model.displayName || ""} ${model.modelId || ""}`.toLowerCase();
if (providerType === "volcano-multimodal") return true;
if (
providerType === "zhipu" &&
/(glm[-_.]?4v|glm[-_.]?4\.?6v|vision|多模态)/i.test(modelText)
) {
return true;
}
if (
providerType === "alibaba" &&
/(qwen|vl|vision|通义|多模态)/i.test(modelText)
) {
return true;
}
if (
["custom", "openai", "local"].includes(providerType) &&
/(doubao[-_.]?seed[-_.]?2[-_.]?0|seed[-_.]?2[-_.]?0|qwen[-_.]?vl|glm[-_.]?4v|gpt[-_.]?4o|vision|vl|多模态)/i.test(
modelText,
)
) {
return true;
}
return false;
}
/**
* 分析用户意图
*/
@ -657,17 +707,13 @@ async function analyzWithLLM(
);
const zhipuVisionModel = allModels.find(
(m) =>
m.model.supportsVision &&
m.model.isEnabled &&
!m.model.isSubModel &&
isLikelyVisionCapableModel(m) &&
isLikelyZhipuVisionModel(m.model.displayName, m.model.modelId, m.provider.type),
);
const qwenVisionModel = allModels.find(
(m) =>
m.provider.type === "alibaba" &&
m.model.supportsVision &&
m.model.isEnabled &&
!m.model.isSubModel &&
isLikelyVisionCapableModel(m) &&
/(qwen|通义|vl)/i.test(`${m.model.displayName} ${m.model.modelId}`)
);
const fallbackVisionModel =
@ -675,25 +721,23 @@ async function analyzWithLLM(
allModels.find(
(m) =>
m.provider.type === "alibaba" &&
m.model.supportsVision &&
m.model.isEnabled &&
!m.model.isSubModel,
isLikelyVisionCapableModel(m),
);
const preferredVisionModel = zhipuVisionModel || fallbackVisionModel;
const preferredVisionModel =
zhipuVisionModel ||
fallbackVisionModel ||
allModels.find((m) => isLikelyVisionCapableModel(m));
const usableAgentModel =
agentModel && isReasoningCompatibleProvider(agentModel.provider.type)
? agentModel
: undefined;
const multimodalAgentVisionModel =
agentModel &&
agentModel.model.isEnabled &&
!agentModel.model.isSubModel &&
agentModel.model.supportsVision &&
isAiModelMultimodal(agentModel.model)
isLikelyVisionCapableModel(agentModel)
? agentModel
: undefined;
const selectedAnalyzerModel = hasImage
? multimodalAgentVisionModel || preferredVisionModel
? multimodalAgentVisionModel || preferredVisionModel || usableAgentModel
: usableAgentModel ||
allModels.find((m) => m.provider.type === "zhipu" && !m.model.isSubModel) ||
preferredVisionModel;