spring-boot项目集成spring-ai

发布于:2025-07-16 ⋅ 阅读:(16) ⋅ 点赞:(0)

引入相关依赖

<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-openai</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-vector-store-elasticsearch</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-ollama</artifactId>
        </dependency>
        <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-mcp-client</artifactId>
    </dependency>
        <dependency>
        <groupId>co.elastic.clients</groupId>
        <artifactId>elasticsearch-java</artifactId>
        <version>8.13.4</version>
    </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-advisors-vector-store</artifactId>
        </dependency>

先做基础的向量库管理

@Component
public class VectorStoreUtil {
    @Autowired
    private VectorStore vectorStore;
    @Autowired
    private EmbeddingModel embeddingModel;
    /**
     * 将单个文档添加到向量索引中

     * @param content 文本内容
     */
    public void insert(String content) {
        Document document = new Document(content);

        vectorStore.add(List.of(document));
    }

    /**
     * 批量添加多个文档
     */
    public void insertBatch(List<String> contents) {
        if (contents == null || contents.isEmpty()) {
            System.out.println("Warning: insertBatch called with empty content list, skipping.");
            return;
        }
        List<Document> docs = contents.stream().map(Document::new).toList();

        vectorStore.add(docs);
    }
    public List<Document> query(String content) {
        List<Document> results = vectorStore.similaritySearch(SearchRequest.builder().topK(1).query(content).build());
        return results;
    }
//    获取向量
    public float[] getEmbedding(String content){
        return embeddingModel.embed(content);
    }

}

做记忆化和RAG相关的advisor

@Configuration
public class ChatAgentConfig {

    @Bean
    public MessageChatMemoryAdvisor memoryAdvisor(ChatMemory chatMemory) {
        return MessageChatMemoryAdvisor.builder(chatMemory).build();
    }

    @Bean
    public QuestionAnswerAdvisor ragAdvisor(VectorStore vectorStore) {
        return QuestionAnswerAdvisor.builder(vectorStore)
                .searchRequest(SearchRequest.builder()
                        .similarityThreshold(0.6d)
                        .topK(5)
                        .build())
                .build();
    }
}

写运行配置

spring:
  elasticsearch:
    uris: http://localhost:9200
    username: elastic
    password: changeme
  data:
    redis:
      host: "localhost"
      port: 6379
      database: 0
      # username:
      # password:
      connect-timeout: 5s
      timeout: 5s
  ai:
    anthropic:
      enabled: false
    mcp:
      client:
        version: 1.0.0
        request-timeout: 60s
        type: SYNC
        toolcallback:
          enabled: true
        stdio:
          servers-configuration:  file:./mcp-servers.json
    vectorstore:
      elasticsearch:
        initialize-schema: true
        index-name: custom-index
        dimensions: 768
        similarity: cosine
    openai:
      base-url: 
      api-key: 
      chat:
        options:
          model: 
          temperature: 0.7

    ollama:
      base-url: http://localhost:11434
      embedding:
        options:
          model: nomic-embed-text
    model:
      embedding: ollama

最后完成我们的终极AI对话类

@Component
public class SuperAiAgent {

    private final ChatClient chatClient;//对话器
    private final ToolCallbackProvider toolCallbackProvider;//MCP工具
    private final QuestionAnswerAdvisor ragAdvisor;//RAG
    @Autowired
    private List<McpSyncClient> mcpSyncClients;

    @Autowired
    public SuperAiAgent(
            @Qualifier("openAiChatModel") ChatModel chatModel,
            MessageChatMemoryAdvisor memoryAdvisor,
            QuestionAnswerAdvisor ragAdvisor,
            ToolCallbackProvider toolCallbackProvider
    ) {
        this.chatClient = ChatClient.builder(chatModel)
                .defaultAdvisors(memoryAdvisor)
                .build();//自带对话id
        this.toolCallbackProvider = toolCallbackProvider;
        this.ragAdvisor = ragAdvisor;
    }

    String sysPrompt="";

    public String ask(String question, Object conversationId, boolean useRag, boolean useTools) {
        var prompt = chatClient.prompt()
                .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId));
        prompt.messages(new SystemMessage(sysPrompt));
        if (useRag) {
            prompt.advisors(ragAdvisor); // 动态启用 RAG
        }
        if (useTools) {
            prompt.toolCallbacks(toolCallbackProvider); // 启用 MCP 工具调用
        }
        try {
            return prompt.user(question)
                    .call()
                    .content();
        } catch (ToolExecutionException e) {
            // 工具调用异常,打印日志或返回默认内容
            System.err.println("工具调用异常: " + e.getMessage());
            // 返回模型基础回答或自定义错误提示
            // 这里可以调用不带工具的对话或者返回固定内容
            return "工具调用失败,已忽略错误。";
        } catch (Exception e) {
            // 其它异常处理
            e.printStackTrace();
            return "对话处理异常,请稍后再试。";
        }
    }
    public String ask(String question, Object conversationId, boolean useRag, boolean useTools, Set<String>mcpList) {
        var prompt = chatClient.prompt()
                .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId));

        if (useRag) {
            prompt.advisors(ragAdvisor); // 动态启用 RAG
        }
        if (useTools) {
            List<McpSyncClient>clients = new ArrayList<>();
            for(var client : mcpSyncClients) {
                if(mcpList.contains(client.getServerInfo().name())){
                    clients.add(client);
                }
            }
            ToolCallbackProvider provider = new SyncMcpToolCallbackProvider(clients);
            prompt.toolCallbacks(provider);
        }

        try {
            return prompt.user(question)
                    .call()
                    .content();
        } catch (ToolExecutionException e) {
            // 工具调用异常,打印日志或返回默认内容
            System.err.println("工具调用异常: " + e.getMessage());
            // 返回模型基础回答或自定义错误提示
            // 这里可以调用不带工具的对话或者返回固定内容
            return "工具调用失败,已忽略错误。";
        } catch (Exception e) {
            // 其它异常处理
            e.printStackTrace();
            return "对话处理异常,请稍后再试。";
        }
    }
}

网站公告

今日签到

点亮在社区的每一天
去签到