iT邦幫忙

2024 iThome 鐵人賽

DAY 28
0
Software Development

從零開始構建能理解語義的 Linebot 架構系列 第 28

OpenAI 概念介紹與實作:核心概念與 Chat Completion 的應用

  • 分享至 

  • xImage
  •  

概述

我們已經從資料的前處理階段(LINE Platform Webhook 處理),一路走到了暫存資料(Kafka)及最終的儲存資料(MongoDB)。作為這個系列文章的最後一部分,將把焦點放在專案的最終階段: 利用OpenAI來進行語意判斷,並提取需要儲存和回應的資訊。本篇會介紹OpenAI的基本觀念,以及我們專案中所使用的Chat Completion功能。最後,還會介紹我們使用的Java library。

內容包含:

  • OpenAI 與 ChatGPT 的關聯
  • Prompt 的設置與運用
  • Chat Completion 的原理及應用
  • OpenAI API

OpenAI

OpenAI是一家專注於開發人工智慧技術的公司,其技術範疇涵蓋自然語言處理、圖像生成等領域。這些技術以模型(Model)的形式被廣泛應用於各種服務中。

OpenAI 與ChatGPT的關係

  • ChatGPT (Generative Pretrained Transformer,生成式預訓練轉換器) 是基於OpenAI的GPT 系列模型的實作。GPT是一種自然語言處理模型,能夠理解人類語言,並根據需求生成大綱、滿足語意或格式要求的文件,甚至模擬不同角色的回應(例如客服人員或某領域專家)。
  • 在這個AI火熱的時代,相信大家對ChatGPT已經不陌生。下面將針對我們專案的核心目的: 為應用程式提供一個自然語言介面(Give software a natural language interface) 介紹相關知識。

API以及OpenAI提供的Model

  • 作為一個實作OpenAI的網頁聊天機器人,ChatGPT可以在網頁上直接使用。但如果需要一些更細節的調整,或者想要在應用程式內加入自然語言處理的功能,就需要使用OpenAI的API。
  • 而使用OpenAI API 時,需要根據不同需求指定不同的模型。
    可以在官方網站查看最新的模型列表。
  • 不同系列的模型(family of models)各有其專門用途,例如: 自然語言處理模型(GPT)、程式碼生成模型(Codex)、圖像生成模型(DALL·E),以及語音識別模型(Whisper)等。
  • 每個系列內的模型可能會根據能力、功能和處理速度進行編號。例如,Turbo版本的模型雖然在精度和多樣性上可能有所降低,但成本較低且反應速度更快,一般客服用的機器人可能就比較適合使用。
  • 目前最新的GPT 4系列不僅能處理自然語言,還能理解圖片,擴展了其應用範圍。

Prompt Engineering

  • Prompt指的是對GPT下的指令。指令越符合條件,GPT越有可能產出更為精確的內容。
  • 官方網站有提供一些下指令的建議,可以參考官網提供的6個建議

ChatGPT 與 Copilot的簡單比較: 個人經驗

  • 根據自己的使用經驗,ChatGPT與微軟提供的程式碼生成AI: Coplot相比大致有幾個特點:
    • 描述方式:
      • Copilot的精神是: Simple, Specific, Short,簡單來說,越短越好,即便用單字組成,不管文法的描述,他也能生成程式,例如這種promt: functino get db sum data,Copilot真的能生出一段計算加總的Function。
      • ChatGPT可能還是需要"夠像人類的描述",才能產出正確的資訊。而他在一個Prompt中,可以接受的長度也比較長。這邊說的可接受長度指的是,不會讓AI產生幻覺(Hallucination,也就是瞎掰答案)的長度。
    • 有範例就加分
      • 無論ChatGPT 或 Copilot,只要是在Prompt提供範例,都會大大的增加正確答案的機率。

Chat Completion

  • Chat Completion 簡單來說就是補完對話,功能是給予AI一組對話作為上文(preface),並且讓AI根據情境以我們設定的條件或角色,去做接下來的回應,也就是把一段對話繼續聊下去
  • ChatGPT網頁版目前就是用Chat Completion的Model。
  • 例如我們可以在API指定以下對話,並要求GPT針對user問的最後一個問題去回答:
messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Who won the world series in 2020?"},
        {"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."},
        {"role": "user", "content": "Where was it played?"}
    ]
  • AI會根據之前對話的內容及角色,來繼續回應user,也就是以一個Good assistant的身份回答比賽地點,並繼續把這段對話給聊下去。
  • 注意:
    • 指定角色的功能只有在API提供,一般在網頁或App版的ChatGPT並沒有提供Role這個參數讓使用者設定,但我們可以在聊天視窗中要求AI去模擬角色。 例如: 你是一個助理,現在我想問你...

Chat Completion 應用於自然語言介面

  • 雖然不需要補完對話,但我們可以利用Chat Completion功能來設定GPT的角色,並透過提供上下文,使其根據不同的前提扮演不同的角色,來提供不同的回應資訊。
  • 事實上,我們專案開發的LineBot除了包裝給AI的指令(Prompt)以外,也包含角色設定(Role),前置條件(上文),以及格式處理,例如我們可以在Prompt中預設User會輸入訓練記錄或者飲食兩種情境,並要求GPT分別做不同的處理。

一個基本範例如下:

要求GPT根據不同的描述,回應不同的內容

  • 使用Curl送出API Request:
curl https://api.openai.com/v1/completions \
 -H 'Content-Type: application/json' \
 -H 'Authorization: Bearer ${你的API Token}' \
 -d '{
 "prompt":"如果以下段落在描述訓練,列出動作名稱,訓練組數,次數,以及重量,如果在描述飲食,列出食物名稱,還有這些食物的營養成分。中間要空行:深蹲115kg3組5下硬舉120kg5組3下洋芋片 蛋餅 鮮奶茶 鹹酥雞",
 "max_tokens": 1,
 "model": "text-davinci-003",
 "max_tokens": 500
}'
  • 註: GPT會把文字拆成token(字段,可以簡單想成單字的概念)處理

  • 參數: max_token 是設定open AI最多可回應的token數目

  • Response如下:

