Start Debugging

Microsoft Agent Framework controla chamadas de ferramentas arriscadas com FunctionApprovalRequestContent

Envolva um AIFunction em ApprovalRequiredAIFunction e o agente para no meio da execução para pedir permissão. Veja como funciona o fluxo de requisição e resposta em C#.

Jeremy Likness publicou Building Blocks for AI Part 3 no .NET Blog em 4 de maio de 2026, e a parte que vale a pena destacar para quem coloca agentes em produção é o fluxo de aprovação humana no laço de chamadas de ferramentas. O Microsoft Agent Framework 1.0 (Microsoft.Agents.AI no NuGet) trata isso como um estado de execução de primeira classe: quando uma ferramenta sensível é invocada, o agente não a chama. Ele pausa, expõe a chamada e espera que sua aplicação aprove ou rejeite antes que a próxima execução continue.

Marque uma função como exigindo aprovação

O wrapper é ApprovalRequiredAIFunction. Você constrói um AIFunction normal a partir de um delegate, envolve uma vez e depois passa a instância envolvida para AsAIAgent. O modelo continua vendo o mesmo schema; apenas o ponto de chamada do framework muda.

using System.ComponentModel;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;

[Description("Get the weather for a given location.")]
static string GetWeather([Description("The location to get the weather for.")] string location)
    => $"The weather in {location} is cloudy with a high of 15C.";

AIFunction weatherFunction = AIFunctionFactory.Create(GetWeather);
AIFunction approvalRequired = new ApprovalRequiredAIFunction(weatherFunction);

AIAgent agent = new AIProjectClient(
    new Uri("<your-foundry-project-endpoint>"),
    new DefaultAzureCredential())
    .AsAIAgent(
        model: "gpt-4o-mini",
        instructions: "You are a helpful assistant",
        tools: [approvalRequired]);

Você não muda o corpo da função. Qualquer coisa que deva exigir um passo de confirmação (escritas no banco de dados, chamadas de pagamento, e-mails de saída, qualquer coisa que você não queira que um argumento alucinado dispare) recebe o wrapper, e somente essas.

Detecte a requisição

Quando o modelo decide chamar uma ferramenta gated por aprovação, o framework retorna uma resposta que contém um ou mais itens FunctionApprovalRequestContent em vez do valor de retorno da ferramenta. Depois de cada RunAsync, você varre o conteúdo das mensagens em busca deles.

AgentSession session = await agent.CreateSessionAsync();
AgentResponse response = await agent.RunAsync(
    "What is the weather like in Amsterdam?", session);

var requests = response.Messages
    .SelectMany(m => m.Contents)
    .OfType<FunctionApprovalRequestContent>()
    .ToList();

foreach (var req in requests)
{
    Console.WriteLine($"Approval needed for {req.FunctionCall.Name}");
    Console.WriteLine($"Arguments: {req.FunctionCall.Arguments}");
}

FunctionCall.Name e FunctionCall.Arguments são o que você renderiza para o usuário. Mostre os argumentos reais, não apenas o nome da função. O propósito do gate é que o modelo escolheu os argumentos, e delete_account(id: 42) é a parte sobre a qual você quer um olho humano.

Devolva a resposta

A resposta é construída a partir da própria requisição. requestContent.CreateResponse(true) produz um FunctionApprovalResponseContent; passe false para rejeitar. Envolva em um ChatMessage de usuário, execute novamente na mesma sessão, e o agente ou executa a ferramenta ou prossegue sem o resultado dela.

var approvalMessage = new ChatMessage(
    ChatRole.User,
    [requests[0].CreateResponse(approve: true)]);

AgentResponse final = await agent.RunAsync(approvalMessage, session);
Console.WriteLine(final);

Itere, não assuma

Um único turno de usuário pode produzir várias requisições de aprovação, especialmente com um planejador que agrupa chamadas. A documentação é explícita: continue procurando por FunctionApprovalRequestContent depois de cada execução até que a resposta não contenha nenhum. Se você tratar apenas a primeira requisição e considerar finalizado, vai descartar silenciosamente as chamadas de ferramenta subsequentes e terminar com uma resposta que está faltando dados.

Para cenários de workflow, AgentWorkflowBuilder.BuildSequential() já entende o contrato de aprovação: pausa o workflow e emite um RequestInfoEvent, sem encanamento extra. Exemplo executável completo no repositório microsoft/agent-framework, e a API está documentada em learn.microsoft.com.

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< Voltar