在人工智能(AI)技术,特别是大型语言模型(LLM)迅猛发展的今天,将 AI 能力无缝、高效、可维护地集成到企业级应用中已成为开发者的核心诉求。Java 作为企业级开发的基石,其生态系统也在积极拥抱这一变革。Spring AIMCP (Model Context Protocol) 正是这一浪潮中的两个关键推动力。Spring AI 提供了优雅的抽象层,而 MCP 则为复杂 AI 交互定义了清晰的通信标准。本文将深入探讨这两者,分析它们如何协同工作,以及如何利用它们构建强大的 AI 增强型 Spring Boot 应用。

1. 引言:AI 集成的挑战与机遇

将 LLM 集成到传统应用中并非易事。开发者面临诸多挑战:

  • API 碎片化: OpenAI, Anthropic, Google, Mistral, 本地部署模型等,每个提供商都有其独特的 API。
  • 提示工程复杂性: 构建有效的提示(Prompt)、处理上下文、管理对话历史、进行函数调用(Function Calling / Tool Calling)等需要大量样板代码。
  • 结果解析: 将 LLM 的非结构化输出(文本、JSON)可靠地解析成应用内部数据结构。
  • 可移植性与测试: 代码与特定模型强耦合,难以切换模型或进行单元/集成测试。
  • 上下文管理: 在多轮对话或复杂工作流中,有效管理与模型交互的上下文信息。

Spring AI 的诞生正是为了解决这些痛点。它借鉴了 Spring 生态系统中成功的抽象模式(如 Spring Data, Spring Security),为 AI 提供了一套统一、简洁、可扩展的 API。而 MCP 则更进一步,它定义了一个协议,旨在标准化 AI 模型与外部工具/系统之间的交互方式,特别是在涉及工具调用(Tool Use)和上下文传递的场景中。

2. 深入理解 Spring AI

Spring AI 是一个由 Pivotal(现 VMware Tanzu)发起的开源项目,目标是让 Java 和 JVM 开发者能够轻松地将 AI 能力集成到 Spring 应用中。它不是一个模型本身,而是一个抽象层集成框架

核心理念:

  • 抽象化: 提供 ChatClient, EmbeddingClient 等接口,屏蔽底层模型提供商(如 OpenAI, Azure AI, Google Vertex AI, Hugging Face, Ollama 等)的具体实现细节。
  • 约定优于配置: 提供合理的默认值,简化配置。
  • Spring 风格: 充分利用 Spring Boot 的自动配置、依赖注入(DI)、条件化配置等特性。
  • 可扩展性: 通过 SPI (Service Provider Interface) 支持轻松添加新的模型提供商。

