No dinâmico mundo do desenvolvimento web, a automação e a inteligência artificial (IA) estão se tornando cada vez mais cruciais. O Microsoft Agent Framework (MAF) surge como uma ferramenta poderosa para simplificar a criação e o gerenciamento de agentes e fluxos de trabalho que automatizam tarefas e processos. Este artigo explora como utilizar o MAF em conjunto com o Azure AI Foundry para construir agentes inteligentes, utilizando um exemplo prático de um agente de viagens do TripAdvisor.
O que é o Microsoft Agent Framework (MAF)?
O MAF é um kit de desenvolvimento de código aberto projetado para agilizar a criação e o gerenciamento de agentes e fluxos de trabalho que automatizam tarefas e processos. Ele se baseia em projetos OSS conhecidos como Semantic Kernel e Autogen, servindo como sua evolução natural, mantendo seus pontos fortes e facilidade de uso. O MAF oferece diversos blocos de construção para a criação de soluções de IA:
- Clientes de Modelos LLM: Para conclusões e respostas de bate-papo.
- Agent Thread: Para lidar com contexto, estado e provedores de memória.
- Middleware: Para interceptar mensagens.
- Clientes MCP: Para adicionar ferramentas a serem usadas pelos agentes.
Atualmente, o MAF suporta .NET e Python para a criação de agentes e fluxos de trabalho. Outras linguagens podem ser suportadas no futuro. A arquitetura do MAF é centralizada no conceito de agentes, permitindo a criação de sistemas complexos de forma modular e organizada.
Criando um Projeto no Azure AI Foundry
Neste guia, criaremos um agente do TripAdvisor que auxilia os usuários com recomendações de viagens e responde a perguntas relacionadas a passeios. Utilizaremos o Azure AI Foundry como nossa infraestrutura de IA. Siga os passos abaixo para criar um novo projeto:
- Acesse https://ai.azure.com e faça login.
- Clique no botão "Create a New Project" e selecione o recurso "Microsoft Foundry" quando solicitado.
- Defina os parâmetros necessários conforme sua conveniência.
- Após a criação do projeto, anote os seguintes valores na seção de visão geral:
- Azure OpenAI endpoint
- Api Key
- Vá para a seção "My Assets > Models + endpoints" e clique no botão "Deploy Model".
- Na tela que aparece, procure por "gpt-4o" (ou o modelo de sua preferência) e clique no botão "Confirm".
- Escolha um nome para sua implantação e anote-o.
- Em "deployment type", escolha "Global Standard".
- Selecione a região onde você tem cota suficiente disponível. Certifique-se de ter capacidade suficiente, em tokens por minuto, para não esgotá-los ao interagir com seu agente.
Com o projeto criado e a implantação concluída no Azure AI Foundry, podemos prosseguir com a codificação do agente.
Codificando o Agente TripAdvisor em C#
Para codificar nosso agente, utilizaremos a linguagem C#. Primeiramente, criaremos um novo projeto de console com o seguinte comando:
dotnet new console -n TripAdvisorAgent -f net10.0
Após a criação do projeto, navegaremos para a pasta do projeto:
cd TripAdvisorAgent/
Em seguida, instalaremos os seguintes pacotes NuGet:
dotnet add package Azure.Identity
dotnet add package Microsoft.Agent.Framework
dotnet add package Azure.AI.OpenAI --prerelease
dotnet add package Microsoft.Agents.AI.OpenAI --prerelease
dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.UserSecrets
dotnet add package Spectre.Console
Agora, configuraremos os segredos que utilizaremos, em vez de codificá-los diretamente no código:
dotnet user-secrets init
dotnet user-secrets set AZURE_OPENAI_ENDPOINT <your_azure_openai_endpoint>
dotnet user-secrets set AZURE_OPENAI_APIKEY <your_azure_openai_apikey>
dotnet user-secrets set AZURE_OPENAI_DEPLOYMENT <your_azure_openai_deployment>
Com os segredos configurados, podemos começar a adicionar o código ao nosso projeto.
Programa Principal (Program.cs) - Versão Inicial
O código abaixo demonstra a versão inicial do programa principal, que cria um agente utilizando o modelo implantado no Azure AI Foundry:
using System.ClientModel;
using Azure.AI.OpenAI;
using Microsoft.Extensions.Configuration;
using OpenAI.Chat;
using Spectre.Console;
// retrieves user secrets
var configuration = new ConfigurationBuilder ()
.AddUserSecrets<Program>()
.Build ();
var systemPrompt = @"
Your are a helpful trip advisor assistant, specialized in recommend activities, places to visit,
culinary tours and activities that tourist will enjoy.
If questions/requests are no related to any of previous subjects just respond 'I'm not able to respond to your request'.
";
// creation of an agent using deployed model in Azure AI Foundry
var agent = new AzureOpenAIClient (
endpoint: new Uri (configuration["AZURE_OPENAI_ENDPOINT"]),
new ApiKeyCredential (configuration["AZURE_OPENAI_APIKEY"])
)
.GetChatClient(configuration["AZURE_OPENAI_DEPLOYMENT"])
.CreateAIAgent(instructions: systemPrompt);
Console.Clear();
while (true)
{
var input = AnsiConsole.Ask<string>("[green]User:[/]");
if (string.IsNullOrEmpty (input))
continue;
if (string.Equals (input, "exit", StringComparison.InvariantCultureIgnoreCase))
break;
// pass the user request to the agent
var response = await agent.RunAsync(input);
Console.WriteLine ($"Agent: {response.Text}");
}
Embora não seja mencionado explicitamente, o agente é executado dentro de um AgentThread que gerencia o estado de uma conversa específica. Se nenhum for definido, um novo AgentThread será criado. Podemos executar o programa com o comando:
dotnet run
No entanto, o agente esquece tudo assim que responde. Para corrigir isso, precisamos fornecer memória ao nosso agente para que ele possa acompanhar a conversa.
Adicionando Memória ao Agente
O MAF oferece suporte a dois tipos de cenários para gerenciamento de memória:
- Armazenamento na memória: A memória é gerenciada pelo AgentThread onde o agente é executado.
- Armazenamento no serviço: A memória é armazenada no serviço onde o agente é construído. O AgentThread que executa o agente deve recuperar a memória desse armazenamento.
Neste exemplo, forneceremos memória ao nosso agente criando um armazenamento temporário na memória:
var messageHistory = new InMemoryChatMessageStore ();
var agentThread = agent.GetNewThread(messageHistory);
Ao criar explicitamente um AgentThread, podemos passar um provedor de memória para ele, neste caso, InMemoryChatMessageStore, para salvar toda a conversa. Isso permite que o agente esteja ciente de suas respostas anteriores. Além disso, nos dá a possibilidade de gerenciar o histórico de mensagens para realizar operações nele, como registrá-lo.
Programa Principal (Program.cs) - Com Memória
O código abaixo demonstra a versão do programa principal com a adição de memória:
using System.ClientModel;
using Azure.AI.OpenAI;
using Microsoft.Agents.AI;
using Microsoft.Extensions.Configuration;
using OpenAI.Chat;
using Spectre.Console;
// retrieves user secrets
var configuration = new ConfigurationBuilder ()
.AddUserSecrets<Program>()
.Build ();
var systemPrompt = @"
Your are a helpful trip advisor assistant, specialized in recommend activities, places to visit,
culinary tours and activities that tourist will enjoy.
If questions/requests are no related to any of previous subjects just respond 'I'm not able to respond to your request'.
";
// creation of an agent using deployed model in Azure AI Foundry
var agent = new AzureOpenAIClient (
endpoint: new Uri (configuration["AZURE_OPENAI_ENDPOINT"]),
new ApiKeyCredential (configuration["AZURE_OPENAI_APIKEY"])
)
.GetChatClient(configuration["AZURE_OPENAI_DEPLOYMENT"])
.CreateAIAgent(instructions: systemPrompt);
// create an InMemory store to hold all conversation messages
var messageHistory = new InMemoryChatMessageStore ();
var agentThread = agent.GetNewThread(messageHistory);
Console.Clear();
while (true)
{
var input = AnsiConsole.Ask<string>("[green]User:[/]");
if (string.IsNullOrEmpty (input))
continue;
if (string.Equals (input, "exit", StringComparison.InvariantCultureIgnoreCase))
break;
// pass the user request to the agent along with the AgentThread
// that will handle conversation state
var response = await agent.RunAsync(input, agentThread);
Console.WriteLine ($"Agent: {response.Text}");
}
// print every message in the history conversation (memory) to the console
AnsiConsole.Write(new Rule("[orange1]Conversation thread[/]") { Justification = Justify.Right });
foreach (var message in messageHistory)
{
AnsiConsole.Write(new Text (message.Role.Value + ": ", new Style(Color.Orange1)));
AnsiConsole.Write(new Text (message.Text + "
", new Style(Color.Orange1)));
AnsiConsole.Write(new Rule("[orange1]Message[/]") { Justification = Justify.Right });
}
Agora, nosso agente pode lembrar suas respostas anteriores e responder de acordo. Além disso, toda a conversa pode ser recuperada, gerenciada e auditada.
Integrando Ferramentas Externas com MCP
Um último aprimoramento que nosso agente pode se beneficiar é a capacidade de obter taxas de conversão de moeda. Para isso, adicionaremos ferramentas de um servidor MCP público que expõe esse tipo de operação.
O MAF oferece suporte à integração com servidores de protocolo de contexto de modelo por meio dos SDKs MCP oficiais. Para adicioná-lo ao nosso agente, precisamos criar um cliente MCP e buscar todas as ferramentas que ele expõe.
Primeiro, adicionaremos o pacote oficial do cliente MCP:
dotnet add package ModelContextProtocol --prerelease
Em seguida, criaremos o cliente MCP apontando para o endpoint que expõe as ferramentas:
var sharedHandler = new SocketsHttpHandler
{
PooledConnectionLifetime = TimeSpan.FromMinutes(2),
PooledConnectionIdleTimeout = TimeSpan.FromMinutes(1)
};
using var httpClient = new HttpClient (sharedHandler);
var transport = new HttpClientTransport (new ()
{
Endpoint = new Uri ("https://currency-mcp.wesbos.com/mcp"),
Name = "Currency Conversion",
}, httpClient);
var mcpClient = await McpClient.CreateAsync(transport);
var mcpTools = await mcpClient.ListToolsAsync().ConfigureAwait(false);
Finalmente, atualizaremos o prompt do sistema para instruir o agente a usar as ferramentas quando necessário:
var systemPrompt = @"
Your are a helpful trip advisor assistant, specialized in recommend activities, places to visit,
culinary tours and activities that tourist will enjoy.
If questions/requests are no related to any of previous subjects just respond 'I'm not able to respond to your request'.
Use tools provided if your information is outdated or need refinement.
";
Programa Principal (Program.cs) - Com MCP
O código abaixo demonstra a versão final do programa principal com a integração do cliente MCP:
using System.ClientModel;
using Azure.AI.OpenAI;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Configuration;
using ModelContextProtocol.Client;
using OpenAI.Chat;
using Spectre.Console;
// retrieves user secrets
var configuration = new ConfigurationBuilder ()
.AddUserSecrets<Program>()
.Build ();
// creates an HttpClient to be used to request MCP Server
var sharedHandler = new SocketsHttpHandler
{
PooledConnectionLifetime = TimeSpan.FromMinutes(2),
PooledConnectionIdleTimeout = TimeSpan.FromMinutes(1)
};
using var httpClient = new HttpClient (sharedHandler);
// create MCP client transport that will use HttpClient created
// when request to the endpoint
var transport = new HttpClientTransport (new ()
{
Endpoint = new Uri ("https://currency-mcp.wesbos.com/mcp"),
Name = "Currency Conversion",
}, httpClient);
// create mcp client and retrieve tools list from the server
var mcpClient = await McpClient.CreateAsync(transport);
var mcpTools = await mcpClient.ListToolsAsync().ConfigureAwait(false);
var systemPrompt = @"
Your are a helpful trip advisor assistant, specialized in recommend activities, places to visit,
culinary tours and activities that tourist will enjoy.
If questions/requests are no related to any of previous subjects just respond 'I'm not able to respond to your request'.
Use tools provided if your information is outdated or need refinement.
";
// creation of an agent using deployed model in Azure AI Foundry
// now including tools retrieved from mcp server
var agent = new AzureOpenAIClient (
endpoint: new Uri (configuration["AZURE_OPENAI_ENDPOINT"]),
new ApiKeyCredential (configuration["AZURE_OPENAI_APIKEY"])
)
.GetChatClient(configuration["AZURE_OPENAI_DEPLOYMENT"])
.CreateAIAgent(instructions: systemPrompt, tools: [..mcpTools.Cast<AITool>()]);
// create an InMemory store to hold all conversation messages
var messageHistory = new InMemoryChatMessageStore ();
var agentThread = agent.GetNewThread(messageHistory);
Console.Clear();
while (true)
{
var input = AnsiConsole.Ask<string>("[green]User:[/]");
if (string.IsNullOrEmpty (input))
continue;
if (string.Equals (input, "exit", StringComparison.InvariantCultureIgnoreCase))
break;
// pass the user request to the agent along with the agentthread
// that will handle conversation
var response = await agent.RunAsync(input, agentThread);
Console.WriteLine ($"Agent: {response.Text}");
}
// print every message in the history conversation (memory) to the console
AnsiConsole.Write(new Rule("[orange1]Conversation thread[/]") { Justification = Justify.Right });
foreach (var message in messageHistory)
{
AnsiConsole.Write(new Text (message.Role.Value + ": ", new Style(Color.Orange1)));
AnsiConsole.Write(new Text (message.Text + "
", new Style(Color.Orange1)));
AnsiConsole.Write(new Rule("[orange1]Message[/]") { Justification = Justify.Right });
}
Agora, podemos solicitar preços com mais confiança sobre as taxas de conversão.
Próximos Passos
O objetivo deste artigo é servir como uma prévia das capacidades do MAF e seu uso básico. No entanto, o exemplo apresentado aqui pode ser estendido adicionando outros elementos como:
- RAG (Retrieval-Augmented Generation): Ter um repositório com documentos fundamentais onde procurar primeiro quando o usuário faz uma solicitação dará ao agente base para responder prontamente e com precisão.
- Melhorar o registro interceptando mensagens com um middleware.
- Adicionar observabilidade com OpenTelemetry.
- Publicar nosso Agente para torná-lo publicamente disponível para todos.
Conclusão
O Microsoft Agent Framework, combinado com o poder do Azure AI Foundry, oferece uma plataforma robusta para a criação de agentes inteligentes capazes de automatizar