SpringAI實現AI應用-自定義顧問(Advisor)

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大模型既可以進行統一配置,也可以在方法上設置

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/904633.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/904633.shtml
英文地址,請注明出處:http://en.pswp.cn/news/904633.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【HarmonyOS 5】App Linking 應用間跳轉詳解

目錄 什么是 App Linking 使用場景 工作原理 如何開發 1.開通 App Linking 2.確定域名 3.服務端部署 applinking.json 文件 4.AGC綁定域名 5.項目配置 6.組裝聚合鏈接 7.解析聚合鏈接中的參數 其他 如何獲取應用ID 什么是 App Linking App Linking 是一款創建跨…

什么是變量提升?(形象的比喻)

當然&#xff01;可以用幾個生活中的比喻來形象地解釋變量提升&#xff1a; ??1. 書架的占位符?? 想象你有一個書架&#xff0c;但還沒放書。 ? 變量提升&#xff08;var&#xff09;&#xff1a; 你先在書架上貼了一個標簽&#xff08;比如寫“我的書”&#xff09;&…

C++面向對象編程入門:從類與對象說起(一)

C語言是面向過程&#xff0c;關注的是過程&#xff0c;分析出求解問題的步驟&#xff0c;通過函數調用逐步解決問題&#xff0c;而C面向的是對象&#xff0c;關注的是對象&#xff0c;將一件事拆解成多個對象&#xff0c;靠對象之間互交完成。 目錄 類的定義 類的兩種定義 …

uniapp tabBar 中設置“custom“: true 在H5和app中無效解決辦法

uniapp小程序自定義底部tabbar&#xff0c;但是在轉成H5和app時發現"custom": true 無效&#xff0c;原生tabbar會顯示出來 解決辦法如下 在tabbar的list中設置 “visible”:false 代碼如下&#xff1a;"tabBar": {"custom": true,//"cust…

SpringBoot學生操行評分系統源碼設計開發

概述 基于SpringBoot框架開發的學生操行評分系統完整項目&#xff0c;該系統采用主流技術棧開發&#xff0c;包含完善的評分管理功能模塊&#xff0c;是學校管理、教育培訓機構理想的數字化解決方案&#xff0c;非常適合作為設計參考或二次開發基礎項目。 主要內容 5.1 管理…

從代碼學習深度學習 - 單發多框檢測(SSD)PyTorch版

文章目錄 前言工具函數數據處理工具 (`utils_for_data.py`)訓練工具 (`utils_for_train.py`)檢測相關工具 (`utils_for_detection.py`)可視化工具 (`utils_for_huitu.py`)模型類別預測層邊界框預測層連接多尺度預測高和寬減半塊基礎網絡塊完整的模型訓練模型讀取數據集和初始化…

基于STM32的溫濕度光照強度仿真設計(Proteus仿真+程序設計+設計報告+講解視頻)

