實作課程 05 — 工作階段¶
目標: 持久保存並繼續 Copilot SDK 交談,這是「代理程式隨處可用」背後的建構基礎。
時間: 約 20 分鐘
必要條件: 實作課程 04 已完成。
步驟 1 — 瞭解持久化的重要性¶
若沒有工作階段持久化,每次處理程序重新啟動都會失去記憶。助理只能看到目前處理程序中傳送的訊息,因此 CLI 當機、瀏覽器重新整理或伺服器回收都會導致交談遺失。
有了已儲存的工作階段,交談便具有身分。您可以在 CLI 中開始、從 Web 應用程式繼續,之後再從手機接續。這就是「代理程式隨處可用」背後的核心模式:用戶端會改變,但工作階段歷程始終與同一個識別碼關聯。
此範例會先示範較有限的證明:在相同處理程序與相同的 CopilotClient。它也支援
--resume <id> ,因此當您的環境使用相同的工作階段持久化存放區與執行階段時,可以嘗試第二個獨立處理程序。
步驟 2 — 使用已知識別碼建立工作階段¶
開啟
SessionsSample.cs
並找到工作階段識別碼:
接著找出它傳入 SDK 的位置:
await using var session = await client.CreateSessionAsync(new SessionConfig
{
SessionId = sessionId,
Model = modelId,
Streaming = false
});
SessionConfig.SessionId 可讓您提供自己的識別碼。若省略,SDK 會代為產生,但應用程式必須擷取並儲存該產生值,之後才能繼續工作階段。
在實際應用程式中,請使用對領域具有意義且唯一的識別碼,例如交談識別碼或支援案例識別碼。請勿在識別碼中放入機密資訊:識別碼經常會出現在記錄、診斷資訊與 URL 中。
步驟 3 — 執行範例¶
預期輸出:
== Lab 05: sessions ==
Model: claude-haiku-4.5
Session id: sdklabs-7946e93975844b2e
--- Turn 1 (new session) ---
You: Remember this: my favourite retail segment is 'At Risk'. Reply with just OK.
Assistant: OK.
Session disposed.
--- Turn 2 (resumed session) ---
You: Which retail segment did I say was my favourite?
Assistant: 'At Risk'.
--- Session metadata ---
id=sdklabs-7946e93975844b2e metadata retrieved
每次執行的工作階段識別碼都是隨機產生,因此您的值會不同。重要的證明不是識別碼值,而是第二回合記得 'At Risk' ,而且第一個工作階段已遭處置。
這次執行證明在單一處理程序中,物件處置後仍可繼續工作階段;但它本身無法證明跨裝置交接或重新啟動復原。
步驟 4 — 繼續工作階段¶
第二個回合使用相同識別碼,但呼叫不同的 SDK 方法:
await using var resumed = await client.ResumeSessionAsync(
sessionId,
new ResumeSessionConfig
{
Model = modelId,
Streaming = false
});
⚠️ 設定參數為必填。 在 SDK v1.0.9 中,以下程式碼無法編譯:
編譯器會回報 CS7036 ,因為必填設定參數沒有對應引數。
⚠️ 請使用 ResumeSessionConfig,而不是 SessionConfig. 建立新工作階段時使用 SessionConfig;繼續現有工作階段則使用 ResumeSessionConfig。繼續工作階段設定包含此處使用的同類設定,包括
Model 以及 Streaming,但型別不同。
為了讓證明更有力,請使用第一次執行所列印的工作階段識別碼,在第二個處理程序中執行繼續路徑:
dotnet run --project src/AgentOrchestrator/samples/SdkLabs -- sessions --resume sdklabs-7946e93975844b2e
第二次呼叫的已驗證輸出:
== Lab 05: sessions ==
Model: claude-haiku-4.5
Session id: sdklabs-7946e93975844b2e
--- Resumed existing session ---
You: Which retail segment did I say was my favourite?
Assistant: 'At Risk'.
--- Session metadata ---
id=sdklabs-7946e93975844b2e metadata retrieved
第二個命令確實會跨越處理程序邊界。若要從另一台電腦繼續,還必須能存取相同的工作階段持久化存放區、使用相容的執行階段,並具備適當授權。
步驟 5 — 探索已儲存的工作階段¶
範例也會向 SDK 要求中繼資料:
該呼叫會傳回已儲存工作階段的中繼資料。若要瀏覽可用的已儲存工作階段,而不是從已知識別碼開始,請使用 ListSessionsAsync(...):
常見模式如下:
- 列出已登入使用者的工作階段
- 讓使用者選擇一個,或選取最新項目
- 將該識別碼傳入
ResumeSessionAsync(id, config)
步驟 6 — 連結至架構¶
工作階段持久化可支援:
- 跨裝置與用戶端交接 — 從一處開始,再到另一處繼續
- 當機復原 — 在處理程序重新啟動後繼續,而不是從頭重建內容
- 可稽核性 — 穩定的識別碼讓交談更容易檢視、整理及追蹤
目前的示範應用程式透過以下項目,將聊天歷程保留在瀏覽器 localStorage 中:
StorageService。這適用於單一裝置上的單一瀏覽器,但無法將交談移至另一部裝置。如果您在手機或另一台電腦上開啟應用程式,歷程記錄便不存在。
SDK 工作階段正是解決方案。UI 可以儲存工作階段識別碼,而不是整段交談內容;經授權且使用相同工作階段存放區的用戶端,就能繼續同一個伺服器端工作階段。
⚠️ 工作階段識別碼不是存取控制機制。 請將識別碼視為識別用途,而不是機密資訊或能力權杖。應用程式在繼續已儲存的交談前,仍需執行一般使用者驗證與授權。
⚠️ 常見陷阱¶
- 識別碼衝突: 工作階段識別碼就是您的索引鍵。重複使用識別碼會繼續舊交談,而不是建立全新的交談。
- 不透明識別碼: 隨機識別碼適合示範,但實際系統應能將識別碼對應回使用者、案例或工作流程。
- 識別碼不是權限: 只知道或猜到識別碼,不應足以存取交談;請另外強制執行授權。
- 識別碼中的機密資訊: 絕不要在工作階段識別碼中包含權杖、電子郵件地址、客戶機密或機密資料。
- 錯誤的繼續多載:
ResumeSessionAsync(sessionId)會失敗並顯示CS7036;請傳入ResumeSessionConfig. - 錯誤的設定型別:
SessionConfig用於建立;ResumeSessionConfig用於繼續。
💡 延伸練習¶
繼續同一工作階段兩次:
- 在中繼資料呼叫後新增第三個回合
- 繼續同一個
sessionId再次 - 針對原本的內容再問一個問題:
'At Risk'訊息
或者,列出已儲存的工作階段,並繼續最近的一個:
接著將選取的識別碼傳入:
await client.ResumeSessionAsync(id, new ResumeSessionConfig
{
Model = modelId,
Streaming = false
});
✅ 檢查點¶
您現在可以說明:
- [x] 瞭解為何沒有持久化時,處理程序重新啟動會遺失內容
- [x] 如何
SessionConfig.SessionId會為應用程式提供穩定的交談索引鍵 - [x] 為何
ResumeSessionAsync(id, config)需要ResumeSessionConfig - [x] 如何
GetSessionMetadataAsync以及ListSessionsAsync(...)協助探索已儲存的工作階段 - [x] 瞭解為何 SDK 工作階段是跨裝置聊天歷程的正確基礎
- [x] 瞭解跨處理程序與跨裝置繼續工作階段,還仰賴共用儲存空間、相容的執行階段行為與授權
相關內容¶
- 上一步: 實作課程 04 — 事件
- 下一步: 實作課程 06 — MCP
- 示範:Copilot SDK 整合
- 疑難排解