管理狀態
適用于: SDK v4
Bot 內的狀態會遵循與新式 Web 應用程式相同的架構,而 Bot Framework SDK 會提供一些抽象概念,讓狀態管理變得更容易。
如同 Web 應用程式,Bot 原本是無狀態的;不同的 Bot 執行個體可處理任何指定的交談回合。 對於某些 Bot 而言,此簡單性是慣用的—Bot 可以在沒有其他資訊的情況下運作,或保證所需的資訊位於傳入訊息內。 對於其他人而言,狀態 (,例如先前收到有關使用者) 的交談或先前收到的資料,Bot 必須要有有用的交談。
為什麼需要狀態?
維護狀態可讓 Bot 藉由記住有關使用者或交談的特定事項,以便進行更有意義的交談。 比方說,如果您之前已跟使用者談話,即可儲存其先前的相關資訊,您就不需要再次詢問。 狀態也可讓資料保存超過目前的回合,以便 Bot 保存多回合交談過程中的資訊。
與 Bot 有關,有一些使用狀態的層:儲存層、狀態管理 (包含在下圖中的 Bot 狀態) ,以及狀態屬性存取子。 此圖說明這些層次之間的互動順序部分,實心箭號表示方法呼叫,而虛線箭頭表示回應 (不論是否有傳回值)。
下列各節說明此圖的流程,包含各層次的詳細資訊。
儲存層
從後端開始,其中實際儲存狀態資訊是 儲存層。 這可視為您的實體儲存體,例如記憶體內部、Azure 或協力廠商伺服器。
Bot Framework SDK 包含儲存層的一些實作:
- 記憶體內部儲存體可將記憶體內部儲存體運用於測試用途。 記憶體內部資料儲存體僅限用於本機測試,因為此儲存體是易變且暫存的。 每次 Bot 重新啟動時,就會清除資料。
- Azure Blob 儲存體會連線到 Azure Blob 儲存體物件資料庫。
- Azure Cosmos DB 分割儲存體會連線到分割的 Cosmos DB NoSQL 資料庫。
重要
「Cosmos DB 儲存體」類別已遭取代。 原本使用 CosmosDbStorage 建立的容器沒有設定資料分割索引鍵,且已獲得預設分割區索引鍵 「/_partitionKey」。
使用 Cosmos DB 儲存體建立的 容器可以搭配 Cosmos DB 分割儲存體使用。 如需詳細資訊,請參閱 Azure Cosmos DB 中的資料分割。
另請注意,不同于舊版 Cosmos DB 儲存體,Cosmos DB 分割儲存體不會在您的 Cosmos DB 帳戶內自動建立資料庫。 您必須 手動建立新的資料庫,但略過手動建立容器,因為 CosmosDbPartitionedStorage 會為您建立容器。
如需有關如何連線到其他儲存體選項的指示,請參閱 直接寫入儲存體。
狀態管理
「狀態管理」 可自動讀取 Bot 的狀態以及將其寫入至基礎儲存層。 狀態會儲存為「狀態屬性」 ,這是 Bot 無須擔心特定基礎實作,即可透過狀態管理物件讀取和寫入的有效索引鍵 / 值組。 這些狀態屬性會定義該資訊的儲存方式。 例如,當您擷取定義為特定類別或物件的屬性時,您知道該資料將如何結構化。
這些狀態屬性會歸併為限域「貯體」,而這只是協助組織這些屬性的集合。 SDK 包含三個「貯體」:
- 使用者狀態
- 交談狀態
- 私人交談狀態
上述所有貯體都是「Bot 狀態」 類別的子類別,可加以衍生來定義具有不同範圍的其他貯體類型。
視貯體而定,這些預先定義的貯體受限於特定可見性:
- 不論交談內容為何,使用者狀態適用於 Bot 在該頻道上與該使用者正在交談的任何回合
- 不論使用者為何,交談狀態都會在任何回合的特定交談中使用,例如在群組交談中
- 私人交談狀態受限於特定交談和該特定使用者
提示
使用者和交談狀態是由通道界定。 使用不同通道來存取 Bot 的相同人員會顯示為不同的使用者,每個通道一個使用者,而各有不同的使用者狀態。
每個預先定義的貯體所用的索引鍵為使用者和交談所特有。 設定狀態屬性的值時,索引鍵會在內部定義,其中包含回合內容上的資訊,以確保每個使用者或交談都放在正確的貯體和屬性中。 具體而言,索引鍵的定義如下所示:
- 使用者狀態會使用「頻道識別碼」 和和「傳送者識別碼」 來建立索引鍵。 例如, {Activity.ChannelId}/users/{Activity.From.Id}#YourPropertyName
- 交談狀態會使用「頻道識別碼」 和「交談識別碼」 來建立索引鍵。 例如, {Activity.ChannelId}/conversations/{Activity.Conversation.Id}#YourPropertyName
- 私人交談狀態會使用「頻道識別碼」 、「傳送者識別碼」 和「交談識別碼」 來建立索引鍵。 例如, {Activity.ChannelId}/conversations/{Activity.Conversation.Id}/users/{Activity.From.Id}#YourPropertyName
何時使用每種類型的狀態
交談狀態很適合追蹤交談內容,例如:
- Bot 是否詢問使用者問題,且問題為何
- 交談的目前主題為何,或最後一個主題是什麼
使用者狀態適合用來追蹤使用者的相關資訊,例如:
- 非重大使用者資訊,例如名稱和喜好設定、警示設定或警示喜好設定
- 他們與 Bot 最後一次交談的相關資訊
- 例如,產品支援 Bot 可能會追蹤使用者所詢問的產品。
私人交談狀態適合於支援群組交談的通道,但您想要在哪裡追蹤使用者和交談特定資訊。 例如,如果您有教室 Clicker Bot:
- Bot 無法彙總並顯示學生對於指定問題的回應。
- Bot 可以彙總每個學生的表現,並且在課程結束時,將該資訊私下轉達給他們。
如需使用這些預先定義貯體的詳細資訊,請參閱狀態操作說明文章。
連線到多個資料庫
如果 Bot 需要連線到多個資料庫,請為每個資料庫建立儲存層。 如果您的 Bot 收集具有不同安全性、並行或資料位置需求的資訊,您可以選擇使用多個資料庫。
針對每個儲存層,建立您需要支援狀態屬性的狀態管理物件。
狀態屬性存取子
「狀態屬性存取子」 用來實際讀取或寫入其中一個狀態屬性,並提供 get、set 和 delete 方法,以便存取一個回合內的狀態屬性。 若要建立存取子,您必須提供屬性名稱,這通常發生於您初始化 Bot 時。 然後,您可以使用該存取子來取得及操作 Bot 狀態的該屬性。
存取子允許 SDK 從基礎儲存體中取得狀態,並且為您更新 Bot 的「狀態快取」 。 狀態快取是由 Bot 維護的本機快取,可為您儲存狀態物件,並允許不需存取基礎儲存體的讀取和寫入作業。 如果狀態尚未位於快取中,則呼叫存取子的 get 方法可擷取狀態並其放入快取中。 擷取之後,即可如同本機變數一樣操作狀態屬性。
存取子的 delete 方法可從快取中移除屬性,也可從基礎儲存體中刪除屬性。
重要
第一次呼叫存取子的 get 方法時,您必須提供 Factory 方法來建立物件 (如果其尚未存在於您的狀態中)。 如果未提供 Factory 方法,您將會收到例外狀況。 在狀態操作說明文章中可找到有關如何使用 Factory 方法的詳細資訊。
對於經由存取子所取得的狀態屬性,若要保存您對其所做的任何變更,就必須更新狀態快取中的屬性。 您可以透過呼叫存取子的 set 方法,該方法會在快取中設定您的屬性值,而且適用於稍後在該回合中讀取或更新屬性。 若要將該資料實際保存到基礎儲存體 (因而在目前回合之後提供使用),您必須接著儲存狀態。
狀態屬性存取子方法的運作方式
存取子方法是 Bot 與狀態互動的主要方式。 每個存取子方法的運作方式,以及基礎層的互動方式,如下所示:
- 存取子的 get 方法:
- 存取子會要求狀態快取中的屬性。
- 如果屬性位於快取中,請將其傳回。 否則,從狀態管理物件中取得。 (如果尚未處於狀態,請使用存取子 get call.) 中提供的 Factory 方法
- 存取子的 set 方法:
- 使用新的屬性值更新狀態快取。
- 狀態管理物件的 save changes 方法:
- 檢查狀態快取中的屬性變更。
- 將該屬性寫入至儲存體。
對話方塊中的狀態
對話方塊程式庫會使用對話狀態存取子,在 Bot 的交談狀態上定義,以保留對話的位置。 對話方塊狀態屬性也允許每個對話方塊在回合之間儲存暫時性資訊。
自適性對話具有更詳細的記憶體範圍結構,可讓您更輕鬆地存取設定和辨識結果,以及其他專案。 對話管理員會使用使用者和交談狀態管理物件來提供這些記憶體範圍。
如需對話方塊程式庫的相關資訊,請參閱 對話方塊程式庫 一文。
儲存狀態
當您呼叫存取子的 set 方法來記錄已更新的狀態時,該狀態屬性尚未儲存到保存的儲存體,而改為只儲存到 Bot 的狀態快取。 若要將狀態快取中的所有變更儲存到保存狀態,您必須呼叫狀態管理物件的「儲存變更」 方法,該方法適用於上述 Bot 狀態類別 (例如使用者狀態或交談狀態) 的實作。
撥號狀態管理物件的儲存變更方法 (例如上述貯體,) 會將所有屬性儲存在您已針對該貯體設定為該點的狀態快取中,但不適用於您在 Bot 狀態中可能擁有的任何其他貯體。
提示
Bot 狀態會實作「以最後寫入者為準」行為,因此最後寫入的狀態將蓋過先前寫入的狀態。 這對許多應用程式來說可能還可以運作,但會有些顧慮,特別是在向外延展的案例中,其中可能正在進行某種程度的並行或延遲作業。
如果您有一些自訂中介軟體,可能在回合處理常式完成後更新狀態,請考慮在中介軟體中處理狀態。