OpenAI API 入門 — Chat Endpoint

Laurice
13 min readSep 20, 2023

--

FB粉專: L’s 碎碎念

上一篇:OpenAI API 入門 — 那些你需要知道的事

這篇會帶大家用Python玩一下OpenAI的Chat API,包括要怎麼查endpoint的用法、chat裡面的一些小細節以及怎麼連續對話,有任何問題都可以留言呦。

Photo by Mohamed Nohassi on Unsplash

基礎篇

OpenAI Python Library: https://github.com/openai/openai-python

如果只是想學會怎麼用Python跟OpenAI講話的話,看這邊就對了。
如同上一篇文章提到的,Chat endpoint最基本的觀念就是給AI一段文字(prompt),而AI會根據這段文字給出對應的回覆。

來看一個簡單的範例

import openai

openai.api_key = "{在上一篇取得的API key}"

# 以user的身份傳 "Hello world" 這段話過去給Chat endpoint
completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "How are you?"}])

上面那段code就可以取得OpenAI的回覆了,接著來看看他回覆長什麼樣子,下面這個是completion這個object的樣子,包括了回覆的message、token數等等的資訊。

{
"id": "chatcmpl-xxxxx",
"object": "chat.completion",
"created": 1695210587,
"model": "gpt-3.5-turbo-0613",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "As an AI, I don't have feelings, but I'm here to help you. How can I assist you today?"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 11,
"completion_tokens": 25,
"total_tokens": 36
}
}

如果要單獨取得回覆的那段文字可以用以下的方式取得

response_text = completion.choices[0].message.content

而usage那塊則可以拿來算花掉的錢是多少,以使用GPT-3.5 Turbo為例

price = completion.usage.prompt_tokens/1000 * 0.0015 + \   # prompt的錢
completion.usage.completion_tokens/1000 * 0.002 # output的錢

恭喜你,已經可以跟OpenAI Chat endpoint互動了!

進階篇

這部分會介紹在message以及回傳中出現的“role”是什麼意思,如何使用不同的role達成不同的目的,以及怎麼跟endpoint連續對話。

可以發現在傳prompt過去時,我們是以{“role”: “user”}傳的,而OpenAI回傳的身份則是{“role”: “assistant”},而去查閱OpenAI的資料會發現還有另外兩個role,分別是“system”和“function”,接下來會講一下他們分別是什麼意思,使用情境又是什麼。

  • user: 顧名思義,就是使用者本人傳的訊息,所以一般來說,我們會使用user這個role傳prompt給OpenAI,就如同上面的範例。
import openai

openai.api_key = "{在上一篇取得的API key}"

# 以user的身份傳 "Hello world" 這段話過去給Chat endpoint
completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "How are you?"}])
  • system: 這個role負責的則是類似系統設定的文字提示,例如跟OpenAI說他是一個工程師,接下來要請他用他的專業寫code;或是跟OpenAI說他是一個厲害的數學家,要請他用他的專業解題。
    我稍微改寫一下前面的例子,就可以得到完全不一樣的回答:OpenAI從回說自己只是一隻AI,變成把自己當成人類的回答了。
    但system這個role目前其實還沒有很明確的定義,因為如果把裡面的內容移給user,效果其實是差不多的。
    網路上有許多整理好的System prompt,這裡是一些範例,大家有興趣可以去探索要怎麼讓AI了解自己的角色。
import openai

openai.api_key = "{在上一篇取得的API key}"


completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "system", "content": "You're a friendly person that tends to encourage others."},
{"role": "user", "content": "How are you?"}])

Response from OpenAI:

I'm doing great, thank you! How about you? How can I encourage you today?
  • assistant: 這個role代表的是AI本人,所以當一個訊息的role是assistant,代表這是AI講的話。例如AI回傳時會說role是assistant,還有另一個用途就是跟AI連續對話時,也可以用這個role去實現。
    可以看到以下對話延續了前面的例子,將OpenAI的回覆放到了messages中,這樣OpenAI才會知道之前自己講過了什麼,從而接續對話。但這邊會有個必要之惡 — input token數會增加,也就是說,只要對話越長,input長度越長,一次request要付的錢就會增加。
import openai

openai.api_key = "{在上一篇取得的API key}"

completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "system", "content": "You're a friendly person that tends to encourage others."},
{"role": "user", "content": "How are you?"},
{"role": "assistant", "content": "I'm doing great, thank you! How about you? How can I encourage you today?"},
{"role": "user", "content": "I would like to know the secret of happiness."}])
  • function: 這是OpenAI最近才推出的新role,功能跟上面的很不一樣。對照著以下的實例會比較好看懂(code from OpenAI)。
import openai
import json

# Example dummy function hard coded to return the same weather
# In production, this could be your backend API or an external API
def get_current_weather(location, unit="fahrenheit"):
"""Get the current weather in a given location"""
weather_info = {
"location": location,
"temperature": "72",
"unit": unit,
"forecast": ["sunny", "windy"],
}
return json.dumps(weather_info)

def run_conversation():
# 在這邊我們提供functions這個data給OpenAI,告訴OpenAI我們的function interface
# 以及他需要的參數等等
messages = [{"role": "user", "content": "What's the weather like in Boston?"}]
functions = [
{
"name": "get_current_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
},
"required": ["location"],
},
}
]
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo-0613",
messages=messages,
functions=functions,
function_call="auto", # auto is default, but we'll be explicit
)

# 這邊user已經很明確的說要Boston的天氣,所以OpenAI會回傳
# {"location": "Boston"}
# 到這邊為止,OpenAI根據我們給的function interface,從user prompt中擷取需要的資訊
# 變成function call的形式回傳回來(見下面的response_message)
response_message = response["choices"][0]["message"]


# 這裡是我們上面想要被操作的function,把它放進dict接下來要提供給OpenAI
available_functions = {
"get_current_weather": get_current_weather,
}
function_name = response_message["function_call"]["name"]
function_to_call = available_functions[function_name]
# 這邊用前一段回傳的response_message中的function_call拿出需要的資訊,傳到我們真正的function中
# get_current_weather(location="Boston, MA")
# 拿到上面function中已經寫的dummy json
function_args = json.loads(response_message["function_call"]["arguments"])
function_response = function_to_call(
location=function_args.get("location"),
unit=function_args.get("unit"),
)

# 前面提過的要把前面的訊息append上去,OpenAI才知道自己講過什麼
messages.append(response_message)
# 將真正的function的回傳json傳給OpenAI
messages.append(
{
"role": "function",
"name": function_name,
"content": function_response,
}
)
# 最後OpenAI將本來是json格式的值,根據我們給的function metadata變成人看得懂的話
# 見下面的second_response
second_response = openai.ChatCompletion.create(
model="gpt-3.5-turbo-0613",
messages=messages,
)
return second_response

print(run_conversation())
response_message:

{
"role": "assistant",
"content": null,
"function_call": {
"name": "get_current_weather",
"arguments": "{\n \"location\": \"Boston, MA\"\n}"
}
}
second_response:
{
"id": "chatcmpl-xxxxx",
"object": "chat.completion",
"created": 1695214115,
"model": "gpt-3.5-turbo-0613",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "The weather in Boston is currently sunny and windy with a temperature of 72 degrees."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 72,
"completion_tokens": 17,
"total_tokens": 89
}
}

希望到這邊大家還沒有被code嚇跑,不過其實跑了也沒差,這篇要講的內容差不多沒了。

在了解OpenAI的Chat endpoint要怎麼使用後,就要看大家的詠唱功力了,怎麼跟AI好好講話就又是另一門學問了,我先簡單貼一些參考資料,這部分寫起來實在是太多太雜了,而且根據model不同,需要的prompt也不盡相同。另外,現在這領域還沒有被研究的很透徹,所謂的best practice其實是指大家目前已經試出來“比較容易”成功的方法,但是不是100%正確也不好說。建議大家可以多看看各種資料,試出最適合自己usecase的prompt!

祝大家當詠唱師愉快囉~🪄🪄🪄

下一篇會來介紹OpenAI的三個Image endpoint,敬請期待!

下一篇:OpenAI API 入門 — Image Endpoints

最後的最後,您的按讚是對我的鼓勵,歡迎按讚分享我的FB粉專 L’s 碎碎念

如果想看看學生時期的我:資工女孩大學回顧 — 初入資工系

如果想看看更多我的文章,歡迎訂閱、瀏覽

--

--