# Multi Agent Orchestration through Azure Durable  Functions in Microsoft Agent Framework

In my previous [article](https://www.azureguru.net/azure-durable-agents-in-microsoft-agent-framework-with-docker-durable-task-scheduler-dts-emulator), I introduced the process of setting up a single durable agent using the Azure Durable Framework and the Docker-based Durable Task Scheduler (DTS) Emulator.

This article will be a step ahead and is focused on setting up a Multi Agent Orchestration based on the similar principal.

The use case in this article is a multi-agent workflow involving two agents.

The first agent, the Football Content Creator Agent is responsible for generating a review of a football club. The second agent, the Football Content Reviewer Agent evaluates and reviews the generated content and produces a more refined version of the original review generated by Content Creator Agent.

I had used a similar use case in one of my earlier article that deep dived into workflow orchestration pattern.

[https://www.azureguru.net/workflow-orchestration-patterns-in-microsoft-agent-framework#group-chat-orchestration-pattern](https://www.azureguru.net/workflow-orchestration-patterns-in-microsoft-agent-framework#group-chat-orchestration-pattern)

> In this example, you could use the same agent for content creation and review but I used two separate agents just to give an idea on how execution of durable multi agents can be orchestrated .

### **SetUp**

To get started, create a new Azure Function project and apply settings covered in my previous [article](https://www.azureguru.net/azure-durable-agents-in-microsoft-agent-framework-with-docker-durable-task-scheduler-dts-emulator#setup) including setting up of the Docker DTS Emulator.

Ensure Docker DTS Emulator is up and navigate to [**http://localhost:8082/**](http://localhost:8082/) to ensure that it is running.

![](https://cdn.hashnode.com/uploads/covers/6693c62c166ee9c594cffda0/72056ed9-a2ed-453f-8c34-14c343a17e39.png align="center")

### **Code**

After the above artifacts are in place, add the following code to read the settings from `appsettings.json` in **Program.cs** of the project.

```csharp
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false)
.Build();
```

Read the credentials and register a `Chatclient`

```csharp
var credential = new AzureKeyCredential(configuration["AppSettings:ApiKey"]);

ServiceCollection servicecollection = new();

builder.Services.AddKeyedChatClient(
    "ChatClient",
    (
        sp =>
            new AzureOpenAIClient(new Uri(configuration["AppSettings:EndPoint"]), credential)
                .GetChatClient(configuration["AppSettings:Chat_DeploymentName"])
                .AsIChatClient()
    )
);
```

In the next step, register the following two **AIAgents** in the hosted DI container.

**FootballContentCreatorAgent >>**

```csharp
servicecollection.AddSingleton<ChatClientAgent>(sp =>

{
    Func<ChatClientAgentOptions> func = () =>
   {
       return new ChatClientAgentOptions
       {
           ChatOptions = new ChatOptions
           {
                Instructions = "You are a content creator. You create content for football teams. Be concise and please stick to the topic.",
           },
           Name = "FootballContentCreatorAgent",
           Id = "1"
       };
   };

    return new ChatClientAgent(sp.GetKeyedService<IChatClient>("ChatClient"), options: func());

});
```

**FootballContentReviewerAgent >>**

```csharp
servicecollection.AddSingleton<ChatClientAgent>(sp =>

{
    Func<ChatClientAgentOptions> func = () =>
   {
       return new ChatClientAgentOptions
       {
           ChatOptions = new ChatOptions
           {
               Instructions = "You are a content reviewer.You review created content for football teams and make necessary changes to it.Be concise and please stick to the topic.",
           },
           Name = "FootballContentReviewerAgent",
           Id = "2"
       };
   };
    return new ChatClientAgent(sp.GetKeyedService<IChatClient>("ChatClient"), options: func());

});
```

Build the service and fetch agents from the **ServiceProvider** as **ChatClientAgent.**

```csharp
ServiceProvider serviceProvider = servicecollection.BuildServiceProvider();

var agents = serviceProvider.GetServices<ChatClientAgent>();

List<ChatClientAgents> chatclientagent = new(agents);
```

Then add these agents as **DurableAgent** to the Azure Function worker.

```csharp
using IHost app = FunctionsApplication
.CreateBuilder(args)
.ConfigureFunctionsWebApplication()
.ConfigureDurableAgents(options => { options.AddAIAgents(chatclientagent).DefaultTimeToLive = TimeSpan.FromHours(1); })
.Build();

app.Run();
```

The time to live for the agents is configured to an hour.

### Orchestration

Define a type record that holds the **AgentResponse** in a new class file called **FunctionTrigger.cs**

```csharp
public record TextResponse(string Response);
```

The orchestration occurs in two steps **Start** and **Run.**

Start is the trigger point that defines the route , creates an orchestration instance for an **DurableTaskClient** and returns a response of type **HttpResponseData.**

**StartOrchestrationAsync >>**

```csharp
 [Function(nameof(StartOrchestrationAsync))]

public static async Task<HttpResponseData> StartOrchestrationAsync([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "footballagent/run")] HttpRequestData req, [DurableClient] DurableTaskClient client)

 {

var instanceId = await client.ScheduleNewOrchestrationInstanceAsync(orchestratorName: nameof(RunOrchestrationAsync));

     var response = req.CreateResponse(HttpStatusCode.Accepted);
         await response.WriteAsJsonAsync(new
         {
             message = "Orchestration started.",
             InstanceId = instanceId
         }
      );
     return response;
 }
```

Run is where an agent orchestration pipeline is triggered post creation of an orchestration instance through **StartOrchestrationAsync**

**RunOrchestrationAsync >>**

```csharp
 [Function(nameof(RunOrchestrationAsync))]
 public static async Task<string> RunOrchestrationAsync([OrchestrationTrigger] TaskOrchestrationContext context)
 {
     DurableAIAgent FootballContentCreatorAgent = context.GetAgent("FootballContentCreatorAgent");
     DurableAIAgent FootballContentReviewerAgent = context.GetAgent("FootballContentReviewerAgent");

     AgentSession Session = await FootballContentCreatorAgent.CreateSessionAsync();

     AgentResponse<TextResponse> initial = await FootballContentCreatorAgent.RunAsync<TextResponse>(
         message: "Summarize the glory of football club FC Barcelona",
         session: Session);

     AgentResponse<TextResponse> refined = await FootballContentReviewerAgent.RunAsync<TextResponse>(
      message: $"Improve and expand the review further while keeping it under 1000 words: {initial.Result.Response}",
      session: Session);

     return refined.Result.Response;
 }
```

In the code above through \*\*TaskOrchestrationContext ,\*\*we get a list of available agents from the context.

The **AgentResponse** output generated by **FootballContentCreatorAgent** acts as input to the **FootballContentReviewerAgent.** The input is reviewed and post modification the modified reviewed is returned as the final output.

Add the above two functions to the **FunctionTrigger.cs** file created earlier.

Our endpoint is **"footballagent/run".** Invoke it through Powershell.

```yaml
Invoke-RestMethod -Method Post -Uri http://localhost:7001/api/footballagent/run
```

![](https://cdn.hashnode.com/uploads/covers/6693c62c166ee9c594cffda0/d949c78e-fd6e-4d7e-ab99-d8137dc15e2d.png align="center")

Post invocation , underlying artifacts are visible on the Durable Task Scheduler Dashboard.

**Orchestration >>**

![Microsoft Agent Framework Azure Durable Functions](https://cdn.hashnode.com/uploads/covers/6693c62c166ee9c594cffda0/9f5bdadf-6b90-468b-b218-6bb54edc7feb.png align="center")

**Entities >>**

![Microsoft Agent Framework Azure Durable Functions](https://cdn.hashnode.com/uploads/covers/6693c62c166ee9c594cffda0/bae96325-b1d3-4708-8e13-a3b983d86fcd.png align="center")

**Agents >>**

![Microsoft Agent Framework Azure Durable Functions](https://cdn.hashnode.com/uploads/covers/6693c62c166ee9c594cffda0/cd81ede8-fd6e-4efa-bd33-542027db61ac.png align="center")

**Execution >>**

![](https://cdn.hashnode.com/uploads/covers/6693c62c166ee9c594cffda0/f6c1a39d-a091-49e3-b38f-30b150e36802.gif align="center")

### Conclusion

In this article, I tried to explore how Azure Durable Functions can be used to orchestrate a multi-agent execution within the Microsoft Agent Framework. I hope this article helps you understand how durable orchestrations can be leveraged to coordinate multi agent execution effectively.

Thanks for reading !!!
