當前位置: 妍妍網 > 碼農

Semantic Kernel 中的流式輸出SSE與Vue3前端接收範例

2024-06-18碼農

本文將介紹如何在使用 Semantic Kernel 框架的 ASP.NET 計畫中使用流式輸出 SSE(Server-Sent Events),並展示如何在Vue3前端套用中接收這些數據。並介紹了如何使用 @microsoft/fetch-event-source 庫使用 POST 方法來接收 SSE 數據。

1. 背景

在大模型的套用場景中,使用者經常需要與模型進行即時互動,例如,生成文本、回答問題等。這些場景要求數據傳輸能夠快速且連續,以提供流暢的使用者體驗。SSE作為一種基於HTTP的標準協定,允許伺服器向客戶端推播即時數據,非常適合於此類套用。

2. 什麽是 SSE

SSE 並不是一種新的技術,但是隨著 ChatGPT 的火熱,這種技術又重新受到了關註。

SSE(Server-Sent Events)是一種基於 HTTP 的伺服器推播技術,允許伺服器即時向客戶端推播數據。與 WebSocket 不同,SSE 是單向通訊,只能由伺服器向客戶端推播數據,而客戶端無法向伺服器發送數據。SSE 使用簡單,易於實作,適用於需要即時數據推播的場景。

SSE 的工作原理是,客戶端透過 EventSource 物件與伺服器建立連線,伺服器端透過發送特定格式的數據(如 data: Hello, world!\n\n )來推播訊息給客戶端。客戶端收到訊息後,可以透過監聽 message 事件來處理數據。

3. 在 Semantic Kernel 中使用 SSE

如果要使用 SSE,首先需要在 ASP.NET 計畫正確的引入 Semantic Kernel,並在控制器中添加 SSE 的處理邏輯。

3.1. 引入 Semantic Kernel

以下是 Program.cs 中引入 Semantic Kernel 的相關程式碼,這裏以 Azure OpenAI 做演示:

usingMicrosoft.SemanticKernel;var builder = WebApplication.CreateBuilder(args);// ··· 略去其他程式碼// 添加語意內核builder.Services.AddKernel();builder.Services.AddOpenAIChatCompletion("gpt-4o", newOpenAIClient(newUri("https://[your-gpt].openai.azure.com/"), newAzure.AzureKeyCredential("[your-key]")));// ··· 略去其他程式碼

3.2. 控制器中添加 SSE 處理邏輯

在控制器中添加 SSE 處理邏輯,需要使用 Kernel InvokePromptStreamingAsync InvokeStreamingAsync 方法來獲取模型的流式結果輸出,並將輸出推播給客戶端。

範例程式碼如下:

usingSang.AspNetCore.CommonLibraries.Models;[HttpPost("test")][Produces("text/event-stream")]public async Task<IResult> SSETest(){var content = _kernel.InvokePromptStreamingAsync("什麽是快樂星球?");Response.Headers.ContentType = "text/event-stream";Response.Headers.CacheControl = "no-cache"; await Response.Body.FlushAsync();if (content isnull) {var error = JsonSerializer.Serialize(MessageModel<string>.Fail("生成失敗"), _jsonSerializerOptions); await Response.WriteAsync($"data: {error}\n\n"); await Response.Body.FlushAsync(); }else { await foreach (var item in content) { await Response.WriteAsync($"data: {MessageModel<string>.Ok(item.ToString())}\n\n"); await Response.Body.FlushAsync(); } }// 結束標記 await Response.WriteAsync($"data: [DONE]\n\n"); await Response.Body.FlushAsync();returnResults.Empty;}

在上面額程式碼中,我們使用 InvokePromptStreamingAsync 方法獲取模型的流式輸出,並透過 Response.WriteAsync 方法將輸出推播給客戶端。每個完整封包後跟隨兩個換行符( \n\n ),這是SSE協定的要求。在客戶端接收到 [DONE] 標記後,表示數據傳輸結束。這裏的 MessageModel 是一個自訂的訊息模型,可以安裝 Sang.AspNetCore.CommonLibraries 包來使用,每個封包(message)都是一個完整的 json 數據,方便解析。下圖是測試結果:

Swagger 流式請求

4. 前端接收

在Vue3套用中,我們可以使用 EventSource 介面或者第三方庫來接收SSE數據。對於原生使用和 EventSource 的更多資訊,請參考 MDN 文件 [1]

這裏,我們將使用 @microsoft/fetch-event-source 庫來演示如何接收伺服器發送的數據。

首先,安裝 @microsoft/fetch-event-source 庫:

npm install @microsoft/fetch-event-source

然後,在Vue元件中,我們可以這樣接收數據:

import { ref } from'vue';import { fetchEventSource } from'@microsoft/fetch-event-source';const dataStream = ref('');const fetchDataStream = () => { fetchEventSource('/test', { method: 'POST', headers: {"Content-Type": 'application/json', }, body: JSON.stringify({ /* 請求體 */ }), onmessage(event) {if (event.data === '[DONE]') { console.log('Stream ended');return; }let data = JSON.parse(event.data); dataStream.value += data.data;// 更新UI等操作 }, onerror(error) { console.error('Stream encountered error:', error); } });};

在上面的程式碼中,我們使用 fetchEventSource 方法訂閱了伺服器端的SSE。每當伺服器發送新的數據時, onmessage 回呼就會被觸發,我們可以在這裏更新Vue元件的狀態,以實作數據的即時展示。

註意,這裏演示使用的是 POST 請求,在這個案例中直接將伺服端和接收端使用 GET 請求也是可以的。但是預設瀏覽器 EventSource API 對允許發出的請求型別施加了一些限制作,其中就包括不允許使用 POST 請求。因此,如果需要使用 POST 請求,可以使用 @microsoft/fetch-event-source 庫。具體的更多資訊可以參考 GitHub 倉庫 Azure/fetch-event-source [2]

5. 結語

SSE提供了一種高效、簡單的方法,允許伺服器向客戶端推播即時數據。透過結合Semantic Kernel和Vue3,我們可以構建出能夠即時響應大模型推理結果的Web套用,從而提供更加流暢和動態的使用者體驗。希望本文所介紹的內容能夠幫助到你,歡迎留言討論。

References

[1] MDN 文件: https://developer.mozilla.org/zh-CN/docs/Web/API/Server-sent_events/Using_server-sent_events
[2] GitHub 倉庫 Azure/fetch-event-source: https://github.com/Azure/fetch-event-source?wt.mc_id=DT-MVP-5005195