Spring Boot3 集成 Spring AI 實現(xiàn) Advisor 增強(qiáng)機(jī)制的完整流程
1、簡述
Spring AI 的 Advisor API 是一種聲明式的攔截機(jī)制,借鑒了 Spring AOP 的設(shè)計理念,允許開發(fā)者在 AI 交互的生命周期關(guān)鍵節(jié)點插入自定義邏輯。
2、實現(xiàn)原理
2.1 核心概念
Advisor(顧問)本質(zhì)上是圍繞 AI 模型調(diào)用的攔截器,在用戶發(fā)送問題之后、調(diào)用大模型之前執(zhí)行一系列增強(qiáng)操作。
┌─────────────────────────────────────────────────────────────────┐ │ Advisor Chain 執(zhí)行流程 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 用戶請求 ──→ Advisor 1 ──→ Advisor 2 ──→ ... ──→ LLM │ │ │ │ │ │ │ ↓ ↓ ↓ │ │ 請求預(yù)處理 請求預(yù)處理 模型調(diào)用 │ │ │ │ 用戶響應(yīng) ←── Advisor 1 ←── Advisor 2 ←── ... ←── LLM │ │ │ │ │ │ │ ↓ ↓ ↓ │ │ 響應(yīng)后處理 響應(yīng)后處理 原始響應(yīng) │ │ │ └─────────────────────────────────────────────────────────────────┘
2.2 核心價值
| 優(yōu)勢 | 說明 |
|---|---|
| 非侵入式增強(qiáng) | 無需修改核心業(yè)務(wù)代碼即可添加功能 |
| 關(guān)注點分離 | 將橫切關(guān)注點(日志、安全、緩存)與業(yè)務(wù)邏輯解耦 |
| 可復(fù)用性 | 同一 Advisor 可在不同 ChatClient 間復(fù)用 |
| 組合性 | 多個 Advisor 可靈活組合形成攔截鏈 |
2.3 執(zhí)行順序控制
Advisor 鏈的執(zhí)行順序通過 getOrder() 方法控制,值越小優(yōu)先級越高(越先執(zhí)行):
public interface Ordered {
int HIGHEST_PRECEDENCE = Integer.MIN_VALUE; // 最高優(yōu)先級
int LOWEST_PRECEDENCE = Integer.MAX_VALUE; // 最低優(yōu)先級
int getOrder();
}
關(guān)鍵理解:由于 Advisor 鏈的堆棧特性,優(yōu)先級最高的 Advisor 最先處理請求,最后處理響應(yīng)。
3、環(huán)境準(zhǔn)備
3.1 Maven 依賴
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring AI OpenAI Starter -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 添加Jackson支持JSON處理 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>3.2 基礎(chǔ)配置
spring:
application:
name: lm-advisor
# DeepSeek API 配置 (兼容 OpenAI API)
ai:
openai:
# DeepSeek API Base URL
base-url: https://api.deepseek.com
# DeepSeek API Key (請?zhí)鎿Q為你的實際API Key)
api-key: ${DEEPSEEK_API_KEY:you-key}
# 使用的模型
chat:
options:
model: deepseek-chat
temperature: 0.7
max-tokens: 20003.3 ChatClient 配置
package com.example.demo.config;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AiConfig {
public static String CONVERSATION_ID = "conversation_id";
@Bean
public ChatClient chatClient(ChatClient.Builder builder) {
// 可在此配置默認(rèn)系統(tǒng)提示詞
return builder
.defaultSystem("你是一個專業(yè)的AI助手,請用中文回答用戶問題。")
.build();
}
}4、內(nèi)置 Advisor 詳解
Spring AI 1.0.0 提供了多個開箱即用的內(nèi)置 Advisor。
4.1 對話記憶 Advisor
MessageChatMemoryAdvisor
將歷史消息直接添加到請求的 messages 列表中,適用于支持結(jié)構(gòu)化消息的 Chat 模型(如 OpenAI GPT 系列)。
package com.example.demo.service;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.stereotype.Service;
@Service
public class MemoryConversationService {
private final String CONVERSATION_ID = "conversation_id";
private final ChatClient chatClient;
public MemoryConversationService(ChatClient.Builder builder) {
// 創(chuàng)建聊天記憶存儲(內(nèi)存窗口模式,保留最近20條消息)
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.maxMessages(20)
.build();
// 創(chuàng)建 MessageChatMemoryAdvisor
MessageChatMemoryAdvisor memoryAdvisor = MessageChatMemoryAdvisor.builder(chatMemory)
.conversationId("default-session")
.build();
this.chatClient = builder
.defaultAdvisors(memoryAdvisor)
.build();
}
/**
* 多輪對話 - 自動保持上下文
* @param conversationId 會話ID(首次調(diào)用可傳null)
* @param message 用戶消息
*/
public String chatWithMemory(String conversationId, String message) {
String convId = conversationId != null ? conversationId : "default-session";
return chatClient.prompt()
.user(message)
.advisors(advisor -> advisor
.param(CONVERSATION_ID, convId))
.call()
.content();
}
}PromptChatMemoryAdvisor
將歷史消息嵌入到系統(tǒng)提示詞(System Prompt)中,適用于不支持結(jié)構(gòu)化消息的文本模型(如本地部署的 LLaMA、BLOOM 等)。
import com.lm.advisor.config.AiConfig;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.stereotype.Service;
@Service
public class PromptMemoryConversationService {
private final ChatClient chatClient;
public PromptMemoryConversationService(ChatClient.Builder builder) {
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.maxMessages(20)
.build();
// 創(chuàng)建 PromptChatMemoryAdvisor
PromptChatMemoryAdvisor memoryAdvisor = PromptChatMemoryAdvisor.builder(chatMemory)
.conversationId("default-session")
.build();
this.chatClient = builder
.defaultAdvisors(memoryAdvisor)
.build();
}
public String chatWithMemory(String conversationId, String message) {
String convId = conversationId != null ? conversationId : "default-session";
return chatClient.prompt()
.user(message)
.advisors(advisor -> advisor
.param(AiConfig.CONVERSATION_ID, convId))
.call()
.content();
}
}4.2 敏感詞過濾 Advisor(SafeGuardAdvisor)
在用戶輸入中檢測敏感詞,發(fā)現(xiàn)敏感詞時阻止調(diào)用模型并返回預(yù)設(shè)響應(yīng)。
package com.example.demo.service;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SafeGuardAdvisor;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class SafeGuardService {
private final ChatClient chatClient;
public SafeGuardService(ChatClient.Builder builder) {
// 配置敏感詞列表
List<String> sensitiveWords = List.of(
"機(jī)密", "絕密", "內(nèi)部資料",
"confidential", "secret", "classified"
);
// 創(chuàng)建 SafeGuardAdvisor
SafeGuardAdvisor safeGuardAdvisor = SafeGuardAdvisor.builder()
.sensitiveWords(sensitiveWords)
.failureResponse("檢測到敏感詞,請修改您的輸入后重試")
.build();
this.chatClient = builder
.defaultAdvisors(safeGuardAdvisor)
.build();
}
public String safeChat(String userMessage) {
return chatClient.prompt()
.user(userMessage)
.call()
.content();
}
}4.3 RAG Advisor(QuestionAnswerAdvisor)
從向量數(shù)據(jù)庫中檢索相關(guān)文檔,增強(qiáng)上下文后傳遞給 LLM。
package com.example.demo.service;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.stereotype.Service;
@Service
public class RagService {
private final ChatClient chatClient;
public RagService(ChatClient.Builder builder, VectorStore vectorStore) {
// 配置 RAG Advisor
QuestionAnswerAdvisor ragAdvisor = QuestionAnswerAdvisor.builder(vectorStore)
.searchRequest(SearchRequest.builder()
.similarityThreshold(0.75) // 相似度閾值
.topK(5) // 返回文檔數(shù)量
.build())
.build();
this.chatClient = builder
.defaultAdvisors(ragAdvisor)
.build();
}
/**
* 基于知識庫的問答
*/
public String askWithRag(String question) {
return chatClient.prompt()
.user(question)
.call()
.content();
}
/**
* 動態(tài)過濾表達(dá)式 - 只檢索特定類型的文檔
*/
public String askWithFilter(String question, String filterExpression) {
return chatClient.prompt()
.user(question)
.advisors(advisor -> advisor
.param(QuestionAnswerAdvisor.FILTER_EXPRESSION, filterExpression))
.call()
.content();
}
}4.4 日志記錄 Advisor(SimpleLoggerAdvisor)
打印請求和響應(yīng)信息,默認(rèn) JSON 格式化輸出。
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.stereotype.Service;
@Service
public class LoggingService {
private final ChatClient chatClient;
public LoggingService(ChatClient.Builder builder) {
// 使用內(nèi)置的 SimpleLoggerAdvisor
this.chatClient = builder
.defaultAdvisors(new SimpleLoggerAdvisor())
.build();
}
public String chat(String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
}5、自定義 Advisor 開發(fā)
5.1 繼承 BaseAdvisor(推薦方式)
Spring AI 1.0.0 推薦繼承 BaseAdvisor 抽象類,只需實現(xiàn) before() 和 after() 方法。
package com.example.demo.advisor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClientRequest;
import org.springframework.ai.chat.client.ChatClientResponse;
import org.springframework.ai.chat.client.advisor.api.*;
import org.springframework.core.Ordered;
@Slf4j
public class PerformanceLoggingAdvisor implements BaseAdvisor, Ordered {
@Override
public ChatClientRequest before(ChatClientRequest request, AdvisorChain chain) {
// 請求前處理:記錄開始時間
long startTime = System.currentTimeMillis();
// 將開始時間存入上下文,供 after 方法使用
request.context().put("startTime", startTime);
log.info("=== AI 請求開始 ===");
log.info("用戶消息: {}", request.prompt().getUserMessage().getText());
log.info("系統(tǒng)消息: {}", request.prompt().getSystemMessage().getText());
return request;
}
@Override
public ChatClientResponse after(ChatClientResponse response, AdvisorChain chain) {
// 響應(yīng)后處理:計算耗時
long startTime = (long) response.context().getOrDefault("startTime", System.currentTimeMillis());
long duration = System.currentTimeMillis() - startTime;
String content = response.chatResponse().getResult().getOutput().getText();
log.info("=== AI 響應(yīng)完成 ===");
log.info("響應(yīng)內(nèi)容: {}", content != null && content.length() > 100
? content.substring(0, 100) + "..." : content);
log.info("耗時: {}ms", duration);
return response;
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 100;
}
}5.2 敏感詞攔截 Advisor(攔截式)
繼承 BaseAdvisor 并重寫 before(),在檢測到敏感詞時提前終止鏈調(diào)用。
package com.example.demo.advisor;
import org.springframework.ai.chat.client.ChatClientRequest;
import org.springframework.ai.chat.client.ChatClientResponse;
import org.springframework.ai.chat.client.advisor.api.*;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.model.Generation;
import org.springframework.core.Ordered;
import java.util.List;
public class SensitiveWordInterceptorAdvisor implements BaseAdvisor, Ordered {
private final List<String> sensitiveWords;
private final String blockMessage;
public SensitiveWordInterceptorAdvisor(List<String> sensitiveWords) {
this(sensitiveWords, "您的輸入包含敏感詞,請修改后重試");
}
public SensitiveWordInterceptorAdvisor(List<String> sensitiveWords, String blockMessage) {
this.sensitiveWords = sensitiveWords;
this.blockMessage = blockMessage;
}
@Override
public ChatClientRequest before(ChatClientRequest request, AdvisorChain chain) {
String userText = request.prompt().getUserMessage().getText();
String detectedWord = detectSensitiveWord(userText);
if (detectedWord != null) {
// 檢測到敏感詞,設(shè)置阻斷標(biāo)記
request.context().put("blocked", true);
request.context().put("blockReason", "敏感詞: " + detectedWord);
}
return request;
}
@Override
public ChatClientResponse after(ChatClientResponse response, AdvisorChain chain) {
// 檢查是否被阻斷
if (Boolean.TRUE.equals(response.context().get("blocked"))) {
// 返回預(yù)設(shè)的阻斷響應(yīng)
List<Generation> generations = new java.util.ArrayList<>();
generations.add(new Generation(new AssistantMessage(blockMessage)));
ChatResponse blockResponse = new ChatResponse(generations);
return new ChatClientResponse(blockResponse, response.context());
}
return response;
}
private String detectSensitiveWord(String text) {
if (text == null) return null;
for (String word : sensitiveWords) {
if (text.contains(word)) {
return word;
}
}
return null;
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 50;
}
}5.3 Re-Reading 增強(qiáng) Advisor
基于 Re-Reading(Re2)技術(shù),通過重復(fù)閱讀問題來提升理解準(zhǔn)確率。
package com.example.demo.advisor;
import org.springframework.ai.chat.client.ChatClientRequest;
import org.springframework.ai.chat.client.ChatClientResponse;
import org.springframework.ai.chat.client.advisor.api.*;
import org.springframework.core.Ordered;
import java.util.HashMap;
import java.util.Map;
/**
* Re-Reading 增強(qiáng) Advisor
* 通過讓模型重復(fù)閱讀問題來提升理解準(zhǔn)確率
* 基于 Re2 技術(shù):https://arxiv.org/abs/2309.06275
*/
public class ReReadingAdvisor implements BaseAdvisor, Ordered {
private static final String RE_READ_TEMPLATE = """
{re2_input_query}
Read the question again: {re2_input_query}
""";
@Override
public ChatClientRequest before(ChatClientRequest request, AdvisorChain chain) {
// 獲取原始用戶消息
String inputQuery = request.prompt().getUserMessage().getText();
// 構(gòu)建增強(qiáng)后的用戶消息參數(shù)
Map<String, Object> params = new HashMap<>(request.prompt().getUserMessage().getMetadata());
params.put("re2_input_query", inputQuery);
// 創(chuàng)建增強(qiáng)后的請求
return request.copy()
.mutate()
.context(params)
.build();
}
@Override
public ChatClientResponse after(ChatClientResponse chatClientResponse, AdvisorChain advisorChain) {
return null;
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE - 100;
}
}6、Advisor 鏈配置與組合
6.1 組合多個 Advisor
package com.example.demo.config;
import com.lm.advisor.advisor.PerformanceLoggingAdvisor;
import com.lm.advisor.advisor.ReReadingAdvisor;
import com.lm.advisor.advisor.SensitiveWordInterceptorAdvisor;
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.MessageWindowChatMemory;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
@Configuration
public class AdvisorChainConfig {
@Bean
public ChatClient chatClientWithAdvisors(
ChatClient.Builder builder,
VectorStore vectorStore) {
// 創(chuàng)建各個 Advisor
SensitiveWordInterceptorAdvisor sensitiveWordAdvisor =
new SensitiveWordInterceptorAdvisor(List.of("敏感詞1", "敏感詞2"));
PerformanceLoggingAdvisor loggingAdvisor = new PerformanceLoggingAdvisor();
MessageChatMemoryAdvisor memoryAdvisor = MessageChatMemoryAdvisor.builder(
MessageWindowChatMemory.builder().maxMessages(20).build())
.conversationId("default")
.build();
QuestionAnswerAdvisor ragAdvisor = QuestionAnswerAdvisor.builder(vectorStore)
.build();
ReReadingAdvisor reReadingAdvisor = new ReReadingAdvisor();
// 按順序配置 Advisor 鏈
// 執(zhí)行順序:敏感詞過濾 -> 日志記錄 -> 對話記憶 -> RAG -> Re-Reading
return builder
.defaultAdvisors(
sensitiveWordAdvisor,
loggingAdvisor,
memoryAdvisor,
ragAdvisor,
reReadingAdvisor
)
.defaultSystem("你是一個樂于助人的 AI 助手,請用中文回答用戶問題。")
.build();
}
@Bean
public VectorStore vectorStore(EmbeddingModel embeddingModel) {
// 使用內(nèi)存向量存儲,適合開發(fā)和測試環(huán)境
return SimpleVectorStore.builder(embeddingModel)
.build();
}
}6.2 運(yùn)行時動態(tài)添加 Advisor
import com.lm.advisor.config.AiConfig;
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.stereotype.Service;
@Service
public class DynamicAdvisorService {
private final ChatClient chatClient;
public DynamicAdvisorService(ChatClient.Builder builder) {
// 基礎(chǔ)配置,不預(yù)設(shè) Advisor
this.chatClient = builder.build();
}
/**
* 運(yùn)行時根據(jù)場景動態(tài)添加 Advisor
*/
public String chatWithRuntimeAdvisors(String question, String conversationId) {
return chatClient.prompt()
.user(question)
// 動態(tài)添加對話記憶 Advisor
.advisors(advisor -> advisor
.param(AiConfig.CONVERSATION_ID, conversationId))
// 動態(tài)添加 RAG Advisor
.advisors(advisor -> advisor
.param(QuestionAnswerAdvisor.FILTER_EXPRESSION, "type == 'knowledge'"))
.call()
.content();
}
}7、常見問題與最佳實踐
7.1 MessageChatMemoryAdvisor 與 PromptChatMemoryAdvisor 的區(qū)別
| 特性 | MessageChatMemoryAdvisor | PromptChatMemoryAdvisor |
|---|---|---|
| 消息存儲方式 | 直接添加到 messages 列表 | 嵌入到系統(tǒng)提示詞 |
| 適用模型 | OpenAI GPT 等 Chat 模型 | LLaMA、BLOOM 等文本模型 |
| 優(yōu)點 | 精確控制消息類型(用戶、系統(tǒng)、助手) | 通用性更強(qiáng),不依賴模型能力 |
| 缺點 | 依賴模型支持 messages 參數(shù) | 可能增加 token 消耗 |
7.2 為什么需要覆蓋 adviseStream 方法
在流式響應(yīng)場景中,多個流式響應(yīng)塊需要合并成一個完整的響應(yīng)對象后,再調(diào)用 after() 方法,確保只保留完整的模型輸出,避免部分信息寫入 memory 導(dǎo)致數(shù)據(jù)混亂。
7.3 性能優(yōu)化建議
// 1. 避免在 Advisor 中進(jìn)行重量級操作
public class LightweightAdvisor extends BaseAdvisor {
@Override
public ChatClientRequest before(ChatClientRequest request, AdvisorChain chain) {
// 快速檢查,避免阻塞
if (skipCondition()) {
return request;
}
// 異步處理非關(guān)鍵邏輯
CompletableFuture.runAsync(() -> asyncProcess(request));
return request;
}
}
// 2. 合理設(shè)置執(zhí)行順序
// 敏感詞過濾應(yīng)最先執(zhí)行(優(yōu)先級最高)
// 日志記錄應(yīng)在中間執(zhí)行
// Re-Reading 應(yīng)在最后執(zhí)行7.4 注意事項
| 注意事項 | 說明 |
|---|---|
| 會話 ID 管理 | 必須妥善維護(hù) chat_memory_conversation_id,避免每次默認(rèn)生成新 ID 導(dǎo)致垃圾數(shù)據(jù) |
| 敏感數(shù)據(jù) | 啟用 prompt/completion 日志記錄時,存在暴露敏感信息的風(fēng)險 |
| 流式處理線程 | BaseAdvisor 默認(rèn)使用 Schedulers.boundedElastic() 進(jìn)行流式處理線程調(diào)度 |
| 順序敏感 | 部分 Advisor(如 SafeGuardAdvisor)需要放在鏈的最前面,才能在早期攔截請求 |
8、總結(jié)
本文全面介紹了 Spring Boot 集成 Spring AI 1.0.0 實現(xiàn) Advisor 增強(qiáng)機(jī)制的完整流程,涵蓋以下核心內(nèi)容:
| 章節(jié) | 核心知識點 |
|---|---|
| 基礎(chǔ)概念 | Advisor 攔截機(jī)制、核心接口、執(zhí)行順序 |
| 環(huán)境配置 | Maven 依賴、配置文件設(shè)置 |
| 內(nèi)置 Advisor | 對話記憶(兩種實現(xiàn))、敏感詞過濾、RAG、日志記錄 |
| 自定義開發(fā) | 繼承 BaseAdvisor、性能日志、敏感詞攔截、Re-Reading 增強(qiáng) |
| 鏈?zhǔn)浇M合 | 多 Advisor 組合、運(yùn)行時動態(tài)添加 |
| 可觀測性 | Micrometer 指標(biāo)、OpenTelemetry 追蹤 |
| 最佳實踐 | 性能優(yōu)化、注意事項、常見問題 |
Spring AI 1.0.0 的 Advisor 機(jī)制為構(gòu)建生產(chǎn)級 AI 應(yīng)用提供了強(qiáng)大的擴(kuò)展能力。通過合理設(shè)計和組合 Advisor,可以實現(xiàn):
- 非侵入式增強(qiáng):無需修改核心業(yè)務(wù)代碼即可添加功能
- 關(guān)注點分離:將橫切關(guān)注點(日志、安全、緩存)與業(yè)務(wù)邏輯解耦
- 可復(fù)用性:同一 Advisor 可在不同 ChatClient 間復(fù)用
- 可觀測性:完整的指標(biāo)收集和鏈路追蹤能力
到此這篇關(guān)于Spring Boot3 集成 Spring AI 實現(xiàn) Advisor 增強(qiáng)機(jī)制的完整流程的文章就介紹到這了,更多相關(guān)Spring Boot 集成 Spring AI Advisor 增強(qiáng)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- LangChain4j 集成 SpringBoot的項目實踐
- springboot3.x版本集成log4j遇到Logging?system?failed?to?initialize?using?configuration?from‘classpath:log4問題
- springboot集成nacos報錯:get data from Nacos error,dataId:null.yaml的原因及解決方法
- Java SpringBoot集成ChatGPT實現(xiàn)AI聊天
- springBoot集成Elasticsearch 報錯 Health check failed的解決
- SpringBoot集成E-mail發(fā)送各種類型郵件
- Springboot源碼 AbstractAdvisorAutoProxyCreator解析
相關(guān)文章
nacos注冊中心調(diào)用服務(wù)失敗的解決方案
nacos注冊中心出現(xiàn)調(diào)用服務(wù)失敗的情況,可能是因為注冊了兩個IP地址,一個是開發(fā)/測試環(huán)境,一個是本地啟動的IP,解決方法是將本地的IP從注冊中心下線,以避免干擾其他環(huán)境,確定哪個IP是開發(fā)環(huán)境/測試環(huán)境的IP,可以使用ifconfig命令查看服務(wù)器的IP地址2026-02-02
Mybatis-plus通過添加攔截器實現(xiàn)簡單數(shù)據(jù)權(quán)限
系統(tǒng)需要根據(jù)用戶所屬的公司,來做一下數(shù)據(jù)權(quán)限控制,具體一點,就是通過表中的company_id進(jìn)行權(quán)限控制,項目使用的是mybatis-plus,所以通過添加攔截器的方式,修改查詢sql,實現(xiàn)數(shù)據(jù)權(quán)限,本文就通過代碼給大家詳細(xì)的講解一下,需要的朋友可以參考下2023-08-08
Java?20在Windows11系統(tǒng)下的簡易安裝教程
這篇文章主要給大家介紹了關(guān)于Java?20在Windows11系統(tǒng)下的簡易安裝教程,學(xué)習(xí)Java的同學(xué),第一步就是安裝好Java環(huán)境,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-07-07
SpringBoot創(chuàng)建maven多模塊項目實戰(zhàn)代碼
本篇文章主要介紹了SpringBoot創(chuàng)建maven多模塊項目實戰(zhàn)代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-09-09

