官方文档 -> https://springdoc.cn/spring-ai/ 

(deepseek也可以用openai sdk,但是没有embedding模型)

(网上代码版本问题老多了,还是看官网来得快)

目录

1、SpringAI-RAG

2、SpringAI-MCP

1、MCP调用

1、工程环境配置

2、客户端装配调用

2、MCP服务搭建

1、工程基本配置

2、MCP服务编写

3、注册Bean

4、打包部署

3、AiAgent组装

1.大模型自定义:

2.MCP工具自定义组装

3.知识库自定义组装

4.完整示例

踩坑总结:

1.版本问题

2.多模型源配置问题


1、SpringAI-RAG

1、总工程通过引入ai包管理版本

Spring AI 物料清单(BOM)声明了指定版本所有依赖的推荐版本。此为纯 BOM 版本,仅包含依赖管理,不涉及插件声明或 Spring/Spring Boot 的直接引用。可使用 Spring Boot Parent POM 或 Spring Boot 的 BOM(spring-boot-dependencies)来管理 Spring Boot 版本。

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-bom</artifactId>
    <version>1.0.0</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

2、根据是使用ollama自配模型(ollama)还是API接口模型(openai)还是qianwen等等,引入对应的包。

<!-- spring ai v1.0.0 start -->
# opendi模型starter
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
​
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-vector-store-pgvector</artifactId>
</dependency>
​
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-client-webflux</artifactId>
</dependency>
​
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-tika-document-reader</artifactId>
</dependency>
# ollama模型starter
<dependency>
   <groupId>org.springframework.ai</groupId>
   <artifactId>spring-ai-starter-model-ollama</artifactId>
</dependency>
spring:
  ai:
    openai:
      api-key: sk-6c5de8d7e46845d79c348a556ce16b41
      base-url: https://api.deepseek.com
      chat:
        options:
          model: deepseek-chat #还可以选择 deepseek-reasoner,深度思考模型
    ollama:
      base-url: http://117.72.57.125:11434
      embedding:
        options:
          num-batch: 512
        model: nomic-embed-text
    mcp:
      client:
        request-timeout: 360s
        sse:
          connections:
            mcp-server-csdn:
              url: http://117.72.57.125:8103
            mcp-server-weixin:
              url: http://117.72.57.125:8102
            mcp-server-talk:
              url: http://117.72.57.125:8101

首先通过OpenAiApi/OllamaAPi来定义调用的模型基本信息,然后通过OpenAiChatModel/OllamaChatModel包装OpenAiApi/OllamaAPi,最后通过model包装ChatCLient。通过ChatCLient调用对话接口。(也不用写OpenAiApi、OpenAiChatModel,可以自动装配)

@Slf4j
@Configuration
public class ChatClientConfig {
​
    @Bean
    public OpenAiApi openAiApi(@Value("${spring.ai.openai.chat.base-url}") String baseUrl,@Value("${spring.ai.openai.api-key}") String apikey) {
        return OpenAiApi.builder().apiKey(apikey).baseUrl(baseUrl).build();
    }
​
    @Bean
    public OpenAiChatModel openAiChatModel(OpenAiApi openAiApi){
        return OpenAiChatModel.builder().openAiApi(openAiApi).build();
    }
    // 可以不要,会自动装配
    @Bean
    public ChatClient chatClient(OpenAiChatModel model) {
        log.debug("初始化ChatClient...");
        // ChatClient chatClient = ChatClient.create(model); // 简单创建实例
        // 或使用builder创建更高级控制
        return ChatClient
                .builder(model) // 也可以使用ChatClient.Builder,利用build获取ChatClient对象
                .defaultSystem("你是一个小混混,说话非常不着边际,是一个非常没有礼貌的人!")
                .build();
    }
    // 可以不要,会自动装配
    @Bean
    public TokenTextSplitter tokenTextSplitter(){
        return new TokenTextSplitter();
    }
    // 嵌入模型
    @Bean
    public PgVectorStore pgVectorStore(JdbcTemplate jdbcTemplate,
                                       OllamaEmbeddingModel embeddingModel) {
        return PgVectorStore.builder(jdbcTemplate,embeddingModel)
                .build();
    }
}

2、SpringAI-MCP

1、MCP调用

1、工程环境配置

MCP分客户端和服务端,先在客户端项目中引入Pom文件

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-mcp-server-spring-boot-starter</artifactId>
</dependency>
​
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-mcp-client-webflux-spring-boot-starter</artifactId>
</dependency>

