diff --git a/assistant-agent-start/src/main/java/com/alibaba/assistant/agent/start/config/CodeactAgentConfig.java b/assistant-agent-start/src/main/java/com/alibaba/assistant/agent/start/config/CodeactAgentConfig.java index 11e4517a..95a03c83 100644 --- a/assistant-agent-start/src/main/java/com/alibaba/assistant/agent/start/config/CodeactAgentConfig.java +++ b/assistant-agent-start/src/main/java/com/alibaba/assistant/agent/start/config/CodeactAgentConfig.java @@ -30,7 +30,9 @@ import com.alibaba.assistant.agent.common.enums.Language; import com.alibaba.assistant.agent.extension.prompt.CodeactToolSignatureInjectionToolCallback; import com.alibaba.assistant.agent.extension.prompt.PromptContributionToolCallback; +import com.alibaba.assistant.agent.start.interceptor.modelInterceptor.DashScopeMultimodalEndpointInterceptor; import com.alibaba.cloud.ai.graph.agent.hook.Hook; +import com.alibaba.cloud.ai.graph.agent.interceptor.ModelInterceptor; import com.alibaba.cloud.ai.graph.checkpoint.savers.MemorySaver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,6 +43,7 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; import java.util.ArrayList; import java.util.List; @@ -222,6 +225,7 @@ def calculate_sum(a, b): @Bean public CodeactAgent grayscaleCodeactAgent( ChatModel chatModel, + @Autowired(required = false) Environment environment, @Autowired(required = false) List replyCodeactTools, @Autowired(required = false) SearchCodeactToolFactory searchCodeactToolFactory, @Autowired(required = false) List triggerCodeactTools, @@ -313,6 +317,9 @@ public CodeactAgent grayscaleCodeactAgent( logger.info("CodeactAgentConfig#grayscaleCodeactAgent - reason=统一配置 Hooks, total={}", allHooks != null ? allHooks.size() : 0); + List modelInterceptors = new ArrayList<>(); + modelInterceptors.add(new DashScopeMultimodalEndpointInterceptor(environment)); + CodeactAgent.CodeactAgentBuilder builder = CodeactAgent.builder() .name("CodeactAgent") .description("通过编写和执行 Python 代码来解决问题的代码驱动智能体") diff --git a/assistant-agent-start/src/main/java/com/alibaba/assistant/agent/start/interceptor/modelInterceptor/DashScopeMultimodalEndpointInterceptor.java b/assistant-agent-start/src/main/java/com/alibaba/assistant/agent/start/interceptor/modelInterceptor/DashScopeMultimodalEndpointInterceptor.java new file mode 100644 index 00000000..a4edef44 --- /dev/null +++ b/assistant-agent-start/src/main/java/com/alibaba/assistant/agent/start/interceptor/modelInterceptor/DashScopeMultimodalEndpointInterceptor.java @@ -0,0 +1,65 @@ +package com.alibaba.assistant.agent.start.interceptor.modelInterceptor; + +import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions; +import com.alibaba.cloud.ai.graph.agent.interceptor.ModelCallHandler; +import com.alibaba.cloud.ai.graph.agent.interceptor.ModelInterceptor; +import com.alibaba.cloud.ai.graph.agent.interceptor.ModelRequest; +import com.alibaba.cloud.ai.graph.agent.interceptor.ModelResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.ai.model.ModelOptionsUtils; +import org.springframework.ai.model.tool.ToolCallingChatOptions; +import org.springframework.core.env.Environment; + +/** + * 确保 Graph 传入的 {@link ModelRequest#getOptions()} 在合并后仍走 DashScope 多模态端点。 + * + *

阿里云文档:qwen3.6-plus 等模型若用纯文本端点会报 {@code url error}。框架层可能下发 + * {@code multiModel=false} 的选项并覆盖 {@code application.yml} 默认值,本拦截器在调用链最前段纠偏。 + */ +public class DashScopeMultimodalEndpointInterceptor extends ModelInterceptor { + + private static final Logger log = LoggerFactory.getLogger(DashScopeMultimodalEndpointInterceptor.class); + + private final Environment environment; + + public DashScopeMultimodalEndpointInterceptor(Environment environment) { + this.environment = environment; + } + + @Override + public String getName() { + return "DashScopeMultimodalEndpointInterceptor"; + } + + @Override + public ModelResponse interceptModel(ModelRequest request, ModelCallHandler handler) { + if (!Boolean.parseBoolean( + environment.getProperty("spring.ai.dashscope.chat.options.multi-model", "true"))) { + return handler.call(request); + } + ToolCallingChatOptions options = request.getOptions(); + if (options == null) { + return handler.call(request); + } + try { + DashScopeChatOptions dash; + if (options instanceof DashScopeChatOptions dso) { + dash = DashScopeChatOptions.fromOptions(dso); + } else { + dash = ModelOptionsUtils.copyToTarget(options, ToolCallingChatOptions.class, DashScopeChatOptions.class); + } + Boolean before = dash.getMultiModel(); + if (!Boolean.TRUE.equals(before)) { + dash.setMultiModel(true); + log.debug("DashScopeMultimodalEndpointInterceptor: set multiModel true (was {})", before); + ModelRequest patched = ModelRequest.builder(request).options(dash).build(); + return handler.call(patched); + } + } catch (Exception e) { + log.warn("DashScopeMultimodalEndpointInterceptor: failed to patch options, passing request through: {}", + e.toString()); + } + return handler.call(request); + } +} \ No newline at end of file