toolNames = convertSet(toolService.getToolList(chatRole.getToolIds()), AiToolDO::getName);
+ toolNames.forEach(toolName -> {
+ ToolCallback toolCallback = toolCallbackResolver.resolve(toolName);
+ if (toolCallback != null) {
+ toolCallbacks.add(toolCallback);
+ }
+ });
+ }
+ // 2. 通过 mcpClients
+ if (CollUtil.isNotEmpty(mcpClients) && CollUtil.isNotEmpty(chatRole.getMcpClientNames())) {
+ chatRole.getMcpClientNames().forEach(mcpClientName -> {
+ // 2.1 标准化名字,参考 McpClientAutoConfiguration 的 connectedClientName 方法
+ String finalMcpClientName = mcpClientCommonProperties.getName() + " - " + mcpClientName;
+ // 2.2 匹配对应的 McpSyncClient
+ mcpClients.forEach(mcpClient -> {
+ if (ObjUtil.notEqual(mcpClient.getClientInfo().name(), finalMcpClientName)) {
+ return;
+ }
+ ToolCallback[] mcpToolCallBacks = new SyncMcpToolCallbackProvider(mcpClient).getToolCallbacks();
+ CollUtil.addAll(toolCallbacks, mcpToolCallBacks);
+ });
+ });
+ }
+ return toolCallbacks;
+ }
+
/**
* 从历史消息中,获得倒序的 n 组消息作为消息上下文
*
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java
index 35fb26d2cf..d209c62d44 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java
@@ -18,12 +18,10 @@ import org.springframework.ai.deepseek.DeepSeekChatOptions;
import org.springframework.ai.minimax.MiniMaxChatOptions;
import org.springframework.ai.ollama.api.OllamaOptions;
import org.springframework.ai.openai.OpenAiChatOptions;
+import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.zhipuai.ZhiPuAiChatOptions;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
/**
* Spring AI 工具类
@@ -40,15 +38,15 @@ public class AiUtils {
}
public static ChatOptions buildChatOptions(AiPlatformEnum platform, String model, Double temperature, Integer maxTokens,
- Set toolNames, Map toolContext) {
- toolNames = ObjUtil.defaultIfNull(toolNames, Collections.emptySet());
+ List toolCallbacks, Map toolContext) {
+ toolCallbacks = ObjUtil.defaultIfNull(toolCallbacks, Collections.emptyList());
toolContext = ObjUtil.defaultIfNull(toolContext, Collections.emptyMap());
// noinspection EnhancedSwitchMigration
switch (platform) {
case TONG_YI:
return DashScopeChatOptions.builder().withModel(model).withTemperature(temperature).withMaxToken(maxTokens)
.withEnableThinking(true) // TODO 芋艿:默认都开启 thinking 模式,后续可以让用户配置
- .withToolNames(toolNames).withToolContext(toolContext).build();
+ .withToolCallbacks(toolCallbacks).withToolContext(toolContext).build();
case YI_YAN:
return QianFanChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build();
case DEEP_SEEK:
@@ -57,30 +55,30 @@ public class AiUtils {
case SILICON_FLOW: // 复用 DeepSeek 客户端
case XING_HUO: // 复用 DeepSeek 客户端
return DeepSeekChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
- .toolNames(toolNames).toolContext(toolContext).build();
+ .toolCallbacks(toolCallbacks).toolContext(toolContext).build();
case ZHI_PU:
return ZhiPuAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
- .toolNames(toolNames).toolContext(toolContext).build();
+ .toolCallbacks(toolCallbacks).toolContext(toolContext).build();
case MINI_MAX:
return MiniMaxChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
- .toolNames(toolNames).toolContext(toolContext).build();
+ .toolCallbacks(toolCallbacks).toolContext(toolContext).build();
case MOONSHOT:
return MoonshotChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
- .toolNames(toolNames).toolContext(toolContext).build();
+ .toolCallbacks(toolCallbacks).toolContext(toolContext).build();
case OPENAI:
case GEMINI: // 复用 OpenAI 客户端
case BAI_CHUAN: // 复用 OpenAI 客户端
return OpenAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
- .toolNames(toolNames).toolContext(toolContext).build();
+ .toolCallbacks(toolCallbacks).toolContext(toolContext).build();
case AZURE_OPENAI:
return AzureOpenAiChatOptions.builder().deploymentName(model).temperature(temperature).maxTokens(maxTokens)
- .toolNames(toolNames).toolContext(toolContext).build();
+ .toolCallbacks(toolCallbacks).toolContext(toolContext).build();
case ANTHROPIC:
return AnthropicChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
- .toolNames(toolNames).toolContext(toolContext).build();
+ .toolCallbacks(toolCallbacks).toolContext(toolContext).build();
case OLLAMA:
return OllamaOptions.builder().model(model).temperature(temperature).numPredict(maxTokens)
- .toolNames(toolNames).toolContext(toolContext).build();
+ .toolCallbacks(toolCallbacks).toolContext(toolContext).build();
default:
throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform));
}
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/mcp/DouBaoMcpTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/mcp/DouBaoMcpTests.java
index b50caef5e2..674553ee1e 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/mcp/DouBaoMcpTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/mcp/DouBaoMcpTests.java
@@ -36,44 +36,47 @@ public class DouBaoMcpTests {
@Test
public void testMcpGetUserInfo() {
-
// 打印结果
System.out.println(chatClient.prompt()
.user("目前有哪些工具可以使用")
.call()
.content());
System.out.println("====================================");
+
// 打印结果
System.out.println(chatClient.prompt()
.user("小新的年龄是多少")
.call()
.content());
System.out.println("====================================");
+
// 打印结果
System.out.println(chatClient.prompt()
.user("获取小新的基本信息")
.call()
.content());
System.out.println("====================================");
+
// 打印结果
System.out.println(chatClient.prompt()
.user("小新是什么职业的")
.call()
.content());
System.out.println("====================================");
+
// 打印结果
System.out.println(chatClient.prompt()
.user("小新的教育背景")
.call()
.content());
System.out.println("====================================");
+
// 打印结果
System.out.println(chatClient.prompt()
.user("小新的兴趣爱好是什么")
.call()
.content());
System.out.println("====================================");
-
}