配置MCP信息(stdio模式,有SSE/stdio),调用分为sse/stdio两种方式调用

1.stdio调用配置

一般是一个json文件指定mcp信息,获取到此mcp的json后(公用 MCP 服务:https://smithery.ai/https://glama.ai/mcp/servers),配置到resource下。然后再yml中配置位置。

stdio模式是本地按命令执行

//mcp-servers-config.json
{
  "mcpServers": {
    "mcp-server-csdn": {
      "command": "java",
      "args": [
        "-Dspring.ai.mcp.server.stdio=true",
        "-jar",
        "/Users/fuzhengwei/Applications/apache-maven-3.8.4/repository/cn/bugstack/mcp/mcp-server-csdn/1.0.0/mcp-server-csdn-1.0.0.jar",
        "--csdn.api.categories=Java场景面试宝典",
        "--csdn.api.cookie=xxxxxx"
      ]
    },
    "mcp-server-weixin": {
      "command": "java",
      "args": [
        "-Dspring.ai.mcp.server.stdio=true",
        "-jar",
        "/Users/fuzhengwei/Applications/apache-maven-3.8.4/repository/cn/bugstack/mcp/mcp-server-weixin/1.0.0/mcp-server-weixin-1.0.0.jar"
      ]
    }
  }
}

classpath:(项目路径)可以改为filepath:(部署服务器路径)

FljIw2uNzYNDvRDHMdFxjRDXu_DG

2.SSE调用配置

SSE模式是将mcp-server部署到服务器以SSE访问

spring: 
  ai:
    mcp:
      client:
        request-timeout: 360s
        sse:
          connections:
            mcp-server-csdn:
              url: http://127.0.0.1:8101
            mcp-server-weixin:
              url: http://127.0.0.1:8102
 #        stdio:
#          servers-configuration: classpath:/config/mcp-servers-config-4.json
2、客户端装配调用

1.自动装配MCPTool

ToolCallbackProvider 会自动装配配置的MCPtool,先将tool注册到chatClient中即可用。

   //Spring-MCP的BUG,会重复配置MCPtools导致报错----->multiname Fund   
    @Bean("syncMcpToolCallbackProvider")
    public SyncMcpToolCallbackProvider syncMcpToolCallbackProvider(List<McpSyncClient> mcpClients) {
    //        mcpClients.remove(0);
        // 用于记录 name 和其对应的 index
        Map<String, Integer> nameToIndexMap = new HashMap<>();
        // 用于记录重复的 index
        Set<Integer> duplicateIndices = new HashSet<>();
​
        // 遍历 mcpClients 列表
        for (int i = 0; i < mcpClients.size(); i++) {
            String name = mcpClients.get(i).getServerInfo().name();
            if (nameToIndexMap.containsKey(name)) {
                // 如果 name 已经存在,记录当前 index 为重复
                duplicateIndices.add(i);
            } else {
                // 否则,记录 name 和 index
                nameToIndexMap.put(name, i);
            }
        }
        // 删除重复的元素,从后往前删除以避免影响索引
        List<Integer> sortedIndices = new ArrayList<>(duplicateIndices);
        sortedIndices.sort(Collections.reverseOrder());
        for (int index : sortedIndices) {
            mcpClients.remove(index);
        }
​
        return new SyncMcpToolCallbackProvider(mcpClients);
    }
 
​
    @Bean
    public ChatClient chatClient(OpenAiChatModel model,@Qualifier("syncMcpToolCallbackProvider")  ToolCallbackProvider toolCallbackProvider,ChatMemory memory) {
        log.info("初始化ChatClient...");
        // ChatClient chatClient = ChatClient.create(model); // 简单创建实例
        // 或使用builder创建更高级控制
        DefaultChatClientBuilder defaultChatClientBuilder = new DefaultChatClientBuilder(model, ObservationRegistry.NOOP, (ChatClientObservationConvention) null);
        return defaultChatClientBuilder.defaultSystem("你是一个小混混,说话非常不着边际,是一个非常没有礼貌的人!")
                .defaultTools(toolCallbackProvider)
                .defaultAdvisors(new PromptChatMemoryAdvisor(memory))
                .build();
        // return ChatClient
        //         .builder(model) // 也可以使用ChatClient.Builder,利用build获取ChatClient对象
        //         .defaultSystem("你是一个小混混,说话非常不着边际,是一个非常没有礼貌的人!")
        //         .build();
    }

2.手动装配MCPTool

可以按需将对应的MCPtool,装配到对应的Client中去。

OpenAiApi openAiApi = OpenAiApi.builder()
        .baseUrl("https://apis.itedus.cn")
        .apiKey("sk-lIqVNiHon00O6veJ15Cc57DaF5Dd401f93B3A107B4B3677e")
        .completionsPath("v1/chat/completions")
        .embeddingsPath("v1/embeddings")
        .build();
​
chatModel = OpenAiChatModel.builder()
        .openAiApi(openAiApi)
        .defaultOptions(OpenAiChatOptions.builder()
                .model("gpt-4.1-mini")
=================================================手动装配===========================================================
                .toolCallbacks(new SyncMcpToolCallbackProvider(stdioMcpClient(), sseMcpClient01(), sseMcpClient02()).getToolCallbacks())
=================================================手动装配===========================================================
                .build())
        .build();
​
​
=================================================手动装配===========================================================
  public McpSyncClient stdioMcpClient() {
​
        // based on
        // https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem
        var stdioParams = ServerParameters.builder("npx")
                .args("-y", "@modelcontextprotocol/server-filesystem", "/Users/fuzhengwei/Desktop", "/Users/fuzhengwei/Desktop")
                .build();
​
        var mcpClient = McpClient.sync(new StdioClientTransport(stdioParams))
                .requestTimeout(Duration.ofSeconds(10)).build();
​
        var init = mcpClient.initialize();
​
        System.out.println("Stdio MCP Initialized: " + init);
​
        return mcpClient;
    }
​
    public McpSyncClient sseMcpClient01() {
        HttpClientSseClientTransport sseClientTransport = HttpClientSseClientTransport.builder("http://192.168.1.108:8102").build();
​
        McpSyncClient mcpSyncClient = McpClient.sync(sseClientTransport).requestTimeout(Duration.ofMinutes(180)).build();
​
        var init = mcpSyncClient.initialize();
        System.out.println("SSE MCP Initialized: " + init);
​
        return mcpSyncClient;
    }
=================================================手动装配===========================================================

2、MCP服务搭建

实际就是预先定义好调用服务的执行逻辑。

以CSDN发帖为例。

1、工程基本配置

导入Pom文件

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
</dependency>
​
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-mcp-server-spring-boot-starter</artifactId>
</dependency>
​
<!-- sse 模式需要配置 webflux -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-mcp-server-webflux-spring-boot-starter</artifactId>
</dependency>

application配置文件编写

spring:
  application:
    name: movie-mcp
  ai:
    mcp:
      server:
        name: ${spring.application.name}
        version: 1.0.0
  main:
    banner-mode: off
  # stdio 模式打开,sse 模式,注释掉。
  #    web-application-type: none
​
logging:
  # stdio 模式打开,sse 模式,注释掉。
  #  pattern:
  #    console:
  file:
    name: data/log/${spring.application.name}.log
    
    
server:
  port: 8101
  servlet:
    encoding:
      charset: UTF-8
      force: true
      enabled: true
2、MCP服务编写

@Tool(description = "发布文章到CSDN")

  • 将普通 Java 方法暴露给 AI 模型作为可调用工具

  • AI 模型可以根据方法描述自动决定何时调用该方法

@Slf4j
@Service
public class CSDNArticleService {
​
    @Resource
    private ICSDNPort port;
​
    @Tool(description = "发布文章到CSDN")
    public ArticleFunctionResponse saveArticle(ArticleFunctionRequest request) throws IOException {
        log.info("CSDN发帖,标题:{} 内容:{} 标签:{}", request.getTitle(), request.getMarkdowncontent(), request.getTags());
        return port.writeArticle(request);
    }
​
}
​
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ArticleFunctionRequest {
​
    @JsonProperty(required = true, value = "title")
    @JsonPropertyDescription("文章标题")
    private String title;
​
    @JsonProperty(required = true, value = "markdowncontent")
    @JsonPropertyDescription("文章内容")
    private String markdowncontent;
​
    @JsonProperty(required = true, value = "tags")
    @JsonPropertyDescription("文章标签,英文逗号隔开")
    private String tags;
​
    @JsonProperty(required = true, value = "Description")
    @JsonPropertyDescription("文章简述")
    private String Description;
​
    public String getContent() {
        return MarkdownConverter.convertToHtml(markdowncontent);
    }
​
}
​
3、注册Bean
@Bean
public ToolCallbackProvider csdnTools(CSDNArticleService csdnArticleService) {
    return MethodToolCallbackProvider.builder().toolObjects(csdnArticleService).build();
}
4、打包部署
# 基础镜像,可以先执行 docker pull openjdk:17-jdk-slim
FROM openjdk:17-jdk-slim
​
# 作者
MAINTAINER yandddeat
​
# 配置
ENV PARAMS=""
​
# 时区
ENV TZ=PRC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
​
# 添加应用
ADD ./mcp-server-movie.jar /mcp-server-movie.jar
​
ENTRYPOINT ["sh","-c","java -jar $JAVA_OPTS /mcp-server-movie.jar $PARAMS"]
version: '3.8'
​
services:
  mcp-server-movie:
    build: .
    container_name: mcp-server-movie
    ports:
      - "8101:8101"  
    environment:
      - TZ=Asia/Shanghai
      - JAVA_OPTS=-Xmx512m -Xms256m
      - PARAMS=--spring.profiles.active=prod
    restart: unless-stopped
    volumes:
      - ./logs:/app/logs  

3、AiAgent组装

通过读取自定义好的多个AIAPI、知识库、MCP配置等,组装为一个个的Client1、Client2等,最后通过拖拉拽拼接Client组合成一个AIAgent工作流。

1.大模型自定义:

openaiAPI可以通过自定义 .apiKey(apiKey) 、.baseUrl(baseUrl),实现调用不同大模型

2.MCP工具自定义组装

可以通过OpenAiChatModel的 .toolCallbacks(new SyncMcpToolCallbackProvider(mcpSSEClient3(),sseMcpClient02()).getToolCallbacks()) 来自定义这个大模型能使用的MCP有哪些。

3.知识库自定义组装

.defaultAdvisors( ​ PromptChatMemoryAdvisor.builder(MessageWindowChatMemory.builder() ​ .maxMessages(100) ​ .build()).build(),

.filterExpression(knowledge) ​ .build()), ​ SimpleLoggerAdvisor.builder().build( ​ )

4.完整示例
@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class AiAgentTest {
    private ChatModel chatModel;
    private ChatClient chatClient;
    @Resource
    private PgVectorStore vectorStore;
    public static final String CHAT_MEMORY_CONVERSATION_ID_KEY = "chat_memory_conversation_id";
    public static final String CHAT_MEMORY_RETRIEVE_SIZE_KEY = "chat_memory_response_size";
​
    // 根据自定配置读取后装配Client
    @Before
    public void armory(){
        String baseUrl="https://api.deepseek.com";
        String apiKey="sk-6c5de8d7e46845d79c348a556ce16b41";
        String modelName="deepseek-chat";
        // https://api.deepseek.com/v1/completions
        String completionsPath="/v1/chat/completions";
        String knowledge="knowledge == 'article-prompt-words'";
        //deepseek暂未提供embedding模型
        String embeddingsPath="";
        OpenAiApi api = OpenAiApi.builder()
                .apiKey(apiKey)
                .baseUrl(baseUrl)
                .completionsPath(completionsPath)
                // .embeddingsPath("")
                .build();
        chatModel = OpenAiChatModel.builder()
                .openAiApi(api)
                .defaultOptions(OpenAiChatOptions.builder()
                        .model(modelName)
                        // 自定义MCP工具
                        .toolCallbacks(new SyncMcpToolCallbackProvider(mcpSSEClient3(),sseMcpClient02()).getToolCallbacks())
                        .build())
                .build();
        chatClient=ChatClient.builder(chatModel)
                .defaultSystem("""
                            你是一个 AI Agent 智能体,可以根据用户输入信息生成文章,并发送到 CSDN 平台以及完成微信公众号消息通知,今天是 {current_date}。
                        
                            你擅长使用Planning模式,帮助用户生成质量更高的文章。
                        
                            你的规划应该包括以下几个方面:
                            1. 分析用户输入的内容,生成技术文章。
                            2. 提取,文章标题(需要含带技术点)、文章内容、文章标签(多个用英文逗号隔开)、文章简述(100字)将以上内容发布文章到CSDN
                            3. 获取发送到 CSDN 文章的 URL 地址。
                            4. 微信公众号消息通知,平台:CSDN、主题:为文章标题、描述:为文章简述、跳转地址:从发布文章到CSDN获
                        """)
                // .defaultToolCallbacks()
                .defaultAdvisors(
                        PromptChatMemoryAdvisor.builder(MessageWindowChatMemory.builder()
                                .maxMessages(100)
                                .build()).build(),
                        new RagAnswerAdvisor(vectorStore, SearchRequest.builder()
                                .topK(5)
                                .filterExpression(knowledge)
                                .build()),
                        SimpleLoggerAdvisor.builder().build()
                )
                .build();
    }
​
    // 根据配置协同调用多个Client组成Agent
    @Test
    public void test_chat_model_stream_01() throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(1);
​
        Prompt prompt = Prompt.builder()
                .messages(new UserMessage(
                        """
                                有哪些工具可以使用
                                """))
                .build();
​
        // 非流式,chatModel.call(prompt)
        Flux<ChatResponse> stream = chatModel.stream(prompt);
​
        stream.subscribe(
                chatResponse -> {
                    AssistantMessage output = chatResponse.getResult().getOutput();
                    log.info("测试结果: {}", JSON.toJSONString(output));
                },
                Throwable::printStackTrace,
                () -> {
                    countDownLatch.countDown();
                    System.out.println("Stream completed");
                }
        );
​
        countDownLatch.await();
    }
​
    @Test
    public void test_chat_model_call() {
        Prompt prompt = Prompt.builder()
                .messages(new UserMessage(
                        """
                                有哪些工具可以使用
                                """))
                .build();
​
        ChatResponse chatResponse = chatModel.call(prompt);
​
        log.info("测试结果(call):{}", JSON.toJSONString(chatResponse));
    }
​
    @Test
    public void test_02() {
        String userInput = "严福建是谁";
        System.out.println("\n>>> QUESTION: " + userInput);
        System.out.println("\n>>> ASSISTANT: " + chatClient
                .prompt(userInput)
                .system(s -> s.param("current_date", LocalDate.now().toString()))
                .call().content());
    }
​
    @Test
    public void test_client03() {
        ChatClient chatClient01 = ChatClient.builder(chatModel)
                .defaultSystem("""
                        你是一个专业的AI提示词优化专家。请帮我优化以下prompt,并按照以下格式返回:
                        
                        # Role: [角色名称]
                        
                        ## Profile
                        - language: [语言]
                        - description: [详细的角色描述]
                        - background: [角色背景]
                        - personality: [性格特征]
                        - expertise: [专业领域]
                        - target_audience: [目标用户群]
                        
                        ## Skills
                        
                        1. [核心技能类别]
                           - [具体技能]: [简要说明]
                           - [具体技能]: [简要说明]
                           - [具体技能]: [简要说明]
                           - [具体技能]: [简要说明]
                        
                        2. [辅助技能类别]
                           - [具体技能]: [简要说明]
                           - [具体技能]: [简要说明]
                           - [具体技能]: [简要说明]
                           - [具体技能]: [简要说明]
                        
                        ## Rules
                        
                        1. [基本原则]:
                           - [具体规则]: [详细说明]
                           - [具体规则]: [详细说明]
                           - [具体规则]: [详细说明]
                           - [具体规则]: [详细说明]
                        
                        2. [行为准则]:
                           - [具体规则]: [详细说明]
                           - [具体规则]: [详细说明]
                           - [具体规则]: [详细说明]
                           - [具体规则]: [详细说明]
                        
                        3. [限制条件]:
                           - [具体限制]: [详细说明]
                           - [具体限制]: [详细说明]
                           - [具体限制]: [详细说明]
                           - [具体限制]: [详细说明]
                        
                        ## Workflows
                        
                        - 目标: [明确目标]
                        - 步骤 1: [详细说明]
                        - 步骤 2: [详细说明]
                        - 步骤 3: [详细说明]
                        - 预期结果: [说明]
                        
                        
                        ## Initialization
                        作为[角色名称],你必须遵守上述Rules,按照Workflows执行任务。
                        
                        请基于以上模板,优化并扩展以下prompt,确保内容专业、完整且结构清晰,注意不要携带任何引导词或解释,不要使用代码块包围。
                        """)
                .defaultAdvisors(
                        PromptChatMemoryAdvisor.builder(
                                MessageWindowChatMemory.builder()
                                        .maxMessages(100)
                                        .build()
                        ).build(),
                        new RagAnswerAdvisor(vectorStore, SearchRequest.builder()
                                .topK(5)
                                .filterExpression("knowledge == 'article-prompt-words'")
                                .build())
                )
                .defaultOptions(OpenAiChatOptions.builder()
                        .model("gpt-4.1")
                        .build())
                .build();
​
        String content = chatClient01
                .prompt("生成一篇文章")
​
                .system(s -> s.param("current_date", LocalDate.now().toString()))
                .advisors(a -> a
                        .param(CHAT_MEMORY_CONVERSATION_ID_KEY, "chatId-101")
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100))
                .call().content();
​
        System.out.println("\n>>> ASSISTANT: " + content);
​
        ChatClient chatClient02 = ChatClient.builder(chatModel)
                .defaultSystem("""
                            你是一个 AI Agent 智能体,可以根据用户输入信息生成文章,并发送到 CSDN 平台以及完成微信公众号消息通知,今天是 {current_date}。
                        
                            你擅长使用Planning模式,帮助用户生成质量更高的文章。
                        
                            你的规划应该包括以下几个方面:
                            1. 分析用户输入的内容,生成技术文章。
                            2. 提取,文章标题(需要含带技术点)、文章内容、文章标签(多个用英文逗号隔开)、文章简述(100字)将以上内容发布文章到CSDN
                            3. 获取发送到 CSDN 文章的 URL 地址。
                            4. 微信公众号消息通知,平台:CSDN、主题:为文章标题、描述:为文章简述、跳转地址:为发布文章到CSDN获取 URL地址 CSDN文章链接 https 开头的地址。
                        """)
//                .defaultTools(new SyncMcpToolCallbackProvider(sseMcpClient01(), sseMcpClient02()))
                .defaultAdvisors(
                        PromptChatMemoryAdvisor.builder(
                                MessageWindowChatMemory.builder()
                                        .maxMessages(100)
                                        .build()
                        ).build(),
                        new SimpleLoggerAdvisor()
                )
                .defaultOptions(OpenAiChatOptions.builder()
                        .model("gpt-4.1")
                        .build())
                .build();
​
        String userInput = "生成一篇文章,要求如下 \r\n" + content;
        System.out.println("\n>>> QUESTION: " + userInput);
        System.out.println("\n>>> ASSISTANT: " + chatClient02
                .prompt(userInput)
                .system(s -> s.param("current_date", LocalDate.now().toString()))
                .advisors(a -> a
                        .param(CHAT_MEMORY_CONVERSATION_ID_KEY, "chatId-101")
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100))
                .call().content());
    }