核心组件与 API:

  1. ChatClient 这是与 LLM 进行对话的核心接口。它抽象了发送消息、接收响应的过程。

    • prompt() 方法: 接收一个 Prompt 对象,该对象封装了消息列表(Message)和可选的请求选项(Options,如温度、最大生成长度等)。
    • Message 类型: 代表对话中的不同角色消息:
      • UserMessage: 用户输入。
      • AssistantMessage: 模型的回复。
      • SystemMessage: 系统指令,用于设定模型行为、角色、格式等(至关重要!)。
    • Response 对象: 包含模型的回复(Data)、元数据(如使用的 Token 数、模型名称)、以及可能的 ToolCall 信息。

    示例:

    @Service
    public class SimpleChatService {
    
        private final ChatClient chatClient;
    
        public SimpleChatService(ChatClient.Builder chatClientBuilder) {
            // 使用 Builder 构建,可以配置选项
            this.chatClient = chatClientBuilder
                .defaultSystem("你是一个乐于助人的助手。")
                .defaultAdvisoryOptions(options -> options.withTemperature(0.7))
                .build();
        }
    
        public String askQuestion(String userQuestion) {
            // 直接使用字符串(会被包装成 UserMessage)
            return chatClient.prompt(userQuestion).call().getResult().getOutput().getContent();
        }
    
        public String askWithCustomSystem(String userQuestion, String systemPrompt) {
            Prompt prompt = new Prompt(
                List.of(
                    new SystemMessage(systemPrompt),
                    new UserMessage(userQuestion)
                ),
                PromptOptions.builder()
                    .withModel("gpt-4-turbo") // 覆盖默认模型
                    .build()
            );
            return chatClient.call(prompt).getResult().getOutput().getContent();
        }
    }
    
  2. PromptOptions 用于配置特定请求的参数,如 model(指定模型)、temperature, maxTokens, topP, frequencyPenalty, presencePenalty 等。ChatClient.Builder 允许设置全局默认值。

  3. Function Calling / Tool Calling Spring AI 支持让 LLM 调用预定义的 Java 方法(工具)。这是实现 AI Agent 能力的关键。

    • 定义一个 POJO 或带有 @Bean 的类,其方法用 @Tool 注解标记。
    • Spring AI 会自动将这些方法注册为 LLM 可用的工具,并生成符合模型要求的 Function/Tool 描述(Schema)。
    • 当 LLM 决定调用工具时,ChatClient 会解析 ToolCall 请求,执行对应的 Java 方法,并将结果返回给 LLM 继续生成最终回复。

    示例(天气工具):

    @Component // 或 @Service
    public class WeatherService {
    
        @Tool(description = "根据城市名称获取当前天气信息")
        public String getCurrentWeather(String cityName) {
            // 调用真实的天气 API
            WeatherData data = weatherApiClient.getWeather(cityName);
            return String.format("城市 %s 的天气是 %s, 温度 %.1f°C",
                                data.getCity(), data.getCondition(), data.getTemperature());
        }
    }
    

    ChatClient 配置中启用工具调用(通常通过 ChatModel 实现类的配置)。

  4. EmbeddingClient 用于生成文本的向量嵌入(Embeddings),是实现语义搜索、文本相似度计算等功能的基础。

    @Service
    public class EmbeddingService {
        private final EmbeddingClient embeddingClient;
    
        public EmbeddingService(EmbeddingClient embeddingClient) {
            this.embeddingClient = embeddingClient;
        }
    
        public List<Double> embedText(String text) {
            return embeddingClient.embed(text);
        }
    }
    
  5. 自动配置与依赖: Spring AI 提供了 spring-ai-openai-spring-boot-starter 等 starter 依赖。引入后,只需在 application.yml 中配置 API Key 和基础 URL,ChatClientEmbeddingClient 的 Bean 就会自动创建。

    # application.yml
    spring:
      ai:
        openai:
          api-key: your-openai-api-key-here
          # base-url: https://api.openai.com/v1 # 可选,用于非官方端点
    
3. 揭秘 MCP (Model Context Protocol)

MCP 是一个相对较新但极具潜力的概念,它由 Anthropic 等公司推动,旨在解决 AI Agent 与外部世界交互的标准化问题。你可以将 MCP 理解为 “AI Agent 的通用语言”

核心思想:

  • 标准化通信: 定义一个清晰、结构化的 JSON 格式协议,用于在 LLM 运行时(如 Anthropic’s Claude)和外部工具/系统之间传递信息。
  • 关注上下文: 协议的核心是传递上下文——不仅仅是工具调用的请求和响应,还包括对话历史、元数据、状态信息等,确保交互的连贯性和一致性。
  • 双向流式通信: 支持流式传输,允许工具在执行过程中逐步返回信息(如进度、中间结果),LLM 也可以流式生成调用请求。
  • 解耦: 工具实现(Tool Implementation)与 LLM 的决策逻辑(Orchestrator)通过 MCP 协议进行通信,实现松耦合。

