跳至內容

實作課程 03 — 工具

目標: 使用以下項目,以模型可視需要呼叫的真正 C# 函式取代靜態提示內容: CopilotTool.DefineTool 以及 SessionConfig.Tools.

時間: 約 20 分鐘

必要條件: 實作課程 02 已完成。

步驟 1 — 為何需要工具

在實作課程 02 中,您將零售資料放入系統訊息,讓助理的回答有所依據。這適用於小型範例,但有三個問題:

  1. 內容是靜態的 — 它只知道您一開始貼入的資訊
  2. 模型必須猜測哪些事實重要
  3. 每項事實都會消耗權杖,即使回答根本不需要該事實

工具會改變問題的處理方式。您不再需要寄望提示中包含正確資料,而是註冊一個 C# 函式。模型會判斷何時需要該函式、要求 SDK 呼叫、接收結果,再撰寫最終答案。

步驟 2 — 檢視工具結構

開啟 ToolsSample.cs 並找到 GetCustomerTotal.

Copilot SDK 工具一開始只是一個一般的 C# 方法:

[Description("Gets the total amount a given retail customer has spent.")]
private static string GetCustomerTotal(
    [Description("Customer identifier, for example C003")] string customerId)
{
    ...
}

最重要的部分是 [Description] 中繼資料,來源為 System.ComponentModel.

這些描述就是模型的 API 文件。若方法描述含糊,模型可能找不到工具;若參數描述含糊,模型可能傳入錯誤值。請像為其他開發人員記錄公用 API 一樣撰寫描述。

步驟 3 — 註冊工具

CopilotTool.DefineTool(GetCustomerTotal) 會將方法轉換為 AIFunction。接著,將該函式指派給工作階段設定:

var modelId = await ModelPicker.PickAsync(client, requestedModelId);
var totalTool = CopilotTool.DefineTool(GetCustomerTotal);

var config = new SessionConfig
{
    Model = modelId,
    Streaming = false,
    Tools = [totalTool]
};

Tools = [totalTool] 行正是「模型只有一些文字內容」與「模型可以要求主機應用程式執行實際工作」之間的差異。 ModelPicker 會保留 claude-haiku-4.5 作為這些實作課程的慣用模型,但若您的帳戶無法使用,則會回復為可用模型。您可以使用以下項目覆寫: --model <id>.

步驟 4 — 執行

dotnet run --project src/AgentOrchestrator/samples/SdkLabs -- tools

預期輸出:

== Lab 03: tools ==

Model: claude-haiku-4.5
Prompt: How much has customer C003 spent in total?


Assistant: 
  [tool] GetCustomerTotal(C003) -> $1,700.00

Assistant: Customer C003 has spent a total of **$1,700.00** across 2 transactions.

⚠️ 請注意第一個空白 Assistant: 行。這是真實行為:助理訊息事件會在工具呼叫附近觸發,早於最終自然語言答案的組合。

步驟 5 — 追蹤實際發生的情況

執行作業包含四個運作部分:

  1. 提示要求查詢客戶的消費總額: C003
  2. 模型判斷已註冊工具是回答問題的正確方式
  3. SDK 會叫用 C# 方法,產生 [tool]
  4. 工具結果會送回模型,再由模型撰寫最終答案

[tool] GetCustomerTotal(C003) -> $1,700.00 行並非模擬輸出,而是由真正的 GetCustomerTotal 方法,而 SDK 正在處理模型的工具呼叫。

步驟 6 — 進行實驗

試試不存在的客戶,例如 C999。工具會傳回一般字串而不是擲回例外,以處理該情況:

Prompt = "How much has customer C999 spent in total? Use the available tool."

重新執行範例,確認助理回報找不到任何交易。

然後試試不需要零售資料的提示:

Prompt = "In one short sentence, define average order value."

模型應該直接回答。由於不需要查詢客戶, [tool] 行不應出現。

步驟 7 — 使用權限控制工具執行

SDK 也公開處理程序內權限掛鉤:

OnPermissionRequest = (request, invocation) =>
{
    return Task.FromResult(PermissionDecision.ApproveOnce());
}

簽章如下:

Func<PermissionRequest, PermissionInvocation, Task<PermissionDecision>>

決策來自 GitHub.Copilot.Rpc.PermissionDecision,包括 ApproveOnce() 以及 Reject(string feedback)。另外也有內建捷徑: PermissionHandler.ApproveAll,適用於允許所有要求的範例。

⚠️ 在 GitHub Copilot SDK v1.0.9 中,此權限決策 API 標示為實驗性。使用 GitHub.Copilot.Rpc.PermissionDecision 會引發建置錯誤 GHCP001 ,除非該內容遭到隱藏。範例專案刻意在以下位置進行此處理: SdkLabs.csproj:

<NoWarn>$(NoWarn);GHCP001</NoWarn>

⚠️ 將此掛鉤當作強制執行點時,務必極度謹慎。根據我們的測試,處理常式 從未叫用 — 即使處理常式拒絕每個要求,命令仍會執行,因為主機 CLI 已預先授予工具核准。請將 OnPermissionRequest 視為只有在主機將決策交給它時才會介入的掛鉤。請在 您的 環境中進行驗證,再將它作為控制措施。

請參閱 PermissionsSample.cs 取得參考程式碼。如需 Shell 掛鉤治理替代方案,請參閱 extra-governance-hooks.

CopilotToolOptions.SkipPermission 也可以在適合您的主機時,讓工具不參與權限流程。

✅ 檢查點

您現在可以說明:

  • [x] 瞭解為何工具優於將動態資料塞入系統訊息
  • [x] 如何 [Description] 屬性會引導工具選擇與引數設定
  • [x] 如何 CopilotTool.DefineTool 會將 C# 方法註冊為 AIFunction
  • [x] 如何 SessionConfig.Tools 會讓模型可以使用該函式
  • [x] 瞭解為何權限掛鉤必須在實際執行的主機中驗證

💡 延伸練習

新增第二個工具,用來傳回客戶購買過的產品類別,例如 Electronics 以及 Fashion 用於 C003。請為方法及其參數提供精確的 [Description] 屬性,並將它註冊在以下項目旁: GetCustomerTotal,接著詢問:

Which categories has customer C003 bought from, and how much have they spent?

確認模型呼叫一個工具、兩個工具,或直接回答。