在springboot項目中調用通義千問api多輪對話并實現流式輸出

官網文檔

阿里靈積提供了詳細的官方文檔

如何實現多輪對話

官方文檔中提到只需要把每輪對話中返回結果添加到消息管理器中,就可以實現多輪對話。本質上就是將歷史對話再次發送給接口。

如何實現流式輸出

官方文檔中提出使用streamCall()方法就可以實現流式輸出,在ResultCallback<GenerationResult>參數中可以指點每個事件的處理動作。

流式調用方法沒有返回GenerationResult結果類,如何實現多輪對話

方法一

我們每次調用完成后把得到的結果手動構建消息對象并加入消息管理類。

不知道是不是我使用的sdk版本問題(因為老的版本有出現調用okhttp報錯的情況,我的在阿里云提交工單后,工作人員給我的最新版本是2.10.1,我當前就在使用這個版本)。經過實際測試,msgManager.get()方法可能會出現第一條對話的發送對象是assistant的情況。

如果第一條對話的發送對象不是user或者system,并且user和assistant沒有在歷史對話中輪流出現接口會報錯的!!!!(我沒有報錯的截圖,哈哈哈哈)

Message assistantMsg = Message.builder().role(Role.ASSISTANT.getValue()).content("如何做西紅柿燉牛腩?").build();
msgManager.add(assistantMsg);

方法二

我們自己來控制歷史對話