MCP 的关键组成部分:

  1. mcp-server 这是一个独立的、可执行的进程或服务,它实现了特定的工具集(如数据库查询、文件操作、API 调用、代码执行等)。它监听来自 LLM 运行时的 MCP 消息。
  2. mcp-client 这是 LLM 运行时(或其代理)的一部分,负责将 LLM 生成的工具调用请求序列化为 MCP 消息,并发送给 mcp-server;同时接收 mcp-server 的响应并反序列化,将结果传递回 LLM。
  3. mcp-spec 定义了消息格式的规范。核心消息类型包括:
    • request: 从客户端发送到服务器的调用请求。
    • response: 从服务器发送回客户端的调用结果。
    • notification: 服务器向客户端发送的异步通知(如日志、进度更新)。
    • error: 传输过程中的错误信息。
  4. mcp-tool 一个工具的定义,包含其名称、描述、输入/输出 Schema (通常用 JSON Schema 描述)。

MCP 的工作流程:

  1. 用户向 LLM 提出一个需要外部工具的问题(如 “查询我账户的最新三笔交易”)。
  2. LLM 分析问题,决定需要调用 get_account_transactions 工具。
  3. LLM 运行时(通过 mcp-client)生成一个符合 MCP 规范的 request 消息,内容类似:
    {
      "type": "request",
      "id": "req-123",
      "method": "get_account_transactions",
      "arguments": { "account_id": "acc_456", "limit": 3 }
    }
    
  4. mcp-client 通过标准传输(如 stdin/stdout, HTTP, gRPC)将此消息发送给 mcp-server
  5. mcp-server 解析消息,调用其内部实现的 get_account_transactions 方法。
  6. mcp-server 执行操作(可能涉及数据库查询),获取结果。
  7. mcp-server 生成一个 MCP response 消息:
    {
      "type": "response",
      "id": "req-123", // 关联回请求
      "result": [
        {"id": "tx_789", "amount": 99.99, "date": "2025-07-30", "desc": "Online Purchase"},
        ... // 其他两笔交易
      ]
    }
    
  8. mcp-server 将响应发送回 mcp-client
  9. mcp-client 将响应结果(result 字段的内容)以自然语言或结构化数据的形式,注入到 LLM 的下一个输入上下文中。
  10. LLM 结合原始问题、系统指令和工具返回的结果,生成最终的人类可读回复:"您账户的最新三笔交易是:1. 7 月 30 日在线购买 99.99 元;2. … "。

MCP 的优势:

  • 标准化: 不再需要为每个模型提供商或每个工具编写特定的适配器。
  • 安全性: 工具在独立的 mcp-server 中运行,与 LLM 运行时隔离,降低了风险(如代码注入攻击)。
  • 可组合性: 可以轻松地将多个 mcp-server(每个提供不同工具集)连接到同一个 LLM 运行时。
  • 可观察性: MCP 消息流(notification)提供了强大的调试和监控能力。
  • 流式支持: 支持长耗时操作的进度反馈。
4. Spring AI 与 MCP:协同增效

Spring AI 和 MCP 并非竞争关系,而是互补的。它们在不同的层次上发挥作用,共同构建更强大、更标准化的 AI 应用生态。

  • Spring AI 的定位: 应用层集成框架。它让 Java 开发者在 Spring Boot 应用内部,以声明式、类型安全的方式与 LLM 交互。它处理了与特定云服务商 API 的对接、提示管理、结果解析、简单的工具调用(在 JVM 内部)等。
  • MCP 的定位: 运行时/代理层通信协议。它定义了 LLM 核心(或其代理)与外部工具执行环境(mcp-server)之间的标准化通信管道。它关注的是跨进程、跨网络、跨信任边界的交互。

它们如何协同工作?

