目錄
小結一下
首頁 科技週邊 人工智慧 ChatGPT是如何做到一個字一個字輸出的?

ChatGPT是如何做到一個字一個字輸出的?

Jun 02, 2023 pm 05:40 PM
大語言模型

ChatGPT是如何做到一個字一個字輸出的?

ChatGPT回答問題時,是一個字一個字彈出的,給人一種在認真思考的感覺。

這段對話的基本內容是:

#問:大語言生成式模型是如何運作的
答案:大型語言生成模型(如GPT-3)是基於深度學習技術的神經網路模型。這些模型通常使用一種稱為"Transformer"的架構,該架構在自然語言處理領域中取得了巨大的成功。

以下是大型語言生成模型的工作原理概述:

...省略一段...

產生文字:一旦模型經過訓練,就可以使用它來產生文字。給定一個初始文字或提示,模型會根據已經學到的機率分佈生成下一個單詞,然後使用生成的單字作為輸入,並繼續生成下一個單詞,以此類推,直到達到所需的文字長度或生成終止符號。

... 省略一段...

大語言模型,Large Language Model,簡稱LLM。

從模型的角度來看,LLM每進行一次推理產生一個token,直到達到文字長度限製或產生終止符。

從服務端的角度來看,產生的token需要透過HTTPS協定逐一回到瀏覽器端。

Client-Server 模式下,常規的互動方式是client端傳送一次請求,接收一次回應。顯然,這無法滿足ChatGPT回覆問題的場景。

其次,我們可能會想到websocket,它依賴HTTP實作握手,升級成WebSocket。不過WebSocket需要client和server都持續佔用一個socket,server側成本比較高。

ChatGPT使用的是一種折衷方案: server-sent event(簡稱SSE). 我們從OpenAI的API 文件可以發現這一點:

ChatGPT是如何做到一個字一個字輸出的?

#SSE 模式下,client只需要向server傳送一次請求,server就能持續輸出,直到需要結束。整個交互過程如下圖所示:

ChatGPT是如何做到一個字一個字輸出的?

SSE仍然使用HTTP作為應用層傳輸協議,充分利用HTTP的長連接能力,實現服務端推送能力。

從程式碼層面來看,SSE模式與單次HTTP請求不同的點有:

  1. client端需要開啟keep -alive,保證連線不會逾時。
  2. HTTP回應的Header包含 Content-Type=text/event-stream,Cache-Cnotallow=no-cache 等。
  3. HTTP回應的body一般是 "data: ..." 這樣的結構。
  4. HTTP回應裡可能有一些空數據,以避免連線逾時。

以ChatGPT API 為例,在傳送請求時,將stream參數設為true就啟用了SSE特性,但在讀取資料的SDK裡需要稍加註意。

在常規模式下,拿到 http.Response 後,請用ioutil.ReadAll 將資料讀出來即可,程式碼如下:

func main() {payload := strings.NewReader(`{"model": "gpt-3.5-turbo","messages": [{"role": "user", "content": "大语言生成式模型是如何工作的"}],"max_tokens": 1024,"temperature": 1,"top_p": 1,"n": 1,"stream": false}`)client := &http.Client{}req, _ := http.NewRequest("POST", "https://api.openai.com/v1/chat/completions", payload)req.Header.Add("Content-Type", "application/json")req.Header.Add("Authorization", "Bearer <openai-token>")resp, err := client.Do(req)if err != nil {fmt.Println(err)return}defer resp.Body.Close()body, _ := ioutil.ReadAll(resp.Body)fmt.Println(string(body))}</openai-token>
登入後複製

執行大概耗費20s ,得到一個完整的結果:

{"id": "chatcmpl-7KklTf9mag5tyBXLEqM3PWQn4jlfD","object": "chat.completion","created": 1685180679,"model": "gpt-3.5-turbo-0301","usage": {"prompt_tokens": 21,"completion_tokens": 358,"total_tokens": 379},"choices": [{"message": {"role": "assistant","content": "大语言生成式模型通常采用神经网络来实现,具体工作流程如下:\n\n1. 数据预处理:将语料库中的文本数据进行预处理,包括分词、删除停用词(如“的”、“了”等常用词汇)、去重等操作,以减少冗余信息。\n\n2. 模型训练:采用递归神经网络(RNN)、长短期记忆网络(LSTM)或变种的Transformers等模型进行训练,这些模型都具有一定的记忆能力,可以学习到语言的一定规律,并预测下一个可能出现的词语。\n\n3. 模型应用:当模型完成训练后,可以将其应用于实际的生成任务中。模型接收一个输入文本串,并预测下一个可能出现的词语,直到达到一定长度或遇到结束符号为止。\n\n4. 根据生成结果对模型进行调优:生成的结果需要进行评估,如计算生成文本与语料库文本的相似度、流畅度等指标,以此来调优模型,提高其生成质量。\n\n总体而言,大语言生成式模型通过对语言的规律学习,从而生成高质量的文本。"},"finish_reason": "stop","index": 0}]}
登入後複製