@Component
public class QwenModelService{private Generation gen;@Resourceprivate AiWebsocketService aiWebsocketService;public void createGen(){gen = new Generation();};private static final Logger logger = LoggerFactory.getLogger(QwenModelService.class);/*** prompt 用戶對話* request 用戶請求對象* identity 用戶身份標識*/public String answer(String prompt, HttpServletRequest request, String identity) {// 通過身份標識在緩存中獲取對話對象、歷史消息對象、參數對象List<AiDialogue> dialogues = CachePool.AI_DIALOGUE_LIST_MAP.get(identity).computeIfAbsent(ConstValuePool.QWEN_DIALOGUES, k -> new LinkedList<>());dialogues.add(AiDialogue.createUserDialogue(prompt));List<Message> msgManager = CachePool.QWEN_MESSAGE_DIALOGUES_MAP.get(identity);QwenParam param = CachePool.QWEN_PARAM_MAP.get(identity);// 如果第一次發送消息需要初始化歷史消息對象if (msgManager == null) {msgManager = new ArrayList<>();CachePool.QWEN_MESSAGE_DIALOGUES_MAP.put(identity, msgManager);Message systemMsg = Message.builder().role(Role.SYSTEM.getValue()).content("You are a helpful assistant.").build();msgManager.add(systemMsg);Message userMsg = Message.builder().role(Role.USER.getValue()).content(prompt).build();msgManager.add(userMsg);}else {msgManager.add(Message.builder().role("user").content(prompt).build());param.setMessages(msgManager);}// 如果第一次發送消息需要初始化參數對象if (param == null) {param = QwenParam.builder().model(Generation.Models.QWEN_MAX).messages(msgManager).resultFormat(QwenParam.ResultFormat.MESSAGE).topP(0.8).enableSearch(true).incrementalOutput(true).build();CachePool.QWEN_PARAM_MAP.put(identity, param);}try {logger.debug("發送的請求為{}",param);// 同步信號量Semaphore semaphore = new Semaphore(0);// 結果拼接對象StringBuilder resultBuilder = new StringBuilder();// 流式調用gen.streamCall(param, new ResultCallback<GenerationResult>(){@Overridepublic void onEvent(GenerationResult generationResult) {String newMessage = generationResult.getOutput().getChoices().get(0).getMessage().getContent();StringBuilder finalResBuilder = resultBuilder.append(newMessage);// 這里是對markdown代碼塊進行判斷,如果當前代碼塊未結束,需要手動結束// 否則前端的代碼塊顯示會出問題// 代碼塊判斷的功能就是對"```"字符串計數,偶數個就是結束了,奇數個就是沒結束if (1 == (1 & StringUtil.countSubStr(finalResBuilder,ConstValuePool.MARKDOWN_CODE_BLOCK_START))) {finalResBuilder = new StringBuilder(finalResBuilder).append(ConstValuePool.MARKDOWN_CODE_BLOCK_END);}// 通過websocket返回給前端aiWebsocketService.sendMessage(finalResBuilder.toString(), identity);}// 結束或者報錯需要釋放同步信號量@Overridepublic void onComplete() {semaphore.release();}@Overridepublic void onError(Exception e) {semaphore.release();logger.error("通義千問運行出錯, 報錯棧如下");Throwable t = e;while (t != null) {logger.error( t.toString());t = e.getCause();}}});semaphore.acquire();String resString = resultBuilder.toString();// 把返回消息加入歷史消息中
msgManager.add(Message.builder().role("assistant").content(resString).build());// 如果歷史消息量過大或者第一條消息發送對象不是user,刪除歷史消息// 下標0是system消息while (msgManager.size() > ConstValuePool.QWEN_MAX_MESSAGE|| !"user".equals(msgManager.get(1).getRole())) {msgManager.remove(1);}// 添加到對話記錄中,方便前端查詢對話記錄dialogues.add(AiDialogue.createAssistantDialogue(resString));return "";} catch (NoApiKeyException e) {logger.error("調用通義千問缺少ApiKey");throw new AiException("沒有ApiKey", e);} catch (Exception e) {logger.error("調用通義千問出現問題:{}",e.getMessage());throw new AiException("出現了一些問題", e);}}}

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

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

相關文章

ViT的若干細節

之前只看了ViT的大概結構&#xff0c;具體的模型細節和代碼實現知之甚少。隨著ViT逐漸成為CV領域的backbone&#xff0c;有必要重新審視下。 patch -> token 為了將圖片處理成序列格式&#xff0c;很自然地想到將圖片分割成一個個patch&#xff0c;再把patch處理成token。 …

Mysql整理-主從復制

MySQL的主從復制是一種常見的數據復制和分布式數據共享方法。在這種架構中,一個MySQL服務器充當主(master)服務器,而一個或多個其他MySQL服務器充當從(slave)服務器。數據從主服務器復制到從服務器,實現數據的分布和備份。這種設置主要用于數據備份、讀取擴展、災難恢復…

Python系列(20)—— 循環語句

Python中的循環控制語句 一、引言 在Python編程中&#xff0c;循環是重復執行一段代碼直到滿足特定條件的基本結構。Python提供了多種循環控制語句&#xff0c;如For 和While &#xff0c;以及用于控制循環流程的輔助語句&#xff0c;如Break、Continue和Pass。這些語句的組合…

SpringBoot緩存

目錄 緩存支持 緩存集成 redis緩存集成 緩存支持 Spring 框架只提供抽象&#xff0c;不提供具體的緩存存儲&#xff0c;底層需要依賴第三方存儲組件&#xff0c;如果當前應用沒有注冊CacheManager 或者 CacheResolver 實例&#xff0c;Spring Boot 會按以下緩存組件的順序來…

[藍橋杯 2020 省 B1] 整數拼接

一、題目描述 P8712 [藍橋杯 2020 省 B1] 整數拼接 二、題目簡析 我們選兩個數 a a a 和 b b b&#xff0c;用 f ( a , b ) f(a, b) f(a,b) 表示 a a a 在前、 b b b 在后的拼接&#xff0c;即 f ( a , b ) a ? 1 0 b . s i z e b f(a, b) a * 10^{b.size} b f(a,…

Linux學習:初始Linux

目錄 1. 引子&#xff1a;1.1 簡述&#xff1a;操作系統1.2 學習工具 2. Linux操作系統中的一些基礎概念與指令2.1 簡單指令2.2 ls指令與文件2.3 cd指令與目錄2.4 文件目錄的新建與刪除指令2.5 補充指令1&#xff1a;2.6 文件編輯與拷貝剪切2.7 文件的查看2.8 時間相關指令2.9 …

洛谷P1256 顯示圖像

廣搜練手題 題目鏈接 思路 打印每個數與其最近的 1 1 1的曼哈頓距離&#xff0c;顯然廣搜&#xff0c;存儲每一個 1 1 1&#xff0c;針對每一個 1 1 1開始廣搜&#xff0c;逐層更新&#xff0c;每輪后更新的為兩輪之中的最小曼哈頓距離 ACcode #include<bits/stdc.h>…

波動數列(藍橋杯)

問題描述&#xff1a; 觀察如下數列&#xff1a; 1 3 0 2 -1 1 -2 … 這個數列中后一項總是比前一項增加 2 或者減少 3。 棟棟對這種數列很好奇&#xff0c;他想知道長度為 n nn 和為 s ss 而且后一項總是比前一項增加 a aa 或者減少 b bb 的整數數列可能有多少種呢&#xff1f…

非專業程序員常用vscode插件

牙叔教程 簡單易懂 我常用的腳本語言是js, python. AutoHotkey v2 Language Support vscode-autohotkey-debug 由于工作有寫重復, 要用到autohotkey, 所以裝這個插件 Black Formatter 格式化python代碼 Bookmarks 書簽 change-case 命名方式: 小駝峰, 下劃線, 等命名風格轉…

【網站項目】202物流管理系統

&#x1f64a;作者簡介&#xff1a;擁有多年開發工作經驗&#xff0c;分享技術代碼幫助學生學習&#xff0c;獨立完成自己的項目或者畢業設計。 代碼可以私聊博主獲取。&#x1f339;贈送計算機畢業設計600個選題excel文件&#xff0c;幫助大學選題。贈送開題報告模板&#xff…

不會代碼的時候,如何使用Jmeter完成接口測試

1.接口測試簡介 接口測試是測試系統組件間接口的一種測試。接口測試主要用于檢測外部系統與系統之間以及內部各個子系統之間的交互點。測試的重點是要檢查數據的交換&#xff0c;傳遞和控制管理過程&#xff0c;以及系統間的相互邏輯依賴關系等。 2.接口測試流程 接口測試的…

【貪玩巴斯】VisualStudio+Github聯合工作指令

實現在本地VisualStudio進行代碼改寫&#xff0c;同時上傳Github和項目組成員實時更新代碼。 格式指令&#xff1a; alt z ctrl shift p后 輸入 wordwrap —— 進行格式排盤&#xff08;在一頁中能夠完全顯示&#xff0c;代碼會自動換行&#xff09; git pull origin mast…

2024.3.1 小項目

1、機械臂 #include <myhead.h> #define SER_IP "192.168.125.32" //服務器端IP #define SER_PORT 8888 //服務器端端口號#define CLI_IP "192.168.68.148" //客戶端IP #define CLI_PORT 9999 /…

串的BF算法(樸素查找算法)

串的模式匹配&#xff1a;在主串str的pos位置查找子串sub&#xff0c;找到返回下標&#xff0c;沒有找到返回-1。 1.BF算法思想 相等則繼續比較&#xff0c;不相等則回退&#xff1b;回退是i退到剛才位置的下一個&#xff08;i-j1&#xff09;;j退到0&#xff1b;利用子串是否…

Python matplotlib

目錄 1、安裝 matplotlib 2、繪制折線圖 修改標簽文字和線條粗細 校正圖形 3、繪制散點圖 繪制單點 繪制一系列點 自動計算數據 刪除數據點的輪廓 自定義顏色 使用顏色映射 自動保存圖表 4、隨機漫步 創建 RandomWalk() 類 選擇方向 繪制隨機漫步圖 給點著色 …

最簡單的ubuntu遠程桌面方法

最簡單的ubuntu遠程桌面方法 部署環境&#xff1a;Ubuntu 20.04 LTS 現在最常用的遠程控制Linux系統的方法是通過XRDP、VNC等&#xff0c;但是安裝配置過程繁瑣復雜&#xff0c;經常出現各種問題導致連接失敗&#xff0c;另外一方面延遲較高&#xff0c;操作卡頓。 經過我堅…

【Java項目介紹和界面搭建】拼圖小游戲——鍵盤、鼠標事件

&#x1f36c; 博主介紹&#x1f468;?&#x1f393; 博主介紹&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高興認識大家~ ?主攻領域&#xff1a;【滲透領域】【應急響應】 【Java】 【VulnHub靶場復現】【面試分析】 &#x1f389;點贊?評論?收藏 …

DDS數據分發服務——提升汽車領域數據傳輸效率

1.引言 隨著智能化技術的快速發展&#xff0c;汽車行業正經歷著一場革命性的變革。如今的分布式系統變得越來越復雜且龐大&#xff0c;對網絡通信基數要求在功能和性能層面越來越高。數據分發服務&#xff08;DDS&#xff09;作為一項先進的數據傳輸解決方案&#xff0c;在汽車…

2369. 檢查數組是否存在有效劃分(動態規劃)

2024-3-1 文章目錄 [2369. 檢查數組是否存在有效劃分](https://leetcode.cn/problems/check-if-there-is-a-valid-partition-for-the-array/)思路&#xff1a;代碼&#xff1a; 2369. 檢查數組是否存在有效劃分 思路&#xff1a; 1.狀態定義:f[i]代表考慮將[0,i]是否能被有效劃…

電腦要用多少V的電源?電腦電源輸入電壓是市電

臺式電源的輸出電壓是多少&#xff1f; 電腦電源輸出一般有三種不同的電壓&#xff0c;分別是&#xff1a; 12V、5V、3.3V。 電腦電源負責給電腦配件供電&#xff0c;如CPU、主板、內存條、硬盤、顯卡等&#xff0c;是電腦的重要組成部分。 工作電流根據不同的硬件及其使用狀…