系列文章:

Open AI - 使用 Embedding 嵌入搭配 ChatGPT 做 QA 聊天機器人(基礎實作)

Open AI - 使用 Embedding 嵌入搭配 ChatGPT 做 QA 聊天機器人(進階實作1)


在上一篇進階實作1中已經讓 QA 聊天機器人有了一定的完成度,不過對於使用 GPT3.5 的人來說,讓它生成我們要的指定格式是需要花很多心思研究和設計 Prompt

就算 Prompt 已經寫的很清楚明白,有時候 GPT3.5 依然會回應非我們所指定之格式,因此都要做回應上的文字處理

💡 由於 GPT3.5 的回應不確定性很高,所以程式碼是用正則表示來篩選出字串內的陣列格式

雖然這個問題換成 GPT4 可能會好很多,不過價格考量下大多是使用 GPT3.5,因此還是會有一大堆例外發生呢!


不過就在2023/06/14(美國時間2023/06/13)收到 OpenAI 的 Mail,主要是發佈了一系列新的 ChatGPT API:

  1. gpt-3.5-turbo-0613
  2. gpt-3.5-turbo-16k-0613
  3. gpt-4-turbo-0613

Mail 大致上內容就是說部分 API 價格調低以及新增一個新的功能:Function Calling,也是本次的主題。

終於期待已久的功能發佈了!先說 Function Calling 不是字面上的函式調用哦!而是 ChatGPT 幫你產生函數調用所需的 JSON 資料規範(JSON Schema),簡單來說就是輸出一個你定義好的JSON 資料格式,如同以前用 Prompt 限制它是一樣的!



API新增參數

首先是API新增了以下兩個參數:

  1. functions:function 定義清單內容
    1. name:function 的名稱
    2. description:對 function 的描述,也可以當作對於 function 執行時的 Prompt
    3. 💡 描述可以當作你定義這個 function 的 Prompt。另外描述的字數也會算在 Token 的數量內哦!
    4. parameters:JSON Schema 定義
  2. function_call:控制 API 如何調用 function
  3. 💡 這裡可以填入三個參數:none、auto 或是{"name": "你的 function name"}。
    none:表示永遠不會調用 function。
    auto:表示 GPT 會自行判斷是否需要調用 function。
    {"name": "你的 function name"}:強制 ChatGPT 每次執行都調用 function。

更詳細的說明可以到 OpenAI 官方的 API Reference 上【點我前往】參考哦!



用 Postman 測試 API

首先指定 ChatGPT 輸出我們所要的格式,如同前一篇文章 Prompt 內規範的:

[{textGuid: \"xxx\", textName: \"zzz\"}]
public string QATextUseSourcePrompt()
{
    return "Each context has a TextGuid and TextName and TextContent followed by the actual message. " +
        "Before providing an answer as accurately as possible, you must select multiple sources that can be used to answer the question and keep the TextGuid and TextName of the selected sources then output the result in the following format, " +
        "e.g. [{textGuid: \"xxx\", textName: \"zzz\"}], only output the format that I have specified. " +
        "If no sources are selected, please output an empty array.\n\nSources:\n";
}

接著定義JSON Schema,另外需要把原本的Prompt移到description內並且修改了一下提示內容

{
  "name": "get_QA_Use_Souce",
  "description": "Each context has a TextGuid and TextName and TextContent followed by the actual message. Before providing an answer as accurately as possible, you must select multiple sources that can be used to answer the question. If no sources are selected, please output an empty array.",
  "parameters": {
    "type": "object",
    "properties": {
      "data": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "textGuid": {
              "type": "string",
              "description": "Each context has a TextGuid followed by the actual message."
            },
            "textName": {
              "type": "string",
              "description": "Each context has a TextName followed by the actual message."
            }
          }
        }
      }
    },
    "required": [
      "textGuid",
      "textName"
    ]
  }
}

而原本放在 content 開頭的 Prompt(圖2)就不需要了(圖1)!

(圖1)改用function calling後的content

(圖2)原本的Prompt提示工程做法

再來使用 Postman 來測試一下新增的參數和觀察回傳結果,我們的提問是:請你介紹 JOString 和 JAString(文本內有關於 JOString 和 JAString 的相關知識),可以看到使用 function calling後的 Response 在 contoent 內就不會有資料(是 null),取而代之的是 function_call 屬性,而在arguments 可以看到 ChatGPT 已經依照提問篩選好可用於回答的資料,並且遵照著我們定義的JSON Schema 格式輸出


我們再來提問一個文本內沒有的問題:請你介紹 Rxjs 的用法,ChatGPT 也依照 function 內的 description(或是 Prompt)回傳一個空陣列

最後我們試著把 description 拔掉不帶入任何提示文字,神奇的事情發生了!ChatGPT 把所有文本的 textGuid 都列出來(可能它不知道我要幹嘛索性就把所有的資料都列出來了XD)

另外可以發現 usage 的 prompt_token 也減少,為了驗證這個我們把 description 貼到 Tokenizer 上計算 Token 數量是 54,3998 + 54 = 4052 因此測試結果可以確定 function 的 description 是一個 Prompt 而且會算在 Tokens 數量內!


總結

這次推出的 function Calling 功能,基本上可以解決在 GPT3.5 上 Prompt 往往沒有辦法好好的限制ChatGPT 回應我們指定的資料格式,這個問題導致應用程式常常會發生奇怪的 Bug。而現在有了 function Calling,完全不需要擔心 ChatGPT 回應出不對的格式囉!這功能也是開啟 ChatGPT API 另一個時代的開始,如現在很夯的Plugin功能,未來聊天 QA 機器人就不再是聊天功能了,甚至可以自動化一些事情!就讓我們期待吧!


最後的最後程式碼有修改的部分我在這裡就不提供了,有興趣可以再到 Github 上看看囉(老話一句很多 Bug 還是沒有修XD)!