將大型語言模型整合到現實世界的產品後端是最新的創新戰場。但與所有科技趨勢一樣,真正的贏家並不是那些急於了解一切的人。相反,它是關於暫停、反思和做出明智的決定。
儘管人工智慧比以往任何時候都更容易獲得,但認為這是一項微不足道的任務是一個很大的錯誤。該領域仍處於起步階段,幾乎技術和商業領域的每個人都在試圖弄清楚如何理解它。網路上充斥著可靠的資訊和誤導性的炒作。
不管你信不信,你不需要對你聽到的每一條人工智慧八卦都熱衷起來。退後一步,深思熟慮地對待它。
如果您是 PHP 開發人員或使用 PHP 程式碼庫,人工智慧可能會感覺像是一個陌生的概念。類別、介面、訊息佇列和框架似乎與 NLP、微調、隨機梯度下降、LoRA、RAG 以及所有這些術語截然不同。我得到它。為了有系統地學習這些概念,就像軟體工程中的任何東西一樣,我們需要時間和良好的實踐。
但是人工智慧、機器學習和資料科學不是 Python 或 R 程式設計師的領域嗎?你說對了一部分。大多數的基礎機器學習都是用 Python 完成。老實說,學習 Python 是一種樂趣——它用途廣泛,可以應用於無數有趣的專案。從建置和訓練語言模型到透過 API 部署它,Python 都能滿足您的需求。
但是讓我們回到 PHP。
別擔心-身為一個普通軟體工程師,你不會被淘汰。恰恰相反。隨著我們越來越期望了解容器化、CI/CD、系統工程和雲端基礎設施等相關領域,人工智慧正迅速成為我們工具包中的另一項基本技能。現在就是開始學習的最佳時機。
也就是說,我不建議一頭栽進從頭開始建立神經網路(除非你真的想這麼做)。很容易不知所措。相反,讓我向您展示人工智慧實驗的實用起點。
以下是我們將在本指南中介紹的內容:
非同步 AI 工作流程
我將向您展示如何使用訊息佇列實現 AI 工作流程 - 無論是 RabbitMQ、Amazon SQS 還是您首選的代理程式。
生產就緒解決方案
您將看到部署在生產系統中的解決方案的真實範例,該解決方案透過 AI 解決基本業務需求
Symfony 整合
該解決方案完全在 Symfony PHP 框架內實現。
OpenAI 工具
我們將使用 OpenAI PHP 函式庫和最新的 OpenAI Assistants 2.0。
資料集結構
如何建立用於訓練和評估 AI 模型的資料集。
微調 OpenAI 模型
了解準備合適的 .jsonl 檔案並根據您的特定業務用例微調 GPT-4o-mini 模型或 GPT 系列中的另一個模型。
建立並測試 OpenAI Assistant 2.0
了解如何設定 OpenAI Assistant 並在 OpenAI Playground 中對其進行測試。
知識庫
深入了解知識庫的概念:為什麼 GPT 不知道一切,以及如何為其提供正確的上下文以顯著提高準確性。
PHP 與 Symfony 整合
了解如何將 AI 代理與 Symfony 應用程式無縫連接。
有興趣嗎?讓我們滾吧。
讓我們深入探討我們正在解決的問題。
從本質上講,我們正在處理代表某種事物的文字區塊——在我們的例子中是一個地址。目標是將其組件分類到預先定義的群組中。
因此,當使用者向我們發送地址時,我們的目標是傳回一個 JSON 結構,該結構將地址分段。例如:
{ "street": "Strada Grui", "block": "Bloc 7", "staircase": "Scara A", "apartment": "Apartament 6", "city": "Zărnești" }
為什麼這很重要?
嗯,這些地址是由人們(我們的客戶)輸入的,而且它們通常不一致。這就是我們需要結構化、解析資料的原因:
為了實現這一目標,我們將地址分解為預先定義的群組,例如「街道」、「房屋」、「郵遞區號」等,然後將其重新組合成所需的序列。
為什麼不使用正規表示式?
乍一看,這聽起來很簡單。如果我們對新客戶強制執行格式設定或知道他們通常以特定方式編寫地址,則正規表示式可能看起來是合理的解決方案。
但是,讓我們考慮一下羅馬尼亞地址的範例:
STRADA GRUI, BLOC 7, SCARA A, APARTAMENT 6, ZĂRNEŞTI BD. 21 DECEMBRIE 1989 nr. 93 ap. 50, CLUJ, 400124
羅馬尼亞地址通常很複雜,沒有特定的順序書寫,並且經常省略郵政編碼等元素。即使是最複雜的正規表示式也很難可靠地處理這種可變性。
這就是 GPT-3.5 Turbo 或 GPT-4o-mini 等人工智慧模型的閃光點——它們可以管理遠遠超出正規表示式等靜態規則所能處理的不一致和複雜性。
是的,我們正在開發一種人工智慧工作流程,可以顯著改進傳統方法。
每個機器學習項目都可以歸結為兩個要素:資料和模型。雖然模型很重要,但數據更為關鍵。
模型已預先打包、測試,並且可以更換以查看哪一個性能更好。但真正的遊戲規則改變者是我們提供給模型的資料的品質。
資料在機器學習中的作用
通常,我們將資料集分為兩部分或三部分:
對於這個項目,我們希望將地址拆分為其各個組成部分 - 使其成為分類任務。為了使用像 GPT 這樣的大型語言模型 (LLM) 獲得良好的結果,我們的訓練資料集中至少需要 100 個範例。
我們資料集的原始格式並不重要,但我選擇了一種直覺且易於使用的結構:
{ "street": "Strada Grui", "block": "Bloc 7", "staircase": "Scara A", "apartment": "Apartament 6", "city": "Zărnești" }
這是一個例子:
STRADA GRUI, BLOC 7, SCARA A, APARTAMENT 6, ZĂRNEŞTI BD. 21 DECEMBRIE 1989 nr. 93 ap. 50, CLUJ, 400124
如您所見,目標是根據輸入位址產生結構化 JSON 回應。
首先,您需要一個 OpenAI API 帳戶。這是一個簡單的過程,我建議添加一些初始資金——10 美元或 20 美元就足夠了。 OpenAI 使用方便的預付訂閱模式,因此您可以完全掌控自己的支出。
您可以在此管理您的帳戶帳單:
探索 OpenAI Playground
您的帳號設定完畢後,請前往 OpenAI Playground。
花點時間熟悉一下介面。準備好後,在左側選單中尋找“助手”部分。
我們將在此處建立自訂 GPT 實例。
自訂您的 GPT 助理
我們將分兩個階段客製化 GPT 助理來滿足我們的特定需求:
詳細的系統說明和範例
這一步可以幫助我們快速測試並驗證解決方案是否有效。這是查看結果的最快方式。
使用知識庫進行微調(簡單 RAG)
一旦我們對初步結果感到滿意,我們就會對模型進行微調。此過程減少了在每個提示中提供大量範例的需要,從而減少了推理時間(模型透過 API 回應所需的時間)。
這兩個步驟的結合為我們提供了最準確、最高效的結果。
那麼,讓我們開始吧。
對於我們的命名實體辨識系統,我們需要模型一致地輸出結構化 JSON 回應。精心設計一個周到的系統提示對於實現這一目標至關重要。
我們將重點放在:
「few-shot」技術是完成此任務的有效方法。它的工作原理是為模型提供一些所需輸入輸出關係的範例。從這些範例中,模型可以概括並處理以前從未見過的輸入。
幾個提示的關鍵要素:
提示由幾個部分組成,應經過深思熟慮的結構以獲得最佳結果。雖然確切的順序可能有所不同,但以下部分是必不可少的:
提示的第一部分概述了我們期望模型完成的任務。
例如,在此用例中,輸入是羅馬尼亞地址,其中可能包括拼字錯誤和格式不正確。此上下文至關重要,因為它為模型奠定了基礎,解釋了它將處理的資料類型。
定義任務後,我們指導 AI 如何格式化其輸出。
這裡詳細解釋了 JSON 結構,包括模型應如何從輸入派生每個鍵值對。包含範例是為了闡明期望。此外,任何特殊字元都會被正確轉義以確保有效的 JSON。
範例是「few-shot」技術的支柱。我們提供的相關範例越多,模型的效能就越好。
得益於 GPT 廣泛的上下文視窗(最多 16K 個令牌),我們可以包含大量範例。
建構範例集:
從基本提示開始並手動評估模型的輸出。
如果輸出包含錯誤,請修正它們並將修復的版本新增至範例集中。
隨著時間的推移,這個迭代過程會提高助手的表現。
這是不可避免的-你的助手會犯錯。有時,它可能會重複犯下同樣的錯誤。
要解決此問題,請在提示中包含清晰且禮貌的糾正訊息。解釋清楚:
助理犯了什麼錯誤。
您期望從輸出中得到什麼。
此回饋有助於模型調整其行為並產生更好的結果。
現在我們已經為我們的概念驗證幾個解決方案製作了初始提示,是時候配置和測試助手了。
步驟1
第 2 步:設定您的助理
第 3 步:選擇合適的型號
對於這個項目,我選擇 GPT-4o-mini 因為:
也就是說,您應該始終根據準確性和成本之間的平衡來選擇模型。執行或搜尋基準測試以確定最適合您的特定任務的方法。
初始配置到位後,我們現在可以直接在助手建立器中指定輸出架構。
第 1 步:使用「產生」選項
我沒有手動創建架構,而是使用助理創建者提供的“生成”選項。方法如下:
該工具在自動產生與您的結構相符的模式方面做得很好。
--
為了確保一致且可預測的反應,請將溫度設定得盡可能低。
什麼是溫度?
溫度控制模型反應的隨機性。較低的溫度值意味著模型會產生更具可預測性和確定性的輸出。
對於我們的用例,這正是我們想要的。當給定與輸入相同的位址時,模型應始終傳回相同的正確回應。一致性是獲得可靠結果的關鍵。
所有參數就位後,前往 Playground 測試您的解決方案。
Playground 提供了一個控制台,您可以在其中讓 Google 助理開始工作。這就是樂趣開始的地方 - 您可以嚴格測試您的基本解決方案以發現:
這些發現將幫助您完善提示的修正訊息部分,讓您的智慧助理更強大。
以下是我的一個手動測試的結果範例:
{ "street": "Strada Grui", "block": "Bloc 7", "staircase": "Scara A", "apartment": "Apartament 6", "city": "Zărnești" }
為什麼手動測試很重要?
老式的實踐測試是建立可靠解決方案的基礎。透過手動評估模型的輸出,您將快速發現問題並了解如何修復它們。雖然自動化稍後會出現,但手動測試是創建可靠的概念驗證的寶貴步驟。
現在是時候將所有內容整合到您的 PHP Symfony 應用程式中了。設定非常簡單,並遵循經典的非同步架構。
以下是流程細分:
1.前端互動
總的來說,我們這裡有一個帶有訊息隊列的經典非同步設定。我們有 2 個 Symfony 應用程式實例在 Docker 容器內運行。第一個是與前端客戶端互動。
例如,當客戶輸入:
STRADA GRUI, BLOC 7, SCARA A, APARTAMENT 6, ZĂRNEŞTI BD. 21 DECEMBRIE 1989 nr. 93 ap. 50, CLUJ, 400124
應用程式處理輸入位址並將其打包成 Message 物件。
然後 Message 物件被包裝在 Symfony Messenger Envelope 實例中。該訊息被序列化為 JSON 格式,並帶有用於處理的附加元資料。
Symfony Messenger 非常適合處理非同步任務。它允許我們將耗時的操作(例如呼叫 OpenAI API)卸載到後台進程。
這種方法確保:
以下是我們系統使用的訊息類別:
{ "street": "Strada Grui", "block": "Bloc 7", "staircase": "Scara A", "apartment": "Apartament 6", "city": "Zărnești" }
應用程式使用 amqp PHP 擴充功能連接到 RabbitMQ 實例。要進行此設置,您需要在 messenger.yaml 設定檔中定義傳輸和訊息綁定。
請參閱 Symfony Messenger 官方文件以取得詳細指示:
Symfony Messenger 傳輸配置
文件:https://symfony.com/doc/current/messenger.html#transport-configuration
訊息被推送到代理程式(例如 RabbitMQ、AmazonMQ 或 AWS SQS)後,它就會被應用程式的第二個實例接收。此實例運行信使守護程序來使用訊息,如架構模式中標記的 3。
消費過程透過運作來處理:
bin/控制台信使:消費
正在按照其流程進行。
守護程式從配置的佇列中取得訊息,將其反序列化回對應的 Message 類,並將其轉送給 Message Handler 進行處理。
這是與 OpenAI Assistant 互動的 訊息處理程序:
STRADA GRUI, BLOC 7, SCARA A, APARTAMENT 6, ZĂRNEŞTI BD. 21 DECEMBRIE 1989 nr. 93 ap. 50, CLUJ, 400124
Handler 的要點
記錄
記錄處理的開始,以進行可追溯性和調試。
標準化服務
呼叫 OpenAIAddressNormalizationService 來透過 Assistant 處理輸入位址。
堅持
規範化位址使用 Doctrine 的 EntityManager 儲存在資料庫中。
訊息處理程序可能看起來像標準的 Symfony 程式碼,但核心位於這一行:
INPUT: <what goes into the LLM> OUTPUT: <what the LLM should produce>
該服務負責透過指定的 PHP 函式庫與 OpenAI 互動。
OpenAI PHP 用戶端
讓我們深入了解如何使用 PHP 用戶端來實作該服務。
這是 OpenAIAddressNormalizationService 的完整實作:
input: STRADA EREMIA GRIGORESCU, NR.11 BL.45B,SC.B NR 11/38, 107065 PLOIESTI output: {{"street": "Eremia Grigorescu", "house_number": "11", "flat_number": "38", "block": "45B", "staircase": "45B", floor: "", "apartment": "", "landmark": "", "postcode": "107065", "county": "Prahova", 'commune': '', 'village': '', "city" "Ploiesti"}}
使用 openai-php/client 函式庫來取得推理(或完成)(本質上是來自 GPT 的回應)的工作流程遵循三個主要階段:
第一步是設定 OpenAI 用戶端並擷取配置的 Assistant:
INPUT: BD. 21 DECEMBRIE 1989 nr. 93 ap. 50, CLUJ, 400124 OUTPUT: { "street": "Bdul 21 Decembrie 1989", "house": "93", "flat": "50", "block": "", "staircase": "", "floor": "", "apartment": "", "landmark": "", "intercom": "", "postcode": "400124", "county": "Cluj", "commune": "", "village": "", "city": "Cluj" }
客戶端初始化: OpenAI::client() 方法使用您的 API 金鑰和組織 ID 建立一個新客戶端。
助理擷取:retrieve() 方法連接到為您的任務配置的特定 Assistant 實例,由其唯一 ID 識別。
客戶端和助理初始化後,您可以建立並執行執行緒來開始互動。線程充當通信管道,處理用戶和助手之間的消息交換。
執行緒的啟動方式如下:
{ "street": "Strada Grui", "block": "Bloc 7", "staircase": "Scara A", "apartment": "Apartament 6", "city": "Zărnești" }
啟動執行緒後,應用程式處理回應。由於 OpenAI 進程可能不會立即完成,因此您需要輪詢執行緒的狀態,直到它被標記為「已完成」:
STRADA GRUI, BLOC 7, SCARA A, APARTAMENT 6, ZĂRNEŞTI BD. 21 DECEMBRIE 1989 nr. 93 ap. 50, CLUJ, 400124
輪詢:應用程式重複檢查執行緒的狀態(已排隊或進行中)。一旦狀態更改為“已完成”,線程就包含最終輸出。
執行緒完成後,應用程式將檢索回應訊息以提取規範化位址:
INPUT: <what goes into the LLM> OUTPUT: <what the LLM should produce>
規範化位址現在可以返回到前端客戶端以立即使用,或作為結構化實體(如 CustomerAddressNormalized)儲存在資料庫中,以供將來處理。
執行此設定時,您應該能夠從 OpenAI 中提取並保存結構化輸出,用於命名實體識別和其他分類或生成任務。
在某些情況下,基本的人工智慧解決方案還不夠。當監管合規性和業務需求要求高精度時,我們需要加倍努力確保輸出真實可靠。
例如,在產生JSON結構時,我們需要確保其內容與實際相符。一個常見的風險是模型產生幻覺訊息,例如根據提供的郵遞區號發明一個地方。這可能會導致嚴重的問題,尤其是在高風險環境中。
具有知識庫的基本事實
為了消除幻覺並確保事實準確性,我們需要為助手提供真實的知識庫。這充當模型的明確參考,確保其在推理過程中使用準確的資訊。
我的方法:郵遞區號知識庫
我創建了一個簡單(但相當大,大約 12 MB)的 JSON 文件,其中包含羅馬尼亞所有郵政編碼的完整劃分。這種類似字典的結構提供:
郵遞區號: 輸入值。
已驗證資訊: 對應城市、縣和整體地名等事實。
此知識庫可作為助手執行命名實體辨識時的參考點。
知識庫的結構
這是知識庫 JSON 結構的範例片段:
{ "street": "Strada Grui", "block": "Bloc 7", "staircase": "Scara A", "apartment": "Apartament 6", "city": "Zărnești" }
知識庫準備好後,就可以指導助手有效地使用它了。雖然您可以將其直接嵌入到提示中,但這種方法會增加令牌的使用和成本。這是引入微調的絕佳時機。
微調涉及修改預訓練模型的最外層(特別是權重矩陣),使其適應特定任務。在我們的例子中,命名實體識別 (NER) 是一個完美的候選人。
微調模型:
主要目標是使模型更緊密地與其將處理的現實世界資料的細微差別保持一致。對特定領域資料的訓練使模型能夠更好地理解和產生適當的反應。它還減少了應用程式進行後處理或糾錯的需要。
為了微調模型,我們需要一個正確格式化的 .jsonl(JSON Lines)格式的資料集,按照 OpenAI 的要求。資料集中的每個條目包括:
此資料集為助手提供了特定領域的範例,使其能夠學習如何在將來回應類似的提示。
以下是如何建立微調條目的範例:
STRADA GRUI, BLOC 7, SCARA A, APARTAMENT 6, ZĂRNEŞTI BD. 21 DECEMBRIE 1989 nr. 93 ap. 50, CLUJ, 400124
讓我們以羅馬尼亞地址處理案例為例,分解 .jsonl 檔案中微調條目的結構:
每個條目都旨在模擬使用者和助手之間的真實交互,封裝:
這種方法有助於模型在現實環境中學習所需的行為。
1。系統角色訊息
描述助理的功能及其功能範圍,為其應識別和提取的實體類型設定期望,例如街道名稱、門牌號碼和郵遞區號。
範例:系統解釋說該助手旨在充當羅馬尼亞地址的命名實體識別模型,詳細說明了它應提取和分類的組件。
2。使用者角色訊息
3。助理角色留言
建立訓練文件後,下一步就是準備驗證文件。此文件評估微調助手對真實數據的準確性。其結構與訓練文件類似,這使得自動建立兩個文件變得更加簡單。
驗證文件旨在測試模型的泛化能力。它確保經過微調的助手能夠處理新的輸入並始終如一地執行,即使面對不熟悉或具有挑戰性的範例也是如此。
系統訊息:
為了保持訓練過程的一致性,系統訊息應該與訓練文件中使用的訊息相同。
使用者留言:
引入未包含在訓練文件中的新輸入(例如地址)。新範例應該是現實的且針對特定領域的,並透過包含小錯誤或複雜性來挑戰模型。
助理訊息:
為新用戶輸入提供預期的結構化回應。
這是驗證模型準確性的黃金標準。
為了簡化訓練和驗證文件的創建,可以使用自動化腳本。這些腳本根據輸入資料集產生格式正確的 .jsonl 檔案。
存取包含腳本的儲存庫以產生訓練和驗證檔案:
自動 .jsonl 產生腳本
這是微調自動化的 Python 版本。 PHP版本即將推出。
為什麼驗證很重要?
如果您願意,您可以使用 OpenAI 的圖形使用者介面 (GUI) 手動微調助理。準備好訓練和驗證文件後,請按照以下步驟開始:
第 1 步: 存取微調嚮導
第 2 步: 設定微調
在微調選單中,更新以下設定:
第 3 步:監控微調過程
微調過程開始後,您可以在微調儀表板中追蹤其進度:
儀表板提供即時更新並顯示多個指標,以幫助您監控和評估訓練過程。
需要理解的關鍵指標
訓練損失 測量模型對訓練資料的適合程度。較低的訓練損失表示模型正在有效地學習資料集中的模式。
完整驗證損失 表示驗證資料集中未見過的資料的效能。較低的驗證損失表明該模型能夠很好地推廣到新的輸入。
步驟與時間 訓練步驟為迭代次數,模型權重依據大量資料更新。
時間戳指示每個步驟的處理時間,這有助於監控訓練的持續時間和評估之間的間隔。
解釋指標
監控以下指標可協助您確定微調過程是否正確收斂或需要調整。
欠擬合:當兩個損失都很高時發生,表示模型沒有有效學習。
您的助手經過培訓和微調後,是時候將其整合到您的應用程式中並開始評估其性能了。
從簡單開始。
從手動測試開始,無論是在 Assistants Playground 中還是直接在您的應用程式中。避免在此階段使您的評估過於複雜;專注於確保基礎知識按預期工作。
例如,您可以使用 Google Sheets 這樣的簡單工具來手動比較輸入和輸出,如下所示:
這是第一步。
人工智慧和機器學習解決方案需要持續評估,以確保效能保持一致。對於命名實體識別等任務,自動化工具(例如 Visual Studio Code 的 PromptFlow 擴充功能)可以幫助簡化測試和驗證。
參考文獻
OpenAI 微調文件
Symfony Messenger 文件
OpenAI PHP 用戶端函式庫
VS Code 的 PromptFlow 擴充
謝謝!
感謝您花時間探索本指南!我希望它能為您建立和微調人工智慧驅動的解決方案奠定堅實的基礎。如果您有任何疑問或建議,請隨時聯繫或發表評論。
祝您編碼愉快,祝您的人工智慧專案好運! ?
以上是利用 OpenAI Assistant 在 PHP/Symfony 7 中進行命名實體識別的詳細內容。更多資訊請關注PHP中文網其他相關文章!