---
title: Microsoft Agent Framework Multi-Turn Conversations and Threading
titleSuffix: Azure AI Foundry
description: Learn Agent Framework Multi-Turn Conversations and Threading.
ms.service: agent-framework
ms.topic: tutorial
ms.date: 09/04/2025
ms.reviewer: ssalgado
zone_pivot_groups: programming-languages
author: TaoChenOSU
ms.author: taochen
---

# Microsoft Agent Framework Multi-Turn Conversations and Threading

The Microsoft Agent Framework provides built-in support for managing multi-turn conversations with AI agents. This includes maintaining context across multiple interactions. Different agent types and underlying services that are used to build agents might support different threading types, and Agent Framework abstracts these differences away, providing a consistent interface for developers.

For example, when using a ChatClientAgent based on a foundry agent, the conversation history is persisted in the service. While, when using a ChatClientAgent based on chat completion with gpt-4.1 the conversation history is in-memory and managed by the agent.

The `AgentThread` type is the abstraction that represents conversation history and other state of an agent.
`AIAgent` instances are stateless and the same agent instance can be used with multiple `AgentThread` instances. All state is therefore preserved in the `AgentThread`.
An `AgentThread` can both represent chat history plus any other state that the agent needs to preserve across multiple interactions.
The conversation history may be stored in the `AgentThread` object itself, or remotely, with the `AgentThread` only containing a reference to the remote conversation history.
The `AgentThread` state may also include memories or references to memories stored remotely.

> [!TIP]
> To learn more about Chat History and Memory in the Agent Framework, see [Agent Chat History and Memory](./agent-memory.md).

### AgentThread Creation

`AgentThread` instances can be created in two ways:

1. By calling `GetNewThreadAsync` on the agent.
1. By running the agent and not providing an `AgentThread`. In this case the agent will create a throwaway `AgentThread` which will only be used for the duration of the run.

Some underlying service stored conversations/threads/responses might be persistently created in an underlying service, where the service requires this, for example, Foundry Agents or OpenAI Responses. Any cleanup or deletion of these is the responsibility of the user.

::: zone pivot="programming-language-csharp"

```csharp
// Create a new thread.
AgentThread thread = await agent.GetNewThreadAsync();
// 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?");
```

::: zone-end

### AgentThread Storage

`AgentThread` instances can be serialized and stored for later use. This allows for the preservation of conversation context across different sessions or service calls.

For cases where the conversation history is stored in a service, the serialized `AgentThread` will contain an
id that points to the conversation history in the service.
For cases where the conversation history is managed in-memory, the serialized `AgentThread` will contain the messages
themselves.

::: zone pivot="programming-language-csharp"

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

// Serialize the thread for storage.
JsonElement serializedThread = thread.Serialize();
// 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);
```

The Microsoft Agent Framework provides built-in support for managing multi-turn conversations with AI agents. This includes maintaining context across multiple interactions. Different agent types and underlying services that are used to build agents might support different threading types, and Agent Framework abstracts these differences away, providing a consistent interface for developers.

For example, when using a `ChatAgent` based on a Foundry agent, the conversation history is persisted in the service. While when using a `ChatAgent` based on chat completion with gpt-4, the conversation history is in-memory and managed by the agent.

The differences between the underlying threading models are abstracted away via the `AgentThread` type.

## Agent/AgentThread relationship

`AIAgent` instances are stateless and the same agent instance can be used with multiple `AgentThread` instances.

Not all agents support all `AgentThread` types though. For example if you are using a `ChatClientAgent` with the responses service, `AgentThread` instances created by this agent, will not work with a `ChatClientAgent` using the Foundry Agent service.
This is because these services both support saving the conversation history in the service, and while the two `AgentThread` instances will have references to each service stored conversation, the id from the responses service cannot be used with the Foundry Agent service, and vice versa.

It is therefore considered unsafe to use an `AgentThread` instance that was created by one agent with a different agent instance, unless you are aware of the underlying threading model and its implications.

## Conversation history support by service / protocol

| Service | Conversation History Support |
|---------|--------------------|
| Foundry Agents | Service stored persistent conversation history |
| OpenAI Responses | Service stored response chains OR in-memory conversation history |
| OpenAI ChatCompletion | In-memory conversation history |
| OpenAI Assistants | Service stored persistent conversation history |
| A2A | Service stored persistent conversation history |

::: zone-end

::: zone pivot="programming-language-python"

### AgentThread Creation

`AgentThread` instances can be created in two ways:

1. By calling `get_new_thread()` on the agent.
1. By running the agent and not providing an `AgentThread`. In this case the agent will create a throwaway `AgentThread` with an underlying thread which will only be used for the duration of the run.

Some underlying service stored conversations/threads/responses might be persistently created in an underlying service, where the service requires this, for example, Azure AI Agents or OpenAI Responses. Any cleanup or deletion of these is the responsibility of the user.

```python
# 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 Storage

`AgentThread` instances can be serialized and stored for later use. This allows for the preservation of conversation context across different sessions or service calls.

For cases where the conversation history is stored in a service, the serialized `AgentThread` will contain an
id that points to the conversation history in the service.
For cases where the conversation history is managed in-memory, the serialized `AgentThread` will contain the messages
themselves.

```python
# 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)
```

### Custom Message Stores

For in-memory threads, you can provide a custom message store implementation to control how messages are stored and retrieved:

```python
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 relationship

`Agents` are stateless and the same agent instance can be used with multiple `AgentThread` instances.

Not all agents support all `AgentThread` types though. For example if you are using a `ChatAgent` with the OpenAI Responses service and `store=True`, `AgentThread` instances used by this agent, will not work with a `ChatAgent` using the Azure AI Agent service.
This is because these services both support saving the conversation history in the service, and while the two `AgentThread` instances will have references to each service stored conversation, the id from the OpenAI Responses service cannot be used with the Foundry Agent service, and vice versa.

It is therefore considered unsafe to use an `AgentThread` instance that was created by one agent with a different agent instance, unless you are aware of the underlying threading model and its implications.

## Practical Multi-Turn Example

Here's a complete example showing how to maintain context across multiple interactions:

```python
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
```

::: zone-end

## Next steps

> [!div class="nextstepaction"]
> [Agent Memory](./agent-memory.md)
