SpringAI實戰鏈接
1.SpringAl實現AI應用-快速搭建-CSDN博客
2.SpringAI實現AI應用-搭建知識庫-CSDN博客
3.SpringAI實現AI應用-內置顧問-CSDN博客
4.SpringAI實現AI應用-使用redis持久化聊天記憶-CSDN博客
5.SpringAI實現AI應用-自定義顧問(Advisor)-CSDN博客
概述
經過前幾篇帖子的鞭打,現在已經對SpringAI有了一定的了解,繼續查看官方文檔,顧問(Advisor)里面還有自定義顧問,這篇帖子就說一下如何進行自定義。
SpringAI官方文檔
中文版:顧問 API :: Spring AI 參考 - Spring 框架
官方:Advisors API :: Spring AI Reference
Advisors原理
在寫代碼之前,得先了解Advisor的一些基本信息,雖然官方文檔里有說明,但還是感覺太官方了
Spring AI 中的?Advisors(顧問)?是一個關鍵概念,用于在模型交互過程中動態調整或增強提示詞(Prompt)、控制生成過程,或注入業務邏輯。它的核心思想是對 AI 模型的輸入/輸出進行攔截和增強,類似于?AOP(面向切面編程)中的攔截器。
核心作用
動態修改提示詞:在發送給模型前,自動添加上下文、示例或格式化內容。
結果后處理:對模型生成的文本進行過濾、校驗或結構化解析。
上下文管理:跨多次對話維護狀態(如歷史記錄、用戶偏好)。
業務規則注入:根據業務需求限制或引導模型的輸出。
工作原理
Advisor 在請求處理鏈中的位置:
用戶輸入 → [Advisor 預處理] → 模型處理 → [Advisor 后處理] → 返回用戶
預處理階段:修改或增強輸入的 AdvisedRequest。
后處理階段:處理模型的 AdvisedResponse。
源碼分析
?
?
通過官方文檔和源碼可知(在此就引用官方的圖片了),SpringAI的幾個內置顧問實現的都是Advisor。
代碼實現
廢話就不多說了,直接開始干!!!
根據前幾篇帖子的,現在已經有一個完整的框架了,能夠直接添加代碼進行測試了
LoggingAdvisor(日志顧問)
import org.springframework.ai.chat.client.advisor.api.*;
import org.springframework.ai.chat.model.MessageAggregator;
import reactor.core.publisher.Flux;/*** @Author majinzhong* @Date 2025/5/8 11:27* @Version 1.0*/
public class LoggingAdvisor implements CallAroundAdvisor,StreamAroundAdvisor {@Overridepublic AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) {System.out.println("調用AI Call之前:"+advisedRequest);AdvisedResponse advisedResponse = chain.nextAroundCall(advisedRequest);System.out.println("調用AI Call之后:"+advisedResponse);return advisedResponse;}@Overridepublic Flux<AdvisedResponse> aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) {System.out.println("調用AI Stream之前:"+advisedRequest);Flux<AdvisedResponse> advisedResponseFlux = chain.nextAroundStream(advisedRequest);Flux<AdvisedResponse> advisedResponseFlux1 = new MessageAggregator().aggregateAdvisedResponse(advisedResponseFlux, advisedResponse -> System.out.println("調用AI Stream之后:"+advisedResponseFlux));return advisedResponseFlux1;}@Overridepublic String getName() {return this.getClass().getSimpleName();}@Overridepublic int getOrder() {return 0;}
}
AiConfig
@BeanChatClient chatClient(ChatClient.Builder builder,VectorStore vectorStore) {return builder// 它定義了聊天機器人在回答問題時應當遵循的風格和角色定位。.defaultSystem("你是一個智能機器人,你的名字叫 Spring AI智能機器人")//這里可以添加多個顧問 order(優先級)越小,越先執行// 注意:顧問添加到鏈中的順序至關重要,因為它決定了其執行的順序。每個顧問都會以某種方式修改提示或上下文,一個顧問所做的更改會傳遞給鏈中的下一個顧問。// 在此配置中,將首先執行MessageChatMemoryAdvisor,將對話歷史記錄添加到提示中。然后,問答顧問將根據用戶的問題和添加的對話歷史進行搜索,從而可能提供更相關的結果。.defaultAdvisors(//內存存儲對話記憶new MessageChatMemoryAdvisor(inMemoryChatMemory()),
// new PromptChatMemoryAdvisor(inMemoryChatMemory()),// QuestionAnswerAdvisor 此顧問使用矢量存儲提供問答功能,實現RAG(檢索增強生成)模式
// QuestionAnswerAdvisor.builder(vectorStore).order(1).build(),// SafeGuardAdvisor是一個安全防護顧問,它確保生成的內容符合道德和法律標準。SafeGuardAdvisor.builder().sensitiveWords(List.of("色情", "暴力")) // 敏感詞列表.order(2) // 設置優先級.failureResponse("抱歉,我無法回答這個問題。").build(), // 敏感詞過濾失敗時的響應// SimpleLoggerAdvisor是一個記錄ChatClient的請求和響應數據的顧問。這對于調試和監控您的AI交互非常有用,建議將其添加到鏈的末尾。new LoggingAdvisor()).defaultOptions(ChatOptions.builder().topP(0.7) // 取值越大,生成的隨機性越高;取值越低,生成的隨機性越低。默認值為0.8.build()).build();}
將原來代碼中的SimpleLoggerAdvisor換成自定義的日志顧問,因為SimpleLoggerAdvisor沒有按照自己的要求進行打印
測試
經過測試,已經在控制臺進行打印了
ReReadingAdvisor(重新閱讀RE2顧問)
import org.springframework.ai.chat.client.advisor.api.*;
import reactor.core.publisher.Flux;import java.util.HashMap;
import java.util.Map;/*** @Author majinzhong* @Date 2025/5/8 15:10* @Version 1.0*/
public class ReReadingAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {private AdvisedRequest before(AdvisedRequest advisedRequest) {Map<String, Object> advisedUserParams = new HashMap<>(advisedRequest.userParams());advisedUserParams.put("re2_input_query", advisedRequest.userText());return AdvisedRequest.from(advisedRequest).userText("你的作用是什么,誰創造的你").userParams(advisedUserParams).build();}@Overridepublic AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) {return chain.nextAroundCall(this.before(advisedRequest));}@Overridepublic Flux<AdvisedResponse> aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) {return chain.nextAroundStream(this.before(advisedRequest));}@Overridepublic int getOrder() {return 0;}@Overridepublic String getName() {return this.getClass().getSimpleName();}
}
繼續修改AIConfig,添加自定義的顧問
測試
經測試可知,自定義的RE2顧問已經成功
RetryAdvisor(異常重試顧問)
import org.springframework.ai.chat.client.advisor.api.*;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import reactor.core.publisher.Flux;/*** @Author majinzhong* @Date 2025/5/8 15:21* @Version 1.0*/
public class RetryAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {private final RetryTemplate retryTemplate;public RetryAdvisor() {this.retryTemplate = new RetryTemplate();// 配置重試策略:最多2次,間隔1秒SimpleRetryPolicy policy = new SimpleRetryPolicy();policy.setMaxAttempts(2);FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();backOffPolicy.setBackOffPeriod(1000); // 1秒retryTemplate.setRetryPolicy(policy);retryTemplate.setBackOffPolicy(backOffPolicy);}@Overridepublic AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) {AdvisedResponse advisedResponse = chain.nextAroundCall(advisedRequest);return retryTemplate.execute(context -> {return advisedResponse;});}@Overridepublic Flux<AdvisedResponse> aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) {return chain.nextAroundStream(advisedRequest);}@Overridepublic String getName() {return this.getClass().getSimpleName();}@Overridepublic int getOrder() {return 0;}
}
還要修改AiConfig
這個沒有進行測試,因為是返回值異常的時候才會進行重試
至此自定義顧問已經完成,可以按照自己的業務需求進行修改
補充
之前說過顧問可以提前統一進行設置,也可以單獨在方法上進行設置
其實,每個AI大模型也可以單獨在方法上進行設置
統一配置AI模型
AI大模型在application.yml文件里設置
在AiConfig里進行配置大模型的名稱、顧問等信息
方法上配置AI大模型
/*** 根據消息直接輸出回答* @param map* @return*/@PostMapping("/ai/call")public String call(@RequestBody Map<String,String> map) {String message = map.get("message");
// return chatClient.prompt().user(message).call().content().trim();OpenAiChatOptions options = OpenAiChatOptions.builder().model("THUDM/GLM-4-9B-0414").temperature(0.5).build();String content = chatClient.prompt().system("你是一個AI小助手,能幫助我們一起學習java").advisors(new LoggingAdvisor(),new ReReadingAdvisor()).user(message).options(options).call().content();return content;}
OpenAiChatOptions進行配置AI大模型
chatClient對OpenAiChatOptions配置的大模型進行配置
測試
統一配置
方法配置
通過測試的結果和日志可以知道,AI大模型既可以進行統一配置,也可以在方法上設置