#如果我們將stream 設為true,不做任何修改,請求總消耗28s ,體現對於很多條stream 訊息:

ChatGPT是如何做到一個字一個字輸出的?

上面這張圖是一張Postman呼叫chatgpt api的圖,走的就是ioutil.ReadAll 的模式。為了實現stream讀取,我們可以分段讀取 http.Response.Body。以下是這種方式可行的原因:

  1. http.Response.Body 的類型是 io.ReaderCloser# ,底層依賴一個HTTP連接,支援stream讀。
  2. SSE 傳回的資料透過換行符號\n進行分割

所以修正的方法是透過 bufio.NewReader(resp.Body)包裝起來,並在一個for-loop裡讀取, 程式碼如下:

// stream event 结构体定义type ChatCompletionRspChoiceItem struct {Deltamap[string]string `json:"delta,omitempty"` // 只有 content 字段Indexint `json:"index,omitempty"`Logprobs *int`json:"logprobs,omitempty"`FinishReason string`json:"finish_reason,omitempty"`}type ChatCompletionRsp struct {IDstring`json:"id"`Objectstring`json:"object"`Created int `json:"created"` // unix secondModel string`json:"model"`Choices []ChatCompletionRspChoiceItem `json:"choices"`}func main() {payload := strings.NewReader(`{"model": "gpt-3.5-turbo","messages": [{"role": "user", "content": "大语言生成式模型是如何工作的"}],"max_tokens": 1024,"temperature": 1,"top_p": 1,"n": 1,"stream": true}`)client := &http.Client{}req, _ := http.NewRequest("POST", "https://api.openai.com/v1/chat/completions", payload)req.Header.Add("Content-Type", "application/json")req.Header.Add("Authorization", "Bearer "+apiKey)req.Header.Set("Accept", "text/event-stream")req.Header.Set("Cache-Control", "no-cache")req.Header.Set("Connection", "keep-alive")resp, err := client.Do(req)if err != nil {fmt.Println(err)return}defer resp.Body.Close()reader := bufio.NewReader(resp.Body)for {line, err := reader.ReadBytes('\n')if err != nil {if err == io.EOF {// 忽略 EOF 错误break} else {if netErr, ok := err.(net.Error); ok && netErr.Timeout() {fmt.Printf("[PostStream] fails to read response body, timeout\n")} else {fmt.Printf("[PostStream] fails to read response body, err=%s\n", err)}}break}line = bytes.TrimSuffix(line, []byte{'\n'})line = bytes.TrimPrefix(line, []byte("data: "))if bytes.Equal(line, []byte("[DONE]")) {break} else if len(line) > 0 {var chatCompletionRsp ChatCompletionRspif err := json.Unmarshal(line, &chatCompletionRsp); err == nil {fmt.Printf(chatCompletionRsp.Choices[0].Delta["content"])} else {fmt.Printf("\ninvalid line=%s\n", line)}}}fmt.Println("the end")}
登入後複製

看完client端,我們再看server端。現在我們嘗試mock chatgpt server逐字回傳一段文字。這裡牽涉到兩個點:

  1. Response Header 需要設定 Connection 為 keep-alive 和 Content-Type 為 text/event-stream。
  2. 寫入 respnose 以後,需要flush到client端。

程式碼如下:

