OSPP项目申请书
项目名称:基于 Spring Cloud Alibaba MCP 服务高效构建通用 AI 智能体
项目导师:牧生
申请人:王子元
邮箱:[email protected]

申请书目录

  1. 项目背景
    • 1.1 社区介绍
    • 1.2 课题介绍
  2. 技术方法及调研
    • 2.1 JManus 调研
    • 2.3 技术选型和项目需求
  3. 项目设计
    • 3.1 MCP 工具的注册
    • 3.2 MCP 工具的筛选增强
    • 3.3 动态开关 MCP 服务
  4. 项目开发时间规划
  5. 个人简介

1. 项目背景

1.1 社区介绍

2025年,AI 技术进入全面落地阶段,智能体(AI Agent)成为热门趋势。微软报告指出,到2025年AI 驱动的智能体将具有更高的自主性,能够在办公和生活中承担更多任务。

Spring AI Alibaba 是一款以 Spring AI 为基础,深度集成百炼平台,支持 ChatBot、工作流、多智能体应用开发模式的 AI 框架。在 1.0 版本中 Spring AI Alibaba 提供了 Graph 多智能体框架,集成了 AI 生态,探索具备自主规划能力的通用智能体产品与平台,让开发者可以快速构建自己的 Agent、Workflow 或 Multi-agent 应用。

目前社区已经实现了 JManus,DeepReSearch 等智能体应用。

1.2 课题介绍

项目背景
2025 年时 AI Agent 爆发的一年,Agent 需要依赖工具辅助完成任务,而 MCP(Model Context Protocol)为智能体与工具交互提供了标准协议。很多企业中有大量使用 Spring Cloud Alibaba 开发的业务系统,通过与 Spring AI Alibaba 社区合作共建的 MCP 解决方案,我们可以将 Spring Cloud 业务系统发布为 MCP 服务。

学生职责&目标
在这个项目中,学生将和社区一起共同探索开发一个通用 AI Agent,重点解决在面对大量 MCP 工具时,如何更有效、智能的过滤筛选 MCP 服务,帮助模型和 Agent 在运行过程中更好的选择 MCP 工具。

学生要求&技术栈
熟练掌握 Java 开发语言
熟悉 AI Agent 开发、MCP 等相关概念
了解 Spring AI、Langchain 等 AI 开发框架

该课题是让学生在 Spring AI Alibaba 的框架基础上设计一个类似 Manus 的通用智能体组件,开发一个通用 AI Agent。

重点解决在面对大量 MCP 工具时,如何更有效、智能的过滤筛选 MCP 服务,帮助模型和 Agent 在运行过程中更好的选择 MCP 工具

2. 技术选型及调研

2.1 JManus 调研

JManus 是一个典型的通用 AI agent 可以自主执行任务,无需用户持续的关注和干预即可完成复杂任务
工作原理图如下

在 Spring AI Aliabab 开源的 JManus 中配置了计划模版,并且可以创建自定义 agent ,但是在任务执行过程中 tools 的保存以及选择都可以进一步的进行优化,也是课题中需要实现的部分

2.2 技术选型和项目需求

  • 项目需求
    设计通用智能体框架,该框架可以在面对大量的 MCP 服务的时候可以有效,智能的筛选 MCP 服务,帮助模型在运行中更好的选择 MCP 服务。
    项目设计主要是在 JManus 基础上做的改变。

  • 技术选型

    • Java 17
    • Spring AI Alibaba
    • Spring Cloud Alibaba
    • Spring Boot

3. 项目设计

3.1 MCP 工具的注册

3.1.1 目前 JManus 中的实现

在目前 JManus 中,MCP 服务的注册是通过手动将带有 MCP 服务信息的 JSON 粘贴到可视化 web 控制台,并选择是 STDIO 或 SSE 模式的服务。

其中可视化的处理是通过 McpConfigRequestVO 对象把配置信息从前端传输到后端通过 Spring JPA 将数据存储到 H2 数据库中,实现持久化 MCP 服务配置的功能。

在执行计划的时候会将配置信息读取到本地缓存中,JManus 在创建计划阶段会判断是否需要调用工具来完成计划,要确保执行计划过程中可以调用正确的工具,需要在后台配置页面时正确的配置 MCP 服务的信息,并将 MCP 服务挂载到对应的 Agent 中。

流程图如下:
![[mcp.png]]

接受前端传输的MCP服务配置信息:

public class McpConfigRequestVO {  

/**
* 连接类型:STDIO, STREAMING, SSE
*/ private String connectionType;

/**
* MCP服务器配置的JSON字符串
*/
private String configJson;

public String getConnectionType() {
return connectionType;
}

public void setConnectionType(String connectionType) {
this.connectionType = connectionType;
}

public String getConfigJson() {
return configJson;
}

public void setConfigJson(String configJson) {
this.configJson = configJson;
}

}

