基于Spring AI构建MCP应用:从架构设计到实战开发

一、项目架构与核心组件设计

MCP应用的核心目标是将大模型能力封装为标准化服务接口,实现模型推理、上下文管理、流量控制等功能的模块化设计。典型项目结构包含服务端(MCP Server)和客户端(MCP Client)两大核心模块:

  1. 服务端工程结构

    1. mcp-server/
    2. ├── src/main/java/
    3. ├── config/ # 配置类(Bean初始化、模型加载)
    4. ├── service/ # 核心业务逻辑(推理服务、上下文管理)
    5. └── controller/ # REST API接口(模型调用、健康检查)
    6. └── src/main/resources/
    7. ├── application.yml # 服务配置(模型路径、端口、超时设置)
    8. └── logback.xml # 日志配置
  2. 客户端工程结构

    1. mcp-client/
    2. ├── src/main/java/
    3. ├── config/ # 客户端自动配置(RestTemplate/WebClient)
    4. └── controller/ # 业务控制器(调用MCP服务)
    5. └── src/main/resources/
    6. └── application.yml # 客户端配置(服务地址、重试策略)

关键设计原则:

  • 解耦原则:服务端与客户端通过REST协议通信,避免强依赖
  • 标准化接口:统一采用/v1/models/{modelId}/predict路径规范
  • 上下文管理:通过Session ID实现多轮对话状态跟踪
  • 流量控制:服务端集成令牌桶算法实现QPS限制

二、服务端核心实现

1. 模型推理服务实现

  1. @Service
  2. public class ModelInferenceService {
  3. @Value("${model.path}")
  4. private String modelPath;
  5. private Predictor predictor; // 模型推理引擎抽象接口
  6. @PostConstruct
  7. public void init() {
  8. // 动态加载模型(支持热更新)
  9. this.predictor = ModelLoader.load(modelPath);
  10. }
  11. public InferenceResult predict(InferenceRequest request) {
  12. // 1. 参数校验
  13. validateRequest(request);
  14. // 2. 上下文注入(多轮对话场景)
  15. Context context = contextManager.get(request.getSessionId());
  16. // 3. 模型推理
  17. Map<String, Object> inputs = buildModelInputs(request, context);
  18. Map<String, Object> outputs = predictor.predict(inputs);
  19. // 4. 结果后处理
  20. return convertToResult(outputs);
  21. }
  22. }

关键实现细节:

  • 模型热加载:通过@PostConstruct和文件监听机制实现模型无感更新
  • 输入预处理:支持JSON/Protobuf等多种格式的请求体转换
  • 输出后处理:自动提取模型输出中的关键字段并标准化

2. 上下文管理模块

  1. @Component
  2. public class ContextManager {
  3. private final ConcurrentHashMap<String, Context> contextStore =
  4. new ConcurrentHashMap<>();
  5. private final ScheduledExecutorService cleaner =
  6. Executors.newScheduledThreadPool(1);
  7. public ContextManager() {
  8. // 定时清理过期上下文(TTL=30分钟)
  9. cleaner.scheduleAtFixedRate(this::cleanExpired,
  10. 10, 10, TimeUnit.MINUTES);
  11. }
  12. public Context get(String sessionId) {
  13. return contextStore.computeIfAbsent(sessionId,
  14. k -> new Context(k, System.currentTimeMillis()));
  15. }
  16. private void cleanExpired() {
  17. long now = System.currentTimeMillis();
  18. contextStore.entrySet().removeIf(e ->
  19. now - e.getValue().getCreateTime() > 1800_000);
  20. }
  21. }

三、客户端开发实践

