實作課程 04 — 事件¶
目標: 瞭解 Copilot SDK 工作階段事件生命週期:SDK 實際發出哪些事件、事件抵達順序,以及哪些事件對串流、遙測、完成和錯誤等常見工作最重要。
時間: 約 20 分鐘
必要條件: 實作課程 03 已完成。
步驟 1 — 執行事件範例¶
在存放庫根目錄執行 SDK 實作課程範例:
預期輸出:
== Lab 04: events ==
Model: claude-haiku-4.5
Prompt: Name two retail KPIs. One line each.
1. SessionStartEvent
2. SessionManagedSettingsResolvedEvent
3. PendingMessagesModifiedEvent
4. SessionSkillsLoadedEvent
5. SystemMessageEvent
6. SessionToolsUpdatedEvent
7. UserMessageEvent
8. HookStartEvent
9. SessionTitleChangedEvent
10. HookEndEvent
11. AssistantTurnStartEvent
12. SessionUsageInfoEvent
13. ModelCallStartEvent
14. AssistantStreamingDeltaEvent
15. AssistantReasoningDeltaEvent
16. AssistantStreamingDeltaEvent
17. AssistantReasoningDeltaEvent
18. AssistantStreamingDeltaEvent
19. AssistantReasoningDeltaEvent
20. AssistantStreamingDeltaEvent
21. AssistantReasoningDeltaEvent
22. AssistantStreamingDeltaEvent
23. AssistantReasoningDeltaEvent
24. AssistantStreamingDeltaEvent
25. AssistantReasoningDeltaEvent
26. AssistantStreamingDeltaEvent
27. AssistantMessageStartEvent
28. AssistantStreamingDeltaEvent
29. AssistantStreamingDeltaEvent
30. AssistantUsageEvent
31. AssistantMessageEvent
content: 1. **Conversion Rate** — The percentage of store visitors or website traffic tha…
(preceded by 3 delta events)
32. AssistantReasoningEvent
33. AssistantTurnEndEvent
34. HookStartEvent
35. HookEndEvent
36. SessionUsageCheckpointEvent
37. AssistantIdleEvent
38. SessionIdleEvent
Total delta events: 3
最令人意外的是事件數量。一次簡單的單一提示交換,所發出的事件遠超過「使用者訊息、助理訊息、完成」。
⚠️ 範例會計算 AssistantMessageDeltaEvent 分開計算,並隱藏這些事件不予列印。這就是為何 Total delta events: 3 即使許多事件出現,仍會顯示 AssistantStreamingDeltaEvent 項目可在事件清單中看到。
⚠️ 上述數字只是某次實際執行的觀察結果,不是固定合約。 清單顯示 38 個 列印了 個事件;另有三個事件已收到但遭隱藏,因此總共收到 41 個事件。確切數量與順序會依模型、提示和 SDK 版本而異 — 請觀察序列的整體結構,不要將其視為固定規格。
步驟 2 — 逐一瞭解生命週期階段¶
若依階段分組,會更容易記住事件串流:
- 工作階段設定(1–6) — 工作階段啟動、受控設定完成解析、待處理訊息與技能載入、系統訊息出現,工具則透過以下事件宣告:
SessionToolsUpdatedEvent - 使用者回合(7–10) — 接受使用者訊息、掛鉤事件在流程內執行,而且工作階段標題可能變更
- 助理回合開始(11–13) — 助理回合開始、使用量資訊出現,模型呼叫隨即開始
- 串流(14–29) — 串流與推理差異陸續抵達,接著是
AssistantMessageStartEvent - 完成(30–33) — 系統會回報助理使用量、最終助理訊息抵達、推理完成,然後助理回合結束
- 結束與閒置(34–38) — 另一組掛鉤會執行、使用量建立檢查點、助理進入閒置狀態,最後整個工作階段進入閒置狀態
掛鉤事件屬於同一個有序串流。如果您正在探索治理掛鉤,此順序很重要,因為 HookStartEvent 以及
HookEndEvent 會出現在工作周圍,而不是獨立的側通道中。請參閱 額外內容 — 治理掛鉤 以及
掛鉤與治理 取得相關示範資料。
使用量也有自己的事件: SessionUsageInfoEvent,
AssistantUsageEvent,以及 SessionUsageCheckpointEvent。當您要取得權杖與成本遙測,而不是文字內容時,應檢視這些事件。
步驟 3 — 使用 v1 模式訂閱¶
開啟
EventsSample.cs
並找到訂閱位置:
⚠️ 明確的 <SessionEvent> 很重要。 在 GitHub Copilot SDK v1.x 中,非泛型形式已不再推斷型別引數:
該舊版 v0.x 結構會在 CS0411 會在 v1.x 中發生。若您複製舊範例並看到該編譯器錯誤,請新增明確的型別引數。
移轉舊程式碼時,也請檢查命名空間。SDK v1.0.0 已從
GitHub.Copilot.SDK 變更為:
步驟 4 — 與應用程式處理的內容比較¶
範例幾乎會記錄所有事件,讓您能學習生命週期。實際應用程式不需要處理所有事件。
開啟
CopilotChatService.cs
並查看事件 switch。它只處理四種事件類型:
case AssistantMessageDeltaEvent delta:
outputChannel.Writer.TryWrite(delta.Data.DeltaContent ?? "");
break;
case AssistantMessageEvent msg:
_logger.LogInformation("Assistant response complete: {Length} chars",
msg.Data.Content?.Length ?? 0);
break;
case SessionIdleEvent:
done.SetResult();
break;
case SessionErrorEvent error:
done.SetException(new Exception(error.Data.Message));
break;
這是合理的正式環境選擇。對瀏覽器串流而言,應用程式需要文字區塊、最終訊息記錄、完成訊號與錯誤路徑;不需要針對每個設定、掛鉤、推理或遙測事件進行分支處理。
⚠️ 有兩個不同的差異事件系列:
AssistantStreamingDeltaEvent 以及 AssistantMessageDeltaEvent。在這次執行中,許多 AssistantStreamingDeltaEvent 項目出現,但範例只計算兩個 AssistantMessageDeltaEvent 值。如果您針對工作訂閱了錯誤的事件類型,看到的區塊可能遠少於預期。請優先測量您的情境實際發出的內容,不要只根據名稱假設兩者意義相同。
步驟 5 — 閒置時完成,發生錯誤時失敗¶
SessionIdleEvent 是範例與應用程式使用的完成訊號。常見模式是使用 TaskCompletionSource ,並在工作階段進入閒置狀態時完成:
var done = new TaskCompletionSource();
session.On<SessionEvent>(evt =>
{
switch (evt)
{
case SessionIdleEvent:
done.TrySetResult();
break;
case SessionErrorEvent error:
done.TrySetException(new Exception(error.Data.Message));
break;
}
});
await session.SendAsync(new MessageOptions { Prompt = prompt });
await done.Task;
⚠️ 務必處理 SessionErrorEvent。若工作階段失敗,而您未在以下項目設定例外: TaskCompletionSource, await done.Task 可能永遠等待下去。這種失敗模式很容易被忽略,因為正常路徑運作得十分順利。
⚠️ 常見陷阱¶
session.On(evt => ...)是舊結構;請改用session.On<SessionEvent>(evt => ...)搭配 SDK v1.x- 使用以下項目的舊命名空間:
GitHub.Copilot.SDK必須變成GitHub.Copilot AssistantStreamingDeltaEvent以及AssistantMessageDeltaEvent是不同的事件類型;請先測量,不要將它們視為可以互換- 記錄每個事件有助於學習,但對應用程式碼而言過於嘈雜
- 只等待助理訊息並不足夠;請在以下事件發生時完成操作:
SessionIdleEvent - 忽略
SessionErrorEvent可能使呼叫端永遠停在等待狀態
💡 延伸練習¶
請嘗試以下其中一項小型實驗:
- 變更範例,只列印工具相關事件,例如名稱包含以下內容的事件:
Tool或工具工作周圍的掛鉤事件 - 如要測量收到第一個權杖的時間,請先啟動
Stopwatch之前SendAsync(...),並在第一個您關注的差異事件出現時停止計時 - 分別計算使用量相關事件,並記錄它們出現在生命週期中的位置
- 新增篩選器,將事件依上述六個生命週期階段分組,而不是列印扁平的編號清單
✅ 檢查點¶
您現在可以說明:
- [x] 瞭解 SDK 發出的有序工作階段生命週期
- [x] 為何
On<SessionEvent>在 v1.x 中需要明確的型別引數 - [x] 瞭解為何實際應用程式通常只處理所有發出事件中的一小部分
- [x] 瞭解觀察所有事件與串流有用區塊之間的差異
- [x] 為何
SessionIdleEvent會完成操作 - [x] 為何
SessionErrorEvent必須讓等待中的工作失敗 - [x] 瞭解掛鉤與使用量事件在生命週期中的位置
相關內容¶
- 上一步: 實作課程 03 — 工具
- 下一步: 實作課程 05 — 工作階段
- 示範:Copilot SDK 整合
- 掛鉤與治理
- 疑難排解