北國春遲,春寒料峭略帶陰霾,但ChatGPT新介面模型gpt-3.5-turbo的更新為我們帶來了一絲暖意,使用成本更加親民,比高階產品ChatGPT Plus更實惠也更方便,畢竟ChatGPT Plus依然是透過網頁端來輸出,Api介面是以token的數量來計算價格的,0.002刀每1000個token,token可以理解為字數,說白了就是每1000個字合0.01381人民幣,以ChatGPT無與倫比的產品力而言,如此低的使用成本讓所有市面上其他所有類ChatGPT產品都黯然失光。
本次讓我們使用Python3.10光速接入ChatGPT API的新模型gpt-3.5-turbo。
OpenAI庫的SDK方式接入
OpenAI官方同步更新了介面Api的三方庫openai,版本為0.27.0,如果要使用新的模型gpt-3.5-turbo,就必須同步安裝最新版本:
pip3 install openai==0.27.0
隨後建立chat.py檔案:
import openai
openai.api_key = "openai的介面apikey"
completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "北國風光,千里冰封,萬里雪飄,請接著續寫,使用沁園春的詞牌"}]
)
print(completion["choices"][0]["message"]["content"])
程式返回:
瑤池冰緣,雪舞悽美, 隔窗寒意,似乎鑽進衣袖。
寒塘渡鴨,雪中梅影, 孤獨是一片銀白的姿態。
冰雪如花,開放在草莓園裡, 可愛的雪人,瑟瑟發抖著歡呼。
北風凜冽,寒暄難擋, 四季明媚,但冬日尤甜美。
千里冰封,萬里雪飄, 窗外天下壯觀,此時正是京城美。
閃電般秒回,讓用慣了ChatGPT網頁端的我們幾乎不能適應。
gpt-3.5-turbo,對得起turbo的加成,帶渦輪的ChatGPT就是不一樣。
ChatGPT聊天上下文
我們知道ChatGPT的最大特色就是可以聯絡語境中的上下文,換句話說,ChatGPT可以根據之前的回答來最佳化之後的回答,形成上下文關係,讓人機對話更加連貫和富有邏輯性。
這裡取決於輸入引數中的role引數,每一個role的取值,對應的場景不一樣,其中system用於在對話開始時給ChatGPT一個指示或宣告,有點像引導詞,使得後續的回答更具有個性化和專業化。user是用於給使用者提問的或者說是用來給使用者輸入引導詞的。assistant顧名思義,是用於輸入ChatGPT的回答內容:
import openai
openai.api_key = "apikey"
class ChatGPT:
def __init__(self,chat_list=[]) -> None:
# 初始化對話列表
self.chat_list = []
# 顯示介面返回
def show_conversation(self,msg_list):
for msg in msg_list:
if msg['role'] == 'user':
print(f"Me: {msg['content']}\n")
else:
print(f"ChatGPT: {msg['content']}\n")
# 提示chatgpt
def ask(self,prompt):
self.chat_list.append({"role":"user","content":prompt})
response = openai.ChatCompletion.create(model="gpt-3.5-turbo",messages=self.chat_list)
answer = response.choices[0].message['content']
# 新增歷史對話,形成上下文關係
self.chat_list.append({"role":"assistant","content":answer})
self.show_conversation(self.chat_list)
這裡每一次會話都會加入chat_list的聊天列表,角色為assistant,為了讓ChatGPT分析上下文,下面開始測試:
if __name__ == '__main__':
chat = ChatGPT()
chat.ask("你是一位南宋詞人,詞風婉約,有點類似李清照女士,請使用蝶戀花詞牌描寫北國春光")
程式返回:
Me: 你是一位南宋詞人,詞風婉約,有點類似李清照女士,請使用蝶戀花詞牌描寫北國春光
ChatGPT: 北國春光,清冽宜人。望眼欲穿的遠山如翠起伏,遙遠而縹緲。層層疊疊的林木,新綠徜徉,婆娑搖曳。風兒吹起,沁人心脾,點點梅花飄至,宛如仙境。
花間蝶戀,春色滿園。鶯鶯燕燕,鳥鳴花落,時時惹人遐思。碧空萬里,藍天白雲,彩雲飄飄,繽紛奪目。柳絮飄飄,輕羽翩翩,小河潺潺,流水聲聲,婉轉動人。
清風拂面,落英繽紛。聽著草蟲唱起,充滿陽光的氣息,輕輕飄蕩,彷彿一條無形的小河,展開春天的美好,留下美好的記憶。人間永珍,卻只有這春色無邊,似乎奔向遠方的快樂。
此時再次發問:
chat.ask("請使用另外一種粗狂陽剛的風格再寫一遍上面的詞")
程式返回:
Me: 請使用另外一種粗狂陽剛的風格再寫一遍上面的詞
ChatGPT: 北國春光,不柔不媚,金色的陽光照在地上,充滿了男子氣概。
草原上風吹不斷,那些瘋狂的野花,在春風中舞蹈。
看!那些猛禽靜靜地盤旋在高空,監視著整片草原,威武雄壯。
花叢間,一隻雄性蜂鷹躍躍欲飛,看上去彷彿要衝破天際。
這裡的春天有時帶著風沙,但這並不能阻止狂放豪邁的草原奔騰前行,而這樣的北國春光,怎會輕易被遺忘!
雖然內容有些尬,但確實聯絡了上下文。
需要注意的是,token不僅計算ChatGPT的介面返回內容,也會計算使用者的傳送內容,token的計算方法不是簡單的一詞一個,例如中文輸入,一箇中文漢字佔2個位元組數,而對於一次中文測試中,50個漢字被算為100個tokens,差不多是英文的一倍,而token還計算api傳送中的角色欄位,如果像上文一樣實現上下文操作,就必須傳送ChatGPT介面返回的歷史聊天列表,這意味著ChatGPT上下文聊天的成本並不是我們想象中的那麼低,需要謹慎使用。
原生ChatGPT介面非同步訪問
除了官方的SDK,新介面模型也支援原生的Http請求方式,比如使用requests庫:
pip3 install requests
直接請求openai官方介面:
import requests
h = {
'Content-Type': 'application/json',
'Authorization': 'Bearer apikey'
}
d = {
"model": "gpt-3.5-turbo",
"messages":[{"role": "user", "content": "請解釋同步請求和非同步請求的區別"}],
"max_tokens": 100,
"temperature": 0
}
u = 'https://api.openai.com/v1/chat/completions'
r = requests.post(url=u, headers=h, json=d).json()
print(r)
程式返回:
{'id': 'chatcmpl-6qDNQ9O4hZPDT1Ju902coxypjO0mY',
'object': 'chat.completion',
'created': 1677902496, 'model': 'gpt-3.5-turbo-0301',
'usage': {'prompt_tokens': 20, 'completion_tokens': 100, 'total_tokens': 120},
'choices': [{'message':
{'role': 'assistant',
'content': '\n\n同步請求和非同步請求是指在客戶端向伺服器傳送請求時,客戶端等待伺服器響應的方式不同。\n\n同步請求是指客戶端傳送請求後,必須等待伺服器響應後才能繼續執行後續的程式碼。在等待伺服器響應的過程中,客戶端的介面會被阻塞,使用者無法進行'},
'finish_reason': 'length', 'index': 0}]}
ChatGPT原生介面也支援非同步方式請求,這裡使用httpx:
pip3 install httpx
編寫非同步請求:
h = {
'Content-Type': 'application/json',
'Authorization': 'Bearer apikey'
}
d = {
"model": "gpt-3.5-turbo",
"messages":[{"role": "user", "content": "請解釋同步請求和非同步請求的區別"}],
"max_tokens": 100,
"temperature": 0
}
u = 'https://api.openai.com/v1/chat/completions'
import asyncio
import httpx
async def main():
async with httpx.AsyncClient() as client:
resp = await client.post(url=u, headers=h, json=d)
result = resp.json()
print(result)
asyncio.run(main())
程式返回:
{'id': 'chatcmpl-6qDNQ9O4hZPDT1Ju902coxypjO0mY',
'object': 'chat.completion',
'created': 1677902496, 'model': 'gpt-3.5-turbo-0301',
'usage': {'prompt_tokens': 20, 'completion_tokens': 100, 'total_tokens': 120},
'choices': [{'message':
{'role': 'assistant',
'content': '\n\n同步請求和非同步請求是指在客戶端向伺服器傳送請求時,客戶端等待伺服器響應的方式不同。\n\n同步請求是指客戶端傳送請求後,必須等待伺服器響應後才能繼續執行後續的程式碼。在等待伺服器響應的過程中,客戶端的介面會被阻塞,使用者無法進行'},
'finish_reason': 'length', 'index': 0}]}
我們也可以將非同步請求方式封裝到對話類中,完整程式碼:
import openai
import asyncio
import httpx
openai.api_key = "apikey"
h = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {openai.api_key}'
}
d = {
"model": "gpt-3.5-turbo",
"messages":[{"role": "user", "content": "請解釋同步請求和非同步請求的區別"}],
"max_tokens": 100,
"temperature": 0
}
u = 'https://api.openai.com/v1/chat/completions'
class ChatGPT:
def __init__(self,chat_list=[]) -> None:
# 初始化對話列表
self.chat_list = []
# 非同步訪問
async def ask_async(self,prompt):
d["messages"][0]["content"] = prompt
async with httpx.AsyncClient() as client:
resp = await client.post(url=u, headers=h, json=d)
result = resp.json()
print(result)
# 顯示介面返回
def show_conversation(self,msg_list):
for msg in msg_list:
if msg['role'] == 'user':
print(f"Me: {msg['content']}\n")
else:
print(f"ChatGPT: {msg['content']}\n")
# 提示chatgpt
def ask(self,prompt):
self.chat_list.append({"role":"user","content":prompt})
response = openai.ChatCompletion.create(model="gpt-3.5-turbo",messages=self.chat_list)
answer = response.choices[0].message['content']
# 新增歷史對話,形成上下文關係
self.chat_list.append({"role":"assistant","content":answer})
self.show_conversation(self.chat_list)
if __name__ == '__main__':
chat = ChatGPT()
chat.ask("你是一位南宋詞人,詞風婉約,有點類似李清照女士,請使用蝶戀花詞牌描寫北國春光")
chat.ask("請使用另外一種粗狂陽剛的風格再寫一遍上面的詞")
asyncio.run(chat.ask_async("請解釋同步請求介面和非同步請求介面的區別"))
結語
低成本ChatGPT介面模型gpt-3.5-turbo更容易接入三方的客戶端,比如微信、QQ、釘釘群之類,比起ChatGPT網頁端,ChatGPT介面的響應速度更加迅速且穩定,ChatGPT,永遠的神,沒有之一,且不可替代,最後奉上非同步上下文封裝專案,與君共觴:github.com/zcxey2911/chatgpt_api_Contextual_async