這里寫目錄標題 **1.****主要功能****2.仿真設計****3.程序設計****4.設計報告****5.下載鏈接** 基于STM32的溫濕度光照強度仿真設計(Proteus仿真程序設計設計報告講解視頻&#xff09; 仿真圖Proteus 8.9 程序編譯器&#xff1a;keil 5 編程語言&#xff1a;C語言 設計編號…

SSH 服務部署指南

本指南涵蓋 OpenSSH 服務端的安裝、配置密碼/公鑰/多因素認證&#xff0c;以及連接測試方法。 適用系統&#xff1a;Ubuntu/Debian、CentOS/RHEL 等主流 Linux 發行版。 1. 安裝 SSH 服務端 Ubuntu/Debian # 更新軟件包索引 sudo apt update# 安裝 OpenSSH 服務端 sudo apt i…

《Python星球日記》 第46天:決策樹與隨機森林

名人說:路漫漫其修遠兮,吾將上下而求索。—— 屈原《離騷》 創作者:Code_流蘇(CSDN)(一個喜歡古詩詞和編程的Coder??) 專欄:《Python星球日記》,限時特價訂閱中ing 目錄 一、前言二、決策樹算法原理1. 決策樹簡介2. 決策樹的分裂準則(1) 信息熵與信息增益(2) 基尼不純…

Vue2:引入公共JS,通過this調用

tools.js // 圖片加上前綴 baseurl 是請求域名 img 是圖片路徑export function getimgurl(img) {return ${this.$baseurl}${img}}main.js import baseUrl from "/api/baseUrl.js" Vue.prototype.$baseurl baseUrlimport {getimgurl} from /api/tool.js; Vue.protot…

【Hot 100】 146. LRU 緩存

目錄 引言LRU 緩存官方解題LRU實現&#x1f4cc; 實現步驟分解步驟 1&#xff1a;定義雙向鏈表節點步驟 2&#xff1a;創建偽頭尾節點&#xff08;關鍵設計&#xff09;步驟 3&#xff1a;實現鏈表基礎操作操作 1&#xff1a;添加節點到頭部操作 2&#xff1a;移除任意節點 步驟…

【Linux】swap交換分區管理

目錄 一、Swap 交換分區的功能 二、swap 交換分區的典型大小的設置 2.1 查看交換分區的大小 2.1.1 free 2.1.2 cat /proc/swaps 或 swapon -s 2.1.3 top 三、使用交換分區的整體流程 3.1 案例一 3.2 案例二 一、Swap 交換分區的功能 計算機運行一個程序首先會將外存&am…

【計算機網絡】用戶從輸入網址到網頁顯示,期間發生了什么?

1.URL解析 瀏覽器分解URL&#xff1a;https://www.example.com/page 協議&#xff1a;https域名&#xff1a;www.example.com路徑&#xff1a;/page 2.DNS查詢&#xff1a; 瀏覽器向DNS服務器發送查詢請求&#xff0c;將域名解析為對應的IP地址。 3.CDN檢查(如果有)&#…

架空輸電線巡檢機器人軌跡優化設計

架空輸電線巡檢機器人軌跡優化 摘要 本論文針對架空輸電線巡檢機器人的軌跡優化問題展開研究,綜合考慮輸電線復雜環境、機器人運動特性及巡檢任務需求,結合路徑規劃算法、智能優化算法與機器人動力學約束,構建了多目標軌跡優化模型。通過改進遺傳算法與模擬退火算法,有效…

根據窗口大小自動調整頁面縮放比例,并保持居中顯示

vue 項目 直接上代碼 圖片u1.png 是個背景圖片 圖片u2.png 是個遮罩 <template><div id"app"><div class"viewBox"><divclass"screen":style"{ transform: translate(-50%,-50%…

初學Python爬蟲

文章目錄 前言一、 爬蟲的初識1.1 什么是爬蟲1.2 爬蟲的核心1.3 爬蟲的用途1.4 爬蟲分類1.5 爬蟲帶來的風險1.6. 反爬手段1.7 爬蟲網絡請求1.8 爬蟲基本流程 二、urllib庫初識2.1 http和https協議2.2 編碼解碼的使用2.3 urllib的基本使用2.4 一個類型六個方法2.5 下載網頁數據2…

oracle 數據庫sql 語句處理過程

14.1SQL語句處理過程 在進行SQL語句處理優化前&#xff0c;需要先熟悉和了解SQL語句的處理過程。 每種類型的語句在執行時都需要如下階段&#xff1a; 第1步: 創建游標。 第2步: 分析語句。 第5步: 綁定變量。 第7步: t運行語句。 第9步: 關閉游標。 如果使用了并行功能&#x…

pm2 list查詢服務時如何通過name或者namespace進行區分

在 PM2 中&#xff0c;如果 pm2 list 顯示的所有服務名稱&#xff08;name&#xff09;相同&#xff0c;就無法直觀地區分不同的進程。這時可以通過 --namespace&#xff08;命名空間&#xff09; 或 自定義 name 來區分服務。以下是解決方案&#xff1a; 方法 1&#xff1a;啟…

[python] 函數基礎

二 函數參數 2.1 必備參數(位置參數) 含義: 傳遞和定義參數的順序及個數必須一致 格式: def func(a,b) def func_1(id,passwd):print("id ",id)print("passwd ",passwd) func_1(10086,123456) 2.2 默認參數 函數: 為函數的參數提供一個默認值,如果調…

超大規模SoC后仿真流程與優化

在超大規模SoC設計中,是否需要進行全芯片后仿真(Full-Chip Post-layout Simulation)取決于多個因素,包括設計復雜度、項目風險、資源限制以及驗證目標。以下是針對這一問題的系統性分析: 1. 全芯片后仿真的必要性 需要全芯片后仿真的場景 系統級交互驗證: 跨模塊信號交互…