Microsoft代理框架多轮对话和线程操作

Microsoft代理框架提供内置支持,用于管理与 AI 代理的多轮次对话。 这包括维护跨多个交互的上下文。 用于生成代理的不同代理类型和基础服务可能支持不同的线程类型,代理框架将这些差异抽象化,为开发人员提供一致的接口。

例如,使用基于 Foundry 代理的 ChatClientAgent 时,会话历史记录将保留在服务中。 虽然使用基于 gpt-4.1 聊天完成的 ChatClientAgent 时,对话历史记录是由代理在内存中管理的。

基础线程模型之间的差异通过 AgentThread 类型抽象化。

AgentThread 创建

AgentThread 可以通过两种方式创建实例:

  1. 在代理上调用 GetNewThread
  2. 在运行代理时不提供 AgentThread。 在这种情况下,代理将创建一个带有基础线程的临时 AgentThread,该线程仅在运行期间使用。

某些底层线程可能在底层服务中持续创建,当服务需要此类功能时,例如 Foundry 代理或 OpenAI 响应。 这些线程的任何清理或删除都是用户的责任。

// Create a new thread.
AgentThread thread = agent.GetNewThread();
// Run the agent with the thread.
var response = await agent.RunAsync("Hello, how are you?", thread);

// Run an agent with a temporary thread.
response = await agent.RunAsync("Hello, how are you?");

AgentThread 存储

AgentThread 实例可以序列化并存储以供以后使用。 这允许在不同会话或服务调用之间保留会话上下文。

对于会话历史记录存储在服务中的情况,序列化 AgentThread 将包含服务中线程的 ID。 对于会话历史记录在内存中管理的情况,序列化 AgentThread 将包含消息本身。

// Create a new thread.
AgentThread thread = agent.GetNewThread();
// Run the agent with the thread.
var response = await agent.RunAsync("Hello, how are you?", thread);

// Serialize the thread for storage.
JsonElement serializedThread = await thread.SerializeAsync();
// Deserialize the thread state after loading from storage.
AgentThread resumedThread = await agent.DeserializeThreadAsync(serializedThread);

// Run the agent with the resumed thread.
var response = await agent.RunAsync("Hello, how are you?", resumedThread);

Microsoft代理框架提供内置支持,用于管理与 AI 代理的多轮次对话。 这包括维护跨多个交互的上下文。 用于生成代理的不同代理类型和基础服务可能支持不同的线程类型,并且 Agent Framework 会将这些差异抽象化,为开发人员提供一致的接口。

例如,使用 ChatAgent 基于 Foundry 代理的会话历史记录将保留在服务中。 当使用基于 ChatAgent 的 gpt-4 聊天完成时,对话历史记录存储在内存中并由代理托管。

基础线程模型之间的差异通过 AgentThread 类型抽象化。

Agent/AgentThread 关系

AIAgent 实例是无状态的,同一代理实例可以与多个 AgentThread 实例一起使用。

但并非所有代理都支持所有线程类型。 例如,如果您使用 ChatClientAgent 响应服务,则由此代理创建的 AgentThread 实例将无法与使用 Foundry 代理服务的 ChatClientAgent 一同工作。 这是因为这些服务都支持在服务中保存会话历史记录,并且 AgentThread 只保留对此服务托管线程的引用。

因此,使用由一个代理创建的 AgentThread 实例与不同的代理实例一起使用是不安全的,除非你了解基础线程模型及其影响。

服务/协议的线程支持

服务 线程支持
铸造剂 服务托管持久线程
OpenAI 响应 服务托管持久线程或内存中线程
OpenAI ChatCompletion (聊天完成工具) 内存中线程
OpenAI 助手 服务托管线程
A2A 服务托管线程

AgentThread 创建

AgentThread 可以通过两种方式创建实例:

  1. 在代理上调用 get_new_thread()
  2. 在运行代理时不提供 AgentThread。 在这种情况下,代理将创建一个带有基础线程的临时 AgentThread,该线程仅在运行期间使用。

