fix: 使用发布快照校验图片输入能力

- 正式聊天和模型编译统一读取发布快照中的图片能力

- 草稿态保留实时模型能力并为旧快照提供安全关闭策略
This commit is contained in:
2026-07-30 15:05:42 +08:00
parent 1b40829135
commit ff5f90121b
5 changed files with 340 additions and 7 deletions

View File

@@ -0,0 +1,80 @@
package tech.easyflow.agent.runtime;
import tech.easyflow.agent.entity.Agent;
import tech.easyflow.ai.entity.Model;
import java.util.Map;
import java.util.function.Supplier;
/**
* 解析 Agent 运行时应使用的模型输入能力。
*
* <p>正式运行严格使用发布快照;草稿试运行使用当前模型配置。</p>
*/
public final class AgentModelCapabilityResolver {
private static final String MODEL_SUMMARY = "modelSummary";
private static final String SUPPORT_IMAGE = "supportImage";
private static final String SUPPORT_IMAGE_BASE64_ONLY = "supportImageB64Only";
/**
* 禁止实例化能力解析工具。
*/
private AgentModelCapabilityResolver() {
}
/**
* 解析 Agent 当前运行模式对应的模型能力。
*
* <p>只要 Agent 携带发布快照,就不会读取实时模型能力。旧快照缺少能力字段时按不支持处理。</p>
*
* @param agent Agent 运行视图
* @param liveModelSupplier 草稿态实时模型提供器
* @return 规范化模型能力
*/
public static Resolution resolve(Agent agent, Supplier<Model> liveModelSupplier) {
Map<String, Object> publishedSnapshot = agent == null
? null : agent.getPublishedSnapshotJson();
if (publishedSnapshot != null && !publishedSnapshot.isEmpty()) {
return fromPublishedSnapshot(publishedSnapshot);
}
Model liveModel = liveModelSupplier == null ? null : liveModelSupplier.get();
return new Resolution(
liveModel != null && Boolean.TRUE.equals(liveModel.getSupportImage()),
liveModel != null && Boolean.TRUE.equals(liveModel.getSupportImageB64Only()));
}
/**
* 从发布快照读取模型能力。
*
* @param publishedSnapshot Agent 发布快照
* @return 快照中的模型能力
*/
private static Resolution fromPublishedSnapshot(Map<String, Object> publishedSnapshot) {
Object summaryValue = publishedSnapshot.get(MODEL_SUMMARY);
if (!(summaryValue instanceof Map<?, ?> modelSummary)) {
return Resolution.disabled();
}
return new Resolution(
Boolean.TRUE.equals(modelSummary.get(SUPPORT_IMAGE)),
Boolean.TRUE.equals(modelSummary.get(SUPPORT_IMAGE_BASE64_ONLY)));
}
/**
* 模型输入能力解析结果。
*
* @param supportImage 是否支持图片输入
* @param supportImageBase64Only 是否仅支持 Base64 图片输入
*/
public record Resolution(boolean supportImage, boolean supportImageBase64Only) {
/**
* 创建关闭全部图片能力的结果。
*
* @return 关闭图片能力的结果
*/
private static Resolution disabled() {
return new Resolution(false, false);
}
}
}

View File

@@ -1482,10 +1482,11 @@ public class AgentRunService {
if (imageUploadIds == null || imageUploadIds.isEmpty()) {
return;
}
tech.easyflow.ai.entity.Model model = agent == null || agent.getModelId() == null
? null
: modelService.getModelInstance(agent.getModelId());
if (model == null || !Boolean.TRUE.equals(model.getSupportImage())) {
AgentModelCapabilityResolver.Resolution capabilities =
AgentModelCapabilityResolver.resolve(agent, () ->
agent == null || agent.getModelId() == null
? null : modelService.getModelInstance(agent.getModelId()));
if (!capabilities.supportImage()) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "当前 Agent 模型未启用多模态图片能力");
}
}

View File

@@ -108,7 +108,12 @@ public class AgentRuntimeCompiler {
if (model == null) {
throw new BusinessException("Agent 模型不存在");
}
return AgentModelSpecMapper.fromModel(model, agent.getModelConfigJson());
AgentModelSpec spec = AgentModelSpecMapper.fromModel(model, agent.getModelConfigJson());
AgentModelCapabilityResolver.Resolution capabilities =
AgentModelCapabilityResolver.resolve(agent, () -> model);
spec.setSupportImage(capabilities.supportImage());
spec.setSupportImageBase64Only(capabilities.supportImageBase64Only());
return spec;
}
private AgentGenerationOptions buildGenerationOptions(Map<String, Object> config) {