func streamHandler(w http.ResponseWriter, req *http.Request) {w.Header().Set("Connection", "keep-alive")w.Header().Set("Content-Type", "text/event-stream")w.Header().Set("Cache-Control", "no-cache")var chatCompletionRsp ChatCompletionRsprunes := []rune(`大语言生成式模型通常使用深度学习技术,例如循环神经网络(RNN)或变压器(Transformer)来建模语言的概率分布。这些模型接收前面的词汇序列,并利用其内部神经网络结构预测下一个词汇的概率分布。然后,模型将概率最高的词汇作为生成的下一个词汇,并递归地生成一个词汇序列,直到到达最大长度或遇到一个终止符号。在训练过程中,模型通过最大化生成的文本样本的概率分布来学习有效的参数。为了避免模型产生过于平凡的、重复的、无意义的语言,我们通常会引入一些技巧,如dropout、序列扰动等。大语言生成模型的重要应用包括文本生成、问答系统、机器翻译、对话建模、摘要生成、文本分类等。`)for _, r := range runes {chatCompletionRsp.Choices = []ChatCompletionRspChoiceItem{{Delta: map[string]string{"content": string(r)}},}bs, _ := json.Marshal(chatCompletionRsp)line := fmt.Sprintf("data: %s\n", bs)fmt.Fprintf(w, line)if f, ok := w.(http.Flusher); ok {f.Flush()}time.Sleep(time.Millisecond * 100)}fmt.Fprintf(w, "data: [DONE]\n")}func main() {http.HandleFunc("/stream", streamHandler)http.ListenAndServe(":8088", nil)}
登入後複製

#在真實場景中,要傳回的資料來自另一個服務或函數調用,如果這個服務或函數呼叫回傳時間不穩定,可能導致client端長時間收不到訊息,所以一般的處理方式是:

  1. #對第三方的呼叫放到一個goroutine 中。
  2. 透過 time.Tick 建立一個計時器,向client端發送空白訊息。
  3. 建立一個timeout channel,避免回應時間太久。

為了能夠從不同的channel讀取數據,select 是一個不錯的關鍵字,例如這段示範程式碼:

// 声明一个 event channel// 声明一个 time.Tick channel// 声明一个 timeout channelselect {case ev := <h2 id="小結一下">小結一下</h2><p style="text-align: justify;"><span style="color: #333333;">大語言模型產生響應整個結果的過程是比較漫長的,但逐token產生的響應比較快,ChatGPT將這一特性與SSE技術充分結合,一個字一個字地彈出回复,在用戶體驗上實現了質的提升。 </span></p><p style="text-align: justify;"><span style="color: #333333;">綜觀生成式模型,不管是LLAMA/小羊駝 (不能商用),還是Stable Diffusion/Midjourney。在提供線上服務時,均可利用SSE技術節省提升使用者體驗,節省伺服器資源。 </span></p>
登入後複製

以上是ChatGPT是如何做到一個字一個字輸出的?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

本地使用Groq Llama 3 70B的逐步指南 本地使用Groq Llama 3 70B的逐步指南 Jun 10, 2024 am 09:16 AM

譯者|布加迪審校|重樓本文介紹如何使用GroqLPU推理引擎在JanAI和VSCode中產生超快速反應。每個人都致力於建立更好的大語言模型(LLM),例如Groq專注於AI的基礎設施方面。這些大模型的快速響應是確保這些大模型更快捷響應的關鍵。本教學將介紹GroqLPU解析引擎以及如何在筆記型電腦上使用API​​和JanAI本地存取它。本文也將把它整合到VSCode中,以幫助我們產生程式碼、重構程式碼、輸入文件並產生測試單元。本文將免費創建我們自己的人工智慧程式設計助理。 GroqLPU推理引擎簡介Groq

七個很酷的GenAI & LLM技術性面試問題 七個很酷的GenAI & LLM技術性面試問題 Jun 07, 2024 am 10:06 AM

想了解更多AIGC的內容,請造訪:51CTOAI.x社群https://www.51cto.com/aigc/譯者|晶顏審校|重樓不同於網路上隨處可見的傳統問題庫,這些問題需要跳脫常規思維。大語言模型(LLM)在數據科學、生成式人工智慧(GenAI)和人工智慧領域越來越重要。這些複雜的演算法提升了人類的技能,並在許多產業中推動了效率和創新性的提升,成為企業保持競爭力的關鍵。 LLM的應用範圍非常廣泛,它可以用於自然語言處理、文字生成、語音辨識和推薦系統等領域。透過學習大量的數據,LLM能夠產生文本

大模型做時序預測也很強!華人團隊啟動LLM新能力,超越一眾傳統模式實現SOTA 大模型做時序預測也很強!華人團隊啟動LLM新能力,超越一眾傳統模式實現SOTA Apr 11, 2024 am 09:43 AM