MCP服务添加的具体代码在 McpService

public List<McpConfigEntity> insertOrupdateMcpRepo(McpConfigRequestVO mcpConfigVO) throws IOException {  
List<McpConfigEntity> entityList = new ArrayList<>();
try (JsonParser jsonParser = new ObjectMapper().createParser(mcpConfigVO.getConfigJson())) {
McpServersConfig mcpServerConfig = jsonParser.readValueAs(McpServersConfig.class);
String type = mcpConfigVO.getConnectionType();
McpConfigType mcpConfigType = McpConfigType.valueOf(type);
if (McpConfigType.STUDIO.equals(mcpConfigType)) {
// STDIO类型的连接需要特殊处理
mcpServerConfig.getMcpServers().forEach((name, config) -> {
if (config.getCommand() == null || config.getCommand().isEmpty()) {
throw new IllegalArgumentException(
"Missing required 'command' field in server configuration for " + name);
}
if (config.getUrl() != null && !config.getUrl().isEmpty()) {
throw new IllegalArgumentException(
"STUDIO type should not have 'url' field in server configuration for " + name);
}
});
}
else if (McpConfigType.SSE.equals(mcpConfigType)) {
// SSE类型的连接需要特殊处理
mcpServerConfig.getMcpServers().forEach((name, config) -> {
if (config.getUrl() == null || config.getUrl().isEmpty()) {
throw new IllegalArgumentException(
"Missing required 'url' field in server configuration for " + name);
}
if (config.getCommand() != null && !config.getCommand().isEmpty()) {
throw new IllegalArgumentException(
"SSE type should not have 'command' field in server configuration for " + name);
}
});
}
else if (McpConfigType.STREAMING.equals(mcpConfigType)) {
throw new UnsupportedOperationException("STREAMING connection type is not supported yet");
}

// 迭代处理每个MCP服务器配置
for (Map.Entry<String, McpServerConfig> entry : mcpServerConfig.getMcpServers().entrySet()) {
String serverName = entry.getKey();
McpServerConfig serverConfig = entry.getValue();

// 使用ServerConfig的toJson方法将配置转换为JSON字符串
String configJson = serverConfig.toJson();

// 查找对应的MCP配置实体
McpConfigEntity mcpConfigEntity = mcpConfigRepository.findByMcpServerName(serverName);
if (mcpConfigEntity == null) {
mcpConfigEntity = new McpConfigEntity();
mcpConfigEntity.setConnectionConfig(configJson);
mcpConfigEntity.setMcpServerName(serverName);
mcpConfigEntity.setConnectionType(mcpConfigType);
}
else {
mcpConfigEntity.setConnectionConfig(configJson);
mcpConfigEntity.setConnectionType(mcpConfigType);
}
McpConfigEntity entity = mcpConfigRepository.save(mcpConfigEntity);
entityList.add(entity);
logger.info("MCP server '{}' has been saved to database.", serverName);

}
}
return entityList;

}

3.1.2 根据课题的改动方案

目前 JManus 中的服务的注册方式是通过接受前端传输的配置进行本地存储,需要的时候读取到缓存 (Guava Cache) 中,再从缓存中进行筛选。

而默认的配置方式是 MCP 服务注册之后,默认放到 DEFAULT_AGENT 中,如果注册的 Tool 的数量过多,对上下文有压力,多出来的 Tool 会被忽略,这样就必须创建新的agent,手动的进行添加。
并且本地 Guava 缓存存储的内存大小有限制,会出现性能问题。

这里的改进思路是可以使用外部的向量数据库(如 Milvus , Weaviate , Pinecone 等)存储 MCP 服务的元数据信息。在后续过程中创建一个与向量数据库交互的 Agent 作为协作过程中的 Tools Agent,并且这样在筛选 MCP 服务的时候可以做到语义级检索。

3.2 MCP 工具的筛选增强

3.2.1 JManus 中的 MCP 工具筛选

在 JManus 中具体的在执行计划时,会在计划创建阶段, PlanCreator 类里面遍历存储 DynamicAgentEntity 的列表,构建可用的 AgentInfo 信息,将 Agent 的信息注入到计划的创建中,对应的 Agent 在执行计划的时候,便会根据计划的上下文,选择可用的 MCP 服务

在这个流程图中也给出了调用的过程

![[mcp 1.png]]

创建计划的代码

