Java如何基于okhttp請求SSE接口流式返回詳解
前言
最近在開發(fā)跟大模型相關(guān)的業(yè)務(wù),需要用java去請求大模型的對話接口并支持流式的返回,變用到了sse接口。首先介紹一下什么是SSE,SSE ( Server-sent Events )是 WebSocket 的一種輕量代替方案,使用 HTTP 協(xié)議。
嚴(yán)格地說,HTTP 協(xié)議是沒有辦法做服務(wù)器推送的,但是當(dāng)服務(wù)器向客戶端聲明接下來要發(fā)送流信息時(shí),客戶端就會(huì)保持連接打開,SSE 使用的就是這種原理。
一、SSE 能做什么?
理論上, SSE 和 WebSocket 做的是同一件事情。當(dāng)你需要用新數(shù)據(jù)局部更新網(wǎng)絡(luò)應(yīng)用時(shí),SSE 可以做到不需要用戶執(zhí)行任何操作,便可以完成。
這種技術(shù)通常用于實(shí)現(xiàn)實(shí)時(shí)更新、通知和事件驅(qū)動(dòng)的應(yīng)用程序,例如實(shí)時(shí)聊天、股票市場更新、新聞通知等。
二、SSE vs. WebSocket
SSE 是單向通道,只能服務(wù)器向客戶端發(fā)送消息,如果客戶端需要向服務(wù)器發(fā)送消息,則需要一個(gè)新的 HTTP 請求。這對比 WebSocket 的雙工通道來說,會(huì)有更大的開銷。這么一來的話就會(huì)存在一個(gè)「什么時(shí)候才需要關(guān)心這個(gè)差異?」的問題,如果平均每秒會(huì)向服務(wù)器發(fā)送一次消息的話,那應(yīng)該選擇 WebSocket。如果一分鐘僅 5 - 6 次的話,其實(shí)這個(gè)差異并不大。
在瀏覽器兼容方面,兩者差不多。在較早之前,每當(dāng)需要建立雙向 Socket 時(shí)就會(huì)使用 Flash,在 移動(dòng)瀏覽器不支持 Flash 的情況下,WebSocket 的兼容是比較難做的。
SSE 我認(rèn)為最大的優(yōu)勢是便利,實(shí)現(xiàn)一個(gè)完整的服務(wù)僅需要少量的代碼;可以在現(xiàn)有的服務(wù)中使用,不需要啟動(dòng)一個(gè)新的服務(wù);可以用任何一種服務(wù)端語言中使用;基于 HTTP / HTTPS 協(xié)議,可以直接運(yùn)行于現(xiàn)有的代理服務(wù)器和認(rèn)證技術(shù)。有了這些優(yōu)勢,在選擇使用 SSE 時(shí)就已經(jīng)為自己的項(xiàng)目節(jié)約了不少成本。
三、下面來寫一下如何用java調(diào)用sse接口
我們可以借助okhttp來實(shí)現(xiàn),首先引入okhttp-sse的依賴:
<dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp-sse</artifactId> <version>4.12.0</version> </dependency>
調(diào)用代碼如下:
OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .writeTimeout(50, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.MINUTES) .build(); EventSource.Factory factory = EventSources.createFactory(client); // 請求體 HashMap<String, Object> map = new HashMap<>(); map.put("prompt","哈嘍,你好"); map.put("history", Arrays.asList()); map.put("temperature",0.9); map.put("top_p",0.7); map.put("max_new_tokens",4096); String json = JsonUtil.objectToString(map); RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),json); // 請求對象 Request request = new Request.Builder() .url("http://localhost:8001/chat") .post(body) .build(); // 自定義監(jiān)聽器 EventSourceListener eventSourceListener = new EventSourceListener() { @Override public void onOpen(EventSource eventSource, Response response) { super.onOpen(eventSource, response); } @Override public void onEvent(EventSource eventSource, @Nullable String id, @Nullable String type, String data) { // 接受消息 data super.onEvent(eventSource, id, type, data); } @Override public void onClosed(EventSource eventSource) { super.onClosed(eventSource); } @Override public void onFailure(EventSource eventSource, @Nullable Throwable t, @Nullable Response response) { super.onFailure(eventSource, t, response); } }; // 創(chuàng)建事件 EventSource eventSource = factory.newEventSource(request, eventSourceListener);
運(yùn)行效果
""
"你"
"你好"
"你好??"
"你好??!"
"你好??!很高興"
"你好??!很高興見到"
"你好??!很高興見到你"
"你好??!很高興見到你,"
"你好??!很高興見到你,歡迎"
"你好??!很高興見到你,歡迎問我"
"你好??!很高興見到你,歡迎問我任何"
"你好??!很高興見到你,歡迎問我任何問題"
"你好??!很高興見到你,歡迎問我任何問題。"
總結(jié)
到此這篇關(guān)于Java如何基于okhttp請求SSE接口流式返回的文章就介紹到這了,更多相關(guān)Java請求SSE接口流式返回內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于Java?CPU或內(nèi)存使用率過高問題定位
Spring?cloud微服務(wù)廣泛應(yīng)用后,服務(wù)的監(jiān)控和運(yùn)維壓力也與日俱增,經(jīng)常有服務(wù)出現(xiàn)CPU或者內(nèi)存使用率過高的告警,那么遇到這樣的問題我們該如何排查呢?我們可以借助哪些工具來定位問題呢?本文將介紹一下遇到此類問題的解決思路和方法2024-10-10SpringBoot?+?Redis如何解決重復(fù)提交問題(冪等)
在開發(fā)中,一個(gè)對外暴露的接口可能會(huì)面臨瞬間的大量重復(fù)請求,本文就介紹了SpringBoot + Redis如何解決重復(fù)提交問題,具有一定的參考價(jià)值,感興趣的可以了解一下2021-12-12基于Jpa中ManyToMany和OneToMany的雙向控制
這篇文章主要介紹了Jpa中ManyToMany和OneToMany的雙向控制,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12Java Spring數(shù)據(jù)單元配置過程解析
這篇文章主要介紹了Java Spring數(shù)據(jù)單元配置過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-12-12