引入相关依赖
<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 {@Autowiredprivate VectorStore vectorStore;@Autowiredprivate EmbeddingModel embeddingModel;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 {@Beanpublic MessageChatMemoryAdvisor memoryAdvisor(ChatMemory chatMemory) {return MessageChatMemoryAdvisor.builder(chatMemory).build();}@Beanpublic QuestionAnswerAdvisor ragAdvisor(VectorStore vectorStore) {return QuestionAnswerAdvisor.builder(vectorStore).searchRequest(SearchRequest.builder().similarityThreshold(0.6d).topK(5).build()).build();}
}
写运行配置
spring:elasticsearch:uris: http://localhost:9200username: elasticpassword: changemedata:redis:host: "localhost"port: 6379database: 0# username:# password:connect-timeout: 5stimeout: 5sai:anthropic:enabled: falsemcp:client:version: 1.0.0request-timeout: 60stype: SYNCtoolcallback:enabled: truestdio:servers-configuration: file:./mcp-servers.jsonvectorstore:elasticsearch:initialize-schema: trueindex-name: custom-indexdimensions: 768similarity: cosineopenai:base-url: api-key: chat:options:model: temperature: 0.7ollama:base-url: http://localhost:11434embedding:options:model: nomic-embed-textmodel:embedding: ollama
最后完成我们的终极AI对话类
@Component
public class SuperAiAgent {private final ChatClient chatClient;private final ToolCallbackProvider toolCallbackProvider;private final QuestionAnswerAdvisor ragAdvisor;@Autowiredprivate List<McpSyncClient> mcpSyncClients;@Autowiredpublic SuperAiAgent(@Qualifier("openAiChatModel") ChatModel chatModel,MessageChatMemoryAdvisor memoryAdvisor,QuestionAnswerAdvisor ragAdvisor,ToolCallbackProvider toolCallbackProvider) {this.chatClient = ChatClient.builder(chatModel).defaultAdvisors(memoryAdvisor).build();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); }if (useTools) {prompt.toolCallbacks(toolCallbackProvider); }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); }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 "对话处理异常,请稍后再试。";}}
}