feat-恢复mcp模块

This commit is contained in:
evo
2026-03-07 15:53:06 +08:00
parent 6c4c661516
commit f160ec714b
43 changed files with 3718 additions and 275 deletions

View File

@@ -8,28 +8,22 @@ import dev.langchain4j.community.model.dashscope.QwenStreamingChatModel;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.SystemMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.mcp.McpToolProvider;
import dev.langchain4j.mcp.client.DefaultMcpClient;
import dev.langchain4j.mcp.client.McpClient;
import dev.langchain4j.mcp.client.transport.McpTransport;
import dev.langchain4j.mcp.client.transport.http.StreamableHttpMcpTransport;
import dev.langchain4j.model.chat.StreamingChatModel;
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
import dev.langchain4j.service.tool.ToolProvider;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.agent.McpAgent;
import org.ruoyi.config.McpSseConfig;
import org.ruoyi.enums.ChatModeType;
import org.ruoyi.service.chat.impl.AbstractStreamingChatService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.ruoyi.common.chat.domain.dto.request.ChatRequest;
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
import org.ruoyi.common.core.utils.SpringUtils;
import org.ruoyi.enums.ChatModeType;
import org.ruoyi.mcp.service.core.ToolProviderFactory;
import org.ruoyi.service.chat.impl.AbstractStreamingChatService;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
/**
@@ -42,20 +36,9 @@ import java.util.concurrent.locks.ReentrantLock;
@Slf4j
public class QianWenChatServiceImpl extends AbstractStreamingChatService {
@Autowired
private McpSseConfig mcpSseConfig;
// 添加文档解析的前缀字段
private static final String UPLOAD_FILE_API_PREFIX = "fileid";
// 缓存不同API Key和模型的MCP智能体实例
private final ConcurrentHashMap<String, SupervisorAgent> supervisorCache = new ConcurrentHashMap<>();
// 缓存不同API Key和模型的MCP客户端实例
private final ConcurrentHashMap<String, McpClient> mcpClientCache = new ConcurrentHashMap<>();
// 缓存不同API Key和模型的MCP工具提供者实例
private final ConcurrentHashMap<String, ToolProvider> toolProviderCache = new ConcurrentHashMap<>();
// 用于线程安全的锁
private final ReentrantLock cacheLock = new ReentrantLock();
@@ -108,77 +91,55 @@ public class QianWenChatServiceImpl extends AbstractStreamingChatService {
}).orElse(messagesWithMemory);
}
/**
* 获取缓存键
*/
private String getCacheKey(ChatModelVo chatModelVo) {
return chatModelVo.getApiKey() + ":" + chatModelVo.getModelName();
}
/**
* 初始化MCP客户端连接
*/
private McpClient initializeMcpClient() {
// 步骤1根据SSE对外暴露端点连接
McpTransport httpMcpTransport = new StreamableHttpMcpTransport.Builder().
url(mcpSseConfig.getUrl()).
logRequests(true).
build();
// 步骤2开启客户端连接
return new DefaultMcpClient.Builder()
.transport(httpMcpTransport)
.build();
}
/**
* 调用MCP服务智能体
* 使用统一的ToolProviderFactory获取所有已配置的工具BUILTIN + MCP
*
* @param userMessage 用户信息
* @param chatModelVo 模型信息
* @return 返回LLM信息
*/
protected String doAgent(String userMessage, ChatModelVo chatModelVo) {
// 判断是否开启MCP服务
if (!mcpSseConfig.isEnabled()) {
return "";
}
// 生成缓存键
String cacheKey = getCacheKey(chatModelVo);
// 尝试从缓存获取监督智能体
SupervisorAgent cachedSupervisor = supervisorCache.get(cacheKey);
if (cachedSupervisor != null) {
// 如果已存在缓存的监督智能体,直接使用
return cachedSupervisor.invoke(userMessage);
}
cacheLock.lock();
try {
// 双重检查,防止并发情况下的重复初始化
cachedSupervisor = supervisorCache.get(cacheKey);
if (cachedSupervisor != null) {
return cachedSupervisor.invoke(userMessage);
}
// 步骤1: 获取统一工具提供工厂
ToolProviderFactory toolProviderFactory = SpringUtils.getBean(ToolProviderFactory.class);
// 获取或初始化MCP客户端
McpClient mcpClient = mcpClientCache.computeIfAbsent(cacheKey, k -> initializeMcpClient());
// 步骤2: 获取 BUILTIN 工具对象
List<Object> builtinTools = toolProviderFactory.getAllBuiltinToolObjects();
// 步骤3将mcp对象包装
ToolProvider toolProvider = toolProviderCache.computeIfAbsent(cacheKey, k -> McpToolProvider.builder()
.mcpClients(List.of(mcpClient))
.build());
// 步骤3: 获取 MCP 工具提供者
ToolProvider mcpToolProvider = toolProviderFactory.getAllEnabledMcpToolsProvider();
// 步骤4加载LLM模型对话
log.info("doAgent: BUILTIN tools count = {}, MCP tools enabled = {}",
builtinTools.size(), mcpToolProvider != null);
// 步骤4: 加载LLM模型
QwenChatModel qwenChatModel = QwenChatModel.builder()
.apiKey(chatModelVo.getApiKey())
.modelName(chatModelVo.getModelName())
.build();
// 步骤5将MCP对象由智能体Agent管控
McpAgent mcpAgent = AgenticServices.agentBuilder(McpAgent.class)
.chatModel(qwenChatModel)
.toolProvider(toolProvider)
.build();
// 步骤5: 创建MCP Agent使用所有已配置的工具
// 使用 .tools() 传入 BUILTIN 工具对象Java 对象,带 @Tool 注解的方法)
// 使用 .toolProvider() 传入 MCP 工具提供者MCP 协议工具)
var agentBuilder = AgenticServices.agentBuilder(McpAgent.class)
.chatModel(qwenChatModel);
// 步骤6将所有MCP对象由超级智能体管控
// 添加 BUILTIN 工具(如果有)
if (!builtinTools.isEmpty()) {
agentBuilder.tools(builtinTools.toArray(new Object[0]));
log.debug("Added {} BUILTIN tools to agent", builtinTools.size());
}
// 添加 MCP 工具(如果有)
if (mcpToolProvider != null) {
agentBuilder.toolProvider(mcpToolProvider);
log.debug("Added MCP tool provider to agent");
}
McpAgent mcpAgent = agentBuilder.build();
// 步骤6: 创建超级智能体协调MCP Agent
SupervisorAgent supervisor = AgenticServices
.supervisorBuilder()
.chatModel(qwenChatModel)
@@ -186,10 +147,7 @@ public class QianWenChatServiceImpl extends AbstractStreamingChatService {
.responseStrategy(SupervisorResponseStrategy.LAST)
.build();
// 缓存监督智能体
supervisorCache.put(cacheKey, supervisor);
// 步骤7调用大模型LLM
// 步骤7: 调用大模型LLM
return supervisor.invoke(userMessage);
} finally {
cacheLock.unlock();