想象一个更复杂的场景:你的 Spring Boot 应用需要一个强大的 AI Agent,该 Agent 需要调用多种外部服务(数据库、内部 API、甚至执行代码片段)。

  1. 场景一(MCP 作为 Spring AI 的后端):

    • 你可以在你的 Spring Boot 应用中启动一个或多个 mcp-server 进程(例如,用 Python, Go 或 Node.js 编写,利用其生态优势)。
    • Spring AI 的 ChatModel 实现(比如一个自定义的 AnthropicChatModel)可以被配置为使用 MCP 作为其与工具交互的机制。
    • 当 Spring AI 的 ChatClient 检测到 LLM 需要调用工具时,它(作为 mcp-client)会通过 MCP 协议将调用请求发送给本地或远程的 mcp-server
    • mcp-server 执行工具逻辑,通过 MCP 返回结果。
    • Spring AI 接收结果,将其整合,继续与 LLM 对话。
    • 优势: Spring Boot 应用利用 Spring AI 的便捷 API,同时通过 MCP 获得了与外部工具安全、标准化交互的能力,特别是当工具用非 Java 语言编写时。
  2. 场景二(Spring AI 应用消费 MCP 服务):

    • 你的组织可能已经部署了通用的 mcp-server 集群,提供如 “文档搜索”、“数据分析”、“审批流程” 等标准工具。
    • 你的 Spring Boot 应用(通过 Spring AI 或其他方式)可以作为一个智能前端,接收用户请求。
    • 当需要调用这些标准工具时,Spring Boot 应用内的组件可以直接作为 mcp-client,与组织的 mcp-server 通信,获取结果,然后可能再将结果送回 LLM 进行最终回复生成或直接返回给用户。
    • 优势: 服务复用,标准化接口,安全隔离。
  3. 场景三(混合模式):

    • 应用内部一些简单的、安全的工具调用(如格式化日期、查询内存缓存)直接用 Spring AI 的 @Tool 注解在 JVM 内执行。
    • 对于涉及敏感数据、复杂计算或需要特定语言库的工具,则通过 MCP 协议调用外部的 mcp-server
    • 优势: 性能与安全性的平衡。
5. 实践:构建一个 Spring AI + MCP 增强的应用(概念性示例)

由于 MCP 生态仍在发展中,直接在 Spring Boot 中集成 MCP 的成熟库可能有限。但我们可以勾勒一个概念性架构。

目标: 创建一个 AI 助手,能回答关于公司销售数据的问题,需要查询数据库。

架构:

  1. Spring Boot 应用 (spring-ai-app):
    • 依赖 spring-ai-openai-spring-boot-starter
    • 配置 ChatClient
    • 实现一个服务,能发起 MCP 请求(可能需要一个 MCP 客户端库或自己实现基础通信)。
  2. MCP Server (sales-data-mcp-server): (用 Python 为例,利用 pandas, sqlalchemy)
    • 实现 mcp-server,监听 stdin/stdout。
    • 提供 query_sales_data 工具,接收查询参数(如时间范围、产品线),连接数据库执行查询,返回结果。
    • 使用 mcp Python 库(如果存在)或手动处理 MCP 消息。
  3. 通信: spring-ai-app 启动 sales-data-mcp-server 进程(或连接到已运行的实例),通过进程间通信(IPC)或网络(HTTP/gRPC)使用 MCP 协议交互。

Spring Boot 侧伪代码:

@Service
public class SalesAssistantService {

    private final ChatClient chatClient;
    private final MpcClient mpcClient; // 假设存在或自实现的 MCP 客户端

    public SalesAssistantService(ChatClient chatClient, MpcClient mpcClient) {
        this.chatClient = chatClient;
        this.mpcClient = mpcClient;
    }

    public String answerSalesQuestion(String question) {
        // 1. 让 LLM 决定是否需要查询数据
        Prompt decisionPrompt = new Prompt(
            List.of(
                new SystemMessage("判断用户问题是否需要查询销售数据库。如果需要,回复 'NEED_QUERY: <查询参数>';如果不需要,回复 'NO_QUERY: <直接回答>'。"),
                new UserMessage(question)
            )
        );
        String decision = chatClient.call(decisionPrompt).getResult().getOutput().getContent();

        if (decision.startsWith("NEED_QUERY:")) {
            String queryArgs = extractQueryArgs(decision); // 解析参数
            // 2. 通过 MCP 调用外部工具
            MpcResponse mpcResponse = mpcClient.call("query_sales_data", queryArgs);
            if (mpcResponse.isSuccess()) {
                Object queryResult = mpcResponse.getResult(); // 从 MCP 响应中获取数据
                // 3. 将查询结果和原始问题一起交给 LLM 生成最终回答
                Prompt finalPrompt = new Prompt(
                    List.of(
                        new SystemMessage("根据以下销售数据,用中文清晰地回答用户的问题。"),
                        new UserMessage("用户问题:" + question + "\n\n查询结果:" + queryResult.toString())
                    )
                );
                return chatClient.call(finalPrompt).getResult().getOutput().getContent();
            } else {
                return "抱歉,查询数据时出错:" + mpcResponse.getError();
            }
        } else if (decision.startsWith("NO_QUERY:")) {
            return extractAnswer(decision);
        } else {
            return "无法理解您的问题。";
        }
    }
}

