Files
gc-plan/week10/src/main/java/com/learn/config/AIConfig.java
2026-04-30 16:08:39 +08:00

130 lines
5.1 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.learn.config;
import com.learn.tool.CalculatorTool;
import com.learn.tool.SearchTool;
import com.learn.tool.WeatherTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.ChatMemoryRepository;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.openai.OpenAiEmbeddingModel;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
/**
* Week 10 核心配置 —— Agent 能力装配
*
* 新增(对比 Week 9
* 1. EmbeddingModel手动创建用 Ollama 本地) → RAG
* 2. VectorStoreSimpleVectorStore内存 → RAG
* 3. ChatMemory 持久化RedisChatMemoryRepository → 记忆不丢失
* 4. ChatClient 注册 Tools + QuestionAnswerAdvisor → Agent
*/
@Configuration
public class AIConfig {
private static final Logger log = LoggerFactory.getLogger(AIConfig.class);
// ==================== Embedding用于 RAG ====================
/**
* EmbeddingModel —— 把文本转成向量。
*
* 这里手动创建 OpenAiEmbeddingModel指向 Ollama 本地服务,
* 因为 Chat 用的是 DeepSeek不支持 Embedding两者 base-url 不同。
*
* 前置条件ollama pull nomic-embed-text
*/
@Bean
@Lazy
public EmbeddingModel embeddingModel(
@Value("${spring.ai.openai.embedding.base-url:http://localhost:11434}") String baseUrl,
@Value("${spring.ai.openai.embedding.api-key:ollama}") String apiKey) {
var api = OpenAiApi.builder()
.baseUrl(baseUrl.endsWith("/v1") ? baseUrl : baseUrl + "/v1")
.apiKey(apiKey)
.build();
log.info("EmbeddingModel created with base-url: {}", baseUrl);
return new OpenAiEmbeddingModel(api);
}
// ==================== VectorStore用于 RAG ====================
/**
* SimpleVectorStore —— 纯内存向量存储,免外部服务。
* 生产环境可替换为 RedisVectorStore / PgVectorStore 等。
*/
@Bean
@Lazy
public VectorStore vectorStore(EmbeddingModel embeddingModel) {
return SimpleVectorStore.builder(embeddingModel).build();
}
// ==================== ChatMemory持久化 ====================
/**
* ChatMemory —— 对话记忆Redis 持久化Day 5
*
* 架构: MessageWindowChatMemory (滑动窗口, 最多 30 条)
* ↓ 存储
* ChatMemoryRepository → RedisChatMemoryRepository (自定义实现)
*
* 切换方案:把注入的 ChatMemoryRepository 换成 InMemoryChatMemoryRepository
* 就回到 Week 9 的内存模式,其他代码完全不用改。
*/
@Bean
public ChatMemory chatMemory(ChatMemoryRepository repository) {
return MessageWindowChatMemory.builder()
.chatMemoryRepository(repository)
.maxMessages(30)
.build();
}
// ==================== ChatClientAgent 入口) ====================
/**
* ChatClient —— Week 10 增强版:
* - 复用 Week 9 的 defaultSystem + MessageChatMemoryAdvisor
* - 新增 defaultTools注册所有 @Tool 方法
* - 新增 QuestionAnswerAdvisorRAG 检索增强
*
* 注意Tool 对象通过 Spring 注入(用 @Component 标注),
* .defaultTools() 接收所有带 @Tool 注解的 Bean。
*/
@Bean
public ChatClient chatClient(
ChatModel chatModel,
ChatMemory chatMemory,
@Lazy VectorStore vectorStore,
WeatherTool weatherTool,
CalculatorTool calculatorTool,
SearchTool searchTool) {
return ChatClient.builder(chatModel)
.defaultSystem("""
你是一个 AI Agent 助手,名字叫"小智 Agent"
你可以调用工具来获取信息或执行计算。
当用户询问天气、计算数学、或搜索信息时,请使用对应的工具。
回答时请用中文,基于工具返回的结果来组织自然流畅的回复。
""")
.defaultTools(weatherTool, calculatorTool, searchTool)
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(chatMemory).build(),
new QuestionAnswerAdvisor(vectorStore)
)
.build();
}
}