130 lines
5.1 KiB
Java
130 lines
5.1 KiB
Java
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. VectorStore(SimpleVectorStore,内存) → 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();
|
||
}
|
||
|
||
// ==================== ChatClient(Agent 入口) ====================
|
||
|
||
/**
|
||
* ChatClient —— Week 10 增强版:
|
||
* - 复用 Week 9 的 defaultSystem + MessageChatMemoryAdvisor
|
||
* - 新增 defaultTools:注册所有 @Tool 方法
|
||
* - 新增 QuestionAnswerAdvisor:RAG 检索增强
|
||
*
|
||
* 注意: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();
|
||
}
|
||
}
|