public void createPlan(ExecutionContext context) {  

String planId = context.getPlanId();
if (planId == null || planId.isEmpty()) {
throw new IllegalArgumentException("Plan ID cannot be null or empty");
}
try {
// 构建代理信息
String agentsInfo = buildAgentsInfo(agents);
ExecutionPlan currentPlan = null;
// 生成计划提示
String planPrompt = generatePlanPrompt(context.getUserRequest(), agentsInfo, planId);

// 使用 LLM 生成计划
PromptTemplate promptTemplate = new PromptTemplate(planPrompt);
Prompt prompt = promptTemplate.create();

ChatClient.CallResponseSpec response = llmService.getPlanningChatClient()
.prompt(prompt)
.toolCallbacks(List.of(planningTool.getFunctionToolCallback()))
.advisors(memoryAdvisor -> memoryAdvisor.param("chat_memory_conversation_id", planId)
.param("chat_memory_retrieve_size", 100))
.call();
String outputText = response.chatResponse().getResult().getOutput().getText();
// 检查计划是否创建成功
if (planId.equals(planningTool.getCurrentPlanId())) {
currentPlan = planningTool.getCurrentPlan();
log.info("Plan created successfully: {}", currentPlan);
currentPlan.setPlanningThinking(outputText);
}
context.setPlan(currentPlan);

}
catch (Exception e) {
log.error("Error creating plan for request: {}", context.getUserRequest(), e);
// 处理异常情况
throw new RuntimeException("Failed to create plan", e);
}
}

读取 Agent 信息的代码:

private String buildAgentsInfo(List<DynamicAgentEntity> agents) {  
StringBuilder agentsInfo = new StringBuilder("Available Agents:\n");
for (DynamicAgentEntity agent : agents) {
agentsInfo.append("- Agent Name: ")
.append(agent.getAgentName())
.append("\n Description: ")
.append(agent.getAgentDescription())
.append("\n");
}
return agentsInfo.toString();
}

3.2.2 根据课题的改动方案

在第一部分 MCP 工具注册的部分提到可以通过向量数据库的方式存储 MCP 工具的元数据信息,这里可以通过类似 Multi-agent 的执行模式来增强 MCP 工具筛选的功能

创建一个智能体负责 MCP 服务的检索(类似 RAG ),而负责执行计划的智能体在需要调用 MCP 服务的时候与负责执行计划的智能体进行交互,返回给负责执行的智能体传输需要实现的。

并且将原来系统中集成的 Guava 作为本地缓存缓存热点 MCP 服务,加快大模型执行计划的速度。

组件选型

组件 描述
Embedding 模型 text-embedding-v1(阿里云百炼平台)
向量数据库 Milvus 或者选用阿里百炼平台的百炼知识库作为向量数据库
Agent 路由器 起到 rag 功能的 agent 用做工具筛选
缓存机制 Guava Cache 保留作为热数据缓存

3.3 动态开关 MCP 服务

3.3.1 在 JManus 中的 MCP 服务动态管理

在 JManus 中 MCP 服务的动态开关主要实现是在配置 Agent 的过程里,可以通过选取是否添加某些MCP 工具 实现开关 MCP 服务

左下角的工具调用列表里:

3.3.2 根据课题的改动方案

在前两个模块中项目设计的想法是把 MCP 服务的元数据信息存储到向量数据库中,通过语义检索的方式筛选 MCP 服务

这样如果涉及到要开关 MCP 服务,主要就变成了对向量数据库中结构化的 metadata 数据进行更新

比如:

{
"id": "baidu-map",
"vector": [...],
"payload": {
"enabled": true,
"description": "百度地图服务,用于路径规划",
"category": "location"
}
}

更新 enabled 字段,在负责进行语义检索的 Agent 中进行限制,过滤掉 enabled = flase 的结果

4. 项目开发时间规划

阶段 时间 具体规划
第一阶段 2025.7.1-2025.7.15 主要进行 MCP 服务注册方面后端代码的改动
第二阶段 2025.7.16-2025.7.30 主要进行 MCP 服务选择增强方面后端代码的改动
第三阶段 2025.8.1-2025.8.15 主要进行 MCP 服务开关方面的改动
第四阶段 2025.8.16-2025.8.30 进行前端代码的改动,撰写文档

5. 个人简介

我叫王子元,这是我的 github主页链接 ,我的主要技术栈为 java 和 go,独立做过一些简单的微服务项目开发,了解 web 应用开发流程。对 AI 开发领域有浓厚的兴趣,目前是 Spring AI Alibaba 社区的贡献者,在技术学习中始终信奉技术人文主义,相信技术最后的目的是促进社会的发展。

在开源贡献方面:

  • 在隐语社区的 kuscia 项目进行了初次贡献,主要完成了 pkg/web 模块的单测覆盖
  • 在 Apache EventMesh 社区为自动保存日志的工具类编写了单元测试
  • 在 Spring AI alibaba 社区
    1,参与了社区 Spring AI Graph 中预定义节点的编写
    2,参与了社区 toolCallBack 插件的重构工作
    3,参与了社区 Spring AI Alibaba 1.0.0 版本的适配工作
    4,对 example 仓库的使用案例进行完善
    5,完善了 dashscope image 模型的可观测完善,并编写了对应的 example
    6,参与了官网文档的编写工作

最后衷心的希望可以参与社区的这次课题。