1. 自动配置类实现

  1. @Configuration
  2. public class McpClientAutoConfiguration {
  3. @Bean
  4. @ConditionalOnMissingBean
  5. public WebClient mcpWebClient(
  6. @Value("${mcp.server.url}") String baseUrl) {
  7. return WebClient.builder()
  8. .baseUrl(baseUrl)
  9. .defaultHeader(HttpHeaders.CONTENT_TYPE,
  10. MediaType.APPLICATION_JSON_VALUE)
  11. .clientConnector(new ReactorClientHttpConnector(
  12. HttpClient.create()
  13. .responseTimeout(Duration.ofSeconds(30))))
  14. .build();
  15. }
  16. }

2. 业务调用示例

  1. @RestController
  2. @RequestMapping("/api/chat")
  3. public class ChatController {
  4. @Autowired
  5. private WebClient mcpClient;
  6. @PostMapping
  7. public ResponseEntity<ChatResponse> chat(
  8. @RequestBody ChatRequest request) {
  9. // 构建MCP请求体
  10. McpRequest mcpRequest = new McpRequest();
  11. mcpRequest.setModelId("chat-llama-7b");
  12. mcpRequest.setInputs(request.getMessages());
  13. mcpRequest.setSessionId(request.getSessionId());
  14. // 调用MCP服务
  15. McpResponse response = mcpClient.post()
  16. .uri("/v1/models/{modelId}/predict",
  17. mcpRequest.getModelId())
  18. .bodyValue(mcpRequest)
  19. .retrieve()
  20. .bodyToMono(McpResponse.class)
  21. .block();
  22. // 结果转换
  23. return ResponseEntity.ok(convertResponse(response));
  24. }
  25. }

四、高级功能扩展

1. 流量控制实现

  1. @RestControllerAdvice
  2. public class RateLimitInterceptor implements HandlerInterceptor {
  3. private final RateLimiter rateLimiter =
  4. RateLimiter.create(100.0); // 100 QPS
  5. @Override
  6. public boolean preHandle(HttpServletRequest request,
  7. HttpServletResponse response, Object handler) {
  8. if (!rateLimiter.tryAcquire()) {
  9. response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
  10. return false;
  11. }
  12. return true;
  13. }
  14. }

2. 监控指标集成

  1. # application.yml 配置示例
  2. management:
  3. metrics:
  4. export:
  5. prometheus:
  6. enabled: true
  7. endpoints:
  8. web:
  9. exposure:
  10. include: health,metrics,prometheus

关键监控指标:

  • 模型推理耗时(histogram)
  • 请求成功率(gauge)
  • 上下文存储大小(gauge)
  • 流量控制拒绝次数(counter)

五、部署与优化建议

  1. 容器化部署

    1. FROM eclipse-temurin:17-jre-jammy
    2. COPY target/mcp-server.jar /app.jar
    3. EXPOSE 8080
    4. ENTRYPOINT ["java", "-jar", "/app.jar"]
  2. 性能优化策略

  • 模型量化:将FP32模型转换为INT8减少内存占用
  • 批处理推理:合并多个请求实现矩阵运算加速
  • 缓存机制:对高频请求结果进行本地缓存
  • 异步处理:非实时请求采用消息队列异步处理
  1. 安全加固方案
  • API鉴权:集成JWT或OAuth2.0认证
  • 输入过滤:防止Prompt注入攻击
  • 审计日志:记录所有模型调用行为
  • 数据脱敏:敏感信息自动屏蔽处理

六、总结与展望

通过Spring AI框架构建MCP应用,开发者可以快速实现大模型能力的标准化封装。本文介绍的架构设计兼顾了灵活性与可扩展性,通过模块化设计支持多种模型格式和推理引擎的集成。未来发展方向包括:

  1. 支持多模态模型(图像/语音/视频)的统一服务接口
  2. 集成模型解释性功能,提供推理过程可视化
  3. 开发管理控制台,实现模型生命周期的图形化管理
  4. 探索Serverless架构下的自动扩缩容方案

完整项目代码已开源至某托管仓库,包含详细的开发文档和测试用例,建议开发者结合实际业务场景进行定制化开发。