Microsoft Agent Framework пропускает рискованные вызовы инструментов через FunctionApprovalRequestContent
Оберните AIFunction в ApprovalRequiredAIFunction, и агент остановится посреди выполнения, чтобы запросить разрешение. Вот как работает поток запроса и ответа в C#.
Джереми Ликнесс опубликовал Building Blocks for AI Part 3 в .NET Blog 4 мая 2026 года, и часть, которую стоит выделить для всех, кто выводит агентов в продакшен, это поток одобрения вызовов инструментов с участием человека. Microsoft Agent Framework 1.0 (Microsoft.Agents.AI в NuGet) рассматривает это как первоклассное состояние выполнения: когда вызывается чувствительный инструмент, агент не вызывает его. Он приостанавливается, выводит вызов наружу и ждёт, пока ваше приложение одобрит или отклонит его, прежде чем следующее выполнение продолжится.
Пометьте функцию как требующую одобрения
Обёртка это ApprovalRequiredAIFunction. Вы создаёте обычный AIFunction из делегата, оборачиваете его один раз и затем передаёте обёрнутый экземпляр в AsAIAgent. Модель по-прежнему видит ту же схему; меняется только место вызова со стороны фреймворка.
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]);
Тело функции не меняется. Всё, что должно требовать шага подтверждения (записи в базу данных, платёжные вызовы, исходящая почта, всё, что вы не хотите запускать галлюцинированным аргументом), получает обёртку, и только это.
Обнаружьте запрос
Когда модель решает вызвать инструмент с обязательным одобрением, фреймворк возвращает ответ, содержащий один или несколько элементов FunctionApprovalRequestContent вместо возвращаемого значения инструмента. После каждого RunAsync вы сканируете содержимое сообщений в их поиске.
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 и FunctionCall.Arguments это то, что вы выводите пользователю. Покажите фактические аргументы, а не только имя функции. Весь смысл этой преграды в том, что модель сама выбрала аргументы, и delete_account(id: 42) это та часть, на которую вы хотите взгляд человека.
Отправьте ответ обратно
Ответ строится из самого запроса. requestContent.CreateResponse(true) производит FunctionApprovalResponseContent; передайте false, чтобы отклонить. Оберните это в пользовательское ChatMessage, запустите снова на той же сессии, и агент либо выполнит инструмент, либо продолжит без его результата.
var approvalMessage = new ChatMessage(
ChatRole.User,
[requests[0].CreateResponse(approve: true)]);
AgentResponse final = await agent.RunAsync(approvalMessage, session);
Console.WriteLine(final);
Циклитесь, не предполагайте
Один пользовательский ход может породить несколько запросов на одобрение, особенно с планировщиком, который пакетирует вызовы. Документация это явно подчёркивает: продолжайте искать FunctionApprovalRequestContent после каждого выполнения, пока ответ не перестанет их содержать. Если вы обработаете только первый запрос и сочтёте дело сделанным, вы тихо потеряете последующие вызовы инструментов и получите ответ, в котором не хватает данных.
Для сценариев workflow, AgentWorkflowBuilder.BuildSequential() уже понимает контракт одобрения: он приостанавливает workflow и испускает RequestInfoEvent, без дополнительной проводки. Полный исполняемый пример в репозитории microsoft/agent-framework, и API задокументирован на learn.microsoft.com.
Comments
Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.