​
​
    public McpSyncClient mcpSSEClient3(){
        HttpClientSseClientTransport sseClientTransport = HttpClientSseClientTransport.builder("http://222.196.35.250:8103").build();
​
        McpSyncClient mcpSyncClient = McpClient.sync(sseClientTransport).requestTimeout(Duration.ofMinutes(180)).build();
​
        var init = mcpSyncClient.initialize();
        System.out.println("SSE MCP Initialized: " + init);
​
        return mcpSyncClient;
    }
    public McpSyncClient sseMcpClient02() {
​
        HttpClientSseClientTransport sseClientTransport = HttpClientSseClientTransport.builder("http://222.196.35.250:8102").build();
​
        McpSyncClient mcpSyncClient = McpClient.sync(sseClientTransport).requestTimeout(Duration.ofMinutes(180)).build();
​
        var init = mcpSyncClient.initialize();
        System.out.println("SSE MCP Initialized: " + init);
​
        return mcpSyncClient;
    }
    public McpSyncClient sseMcpClient01() {
​
        HttpClientSseClientTransport sseClientTransport = HttpClientSseClientTransport.builder("http://222.196.35.250:8101").build();
​
        McpSyncClient mcpSyncClient = McpClient.sync(sseClientTransport).requestTimeout(Duration.ofMinutes(180)).build();
​
        var init = mcpSyncClient.initialize();
        System.out.println("SSE MCP Initialized: " + init);
​
        return mcpSyncClient;
    }
​
​
}

踩坑总结:

1.版本问题

1.0.0是正式版本,1.0.0-M~系列,所对应的openai、ollama等starter都不一致。

解决:1.看官网更换正确artifactId。2.对应部分的操作参照官网配置。

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-bom</artifactId>
    <version>1.0.0</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

2.多模型源配置问题

1.embedding模型问题

使用VectorStore上传向量库时,若是openai模型,配置后会自动配置embedding模型,但是同时又装配了用的ollama embedding,会导致有两个embeddingmodel。这时需要自己进行手动装配VectorStore。

@Bean
public PgVectorStore pgVectorStore(JdbcTemplate jdbcTemplate, OllamaEmbeddingModel embeddingModel) {
    return PgVectorStore.builder(jdbcTemplate, embeddingModel)
            .vectorTableName("vector_store")
            .dimensions(768)
            .build();
}
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