大語言模型潛力被激發-無需訓練大語言模型就能實現高精度時序預測,超越一切傳統時序模型。蒙納士大學、螞蟻和IBM研究院共同開發了一個通用框架,成功推動了大語言模型跨模態處理序列資料的能力。該框架已成為一項重要的技術創新。時序預測有益於城市、能源、交通、遙感等典型複雜系統的決策。自此,大模型可望徹底改變時序/時空資料探勘方式。通用大語言模型重編程框架研究團隊提出了一個通用框架,將大語言模型輕鬆用於一般時間序列預測,而無需做任何訓練。主要提出兩大關鍵技術:時序輸入重編程;提示做前綴。 Time-

在OpenHarmony本地部署大語言模型 在OpenHarmony本地部署大語言模型 Jun 07, 2024 am 10:02 AM

本文將第二屆OpenHarmony技術大會上展示的《在OpenHarmony本地部署大語言模型》成果開源,開源位址:https://gitee.com/openharmony-sig/tpc_c_cplusplus/blob/master/thirdparty/InferLLM/docs/ hap_integrate.md。實作思路與步驟移植輕量級LLM模型推理架構InferLLM到OpenHarmony標準系統,編譯出能在OpenHarmony運作的二進位產物。 InferLLM是個簡單又有效率的L

鴻蒙智行享界S9全場景新品發表會,多款重磅新品齊發 鴻蒙智行享界S9全場景新品發表會,多款重磅新品齊發 Aug 08, 2024 am 07:02 AM

今天下午,鸿蒙智行正式迎来了新品牌与新车。8月6日,华为举行鸿蒙智行享界S9及华为全场景新品发布会,带来了全景智慧旗舰轿车享界S9、问界新M7Pro和华为novaFlip、MatePadPro12.2英寸、全新MatePadAir、华为毕昇激光打印机X1系列、FreeBuds6i、WATCHFIT3和智慧屏S5Pro等多款全场景智慧新品,从智慧出行、智慧办公到智能穿戴,华为全场景智慧生态持续构建,为消费者带来万物互联的智慧体验。鸿蒙智行:深度赋能,推动智能汽车产业升级华为联合中国汽车产业伙伴,为

激發大語言模型空間推理能力:思考視覺化提示 激發大語言模型空間推理能力:思考視覺化提示 Apr 11, 2024 pm 03:10 PM

大語言模型(LLMs)在語言理解和各種推理任務中展現出令人印象深刻的表現。然而,它們在人類認知的關鍵一面——空間推理上,仍然未被充分研究。人類具有透過一種被稱為心靈之眼的過程創造看不見的物體和行為的心智圖像的能力,從而使得對未見世界的想像成為可能。受到這種認知能力的啟發,研究人員提出了「思維視覺化」(VisualizationofThought,VoT)。 VoT旨在透過視覺化其推理跡象來引導LLMs的空間推理,從而引導後續的推理步驟。研究人員將VoT應用於多跳空間推理任務,包括自然語言導航、視覺

總結374篇相關工作,陶大程團隊聯合港大、UMD發布LLM知識蒸餾最新綜述 總結374篇相關工作,陶大程團隊聯合港大、UMD發布LLM知識蒸餾最新綜述 Mar 18, 2024 pm 07:49 PM

大語言模型(LargeLanguageModels,LLMs)在過去兩年內迅速發展,湧現出一些現象級的模型和產品,如GPT-4、Gemini、Claude等,但大多數是閉源的。研究界目前能接觸到的大部分開源LLMs與閉源LLMs存在較大差距,因此提升開源LLMs及其他小模型的能力以減小其與閉源大模型的差距成為了該領域的研究熱點。 LLM的強大能力,特別是閉源LLM,使得科研人員和工業界的從業者在訓練自己的模型時都會利用到這些大模型的輸出和知識。這個過程本質上是知識蒸餾(Knowledge,Dist

OWASP發布大語言模型網路安全與治理清單 OWASP發布大語言模型網路安全與治理清單 Apr 17, 2024 pm 07:31 PM

目前人工智慧技術面臨的最大風險是大語言模型(LLM)和生成式人工智慧技術的發展和應用速度已經遠遠超過了安全和治理的速度。 OpenAI、Anthropic、Google和微軟等公司的生成式人工智慧和大語言模式產品的使用正呈指數級增長。同時,開源大語言模型方案也在高速成長,HuggingFace等開源人工智慧社群提供了大量開源模型、資料集和AI應用。為了推動人工智慧的發展步伐,OWASP、OpenSSF、CISA等產業組織正在積極開發和提供人工智慧安全與治理關鍵資產,例如OWASPAIExchange、

See all articles