ChatGPT가 질문에 답변하면 한 단어씩 팝업되어 사람들에게 진지하게 생각하는 느낌을 줍니다.
이 대화의 기본 내용은 다음과 같습니다.
Q: 대규모 언어 생성 모델은 어떻게 작동하나요?
A: 대규모 언어 생성 모델(예: GPT-3)은 딥 러닝 기술을 기반으로 하는 신경망입니다. 모델. 이러한 모델은 자연어 처리 분야에서 큰 성공을 거둔 "Transformer"라는 아키텍처를 사용하는 경우가 많습니다.대규모 언어 생성 모델의 작동 방식에 대한 개요는 다음과 같습니다.
… 단락 생략…
텍스트 생성: 모델이 훈련되면 이를 사용할 수 있습니다. 텍스트를 생성합니다. 초기 텍스트 또는 프롬프트가 주어지면 모델은 학습한 확률 분포를 기반으로 다음 단어를 생성한 다음 생성된 단어를 입력으로 사용하고 다음 단어를 계속 생성하는 방식으로 원하는 텍스트 길이에 도달하거나 생성될 때까지 계속됩니다. 상징.
... 단락 생략...
LLM이라고 하는 대형 언어 모델.
모델 관점에서 LLM은 텍스트 길이 제한에 도달하거나 종결자가 생성될 때까지 추론을 수행할 때마다 토큰을 생성합니다.
서버 입장에서는 생성된 토큰을 HTTPS 프로토콜을 통해 하나씩 브라우저에 반환해야 합니다.
클라이언트-서버 모드에서 일반적인 상호작용 방식은 클라이언트가 요청을 보내고 응답을 받는 것입니다. 분명히 이것은 ChatGPT가 질문에 응답하는 시나리오를 충족할 수 없습니다.
두 번째로 HTTP를 사용하여 Handshake를 구현하고 WebSocket으로 업그레이드되는 websocket을 생각할 수 있습니다. 그러나 WebSocket은 클라이언트와 서버 모두 지속적으로 소켓을 점유해야 하며, 서버 측의 비용이 상대적으로 높습니다.
ChatGPT는 타협: 서버 전송 이벤트(줄여서 SSE)를 사용합니다. OpenAI의 API 문서에서 이를 확인할 수 있습니다.
SSE 모드에서 클라이언트는 서버에 한 번만 메시지를 보내면 됩니다. 요청된 경우 서버는 끝이 필요할 때까지 계속해서 출력할 수 있습니다. 전체 상호 작용 프로세스는 아래 그림에 나와 있습니다.
SSE는 여전히 HTTP를 애플리케이션 계층 전송 프로토콜로 사용하여 HTTP의 긴 연결 기능을 최대한 활용하여 서버 측 푸시 기능을 달성합니다.
코드 수준에서 SSE 모드와 단일 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>
실행하는 데 약 20초 이상이 걸리며 완전한 결과를 얻습니다.
{"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}]}
수정 없이 스트림을 true로 설정하면 총 요청 소비는 28초 이상이 되며 이는 많은 스트림 메시지에 반영됩니다.
위 사진은 Postman이 ioutil.ReadAll 모드를 이용해 chatgpt api를 호출하는 사진입니다. 스트림 읽기를 구현하기 위해 http.Response.Body를 세그먼트로 읽을 수 있습니다. 이 방법이 가능한 이유는 다음과 같습니다.
으로 분할되므로 수정 방법은 이를 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")}
클라이언트 측을 읽은 후 서버 측을 살펴보겠습니다. 이제 우리는 chatgpt 서버를 모의하고 텍스트를 그대로 반환하려고 합니다. 여기에는 두 가지 사항이 관련됩니다.
코드는 다음과 같습니다.
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)}
실제 시나리오에서 반환할 데이터는 다른 서비스 또는 함수 호출에서 가져온 것입니다. 이 서비스 또는 함수 호출의 반환 시간이 불안정할 경우 클라이언트가 발생할 수 있습니다. 오랫동안 데이터를 수신할 수 없으므로 일반적인 처리 방법은 다음과 같습니다.
다른 채널의 데이터를 읽을 수 있으려면 다음 데모 코드와 같이 select가 좋은 키워드입니다.
// 声明一个 event channel// 声明一个 time.Tick channel// 声明一个 timeout channelselect {case ev := <h2>요약하자면</h2><p style="text-align: justify;"><span style="color: #333333;">전체 결과에 대한 응답을 생성하는 프로세스 대규모 언어 모델은 상대적으로 길지만 토큰으로 생성된 응답은 상대적으로 빠릅니다. ChatGPT는 이 기능을 SSE 기술과 완전히 결합하여 단어 단위로 응답을 팝업하여 사용자 경험의 질적 향상을 달성합니다. </span></p><p style="text-align: justify;"><span style="color: #333333;">생성 모델을 살펴보면 LLAMA/Little Alpaca(상용 아님) 또는 Stable Diffusion/Midjourney 등이 있습니다. 온라인 서비스를 제공할 때 SSE 기술을 사용하면 사용자 경험을 개선하고 서버 리소스를 절약할 수 있습니다. </span></p>
위 내용은 ChatGPT는 어떻게 단어별로 출력하나요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!