Magic:
{
  "id": "cmpl-6hcacsycbSA3c4GU3b9LIQBlWLo64",
  "object": "text_completion",
  "created": 1675854462,
  "model": "text-davinci-003",
  "choices": [
    {
      "text": "\n\n深蹲 115kg  3組  5下  硬舉 120kg  5組  3下 \n\n洋芋片:卡路里 439 kcal 、碳水化合物 68.3克、蛋白質 6.6克、脂肪 18.8克; \n\n蛋餅:卡路里 151 kcal 、碳水化合物 15克、蛋白質 8克、脂肪 8克; \n\n鮮奶茶:卡路里 63 kcal 、碳水化合物 12.3克、蛋白質 3.3克、脂肪 0.7克; \n\n鹹酥雞:卡路里451 kcal 、碳水化合物31克、蛋白質21克、脂肪27克。",
      "index": 0,
      "logprobs": null,
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 193,
    "completion_tokens": 297,
    "total_tokens": 490
  }
}

更過分一點...

  • 我們還可以要求他指定我們要的格式。
    使用Curl送出API Request:
curl https://api.openai.com/v1/completions \
 -H 'Content-Type: application/json' \
 -H 'Authorization: Bearer ${你的API Token}' \
 -d '{
 "prompt":"如果以下段落在描述訓練,列出動作名稱,訓練組數,次數,以及重量,如果在描述飲食,列出食物名稱,還有這些食物的營養成分。中間要空行並整理成JSON格式:深蹲115kg3組5下硬舉120kg5組3下洋芋片 蛋餅 鮮奶茶 鹹酥雞",
 "max_tokens": 1,
 "model": "text-davinci-003",
 "max_tokens": 500
}'
  • Respone如下:
{
  "id": "cmpl-6hcdrQVOI0tjvkL75QKEVlhjveAj4",
  "object": "text_completion",
  "created": 1675854663,
  "model": "text-davinci-003",
  "choices": [
    {
      "text": "\n\n{\"訓練\": [{\"動作名稱\": \"深蹲\", \"訓練組數\": 3, \"次數\": 5, \"重量\": 115},{\"動作名稱\": \"硬舉\", \"訓練組數\": 5, \"次數\": 3, \"重量\": 120}],\n\"飲食\": [{\"食物名稱\": \"洋芋片\", \"營養成分\": \"\"}, {\"食物名稱\": \"蛋餅\", \"營養成分\": \"\"}, {\"食物名稱\": \"鮮奶茶\", \"營養成分\": \"\"}, {\"食物名稱\": \"鹹酥雞\", \"營養成分\": \"\"}]}",
      "index": 0,
      "logprobs": null,
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 206,
    "completion_tokens": 254,
    "total_tokens": 460
  }
}

可以看到,text的內容真的是可用的JSON格式。
https://ithelp.ithome.com.tw/upload/images/20241012/20105227PFyG5VoeuG.png
圖:在JSON驗證網站上整理後的回應

  • 當然,就算指定角色是肌力與體能教練,OpenAI也無法具備專業教練的技能給出這方面的建議或預測。畢竟這方面的知識太吃個體差異及更複雜的知識。
  • 但我們可以讓AI提供基本的建議,以及更重要的,讓AI提取我們需要的資訊,並且整理在我們要的欄位內。
    • 例如,從User的訊息提取出訓練動作(深蹲)、重量(115)、組數(3),以及次數(5)。
      光是把這些資訊從訊息中提取,並且對應到正確的欄位,程式就有了依照結構保存資料的依據,就可以大幅減少User在UI上所做的重複點擊數

https://ithelp.ithome.com.tw/upload/images/20241012/20105227e2U1r60B9d.jpg
圖: 如我們在專案緣起提到的,上述資訊在App的UI上還是需要不少點擊和消耗眼力的過程

OpenAI API

官網有提供程式可呼叫的API,你可以透過不同程式語言實作的Library,也可以透過官網提供的Curl範例,例如所有Chat Completion相關的API清單可以看這裡。
https://ithelp.ithome.com.tw/upload/images/20241012/201052276CEu7RA3BT.png
圖: 官方提供的API Reference及相關資訊

以下介紹官網介紹的Java Library:

OpenAI Java Library: OpenAI Java

  • 我們可以使用作者提供的範例,在new OpenAiService Instance時,把Token換成自己的,就可以成功用程式呼叫OPEN AI API。
OpenAiService service = new OpenAiService("your_token");
CompletionRequest completionRequest = CompletionRequest.builder()
        .prompt("Somebody once told me the world is gonna roll me")
        .model("babbage-002"")
        .echo(true)
        .build();
service.createCompletion(completionRequest).getChoices().forEach(System.out::println);
  • 註: 這個Library在鐵人賽期間已經不維護了,也沒有提供最新的GPT-4的功能,但是官網還是有提供其他選擇,例如Azure就有開發Java的Library可以用。

Trouble shooting

設定API timeout的方式

  • 可以在OpenAiService的constructor以秒為單位設定timeout, 不過進去程式碼看會發現這個constructor是被deprecated的。
  • 比較建議用Duration這個class來設定timeout:
    OpenAiService service = new OpenAiService(token, ofSeconds(50));
    

Call API的時候回應HTTP 429

  • Exception: retrofit2.adapter.rxjava2.HttpException: HTTP 429
  • Debug過程:
    • 1.進去TheoKanning/openai-java的git搜尋issue:is:issue is:open 429,找到相關討論,似乎是超過API rate limit上限,這有可能是程式寫錯造成Request數超過單位時間內的限制,或者別的原因。
    • 2.直接用Curl打API看看:
      Curl Request
curl https://api.openai.com/v1/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${你的API Token}" \
  -d '{
    "model": "text-davinci-003",
    "prompt": "Say this is a test",
    "max_tokens": 7,
    "temperature": 0
  }'

Response如下:

{
    "error": {
        "message": "You exceeded your current quota, please check your plan and billing details.",
        "type": "insufficient_quota",
        "param": null,
        "code": null
    }
}
  • 結果在Response的message中,發現原因是API的request token總數到達免費上限了("message": "You exceeded your current quota, please check your plan and billing details.")。
  • 到官網設定好付錢的魔法小卡後,API一切正常。

總結

  • 本章介紹了OpenAI與ChatGPT的關係,以及我們如何利用GPT的核心功能: Chat Completion,來包裝前提(Preface)、角色(Role)和實際的指令(Prompt),讓AI根據不同的情境提供我們所需的內容。這也正是專案的核心目標: 為應用程式提供一個自然語言介面的實作方式。
  • 下一章將深入探討如何在程式中使用Chat Completion的細節,並說明我們如何將這個功能整合到Backend Bot Server 中,包括請求OpenAI的回應方式、角色限定等實作細節。

Citation

https://platform.openai.com/docs/models


上一篇
MongoDB 概念及部署: 使用 Docker 設置含初始資料庫與用戶驗證的 MongoDB 服務
下一篇
OpenAI 概念介紹與實作:使用 API 進行 Prompt 與角色設定,並整合到 Bot Server
系列文
從零開始構建能理解語義的 Linebot 架構30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言