打造專屬ChatGPT:OpenAI Chat Completion API參數解析(20241111更新)
內容目錄
A. 前言
1. API端點
這篇文章記錄的是OpenAI的Chat Completion API端點:
POST https://api.openai.com/v1/chat/completions
2. OpenAI Python SDK基礎用法
使用的模型為gpt-4o,同時透過OpenAI的Python SDK操作API,以下為基礎用法:
client = OpenAI()
completion = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello!"},
],
)
print(completion.usage)
3. 請求參數
文章將會記錄create方法的相關參數,參數分為兩類:
- REST API的參數:OpenAI提供REST API,讓我們可以呼叫相關支援。
- OpenAI Python SDK封裝的其他參數:OpenAI對REST API封裝後,衍生的相關參數,如:timeout。
4. 回傳結構
透過REST API進行請求時,回傳的資料會是JSON物件,透過OpenAI的Python SDK操作時,OpenAI已經將JSON物件映射為Python物件,JSON物件的key就會是Pyhton物件的屬性,用法可以參考前面基礎用法的print(completion.usage)
,從create方法回傳的物件取出usage屬性,就可以得知這次的API請求用了多少的額度。
整體而言回傳結構有兩大分類:
a. The chat completion object
當不是以串流方式取得資料,就會是這個格式,根據請求參數會有所不同,其中有以下資訊:
id
:string,唯一值,請求的ID。choices
:array,回答的內容,根據不同請求參數,可能可以得到多個答案。created
:integer,Unix時間戳記,請求建立的時間。model
:string,本次使用的模型。service_tier
:string or null,請求API時如果有帶入相關資訊,回傳結果上才會出現,詳見請求參數中的說明。system_fingerprint
:string,系統的指紋,有助於確認輸出變化是否是OpenAI模型後端更新導致,當設定更改時,即使使用相同的seed
,結果也可能不同。object
:string,物件名稱,使用Chat Completion API時,值會是chat.completion
。usage
:object,此次請求的用量。
詳細說明請參考C. The chat completion object。
b. The chat completion chunk object
當透過串流方式取得資料時,一次請求會分解成多個區塊(chunk)進行回傳,根據請求參數會有所不同,其中每個區塊(chunk)含有的資訊主要的key與非串流相同,詳細差異請參考D. The chat completion chunk object。
B. 請求參數
1. REST API的參數
a. model,string,Required
使用的模型,不同端點可用的模型不同(各端點可用模型),使用GPT 4o時填入gpt-4o。
b. messages:array,Required
總共有4個類型的訊息可以傳遞給OpenAI,透過傳遞多組訊息(如:User、Assistant交錯),可以模擬一組對話紀錄,同時讓模型能夠根據對話內容,調整出最適合的回應方式,並具有記憶功能。
由於一次可以傳遞多組訊息,所以這個參數的值是一個array,array中的每個元素都是一個物件,定義物件時,不管是何種類型的訊息都會定義key content
跟role
,其中role
代表的是訊息類別,content
則是實際內容。
key content
的值可以是string或array,直接是string時代表只有講一句話,但如果某個類型(角色)一次講了很多句話,此時就會使用array。
根據以上內容,把它整理成一個messages array的範例,範例中先給了一個系統訊息,提示系統(system)他的角色是品牌形象大師,使用者(user)接著傳了兩則文字訊息及兩張圖片,接著模型(assistant)回覆了一些內容:
messages = [
{
"role": "system",
"content": "你是品牌形象大師"
},
{
"role": "user",
"content": [
{"type": "text", "text": "這個Logo好嗎"},
{"type": "text", "text": "你可以給我一些建議嗎"},
{
"type": "image_url",
"image_url": {
"url": "https://i0.wp.com/www.alfred.wiki/wp-content/uploads/2024/11/cropped-Logo_info_2400x900_transparent.png?resize=1024%2C307&ssl=1"
},
},
{
"type": "image_url",
"image_url": {
"url": f"data:{image_mime_type};base64,{base64_image}"
},
},
],
},
{
"role": "assistant",
"content": "這個Logo設計有一些優點和改進的建議:..."
},
]
雖然有四種類型的訊息,但只有User這個類型能夠傳遞圖片,圖片可以使用一般的URL或是直接輸入Base64字串,詳細請參考OpenAI關於Vision的文件。
除此之外還有音訊的訊息,但必須使用特殊版本的模型,一般的gpt-4o並不支援,而且目前也不是太好用,等OpenAI繼續優化,這邊暫不做討論。
b-1. System message
用於設定聊天的上下文和行為指導,例如:指示模型應以什麼樣的風格回答或執行哪些任務。通常在對話開始時使用,以確定對話的基調和規則。
- content:string or array,Required。
- role:string,Required,
system
。 - name:string,Optional,參與者的名稱,提供模型資訊來區分相同角色的多個參與者。
b-2. User message
代表用戶向模型發送的消息或輸入。這是用戶在對話中提出問題或請求的主要方式,模型會根據這些消息生成相應的回覆。
- content:string or array,Required。
- role:string,Required,
user
。 - name:string,Optional,參與者的名稱,提供模型資訊來區分相同角色的多個參與者。
b-3. Assistant message
代表模型生成的回覆或回答,這是模型對用戶消息的回應。
- content:string or array,Required,除了一般文字輸入,還有
{"type":"refusal", "refusal":"string, refusal message"}
,refusal只有在設定結構化輸出時會出現,結構化輸出請參考〖打造專屬ChatGPT:利用LLM進行結構化輸出(Structured Outputs)〗。設定tool_calls時content不需設定。 - role:string,Required,
assistant
。 - name:string,Optional,參與者的名稱,提供模型資訊來區分相同角色的多個參與者。
- refusal:string or null,Optional,只有在設定結構化輸出時會出現,後續有相關範例。
- tool_calls:array,Optional,過去叫做function_call,其中元素為一個物件,結構為
{"id":"tool call id", "type":"function", "function":{"name":"tool name", "arguments":"string"}}
,詳細用法請參考〖打造專屬ChatGPT:透過OpenAI Tool Calling深度整合資源〗。
b-4. Tool message
由模型使用工具或外部資源時產生的消息類型,表示模型從工具中獲取的資訊或由工具執行的動作。這種類型的消息在模型需要與外部系統交互以完成指定任務時特別有用。
- content:string or array,Required。
- role:string,Required,
tool
。 - tool_call_id:string,Required,用於追踪特定工具調用的過程和相關活動,使得多工具、多調用場景管理變得更加容易,尤其是在需要高效處理多個並行或順序工具操作的應用程序中格外有用。
當我們要表達一串聊天記錄中有使用tool_calls時,Assistant message會先加入一個訊息代表使用tool calling功能,接著我們會實際呼叫我們的tool,我們的tool回傳的內容就會放在tool message中,此時我們可以以這樣的歷史紀錄再次呼叫chat completion API幫我們組織語言,tool call的相關功能請參考〖打造專屬ChatGPT:透過OpenAI Tool Calling深度整合資源〗。
c. response_format:object,Optional
OpenAI支援的輸出格式有以下三種,根據不同格式response_format設定的值有所不同
- text:
{"type": "text"}
- json_object:
{"type": "json_object"}
- json_schema:
{"type": "json_schema", "json_schema": ...}
使用JSON模式(json_object
)時,必須使用system message或user message自行指示模型產生JSON。否則,模型可能會生成無止盡的空白字符流,直到生成達到令牌限制,導致請求長時間運行且看似「卡住」。另外要注意,如果finish_reason="length"
,則表示生成超過了 max_tokens
或對話超出了最大上下文長度,此時消息內容可能會被部分截斷。
使用json_schema
時,基本格式如下:
{
"type" :"json_schema",
"json_schema" {
"name": Required,a-zA-Z0-9_-,最大長度64
"description": 協助模型了解該如何使用這個結構
"schema": JSON Schema物件
"strict": boolean or null,是否嚴格遵循定義。設為True時,只支持部分JSON Schema。預設為False
}
}
OpenAI的Python SDK有較為方便表示法,請參考〖打造專屬ChatGPT:利用LLM進行結構化輸出(Structured Outputs)〗。
d. 取樣方式(創意):temperature、top_p
d-1. temperature:numbers or null,Optional,Defaults to 1
0-2之間的任意數值,數值越大隨機性越高。通過調整概率分佈的平滑度實現:值越大時,機率分佈會變得更加平坦,模型選擇詞彙時會更隨機且更有創意;值越小時,機率分佈更尖銳,模型更傾向於選擇機率最高的那些詞。
d-2. top_p:numbers or null,Optional,Defaults to 1
0-1間任意數值,相較於temperature的另一種取樣方式,稱為「核心取樣」(nucleus sampling),模型只考慮部分詞彙,這些詞的累積機率達到指定的`top_p`,其組成的綜合機率視為100%,其他詞則忽略。具體實現是通過按概率從高到低排序,選擇累計機率不超過`top_p`的詞集進行抽樣。
這兩種方法都旨在控制生成過程的隨機程度,不過從不同的角度出發,分別改變選擇的廣度
temperature
和截斷的深度top_p
。官方建議兩者擇一使用。
temperature
:主要是在調整機率分佈的平滑度和形狀,對所有詞依然維持考慮,只是可能性被重新調整。top_p
:則在機率累計到達一定程度時進行硬性截斷,只考慮這部分詞,由此讓選擇範圍集中在機率較高的前p
部分上。
e. 重複內容控制:frequency_penalty、presence_penalty
e-1. frequency_penalty:number or null,Optional,Defaults to 0
-2和2之間任意數值,正值會根據新詞在已生成文件中出現的頻率進行懲罰,降低模型逐字重複
相同語句的可能性。
e-2. presence_penalty:boolean or null,Optional
-2和2之間任意數值,正值會根據新詞在已生成文件中出現的頻率進行懲罰,增加討論新話題的可能性。
這兩個參數可以根據需要結合使用,來調整生成文本的特點:
- frequency_penalty則更關注於控制單詞的重複度。
- presence_penalty更注重新內容的引入。
f. tool call:tools、tool_choice、parallel_tool_calls
Tool Calling用法及範例:〖打造專屬ChatGPT:透過OpenAI Tool Calling深度整合資源〗。
f-1. tools:array,Optional
透過array將tool物件傳入,最多可以設定128個工具。每個tool物件結構如下:
{
"type": "function",
"function" : {
"name": string,Required,function(tool)的名稱,
"description": string,Optional,描述function(tool)的用途,讓模型知道使用時機
"parameters": object,Optional,描述function需要的參數,使用JSON Schema物件。{
"type": "object",
"properties": {
"參數名稱": {
"type": "參數類型",
"description": "參數說明"
}
}
},
"strict": "boolean or null,Optional,Defaults to false,控制是否嚴格遵守papameters的設定(只支援部分的JSON Schema)"
}
}
其中function的parameters使用的是JSON Schema,撰寫可以參考結構化輸出的介紹文章。
官方指南:https://platform.openai.com/docs/guides/function-calling
JSON Schema:https://json-schema.org/understanding-json-schema/
f-2. tool_choice:string or object,Optional
選擇是否呼叫工具,使用字串輸入時有三種選擇:
- none:不使用外部工具,沒有傳遞tools參數的預設選項。
- auto:自動選擇是否使用外部工具,有傳遞tools參數的預設選項。
- required:必須使用一個或多個外部工具。
如果要指定使用特定工具,則設定一個物件:
{
"type": "function",
"function" : {
"name": string,Required,function(tool)的名稱
}
}
選擇特定工具
或是required
時,finish_reason
就會是stop
而不是tool_calls
。
f-3. parallel_tool_calls:boolean or null,Optional,Defaults to true
是否一次呼叫多個工具,一次呼叫多個工具可能導致function
參數中的strict
參數失效,請參考官方文件。
g. stream相關:stream、stream_options
g-1. stream:boolean or null,Optional,Defaults to false
# a ChatCompletion request
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "What's 1+1? Answer in one word."}],
temperature=0,
stream=True, # this time, we set stream=True
)
for chunk in response:
print(content=chunk.choices[0].delta.content)
print("****************")
設置後,會以Stream的方式接收數據,每次獲得一個片段(Chunk),組裝後才是完整回覆,。
g-2. stream_options:object or null,Optional,Defaults to null。
只有在stream設定為true時才會生效。可用key為include_usage(boolean,Optional,Defaults to false),設定後可以取得這個問題是API用量資訊。
h. 控制生成行為:max_completion_tokens、n、logit_bias、stop
h-1. max_completion_tokens:integer or null,Optional
控制生成的最大token數量。
h-2. n:integer or null,Optional,Defaults to 1
模型回傳結果有幾個版本(choice),版本越多成本越高。
h-3. logit_bias:map,Optional,Defaults to null
用於調整特定token在生成文本中的出現機率。在數學上,偏差被添加到模型生成的logits中,再進行抽樣。通過為標記指定偏差值,用戶可以增加或減少其被選擇的可能性,從而更好地控制模型生成的結果。這對於引導生成特定風格或內容非常有用。
接收一個JSON object,將tokenizer中的token ID映射到一個-100和100間的值,數值越高出現的可能越高。
h-4. stop:string / array / null,Optional,Defaults to null
最多可以設定4個序列(sequences),使API停止生成更多的token。像是提到習維尼時,就停止生成更多內容。
i. Log properties:logprobs、top_logprobs
i-1. logprobs:boolean or null,Optional,Defaults to false
是否回傳輸出token的對數機率,設定為True時,可以在choices中的logprobs取得資訊。
i-2. top_logprobs:integer or null,Optional
0-20間的整數,當logprobs為True時,控制每個位置上最可能的token數量。
j. 評估與管理:store、metadata、seed、user
j-1. store:boolean or null,Optional,Defaults to false
是否儲存這次請求的資料,儲存後可以使用OpenAI的model distillation及evals功能。
j-2. metadata:object or null,Optional
開發者定義的資料,能夠在OpenAI Dashboard中用來篩選資料。
j-3. seed:integer or null,Optional。
控制回答隨機性的參數,如果設定為定值,會回傳相同的結果。需要搭配請求API後回傳的system_fingerprint,搭配這個資訊就能夠了解請求結果改變的原因。
j-4. user:string,Optional。
代表終端用戶的唯一標識符,可以幫助OpenAI監控和檢測濫用行為。
k. 其他:modalities、prediction
k-1. modalities:array or null,Optional
希望模型生成的內容格式,一般都是["text"]
,gpt-4o-audio-*可選擇["text", "audio"]
。
k-2. prediction:object,Optional
針對預測輸出的設定,可以在預先知道模型回應的大部分內容時大幅提高回應速度。這種情況最常見於僅對大部分內容進行微小更改後重新生成文件的時候。
官方範例:程式碼重構。
{
"type": "content",
"content": string or array
}
2. OpenAI Python SDK封裝的其他參數
a. 額外參數
如果有額外的參數要在API傳遞,依據不同的位置使用不同的名稱,
extra_query
:查詢字串extra_body
:請求Bodyextra_headers
:請求Header
資料皆為key-value對應,Python中使用dict資料類型。
b. timeout
預設情況(httpx.Timeout(timeout=600.0, connect=5.0)
)下,請求在10分鐘後會超時。透過timeout選項進行調整,接受浮點數(秒)或httpx.Timeout
物件。
# Configure the default for all requests
client = OpenAI(
timeout=20.0,
)
# More granular control:
client = OpenAI(
timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0)
)
# Override per-request:
client.with_options(timeout=5.0).chat.completions.create(
messages=[{"role": "user", "content": "Hello"}],
model="gpt-4o"
)
# Override the client-level default timeout for this request, in seconds
client.chat.completions.create(
messages=[{"role": "user", "content": "Hello"}],
model="gpt-4o",
timeout=5
)
某些錯誤在預設情況下會自動重試兩次,並採用短暫的指數退避策略。連線錯誤(例如,由於網絡連接問題)、408 Request Timeout, 409 Conflict, 429 Rate Limit, and >=500 Internal errors皆會被預設重試。改寫方式:
# Configure the default for all requests:
client = OpenAI(max_retries=0) # default is 2
# Or, configure per-request:
client.with_options(max_retries=5).chat.completions.create(
messages=[{"role": "user", "content": "Hello"}],
model="gpt-3.5-turbo",
)
C. The chat completion object
一般請求下,Chat Completion API回傳的物件結構:
id
,string,唯一值,請求的ID。choices
,array,回答的內容,根據不同請求參數n,array中會有n個元素,每個元素都是一個物件,結構如下:- finish_reason,string,模型停止生成標記的原因:
- index,integer,choices的索引值,與請求參數n對應。
- message,object,模型回傳的訊息,結構如下:
- content:string or null,訊息內容。
- refusal:string or null,拒絕的訊息,請求時設定參數response_format使用
json_schema
相關時才會出現。 - tool_calls,array,此次請求中模型回應所需的Tool們,並以object表示,給個object格式如下:
- id:string,這次呼叫的ID。
- type:string,這裡只會是function。
- function,object:
- name:Tool(function)的名稱,與傳入參數Tools中的name相同。
- arguments:string,通常是json字串,代表呼叫Tool所需的參數。請注意,模型並不總是生成有效的JSON,並且可能會臆測出您函數結構中未定義的參數。在呼叫函數之前,請在您的代碼中驗證這些引數。
- role:訊息角色,這裡通常會是Assistant message。
- logprobs:object or null,啟用參數logprobs時,模型提供的相關資訊,跟著message中的content或refusal的每一個token的log probability。結構如下:
- content:array or null。
- refusal:array or null。
created
,integer,Unix時間戳記,請求建立的時間。model
,string,本次使用的模型。service_tier
,string or null,請求API時如果有帶入相關資訊,回傳結果上才會出現,該參數請參考官方說明。system_fingerprint
,string,系統的指紋,有助於確認輸出變化是否是OpenAI模型後端更新導致,當設定更改時,即使使用相同的seed
,結果也可能不同。object
,string,物件名稱,使用Chat Completion API時,值會是chat.completion
。usage
,object,此次請求的用量,結構如下:- completion_tokens:integer,生成回覆的token數量。
- prompt_tokens:integer,問題的token數量。
- total_tokens:integer,completion_tokens+prompt_tokens的總額。
- completion_tokens_details:object,結構如下,
- reasoning_tokens:integer,用於推理的token。
- accepted_prediction_tokens:integer,使用參數prediction時,預測的token有出現在結果的數量。
- rejected_prediction_tokens:integer,使用參數prediction時,預測的token未出現在結果的數量。但就像推理token一樣,這些token在計算總完成token數時仍會被包含在內,用於計費、輸出和上下文窗口限制。
- audio_tokens:integer,音訊使用的token。
- prompt_tokens_details:object,結構如下,
- audio_tokens:integer,音訊使用的token。
- cached_tokens:integer,快取使用的token。
D. The chat completion chunk object
Stream請求下,Chat Completion API回傳每個Chunk的結構:
id
:string,唯一值,請求的ID,同個請求不同Chunk的ID相同。choices
:array,回答的內容,根據不同請求參數n,array中會有n個元素。設定stream_options: {"include_usage": true}
時,最後一則訊息choices為空,此時usage為此次請求的總API用量。每個元素都是一個物件,結構如下,- finish_reason:string,模型停止生成標記的原因,有以下幾種可能,
- index:integer,choices的索引值,與請求參數n對應。
- delta:object,模型回傳的訊息,結構如下,
- content:string or null,訊息內容。
- refusal:string or null,拒絕的訊息,請求時設定參數response_format使用json_schema時才會出現。
- tool_calls:array,此次請求中模型回應所需的Tool們,並以object表示,給個object格式如下,
- id:string,這次呼叫的ID。
- type:string,這裡只會是function。
- function:object
- name:Tool(function)的名稱,與傳入參數Tools中的name相同。
- arguments:string,通常是json字串,代表呼叫Tool所需的參數。請注意,模型並不總是生成有效的JSON,並且可能會臆測出您函數結構中未定義的參數。在呼叫函數之前,請在您的代碼中驗證這些引數。
- role:訊息角色,這裡通常會是Assistant message。
- logprobs:object or null,啟用參數logprobs時,模型提供的相關資訊,跟著message中的content或refusal的每一個token的log probability。結構如下:
- content:array or null。
- refusal:array or null。
created
:integer,Unix時間戳記,請求建立的時間。model
:string,本次使用的模型。service_tier
:string or null,請求API時如果有帶入相關資訊,回傳結果上才會出現,該參數請參考官方說明。system_fingerprint
:string,系統的指紋,有助於確認輸出變化是否是OpenAI模型後端更新導致,當設定更改時,即使使用相同的seed
,結果也可能不同。object
:string,物件名稱,使用Chat Completion API時,值會是chat.completion
.chunk。usage
:object,此次請求的用量,設定stream_options: {"include_usage": true}
時才會出現,此時choices為null
。結構如下,- completion_tokens:integer,生成回覆的token數量。
- prompt_tokens:integer,問題的token數量。
- total_tokens:integer,completion_tokens+prompt_tokens的總額。
E. 總結
文章中,探討了如何使用OpenAI的Python SDK來操作Chat completions API,特別關注gpt-4o模型所需的參數以及回傳物件的結構,並針對不太容易理解的參數進行重新分組和白話文解釋,希望能讓OpenAI虛無縹緲的說明稍微具象化。
從模型輸入參數中,衍生出了兩個主題:
1. 〖打造專屬ChatGPT:利用LLM進行結構化輸出(Structured Outputs)〗:在這部分,將記錄如何設計並生成結構化的文本輸出,讓我們可以輕易的利用LLM強大的語言能力,直接從對話中(非結構化資料)萃取出特定關鍵資訊(結構化資料)。
2. 〖打造專屬ChatGPT:透過OpenAI Tool Calling深度整合資源〗:這個主題關注如何通過OpenAI的Tool Calls(前身為function calls),將模型與外部資源深度整合。將記錄如何利用這些工具來擴展模型的能力,從而獲取更豐富和專業化的服務。
OpenAI Chat completions API的參數眾多,希望這樣的整理,能夠更有效率的查詢所需資料。