如何使用OpenAI API X Flask 建立網路服務-以範例為例說明-3
在今天的數位時代,程式設計與AI人工智能技術成為現代學習的重要一環。尤其是對於現代的年輕人而言,了解這些先進技術的基礎知識,就像學會閱讀和寫作一樣必要。在過去兩篇文章中,我們已經帶領大家初步接觸到了OpenAI的「Quickstart Sample App」,這個簡易的範例程式不僅讓我們一窺Flask Web應用的基本操作,更開啟了與人工智能對話的大門。
然而,技術的世界永遠充滿著更多的探索與學習。今天,將會進一步深入探討如何與OpenAI的API溝通:從發送問題(prompt)到接收回答,每一步都是通往生成式人工智能深海的重要腳步。對於尚未接觸過的人來說,這或許是一次全新的挑戰,但別擔心,我會試著用最淺顯易懂的方式,帶領大家一探究竟。讓我們一起打開這扇知識的大門,繼續AI的探險之旅。
進一步了解OpenAI API的使用,可以讓我們更靈活地與這項強大技術互動。為了讓API能準確地執行我們的指令,了解如何正確設定「標頭(Header)」和「內容(Body Content)」是非常關鍵的。
標頭(Header)
首先來談談標頭部分。在標頭中,「Authorization」這個字段確保了您的身份得到API的確認,就像是進入一個只有特定成員才能進入的俱樂部,API金鑰是您的專屬會員卡。
"Authorization": "Bearer (API金鑰)"
"Content-Type": "application/json",
不但如此,我們從上面的程式碼看到在金鑰前面需要加上「Bearer」這個文字。「Bearer」一詞是用來表示這是一種 OAuth 2.0 等認證機制使用的 Bearer Token。可以把「Bearer」想像成是卡片的稱號,沒有它,API就像是個不認識您的門衛,不會讓您通行。所以,每次發送請求時,千萬不要忘了帶上這個重要的「入場券」。
再來是「Content-Type」,它告訴API你準備傳送的資料型態。就像你去郵局寄信,需要告訴郵局這是掛號還是平信,API也需要透過「Content-Type」來了解你發送的是什麼格式的資料包裹。比較常被指定的格式是「application/json」。
內容(Body Content)
至於「內容」的部分,它就像是你寄出去的信件內容,其中「model」、「prompt」和「max_tokens」這三項設定(如下面的JSON格式),決定了你要發送的問題的精確度和深度。
{
"model": "模型名稱",
"prompt": "提示指令",
"max_tokens": 整數
}
在JSON的model
裡面,需要指定要用的AI模型名稱;prompt
則是填入您想要問的問題;而max_tokens
則是限制可容許的最大Token使用數量,這個數量要使用「整數」來表示。這些細節一點都不能馬虎,因為它們直接關係到你會得到什麼樣的回應。
這些設定都搞定後,我們就可以進入下一階段:使用程式碼來建立與API的連線,並將問題寄出去,等待OpenAI的回答。讓我們繼續往下看。
單純使用request 連結API
當我們在Python裡使用OpenAI的API,有幾種不同的方式可以進行連結。大家可能都知道OpenAI官方提供了一個Python套件叫做openai
,這是一個很方便的工具,不過,今天我們先要來講的是另一種方法 — — 使用requests
套件。
requests
套件在Python裡頭算是非常受歡迎的,因為它簡單易用,幾行程式碼就能完成HTTP請求。這對於開發者來說,是一大福音,它讓程式開發者不需要處理繁瑣的底層網路通訊協議,直接用幾個簡單的函數就能跟OpenAI API溝通。
實際上,透過HTTP協議與OpenAI API溝通,只需要準備好URL、所使用的HTTP方法(像是GET或POST),以及正確的標頭(Headers)和請求主體(Body Content)。這就像是你去便利商店買東西,知道要去哪裡(URL),要買什麼(HTTP方法),然後拿出錢(Headers)和購物清單(Body Content),就可以順利結帳了。
至於OpenAI API提供的模型(Model)種類,它其實有好幾種(例如:chat、Completion、Edit等等),而在這裡我們主要關注的是 Completion模型。這個模型在AI的內容生成方面相當基礎,但也非常強大。這就像是學校裡的基礎課程一樣,雖然簡單,但卻是建立知識大樓的重要基石。
接下來,我們將會用一個簡單的例子,來示範如何使用requests
套件來與OpenAI API進行連結,並且發送一個簡單的請求。準備好了嗎?
Completions API介紹
在OpenAI,有一個模型叫做「Completions API」。想像一下,當我們玩文字接龍遊戲,每個人依序加上一個字或一句話,故事就這樣一步步堆疊而豐富起來。ChatGPT也是運作在這樣的原理上。只要給它一段話,它就根據這段話,依照機率決定最可能接上去的文字。這過程中,它會計算出各種可能性,嘗試找到最合適、最有意義的回答來回應你。
這就是「Completions API」的魅力所在 — — 我們開始一個話題,AI則扮演著那個接話的夥伴,繼續延伸我們的故事。這不僅僅是單純的回答問題,更是一種創造性的對話過程。
如果要使用這個Completions API,就須要透過POST方法,把文字送給它。這個API的存取網址為:
# POST 方法
<https://api.openai.com/v1/completions>
使用 requests 套件1: 安裝
在Python世界中,若想與OpenAI API進行交流,除了OpenAI官方的openai
套件之外,我們還有另一個選擇——那就是requests
套件,它提供了一種簡潔且直觀的方法來發送HTTP請求。
首先,確保您的開發環境中已經安裝了requests
。方式很簡單,只需在終端機輸入pip install requests
,或者在Jupyter Notebook中加上驚嘆號變為!pip install requests
即可。
# 終端機
pip install requests
或
# Jupyter Notebook
!pip install requests**
如果您在Google Colab這樣的雲端開發環境中工作,那麼requests
已經為您準備好了,Colab 預設上已經安裝 requests 套件,無需額外安裝。
使用 requests 套件2: 匯入並使用post方法
安裝好requests
後,就可以導入它,並利用post
方法來向API發出請求。在這過程中,我們會設定必要的HTTP標頭,如授權和內容類型,並將訊息打包為JSON格式發送。post()
傳回的是 Reponse 類別的物件,可透過 text 屬性取得 API 傳回的內容。由於回傳的內容是JSON格式的文字資料,我們需要對這個資料進行轉換。
import requests
import os
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())
response = requests.post('<https://api.openai.com/v1/chat/completions>',
headers = {
'Authorization': f'Bearer {os.getenv("OPENAI_API_KEY")}',
'Content-Type': 'application/json'
},
json = {'model': 'gpt-3.5-turbo',
"messages":[{"role": "user", "content":"Hello"}]}
)
另外,您需確保在發送請求前,環境變數中已經設置了API金鑰,這一步是必不可少的,因為沒有金鑰,API就像是一扇您無法打開的門。
使用 requests 套件3: 取json
發出POST請求後,requests
會回傳一個包含API回應的Response物件。要獲取這些資料,我們可以直接透過Response物件的json()
方法,將JSON格式的回應轉化為Python字典,這樣就能更方便地操作了。
reply = response.json()
撰寫至此,我們可以先執行看看,到底會得到什麼樣的結果。
print(reply)
以下是直接顯示出來reply的結果。我們可以發現這是一串JSON格式的資料。
{'id': 'chatcmpl-8H6LZzOqxyVrahCLEZFjcn3RpD6CZ',
'object': 'chat.completion',
'created': 1699086665,
'model': 'gpt-3.5-turbo-0613',
'choices': [
{'index': 0,
'message': {
'role': 'assistant',
'content': 'Hello! How can I assist you today?'},
'finish_reason': 'stop'}
],
'usage': {
'prompt_tokens': 10,
'completion_tokens': 9,
'total_tokens': 19}
}
這份JSON格式的資料中,有下面幾個部分值得特別說明的:
# model
這裡告訴我們這次API使用什麼樣的模型。不過,有趣的是您可以看到雖然我們在request 的header資訊中指定了 gpt-3.5-turbo
作為模型,但實際上reply回來,卻用的是 gpt-3.5-turbo-0613
模型,這是因為API會自動提供您該版本下最優的模型。
# choices
這是我們最需要的部分。它是個list串列,代表 API 回覆訊息的內容。串列中可以有很多組,每一組元素({}
)的 message 項目就是一個訊息。由於預設的 API 只會回覆一個訊息,因此串列中就只有一個元素({}
)。
# usage
是表示本次 API 的使用量,會以字典的形式呈現給我們。其中:
prompt_tokens
表示傳送給 API 的訊息換算為 token 的數量;completion_tokens
表示API 回覆的訊息換算為 token 的數量;total_tokens
則表示這次詢問所用到的總 token 數。也就是前兩項的加總。
綜上所述,我們從回應中獲得了一些有用的信息,比如API所使用的模型、回應的token數量,以及這次互動的總token數。這些訊息不僅幫助我們了解AI的運作,也是控制成本和使用效率的重要指標。
使用 requests 套件4:顯示覆結果
接著, 就可以取得回覆訊息的內容了,也就是choices的部分。
print(reply["choices"][0]["message"]["content"])
以下是執行的結果:
只顯示出回覆的結果:『Hello! How can I assist you today?』。
使用openai 套件
Python的世界裡,當我們想要和OpenAI的AI模型進行交流,還有一個專門的工具可以使這個過程變得簡單許多,那就是官方提供的openai
套件。這個套件將複雜的HTTP通訊細節打包在內,讓我們可以專注於和AI對話的內容本身。
首先,您需要在Python程式碼中匯入openai
套件,就像這樣:
import openai
這行程式碼可以讓我們取用openai
提供的所有功能。接著,我們會用到Completion這個模式,這是一個非常基礎,卻也是非常強大的API模式。它讓我們可以給AI模型一個開端,AI模型會在這個基礎上生成接續的文字。
使用openai
套件時,我們會這樣寫程式碼:
變數 = openai.Completion.create(
model=模型名稱,
prompt=提示文字,
max_tokens=Token數量
)
上面程式碼的create
方法會建立一個「Generator」的物件。雖然我們可以選擇不同的參數放在「Generator」裡面,但至少要放以下三個:
model
跟前面討論的一樣,這裡需要設定這次API將使用哪一種模型。我們可以指定 gpt-3.5-turbo
或text-davinci-003
等,當然如果您的口袋深,也可以指定gpt-4
作為使用的模型。
prompt
這裡要填入您想要問的問題,也就是「提示文字」或「prompt」。我們會將這裡面的文字送到AI模型。OpenAI 的 AI模型會根據這文字來生成回應。
max_tokens
這是生成文字的最大Token數。您可以限制可容許的最大Token使用數量,這個數量要使用「整數」來表示。
這樣一來,我們就不需要直接處理HTTP請求的複雜性,可以更直接地與AI進行互動。這對於想要迅速獲得結果的開發者來說,無疑是一個非常方便的選擇。
關於access_openai
函式
在Python中,透過openai
套件的幫助,我們可以輕鬆地發送問題與OpenAI API進行溝通。接下來,我們可以來上一篇文章中提到的簡化型範例「精簡啟動應用程式(Simplified Sample App)」。
大家還記得在「精簡啟動應用程式(Simplified Sample App)」裡面有一個access_openai
函式嗎?當時我們稱這個函式為「只要傳入prompt指令,就會返回GPT結果的一個百寶箱」,只要您給它一段prompt指令,它就會回給您GPT模型生成的文字。今天我們就要來打開百寶箱一探究竟。
以下程式碼就是「精簡啟動應用程式(Simplified Sample App)」中的access_openai
函式:
import openai
# 這裡是你的OpenAI API金鑰
api_key = "你的API金鑰"
def access_openai(prompt_value):
openai.api_key = api_key
response = openai.Completion.create(
model="text-davinci-003",
prompt=prompt_value,
max_tokens=100,
n=2,
stop=None,
temperature=0.5
)
return response.choices[0].text.strip()
access_openai
函式定義完成後,我們可以將它放到實際的使用情境中。為了要單獨測試這段程式碼,我們需要在前後加上別的程式碼。在access_openai
函式的前面要加上:
import openai
api_key = "... 這裡填你的API金鑰 ..."
access_openai
函式的後面則需要加上下面這一段。它可以讓使用者輸入一段文字,然後將這段文字作為access_openai
函式的參數來獲得AI的回答:
if __name__ == "__main__":
input_text = input("請輸入文字:")
access_openai(input_text)
在前面 api_key
的地方,需要填入自己拿到的API金鑰。接著,儲存為python檔案(副檔名.py
)後,就可以將寫好的程式碼,拿來執行看看。
整個程式會從 if __name__ == "__main__":
這一行以下開始執行,當這段程式碼被執行時,會提示使用者輸入prompt指令,然後將這些指令文字發送給OpenAI API,API會根據您的輸入生成一段文字,最後將這段文字顯示出來。不過,依照目前的程式寫法,從送出問題到顯示結果之間,會需要稍微等一下。
Generator物件的參數
在Python程式設計中,當我們要和OpenAI API交流,openai
套件提供了一個方便的連接方式,這個接觸點就是openai.Completion.create
。透過這個方法,可以讓我們方便地與AI模型進行溝通,只需要給它一些基本參數,它就會返回AI生成的內容。
在access_openai
函式中,我們使用了這個接觸點。來看看我們用了哪些參數:
response = openai.Completion.create(
model="text-davinci-003",
prompt=prompt_value,
max_tokens=100,
n=2,
stop=None,
temperature=0.5
)
其中,model
參數決定了我們使用哪個AI模型,這裡我們使用的是text-davinci-003
。prompt
參數則是我們給AI的提示文字,這個文字會影響AI生成的內容。而max_tokens
則限定了AI回應的長度。
除此之外,我們還有另外三個進階參數:n
、stop
和temperature
。
n
參數讓我們可以獲得多個回應選項,這裡設定為2(n=2
),意味著AI會生成兩個可能的回應。stop
參數可以指定一個或多個終止符號,當AI在生成內容時遇到這些符號,就會停止生成。stop參數的預設值為空的list串列。temperature
參數則控制生成文字內的隨機性,數值越高,生成的內容樣化越多;數值越低,內容則越可以預測。
這些參數組合起來,就像是給AI模型的一個設計藍圖,告訴它我們的需求和期望。當然,要精準地把握這些參數對生成結果的影響,可能需要一些實驗和經驗累積。但這正是程式設計的樂趣所在,透過不斷試驗,可以更深入地了解AI模型的運作,並有效地利用它來完成我們的任務。
解釋完「Generator」物件的參數後,我們來看一下access_openai 函式的運作。其中最重要的部分實際上是在使用後它所回傳的結果。
Generator 的回傳值
在Python程式中,我們通常會這樣取得模型生成的結果:
result = response.choices[0].text.strip()
這裡的「Generator」物件所回傳的response
,其實是一個包含了豐富資訊的物件。它不僅承載了我們先前所見的那串JSON格式的資料,還有更多與產出結果相關的細節。這個response
物件大致包含了以下結構:model
、choices
與usage
等欄位。
{
"choices": [
{
"finish_reason": "stop",
"index": 0,
"logprobs": null,
"text": "\\\\n\\\\nHello World is a common phrase used as a simple greeting to someone or a group of people. It is commonly used to test the functionality of a new computer program or other technology."
},
{
"finish_reason": "stop",
"index": 1,
"logprobs": null,
"text": "\\\\n\\\\nHello! My name is Ryan. It is nice to meet you."
}
],
"created": 1699267267,
"id": "cmpl-8HrKV6jhaTprLtEOeo5421DViJPNB",
"model": "text-davinci-003",
"object": "text_completion",
"usage": {
"completion_tokens": 54,
"prompt_tokens": 2,
"total_tokens": 56
},
關於 choices
部分
choices
就是 AI 模型根據輸入的資料所生成的結果,我們可以從 choices[0]
中取出結果。一般情況下,系統預設只會產生一個結果,但如果我們設置了n
參數為2,那麼就會產生兩個結果。這也解釋了為什麼這裡會有兩個不同的index
。 "index"
是指在陣列中的位置。而"text"
中就包含了 AI 模型的回應,這通常是我們最關心的部分。
此外,"finish_reason"
告訴我們,AI生成在什麼狀況下結束了。它可能會因為以下幾種情況而終止:
"stop"
:達到了設定的停止條件,AI生成作業就此結束。"length"
:生成的 token 數量已超過了最大限制,因此停止AI生成。"content_filter"
:部分內容因為「內容過濾規則」而被排除。
這些細節有助於我們了解 AI 如何工作,並適當地調整我們的請求以獲取最佳結果。
「Quickstart Sample App」範例程式
前面,我們已經看過簡化型範例「精簡啟動應用程式(Simplified Sample App)」中的access_openai
,接下來我們再來看看 OpenAI 提供的範例程式「Quickstart Sample App」,這裡我們將一探究竟。
首先,來看看這個範例應用程式的第一部分(Part 1):
@app.route("/", methods=("GET", "POST"))
def index():
if request.method == "POST":
animal = request.form["animal"]
response = openai.Completion.create(
model="text-davinci-003",
prompt=generate_prompt(animal),
temperature=0.6,
)
return redirect(url_for("index", result=response.choices[0].text))
result = request.args.get("result")
return render_template("index.html", result=result)
在這段程式碼中,當使用者透過表單送出資料時,後端會根據送出的動物名稱(animal),使用generate_prompt
函式產生一個prompt指令,再藉由OpenAI的API生成一段文字內容。
這裡的response
變數就是一個包含API回應的「Generator」物件。它主要包含三個參數:必填的model
與prompt
,以及選填的temperature
。
生成的文字內容會透過response.choices[0].text
取得,然後重新指向至首頁,並將生成的內容作為結果參數。
再來看看generate_prompt
函式的內容:
def generate_prompt(animal):
return """Suggest three names for an animal that is a superhero.
Animal: Cat
Names: Captain Sharpclaw, Agent Fluffball, The Incredible Feline
Animal: Dog
Names: Ruff the Protector, Wonder Canine, Sir Barks-a-Lot
Animal: {}
Names:""".format(animal.capitalize())
這個函式利用使用者輸入的動物種類(透過animal
參數),自動產生一串格式化的prompt指令。這種結構清晰地分開了API設定與prompt提示指令,使得開發者可以簡便地修改generate_prompt
來調整提示內容,或者直接在index
函式中調整API的其他設定,而不會影響到prompt指令的結構。
透過這樣的結構,我們可以清晰地管理程式碼,方便後續的維護與更新。
從 Completion 跨越到Chat Completion
提到OpenAI的API使用,我們之前都是圍繞著Completion API
進行討論。不過來到了2023年7月,OpenAI 推出了專為 Chat Completion 設計的強大新模型「GPT-4」,它在多方面都超越了前代的 GPT-3.5。隨著這項進展,OpenAI 也決定將逐步淘汰Completions API
。
有人可能會問:「既然Completions API
終將退出歷史舞台,我們還需要學習它嗎?」
這是一個好問題。其實,無論是Completion
還是Chat Completion
,它們在設計Prompt指令的基本理念上是相通的。只是Chat Completion
加入了「角色(Role)」這個新功能,允許我們更精確地設計Prompt指令。所以,你在Completion
上學到的技能,在Chat Completion
上依然適用,甚至可以發揮得更淋漓盡致。
因此,對於有志於掌握最新AI技術的開發者來說,即使Completions API
將被新技術取代,學習它的經驗仍然是寶貴的資產。畢竟,技術的演進永遠都是站在巨人的肩膀上,過去的知識為我們提供了更高的起點。在這個快速變遷的時代,積累的知識和經驗,將成為我們應對未來挑戰的堅實基石。
結論
走過一連串對OpenAI API的探索後,終於來到了這系列文章的尾聲,讓我們在此做個總結。
在這趟學習旅程中,我們理解到,利用OpenAI提供的API,就能夠輕鬆地將先進的人工智慧技術融入平常的應用情境中。正如同打開一道通往未來的門,OpenAI API成為我們實現創新與解決問題的利器。然而,要有效地揮舞這把魔法棒,並非只是了解其表象,而是需要深入其內層的實踐與實作。
這次,透過實際操作OpenAI範例「Quickstart Sample App」,開啟了我們如何啟動AI的力量。期間並透過Flask框架,讓我們體驗到從接收用戶輸入的指令,到發起對OpenAI API的請求,再到呈現結果於網頁的全流程,這個過程的簡潔與直覺,令人印象深刻。
此外,我們也探討了如何精準地從OpenAI獲取所需資料,並深入範例應用程式的結構與邏輯,洞察其中的精妙。
有句俗諺說:「工欲善其事,必先利其器。」OpenAI API就是那把鋒利的瑞士刀,在這生成式AI的浪潮中,我們不僅要學會如何使用這些工具,更要學會如何創造、如何創新。這樣,在這日新月異的時代裡,我們才能夠更自在地前進、邁向未來。