在2024/10/01 微軟宣布Azure.AI.OpenAI 2.0.0正式發布,這是一個重大的里程碑,因為這是一個全新的版本,並且有許多新功能和改進。在此之前,所使用的Azure OpenAI client library for .NET 套件都是Beta 版本,而在此正式版堆出之後,將會有一些使用方式的改變與增加許多功能,所以,將會針對這些Azure OpenAI client library for .NET 2.0 版本進行一系列的教學。
在這裡先要來了解AOAI 採用的是大語言模型技術,使用者可以傳入文字,透過大語言模型的處理,就會產生出一段回應文字,這樣的技術可以應用在許多場景,例如:對話式應用程式、自動回覆、自動翻譯、自動摘要、自動產生程式碼等等。
這個傳入的文字可以稱之為Prompt 「提示詞」、「提示訊息」或「引導詞」,而產生的回應文字可以稱之為Completion 「完成字」、「完成訊息」或「完成句」。
在這個教學中,將會介紹如何使用Azure.AI.OpenAI 2.0.0 來開發一個提問與回答的應用程序,這個應用程序可以通過Prompt 提問,然後通過Completion 來回答,這個應用程序可以應用在許多場景,例如:自動回复、自動翻譯、自動摘要、自動產生代碼等等。
例如,若使用者輸入了一個Prompt “Say 'this is a test.'”,這個Prompt 將會被傳入到Azure OpenAI 服務中,然後Azure OpenAI 服務將會產生一段Completion 回應文字[ This is a test. ]。下圖將會展示這個應用程式的運作方式。
請依照底下的操作,建立起這篇文章需要用到的練習項目
- 打開Visual Studio 2022 IDE 應用程式
- 從[Visual Studio 2022] 對話窗中,點選右下方的[建立新的項目] 按鈕
- 在[建立新項目] 對話窗右半部
- 切換[所有語言(L)] 下拉選單控制項為[C#]
- 切換[所有項目類型(T)] 下拉選單控制項為[控制台]
- 在中間的項目模板清單中,找到並且點擊[控制台應用程式] 項目模板選項
項目,用於建立可在Windows、Linux 及macOS 於.NET 執行的命令列應用程序
- 點擊右下角的[下一步] 按鈕
- 在[設定新的項目] 對話窗
- 找到[項目名稱] 字段,輸入
csAzureAIOpenAIQuickStart
作為項目名稱 - 在剛剛輸入的[項目名稱] 欄位下方,確認沒有勾選[將解決方案與項目至於相同目錄中] 這個檢查盒控制項
- 點擊右下角的[下一步] 按鈕
- 現在將會看到[其他資訊] 對話窗
- 在[架構] 欄位中,請選擇最新的開發框架,這裡選擇的[架構] 是 :
.NET 8.0 (長期支援)
- 在這個練習中,需要去勾選[不要使用最上層陳述式(T)] 這個檢查盒控制項
這裡的這個操作,可以由讀者自行決定是否要勾選這個檢查盒控制項
- 請點擊右下角的[建立] 按鈕
稍微等候一下,這個背景工作服務項目將會建立完成
因為開發此專案時會使用這些NuGet 套件,請依照底下說明,將需要用到的NuGet 套件安裝。
請依照底下說明操作步驟,將這個套件安裝到專案內
- 鼠標右擊[方案總管] 視窗內的[專案節點] 下方的[依賴] 節點
- 從彈出功能表清單中,點選[管理NuGet 套件] 這個功能選項清單
- 此時,將會看到[NuGet: csAzureAIOpenAIQuickStart] 視窗
- 切換此視窗的標籤頁次到名稱為[瀏覽] 這個標籤頁次
- 在左上方找到一個搜尋文字輸入盒,在此輸入
Azure.AI.OpenAI
- 在視窗右方,將會看到該套件詳細說明的內容,其中,右上方有的[安裝] 按鈕
請確認有取消Pre-release 這個選項,與選擇2.0 正式版
- 點擊這個[安裝] 按鈕,將這個套件安裝到專案內
在這篇文章中,將會把會使用到的新類別與代碼,都寫入[Program.cs] 這個檔案中,請依照底下的操作,修改[Program.cs] 這個檔案的內容
- 在專案中找到並開啟[Program.cs] 檔案
- 將底下的代碼取代掉
Program.cs
檔案中內容
using Azure.AI.OpenAI;
using Azure;
using OpenAI.Chat;
using System.Net;
namespace csAzureAIOpenAIQuickStart;
internal class Program
{
static void Main(string[] args)
{
// 讀取環境變數 AOAILabKey 的 API Key
string apiKey = System.Environment.GetEnvironmentVariable("AOAILabKey");
AzureOpenAIClient azureClient = new(
new Uri("https://gpt4tw.openai.azure.com/"),
new System.ClientModel.ApiKeyCredential(apiKey));
ChatClient chatClient = azureClient.GetChatClient("gpt-4");
string userPrompt = "Say 'this is a test.'";
Console.WriteLine($"{DateTime.Now} [User]: {userPrompt}");
ChatCompletion completion = chatClient.CompleteChat("Say 'this is a test.'");
foreach (var message in completion.Content)
{
Console.WriteLine($"{DateTime.Now} {message.Text}");
}
Console.WriteLine($"Role : {completion.Role}");
Console.WriteLine($"InputTokenCount : {completion.Usage.InputTokenCount}");
Console.WriteLine($"OutputTokenCount : {completion.Usage.OutputTokenCount}");
Console.WriteLine($"ReasoningTokenCount : {completion.Usage.OutputTokenDetails?.ReasoningTokenCount}");
Console.WriteLine($"TotalTokenCount : {completion.Usage.TotalTokenCount}");
}
}
當要使用Azure OpenAI library for .NET 來呼叫ChatGPT 相關應用API 的時候,首先需要建立一個[AzureOpenAIClient] 類別的物件,這個物件是用來建立一個Azure OpenAI client library for .NET 的物件,這個物件是用來呼叫Azure OpenAI 的API 服務。
在此需要宣告與傳入兩個參數,第一個參數是Azure OpenAI 的API 服務的網址,第二個參數是Azure OpenAI 的API 服務的密鑰,這個密鑰是用來驗證使用者的身份,這個金鑰是在Azure OpenAI 的網站上申請的。有了這兩個信息,便可以取得與使用Azure 所提供的OpenAI 服務,透過其云大語言模型技術,來進行文字的生成。
因此,在這裡使用了AzureOpenAIClient azureClient = new(new Uri("https://gpt4tw.openai.azure.com/"), new System.ClientModel.ApiKeyCredential(apiKey));
敘述來完成上述需求,不過,對於Azure OpenAI 用到的密鑰信息,是具有敏感性的,因為,任何人取得了服務端點與該密鑰,就可以使用你訂閱的服務,所產生的費用,是由你負擔,因此,在這裡不會將該密鑰放在項目原始碼內,而是通過環境變量的方式來取得。這樣的好處是,可以避免密鑰資訊洩露,而且,可以在不同的環境中,使用不同的密鑰資訊。
此時,開啟指令提示字元視窗,輸入[set] 指令,便可以看到所有環境參數的清單
從上面螢幕截圖,可以看到已經有設定一個環境變數AOAILabKey
,這個環境變量是用來存放Azure OpenAI 金鑰資訊的。
使用底下指令將建立OpenAI Key 永久性的環境變數,這代表這個環境變量將會一直存在,不會因為該系統重新開機之後,該環境變量就不存在了,直到你刪除它為止
setx AOAILabKey "剪貼簿內的 OpenAI Key 值" /M
如何刪除此環境變數
REG delete "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /V AOAILabKey /f
若金鑰與服務端點都設定完成,且AzureOpenAIClient azureClient 可以正常運作,接下來就要產生ChatClient chatClient 物件,這裡使用了ChatClient chatClient = azureClient.GetChatClient("gpt-4");
敘述來取得ChatClient 類別的物件,這個物件是用來呼叫ChatGPT 相關應用API 服務的。
想要知道有那些模型可以使用,可以透過Azure 網頁查詢
進入Azure 網頁,搜尋或找到[Azure OpenAI] 服務
點擊進入後,參考下圖,在網頁中間下方,可以看到[Explore and deploy] 選項
點擊進入後,可以看到[Azure OpenAI Studio] 頁面,在最左方找到[部署] 鏈接,就可以看到所有的模型清單,這裡使用的是gpt-4
模型
現在要來建立一個ChatClient chatClient 物件,這個物件是用來呼叫ChatGPT 相關應用API 服務的,這裡使用了ChatClient chatClient = azureClient.GetChatClient("gpt-4");
敘述來取得ChatClient 類別的物件,這個物件是用來呼叫ChatGPT 相關應用API 服務的。 azureClient.GetChatClient("gpt-4");
在AzureOpenAIClient Class Methods中,有列出所有可用取得特定服務方法
GetAudioClient(String)
取得一個新的OpenAI.Audio.AudioClient實例,該實例配置為與Azure OpenAI 服務一起使用音頻操作。
GetChatClient(String)
取得一個新的OpenAI.Chat.ChatClient實例,該實例配置為與Azure OpenAI 服務一起使用聊天完成操作。
GetEmbeddingClient(String)
取得一個新的OpenAI.Embeddings.EmbeddingClient實例,該實例配置為與Azure OpenAI 服務一起使用嵌入操作。
GetImageClient(String) 取得一個新的OpenAI.Images.ImageClient實例,該實例配置為與Azure OpenAI 服務一起使用映像操作。
透過這個方法GetChatClient 所取得的物件,可以進行對指定大語言模型進行對話式應用程式的操作,這個對像是用來呼叫ChatGPT 相關的應用API 服務。
想要對大語言模型提出問題,可以使用類似這樣用法chatClient.CompleteChat("Say 'this is a test.'")
;其中,使用CompleteChat 方法傳入進去的字符串,就是Prompt,該方法將會回傳[ChatCompletion],透過這個物件,就可以得到大語言模型生成的文字內容。
在[ChatCompletion] 物件內有個類型為[ChatMessageContent] 的屬性[Content] ,這個屬性是用來存放ChatGPT 產生的文字內容,透過這個屬性,就可以取得ChatGPT 產生的文字內容。這裡使用底下方法將生成文字內容印在螢幕上。
foreach (var message in completion.Content)
{
Console.WriteLine($"{DateTime.Now} {message.Text}");
}
該物件也可以取得ChatGPT 產生的文字內容的其他信息,例如:Role、InputTokenCount、OutputTokenCount、ReasoningTokenCount、TotalTokenCount 等等,這些資訊可以透過ChatCompletion 物件的屬性來取得。有了這些信息,便可以計算出這次呼叫GPT 運算的成本,這樣就可以控制Azure OpenAI 服務的使用成本。
Console.WriteLine($"Role : {completion.Role}");
Console.WriteLine($"InputTokenCount : {completion.Usage.InputTokenCount}");
Console.WriteLine($"OutputTokenCount : {completion.Usage.OutputTokenCount}");
Console.WriteLine($"ReasoningTokenCount : {completion.Usage.OutputTokenDetails?.ReasoningTokenCount}");
Console.WriteLine($"TotalTokenCount : {completion.Usage.TotalTokenCount}");
- 按下
F5
開始執行專案 - 將會看到輸出結果
2024/10/23 上午 10:14:24 [User]: Say 'this is a test.'
2024/10/23 上午 10:14:26 This is a test.
Role : Assistant
InputTokenCount : 14
OutputTokenCount : 5
ReasoningTokenCount :
TotalTokenCount : 19