某些基础线程可能在基础服务中永久创建,其中服务需要此服务,例如 Azure AI 代理或 OpenAI 响应。 这些线程的任何清理或删除都是用户的责任。

# Create a new thread.
thread = agent.get_new_thread()
# Run the agent with the thread.
response = await agent.run("Hello, how are you?", thread=thread)

# Run an agent with a temporary thread.
response = await agent.run("Hello, how are you?")

AgentThread 存储

AgentThread 实例可以序列化并存储以供以后使用。 这允许在不同会话或服务调用之间保留会话上下文。

对于会话历史记录存储在服务中的情况,序列化 AgentThread 将包含服务中线程的 ID。 对于会话历史记录在内存中管理的情况,序列化 AgentThread 将包含消息本身。

# Create a new thread.
thread = agent.get_new_thread()
# Run the agent with the thread.
response = await agent.run("Hello, how are you?", thread=thread)

# Serialize the thread for storage.
serialized_thread = await thread.serialize()
# Deserialize the thread state after loading from storage.
resumed_thread = await agent.deserialize_thread(serialized_thread)

# Run the agent with the resumed thread.
response = await agent.run("Hello, how are you?", thread=resumed_thread)

自定义消息存储

对于内存中线程,可以提供自定义消息存储实现来控制消息的存储和检索方式:

from agent_framework import AgentThread, ChatMessageStore, ChatAgent
from agent_framework.azure import AzureAIAgentClient
from azure.identity.aio import AzureCliCredential

class CustomStore(ChatMessageStore):
    # Implement custom storage logic here
    pass

# You can also provide a custom message store factory when creating the agent
def custom_message_store_factory():
    return CustomStore()  # or your custom implementation

async with AzureCliCredential() as credential:
    agent = ChatAgent(
        chat_client=AzureAIAgentClient(async_credential=credential),
        instructions="You are a helpful assistant",
        chat_message_store_factory=custom_message_store_factory
    )
    # Or let the agent create one automatically
    thread = agent.get_new_thread()
    # thread.message_store is not a instance of CustomStore

Agent/AgentThread 关系

Agents 是无状态的,同一个代理实例可以与多个 AgentThread 实例一起使用。

但并非所有代理都支持所有线程类型。 例如,如果您使用ChatAgent OpenAI 响应服务,并且此代理正在使用的 store=TrueAgentThread 实例将无法与使用 Azure AI 代理服务的 ChatAgent 兼容,因为 thread_ids 不兼容。

因此,使用由一个代理创建的 AgentThread 实例与不同的代理实例一起使用是不安全的,除非你了解基础线程模型及其影响。

实用多轮次示例

下面是一个完整示例,展示如何跨多个交互维护上下文:

from agent_framework import ChatAgent
from agent_framework.azure import AzureAIAgentClient
from azure.identity.aio import AzureCliCredential

async def multi_turn_example():
    async with (
        AzureCliCredential() as credential,
        ChatAgent(
            chat_client=AzureAIAgentClient(async_credential=credential),
            instructions="You are a helpful assistant"
        ) as agent
    ):
        # Create a thread for persistent conversation
        thread = agent.get_new_thread()

        # First interaction
        response1 = await agent.run("My name is Alice", thread=thread)
        print(f"Agent: {response1.text}")

        # Second interaction - agent remembers the name
        response2 = await agent.run("What's my name?", thread=thread)
        print(f"Agent: {response2.text}")  # Should mention "Alice"

        # Serialize thread for storage
        serialized = await thread.serialize()

        # Later, deserialize and continue conversation
        new_thread = await agent.deserialize_thread(serialized)
        response3 = await agent.run("What did we talk about?", thread=new_thread)
        print(f"Agent: {response3.text}")  # Should remember previous context

后续步骤