MCP Server 侧 (Python) 伪代码:

# sales_data_mcp_server.py
import sys
import json
from mcp import Server, StdioServerTransport # 假设存在 mcp 库
import database_query # 你的数据库查询逻辑

server = Server(transport=StdioServerTransport())

@server.tool("query_sales_data")
def query_sales_data(time_range: str, product_line: str = None):
    """查询销售数据"""
    try:
        result = database_query.execute(time_range, product_line)
        return result # 返回字典或列表
    except Exception as e:
        raise Exception(f"Query failed: {str(e)}")

# 启动服务器,监听 stdin/stdout
server.run()
6. 挑战与未来展望
  • MCP 生态成熟度: MCP 规范仍在演进,成熟的客户端/服务器库(尤其在 JVM 生态)可能还不丰富,需要更多社区投入。
  • 性能开销: 进程间或网络通信会带来延迟,对于简单工具,JVM 内调用(Spring AI @Tool)可能更高效。
  • 错误处理与重试: 需要完善的机制处理 MCP 通信失败、工具执行失败等情况。
  • 认证与授权: MCP 通信的安全性(如 mTLS, API Key)需要仔细设计。
  • 调试复杂性: 调试跨越多个进程和协议的 AI 工作流更具挑战性。

未来展望:

  • Spring AI 内建 MCP 支持: 未来 Spring AI 可能会提供原生的 McpChatModel 或相关模块,简化集成。
  • 标准化工具市场: 基于 MCP 的通用工具市场可能出现,方便复用。
  • 更智能的 Agent 框架: 结合 Spring AI 的易用性和 MCP 的强大通信能力,会出现更复杂的、能自主规划、多步执行的 AI Agent 框架。
  • 与 Spring 生态深度整合: MCP 工具可以轻松访问 Spring Data JPA, Spring Security, Spring Cloud 等。
7. 结论

Spring AI 和 MCP 代表了 AI 集成的两个重要方向:应用层的简化运行时的标准化

  • Spring AI 是 Java 开发者拥抱 AI 的最佳起点。它极大地降低了门槛,让你能快速在 Spring Boot 应用中添加聊天、文本生成、嵌入等功能,并通过 @Tool 实现基本的 AI Agent 能力。
  • MCP 则着眼于构建更安全、更强大、更可扩展的 AI Agent 生态系统。它通过定义清晰的协议,解决了工具调用的标准化和安全隔离问题,为复杂、企业级的 AI 应用铺平了道路。

最佳实践建议:

  1. 从 Spring AI 开始: 对于大多数 Java 项目,优先使用 Spring AI 来集成 LLM。它成熟、文档丰富、社区活跃。
  2. 评估 MCP 需求: 如果你的应用需要:
    • 调用大量用非 Java 编写的工具。
    • 需要严格的安全隔离(如执行不受信任的代码)。
    • 希望构建可复用的、标准化的工具服务供多个 AI 应用使用。
    • 需要强大的流式进度反馈和可观测性。
      那么,探索 MCP 集成是值得的。
  3. 关注演进: 密切关注 Spring AI 和 MCP 项目的发展。它们的融合将催生下一代企业级 AI 应用。

Spring AI 为你提供了在 Java 世界中驾驭 AI 的“方向盘”和“油门”,而 MCP 则在构建一个更广阔、更互联的“AI 高速公路”。掌握这两者,你将能更自信地驶向智能化应用的未来。


参考资料:

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