引入相关依赖
<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;
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;
private final QuestionAnswerAdvisor ragAdvisor;
@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();
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 "对话处理异常,请稍后再试。";
}
}
}