客服人員聊天歷史與記憶是關鍵功能,能讓客服人員在對話間維持上下文、記住使用者偏好,並提供個人化體驗。 代理框架提供多種功能以適應不同使用情境,從簡單的記憶體內聊天訊息儲存,到持久化資料庫及專門的記憶體服務。
聊天記錄
代理框架支援各種聊天記錄儲存選項。 可用的選項會因代理程式類型和用於建置代理程式的基礎服務而異。
以下是支援的兩個主要案例:
-
記憶體儲存:Agent 建立在不支援聊天記錄服務內儲存的服務上(例如 OpenAI Chat Completion)。 根據預設,代理程式架構會將完整的聊天記錄儲存在物件的
AgentThread記憶體中,但開發人員可以視需要提供自訂ChatMessageStore實作,將聊天記錄儲存在第三方存放區中。 -
服務內儲存體:代理程式是建置在需要聊天記錄的服務內儲存體的服務上 (例如 Azure AI Foundry 持續性代理程式) 。 客服專員架構會將遠端聊天記錄的 ID 儲存在物件中
AgentThread,並且不支援其他聊天記錄儲存選項。
記憶體內聊天記錄儲存
當使用不支援聊天記錄的服務儲存時,代理程式架構將預設將聊天記錄儲存在物件的 AgentThread 記憶體中。 在此情況下,儲存在執行緒物件中的完整聊天記錄,以及任何新訊息,都會在每次代理程式執行時提供給基礎服務。 這允許與客服專員獲得自然的對話體驗,其中呼叫者僅提供新用戶消息,客服專員僅返回新答案,但客服專員可以訪問完整的對話歷史記錄,並將在生成響應時使用它。
當使用 OpenAI 聊天完成作為代理程式的基礎服務時,下列程式碼將導致執行緒物件包含代理程式執行的聊天記錄。
AIAgent agent = new OpenAIClient("<your_api_key>")
.GetChatClient(modelName)
.CreateAIAgent(JokerInstructions, JokerName);
AgentThread thread = agent.GetNewThread();
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", thread));
當訊息儲存在記憶體中時,可以從執行程擷取訊息清單,並在需要時直接操作訊息。
IList<ChatMessage>? messages = thread.GetService<IList<ChatMessage>>();
備註
只有在使用記憶體時,才能以這種方式從物件擷取 AgentThread 訊息。
使用 In-Memory 存儲減少聊天記錄
底層服務不支援服務內儲存時預設使用的內建 InMemoryChatMessageStore ,可以配置一個 reducer 來管理聊天記錄的大小。
這有助於避免超出基礎服務的內容大小限制。
可以 InMemoryChatMessageStore 採取選擇性 Microsoft.Extensions.AI.IChatReducer 實作來減少聊天記錄的大小。
它還允許您配置調用 reducer 的事件,無論是在將消息添加到聊天歷史記錄之後,還是在返回聊天歷史記錄以進行下一次調用之前。
要使用減速器配置,InMemoryChatMessageStore您可以提供一個工廠來為每個新工廠InMemoryChatMessageStore構建一個新的AgentThread,並傳遞給它您選擇的減速器。 也可以 InMemoryChatMessageStore 傳遞一個選擇性的觸發事件,該事件可以設定為 InMemoryChatMessageStore.ChatReducerTriggerEvent.AfterMessageAdded 或 InMemoryChatMessageStore.ChatReducerTriggerEvent.BeforeMessagesRetrieval。
AIAgent agent = new OpenAIClient("<your_api_key>")
.GetChatClient(modelName)
.CreateAIAgent(new ChatClientAgentOptions
{
Name = JokerName,
Instructions = JokerInstructions,
ChatMessageStoreFactory = ctx => new InMemoryChatMessageStore(
new MessageCountingChatReducer(2),
ctx.SerializedState,
ctx.JsonSerializerOptions,
InMemoryChatMessageStore.ChatReducerTriggerEvent.AfterMessageAdded)
});
備註
只有在使用 .InMemoryChatMessageStore 當服務具有服務中的聊天記錄儲存體時,由服務本身來管理聊天記錄的大小。 同樣,當使用第 3 方存儲(見下文)時,由第 3 方存儲解決方案來管理聊天記錄大小。 如果您為訊息存放區提供 a, ChatMessageStoreFactory 但您使用具有內建聊天記錄儲存的服務,則不會使用工廠。
推理服務聊天記錄儲存
當使用需要在服務中儲存聊天記錄的服務時,代理程式架構會將遠端聊天記錄的 ID 儲存在物件中 AgentThread 。
例如,當使用 store=true 的 OpenAI Responses 作為代理的底層服務時,以下程式碼將導致執行緒物件包含服務傳回的最後一個回應 ID。
AIAgent agent = new OpenAIClient("<your_api_key>")
.GetOpenAIResponseClient(modelName)
.CreateAIAgent(JokerInstructions, JokerName);
AgentThread thread = agent.GetNewThread();
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", thread));
備註
某些服務,例如 OpenAI Responses 支援聊天記錄的服務內儲存 (store=true),或在每次調用時提供完整的聊天記錄 (store=false)。 因此,視服務使用的模式而定,代理程式架構會預設將完整聊天記錄儲存在記憶體中,或儲存服務儲存聊天記錄的 ID 參考。
第三方聊天記錄存儲
當使用不支援聊天記錄的服務內儲存時,代理程式架構可讓開發人員以第三方聊天記錄儲存取代聊天記錄的預設記憶體內儲存。 開發人員必須提供基底抽象 ChatMessageStore 類別的子類別。
該 ChatMessageStore 類定義了用於存儲和檢索聊天消息的接口。 開發人員必須實作 AddMessagesAsync and GetMessagesAsync 方法,以便在產生訊息時將訊息新增至遠端存放區,並在叫用基礎服務之前從遠端存放區擷取訊息。
代理程式將在處理使用者查詢時使用傳 GetMessagesAsync 回的所有訊息。 由實 ChatMessageStore 作者確定聊天記錄的大小不會超過基礎服務的上下文視窗。
在遠端存放區中實作 ChatMessageStore 將聊天記錄儲存在自訂時,該執行緒的聊天記錄應該儲存在該執行程唯一的金鑰下。 實作應該 ChatMessageStore 會產生此金鑰,並使其保持在其狀態。
ChatMessageStore 有一個 Serialize 方法,可以在線程序列化時覆寫以序列化其狀態。 也 ChatMessageStore 應該提供建構函式,以 作為 JsonElement 輸入,以支援其狀態的還原序列化。
若要將自訂ChatMessageStoreChatClientAgent提供給 ,您可以在建立代理程式時使用該ChatMessageStoreFactory選項。
以下是範例,示範如何將 的ChatMessageStore自訂實作傳遞至以 Azure OpenAI 聊天完成為基礎的 。ChatClientAgent
AIAgent agent = new AzureOpenAIClient(
new Uri(endpoint),
new AzureCliCredential())
.GetChatClient(deploymentName)
.CreateAIAgent(new ChatClientAgentOptions
{
Name = JokerName,
Instructions = JokerInstructions,
ChatMessageStoreFactory = ctx =>
{
// Create a new chat message store for this agent that stores the messages in a custom store.
// Each thread must get its own copy of the CustomMessageStore, since the store
// also contains the id that the thread is stored under.
return new CustomMessageStore(vectorStore, ctx.SerializedState, ctx.JsonSerializerOptions);
}
});
小提示
如需如何建立自訂訊息存放區的詳細範例,請參閱在 第三方儲存體中儲存聊天記錄 教學課程。
長期記憶
代理框架允許開發人員提供自訂元件,這些元件可以提取記憶或向代理提供記憶。
若要實作這樣的記憶體元件,開發人員需要將抽象基類子 AIContextProvider 類別化。 這個類別有兩個核心方法, InvokingAsync 以及 InvokedAsync。 覆寫時, InvokedAsync 允許開發人員檢查使用者提供或代理程式產生的所有訊息。
InvokingAsync 允許開發人員為特定代理程式執行注入額外的內容。 可以提供系統說明、附加消息和附加功能。
小提示
如需如何建立自訂記憶體元件的詳細範例,請參閱將 記憶體新增至代理程式 教學課程。
AgentThread序列化
能夠在代理程式呼叫之間保存物件 AgentThread 非常重要。 這允許使用者向客服專員提出問題,並需要很長時間來提出後續問題的情況。 這可讓狀態在 AgentThread 服務或應用程式重新啟動後繼續運作。
即使聊天記錄儲存在遠端存放區中,物件 AgentThread 仍包含參考遠端聊天記錄的 ID。 因此,失去狀態也 AgentThread 會導致遠端聊天記錄的 ID 遺失。
因此,以及 AgentThread 附加到它的任何物件都提供了 SerializeAsync 序列化其狀態的方法。 也 AIAgent 提供從 DeserializeThread 序列化狀態重新建立執行緒的方法。 此DeserializeThread方法會在代理程式上重新建立具有 和 ChatMessageStore 的執行緒AIContextProvider。
// Serialize the thread state to a JsonElement, so it can be stored for later use.
JsonElement serializedThreadState = thread.Serialize();
// Re-create the thread from the JsonElement.
AgentThread resumedThread = AIAgent.DeserializeThread(serializedThreadState);
備註
AgentThread 物件可能包含的不僅僅是聊天記錄,例如上下文提供者也可能將狀態儲存在執行緒物件中。 因此,請務必一律序列化、儲存和還原序列化整個 AgentThread 物件,以確保保留所有狀態。
這很重要
始終將物體視為 AgentThread 不透明的物體,除非您非常確定內部結構。 內容可能不僅因代理類型而異,還因服務類型和配置而異。
警告
使用與最初建立執行緒的代理程式不同的代理程式,或使用與原始代理程式具有不同配置的代理程式來還原執行緒,可能會導致錯誤或非預期的行為。
記憶體類型
代理框架支援多種類型的記憶體以適應不同的用例,包括將聊天記錄作為短期記憶的一部分進行管理,以及提供用於提取、儲存和注入代理的擴展點。
In-Memory 儲存體 (預設)
最簡單的記憶體形式,其中交談歷程記錄會在應用程式執行階段期間儲存在記憶體中。 這是預設行為,不需要額外的設定。
from agent_framework import ChatAgent
from agent_framework.openai import OpenAIChatClient
# Default behavior - uses in-memory storage
agent = ChatAgent(
chat_client=OpenAIChatClient(),
instructions="You are a helpful assistant."
)
# Conversation history is maintained in memory for this thread
thread = agent.get_new_thread()
response = await agent.run("Hello, my name is Alice", thread=thread)
持續性訊息存放區
對於需要跨會話保存對話歷史記錄的應用程序,框架提供了 ChatMessageStore 實現:
內建 ChatMessageStore
可序列化的預設記憶體內實作:
from agent_framework import ChatMessageStore
# Create a custom message store
def create_message_store():
return ChatMessageStore()
agent = ChatAgent(
chat_client=OpenAIChatClient(),
instructions="You are a helpful assistant.",
chat_message_store_factory=create_message_store
)
Redis 訊息存放區
對於需要持續儲存的生產應用程式:
from agent_framework.redis import RedisChatMessageStore
def create_redis_store():
return RedisChatMessageStore(
redis_url="redis://localhost:6379",
thread_id="user_session_123",
max_messages=100 # Keep last 100 messages
)
agent = ChatAgent(
chat_client=OpenAIChatClient(),
instructions="You are a helpful assistant.",
chat_message_store_factory=create_redis_store
)
自訂訊息存放區
您可以實作自己的儲存後端,方法是實作 ChatMessageStoreProtocol:
from agent_framework import ChatMessage, ChatMessageStoreProtocol
from typing import Any
from collections.abc import Sequence
class DatabaseMessageStore(ChatMessageStoreProtocol):
def __init__(self, connection_string: str):
self.connection_string = connection_string
self._messages: list[ChatMessage] = []
async def add_messages(self, messages: Sequence[ChatMessage]) -> None:
"""Add messages to database."""
# Implement database insertion logic
self._messages.extend(messages)
async def list_messages(self) -> list[ChatMessage]:
"""Retrieve messages from database."""
# Implement database query logic
return self._messages
async def serialize(self, **kwargs: Any) -> Any:
"""Serialize store state for persistence."""
return {"connection_string": self.connection_string}
async def update_from_state(self, serialized_store_state: Any, **kwargs: Any) -> None:
"""Update store from serialized state."""
if serialized_store_state:
self.connection_string = serialized_store_state["connection_string"]
小提示
如需如何建立自訂訊息存放區的詳細範例,請參閱在 第三方儲存體中儲存聊天記錄 教學課程。
內容提供者 (動態記憶體)
上下文提供者通過在每次代理呼叫之前注入相關上下文來實現複雜的記憶模式:
基本內容提供者
from agent_framework import ContextProvider, Context, ChatMessage
from collections.abc import MutableSequence
from typing import Any
class UserPreferencesMemory(ContextProvider):
def __init__(self):
self.preferences = {}
async def invoking(self, messages: ChatMessage | MutableSequence[ChatMessage], **kwargs: Any) -> Context:
"""Provide user preferences before each invocation."""
if self.preferences:
preferences_text = ", ".join([f"{k}: {v}" for k, v in self.preferences.items()])
instructions = f"User preferences: {preferences_text}"
return Context(instructions=instructions)
return Context()
async def invoked(
self,
request_messages: ChatMessage | Sequence[ChatMessage],
response_messages: ChatMessage | Sequence[ChatMessage] | None = None,
invoke_exception: Exception | None = None,
**kwargs: Any,
) -> None:
"""Extract and store user preferences from the conversation."""
# Implement preference extraction logic
pass
小提示
如需如何建立自訂記憶體元件的詳細範例,請參閱將 記憶體新增至代理程式 教學課程。
外部記憶體服務
該框架支持與 Mem0 等專用內存服務的集成:
from agent_framework.mem0 import Mem0Provider
# Using Mem0 for advanced memory capabilities
memory_provider = Mem0Provider(
api_key="your-mem0-api-key",
user_id="user_123",
application_id="my_app"
)
agent = ChatAgent(
chat_client=OpenAIChatClient(),
instructions="You are a helpful assistant with memory.",
context_providers=memory_provider
)
執行緒序列化和持久性
架構支援序列化整個執行緒狀態,以便在應用程式重新啟動時持續存在:
import json
# Create agent and thread
agent = ChatAgent(chat_client=OpenAIChatClient())
thread = agent.get_new_thread()
# Have conversation
await agent.run("Hello, my name is Alice", thread=thread)
# Serialize thread state
serialized_thread = await thread.serialize()
# Save to file/database
with open("thread_state.json", "w") as f:
json.dump(serialized_thread, f)
# Later, restore the thread
with open("thread_state.json", "r") as f:
thread_data = json.load(f)
restored_thread = await agent.deserialize_thread(thread_data)
# Continue conversation with full context
await agent.run("What's my name?", thread=restored_thread)