logo
Loading...

OpenAI API X python - 自己開始寫LLM應用程式(基礎應用篇) - 生成式AI從No-Code到Low-Code開發與應用四部曲 - Cupoy

Python + openAI 套件 想透過python使用openAI API最簡單的方式就是透過OpenAI提供的”openai”套件了。 開啟一個新的colab介面,並且記得存到自己的goog...

Python + openAI 套件 想透過python使用openAI API最簡單的方式就是透過OpenAI提供的”openai”套件了。 開啟一個新的colab介面,並且記得存到自己的google drive或github或Github Gist設定存為副本。不然可能會遺失掉(雖然colab有自動儲存功能但還是存為副本為妙)。 colab AI : colab現在也把自家的大型語言模型”codey”直接嵌入colab環境中,以後在打程式碼的時候遇到一一些error或是想要創建的內容都可以直接在colab環境裡面問這個生成式AI了,但由於才剛上線所以可能不會太準確,所以如果真的無法得到很好的答案,還是建議轉回chatGPT4 。 安裝與使用openai套件 使用前記得先安裝此套件於我們自己的環境python : 可以在terminal輸入:pip install openai 抑或是在colab中輸入: !pip install openai 安裝完之後即可匯入模組並使用要使用的金鑰openai API key, 請先將以下儲存格內的“你的金鑰”字樣替換成你自己剛剛辦好的金鑰後執行。 import openai openai.api_key = "你的金鑰" openAI模組有三種設定金曜的方法: 1.如同剛剛執行的儲存格那樣直接透過模組本身的openai.api_key(呼叫openai 類別裡面的方法api_key)設定金鑰。 2.將金鑰儲存在某個檔案中,並透過模組的openai.api_key_path指定檔案路徑,就會從該檔案取得金鑰。 3.如果沒有透過上述兩種放髮設定金鑰,Default會尋找名為OPENAI_API_KEY的環境變數,並使用它的值(value)作為金鑰。  可以想成一個字典結構裡面有一組 {{OPENAI_API_KEY:”你的金鑰” }} 由於目前我們重點在使用API,因此先以最簡單方式直接透過openai.api_key設定金鑰。 這種做法因為把金鑰大辣辣的直接寫在程式碼中,當你分享程式碼給其他人時如果忘記刪除然後分享程式碼檔案給其他人時可能會有洩漏金曜的危機。稍等會分享如何“隱藏金鑰”進而避免洩漏風險的方法。 接著就可以透過openai.ChatCompletion.create() (library.封裝的類別.屬性方法)=>python呼叫方法都用“.”做區隔層層調用、呼叫。 接著就透過openai.ChatCompletion.create()函式連線使用API,這個函式有兩個地要參數。 model: 指定要用的模型,我們將可以用穩定版本的gpt3.5-turbo或gpt-4模型執行範例。但是gpt-4費用較高,通常用3.5turbo做測試就可以了。 message: 這是串列訊息,其中“每個元素都是一個字典”字典中role也就是發言的角色也就是“user”、“assistant”、”system”其中一個; “content”項目是訊息的內容。 以下就來看最簡單的範例:在code上面我都會打上comment給同學參考 reply = openai.ChatCompletion.create( model = "gpt-3.5-turbo", #使用3.5 turbo引擎 # model = "gpt-4", messages = [ {"role":"user", "content": "你好"}。 #傳給API一個user的角色說“你好” ] ) 執行後回傳回一個OpenAIObject類別的物件,具有字典功能,可以用字典的方式使用。 字典裡面有給各種資訊包括所用的模型、內容、還有各種token使用的數量。 usage項目是一項字典,表示本次API用量,個別項目為: Note:最新價目表請查:https://openai.com/api/pricing 建議大家練習時都只使用gpt3.5-turbo就好gpt4的部分真的是挺貴的,等在某個項目有發現明顯模型上的差異時再換乘gpt4即可。 choice項目是一個串列,代表API回覆的訊息。 要特別注意的是content他在print出來的第一時間是會遇到非ASCll字元時會以“\u+”Unicode編碼格式表示。 我們可以利用: print(reply["choices"][0]["message"]["content"]) 來得到API開頭的: "content": "\u4f60\u597d\uff01\u9700\u8981\u5e2e\u52a9\u5417\uff1f” 到底是表示啥? Tips:在傳送中文提示給模型時若沒有強制添加額外的只是強調要繁體中文,很大的機會模型會以簡體中文做回應(畢竟簡體中文的taining量比繁體中文多得多)。 我先以聚焦在主題,簡化程式碼為主,先不會特別把output翻成繁體中文。 另外,finish_reasona表示該回覆訊息是否完結整個語句,有下表兩種可能: 除非用下一小節介紹的“限制回覆長度參數”,否則API回覆的應該都是完整語句。 傳遞多筆訊息: 現在我們知道API在python中的基本用法,接下來就來模擬我們方才在遊樂園(playground)上測試過的功能,傳送API給額外的system角色訊息。請執行以下code: reply = openai.ChatCompletion.create( model = "gpt-3.5-turbo", messages = [ {"role":"system", "content":"你是條住在深海、只會台灣中文的魚"}, {"role":"user", "content": "你住的地方很亮嗎?"} ] ) 然後一樣以調choice串列的方式印出來: print(reply["choices"][0]["message"]["content"]) output: 我住在深海的深處,所以在那裡相當黑暗,沒有太多光線透過。 不過,有些生物會發光,使整個深海中的某些區域變得明亮。 這些生物使用生物發光的能力來吸引獵物、威嚇敵人或吸引伴侶。但總體而言,深海環境是相當暗淡的。 這次多加上了system的角色訊息,印出來發現的確有所差別。變成了繁體中文,然後回答變成有關乎“深海“這個議題。 設定與隱藏金鑰的方法: 前面剃到過,使用openai.api_key直接設定金鑰會將金耀直接留在程式碼當中,其實非常危險。因為當你分享的時候就可能洩露了自己的金鑰導致自己存的錢一直被扣款。 所以我們一般的做法會將金鑰放在一個“設定的環境變數檔案”中。 在colab中你可以透過%%env(稱為魔法指令magic command)設定環境變數。 比如說: %env OPENAI_API_KEY = 你的金鑰 不過這樣在分享code的時候還是會洩漏金鑰,為了避免這個問題我會採用python-dotenv 這個套件,讓我們可以從“隱藏檔案”中讀取資料並依讀取內容設定環境變數。 由於colab分享筆記本時不會分享你的檔案,因此就不會洩漏記錄在檔案中的金鑰了。 (隱藏重要API金鑰至其他設定環境變數這個技巧在軟體業界非常常用到,請務必學起來) 在使用python-dotenv 此套件前請先準備一個儲存有環境變數設定的文字檔,並命名為“.env”然後上傳或是拖移至colab中。你可以使用任何文字編輯器,可以直接使用記事本。 方法一:在本機建立環境變數隱藏檔 使用記事本或是任何文字編輯軟體建立 .env 檔後再拖曳到 Colab 的檔案窗格上傳到 Colab 中。 方法二:在 Colab 建立環境變數隱藏檔 請先建立 env 檔案 在 env 檔案中依照 OPENAI_API_KEY=你的金鑰 這樣的格式記錄環境變數 將 env 檔案重新命名為 .env 檔 之所以要先建立 env 檔再重新命名為 .env, 是因為 Colab 不允許編輯 . 開頭的隱藏檔。 接著先安裝一下python-dotenv: !pip install python-dotenv from dotenv import load_dotevn 成功讀取到.env檔後會回傳“True”。 然後: import os os.getenv("OPENAI_API_KEY") 如果點下執行後出現是你的金鑰,就代表成功了。 即使不是使用colab,利用python-dotenv在檔案中設定環境變數也很有用,例如不同的專案會用到不同的金鑰,就可以建立各自的.env檔,這樣就不需要一直手動將環境變數改來改去了。 轉換成token其實是為了讓模型處理,從上面的展示來看也可以知道,轉換成token後,數量顯然會比原始的英文單字或中文字數多,OpenAI官方建議概略的計算方式是英文單字數約為token的0.75倍,但中文就沒有這樣的概略算法了。 使用“tiktoken套件”計算精確的token數: 如果想知道傳送訊息的確切token數,或是想要在程式中預先計算token數,避免超過模型的限制數量,OpenAI提供有tiktoken套件,首先執行以下的code安裝並匯入到環境中: !pip install tiktoken import tiktoken 接著就可以透過tiktoken模組內的encoding_for_model()方法,取得指定模型中負責切割文字成為token的編碼器,也可以取得編碼器讀名稱。請執行以下code分別取的gpt3.5-turbo和gpt-4模型的token編碼器: encoder = tiktoken.encoding_for_model('gpt-3.5-turbo') #指定gpt43.5 turbo模型 print(encoder.name) encoder = tiktoken.encoding_for_model('gpt-4') #指定gpt4模型 print(encoder.name) model: 指定要用的模型,我們將可以用穩定版本的gpt3.5-turbo或gpt-4模型執行範例。但是gpt-4費用較高,通常用3.5turbo做測試就可以了。 message: 這是串列訊息,其中“每個元素都是一個字典”字典中role也就是發言的角色也就是“user”、“assistant”、”system”其中一個; “content”項目是訊息的內容。 紫色框為編碼器名稱 你可以看到這兩個模型用同一種編碼器,取得編碼器後就可以利用編碼器下的encoder()方法從文字轉為token,或是利用decoder()從token轉回文字。請複製貼上以下code至你的下一個colab notebook儲存格。我們試著將“你好”轉換成token在從token轉回“你好“。 tokens = encoder.encode("你好") print(tokens) print(encoder.decode(tokens)) 為了讓大家方便觀察token切割結果,仿照了tokenizer網頁的做法設計了一個可以視覺化切割文字結果的工具。由於colab的執行過果支援標準終端機ANSI碼的功能,所以就可以幫文字上色。以下我們使用“ansicolors”這個套件,並從套件中的colors模組匯入color()函式: !pip install ansicolor from colors import color color的使用方式很簡單,只要傳入文字並用bg(background)或是fg(front ground)參數以網頁色碼的方式指定背景顏色,即可幫文字加上ANSI碼,列印出來就會上色了。請執行以下程式碼在您下一個colab儲存格: 可以看到因為指定了不同顏色的背景顏色,所以列印出來的結果文字都有各自的背景顏色。 這要就可以根據編碼得到的token,再反向解回文字並以不同的背景顏色相鄰的token, 看出文字切割效果了,請執行下一個儲存格:來定義一個tokenizer()函數。 def tokenizer(msg, model="gpt-3.5-turbo", show=False): encoder = tiktoken.encoding_for_model(model) color_pallet = ( '#FFB347', # Pastel orange (淡橙色) '#FFCC99', # Peach (桃色) '#FFFF66', # Pastel yellow (淡黃色) '#64fa64', # Tea green (茶綠色) '#CCFFCC', # Aero blue (天青色) '#CB99C9', # Thistle (薊色) '#FFB6C1', # Light pink (淺粉紅色) '#FFCCDD', # Pink lace (粉翠珠色) '#CCCCFF' # Lavender blue (薰衣草藍) ) idx = 0 tokens = encoder.encode(msg) if show: for token in tokens: print(color(encoder.decode([token]), bg=color_pallet[idx], fg='black'), end='') idx = (idx + 1) % len(color_pallet) print() return tokens tokenizer('Alphabet Inc is Google\'s parent company.', show=True) chatML標記語言 相信細心的人已經發現一件事情,就是我們明明只有輸入“你好”給API。然後從編碼器得到“你好”的token數量是2不是9對吧?!那中間的7又是怎麼來的呢? 因為,訊息中除了文字的訊息之外還有角色的訊息,所以當然不會只有2個token囉!事實上我們送給API的訊息在餵入模型處理前會先轉換成Chat Markup Language(ChatML)語言的格式,在訊息串列中的每一個訊息,都會轉成以下格式。 <|im_start|>角色\n{訊息內容}<|im_end|> 其中<|im_start|>、<|im_end|>兩個的是所位特殊的token, 代表單一訊息的開始與結尾。“\n”則代表換行符號字元,和各種角色一樣都會轉換成一個token。我們執行以下代碼就會知道。 print(tokenizer("user")) print(tokenizer("assistant")) print(tokenizer("system")) print(tokenizer("\n")) 以剛剛示範的內容: {"role":"user", "content": "你好"} 因為只有單一訊息,就會轉變成: <|im_start|>user\n妳好<|im_end|> 如果有多個訊息,就會將個別訊息轉換後串接在一起。轉換玩個別的訊息後,最後還會再加上這樣的結尾。 assistant\n. 表示接下來應該交由AI回覆。 也就是喔,每一個訊息除了訊息實際的內容轉換得到的token之外,還會額外加上4個(2個特殊1個換行1個角色)token,以及最後結尾固定的三個(交接給AI的三個)。 因此,已傳送user的訊息“你好”來說,實際上轉換成ChatML就是總共 4+2+3=9個token了。 我們也可以簡單地自己寫一個tokem計數器,如下: def tokens_in_messages(messages, model="gpt-3.5-turbo", show=False): totals = 0 for message in messages: for k in message: if k == "content": totals += 4 # ###draft_code_symbol_lessthen###|im_start|>user\n{內容}###draft_code_symbol_lessthen###|im_end|> print(totals). #4 totals += len(tokenizer(message[k], model, show)) print(totals) #4+2 = 6 totals += 3 # ###draft_code_symbol_lessthen###|im_start|>assistant###draft_code_symbol_lessthen###|message|> return totals. #6+3=9 print(tokens_in_messages([ {"role":"user", "content": "你好"} ])) output: 4, 6, 9 最後的結果果然是9, 這樣這個概念也算是告一段落了,相信到這同學都清楚為什麼token不是簡簡單單的2而是9了吧。