Functiehulpprogramma's gebruiken met goedkeuringen waarbij mensen betrokken zijn.

Deze zelfstudiestap laat zien hoe u functiehulpprogramma's gebruikt waarvoor menselijke goedkeuring met een agent is vereist, waarbij de agent is gebouwd op de Azure OpenAI Chat Completion-service.

Wanneer agents gebruikersinvoer nodig hebben, bijvoorbeeld om een functieaanroep goed te keuren, wordt dit een human-in-the-loop-patroon genoemd. Een agentuitvoering waarvoor gebruikersinvoer is vereist, wordt voltooid met een antwoord dat aangeeft welke invoer van de gebruiker is vereist, in plaats van een definitief antwoord te voltooien. De aanroeper van de agent is vervolgens verantwoordelijk voor het ophalen van de vereiste invoer van de gebruiker en het aan de agent doorgeven ervan als onderdeel van een nieuwe agent-uitvoering.

Prerequisites

Zie de stap Een eenvoudige agent maken en uitvoeren in deze zelfstudie voor vereisten en het installeren van NuGet-pakketten.

De agent maken met functiehulpprogramma's

Wanneer u functies gebruikt, is het mogelijk om aan te geven voor elke functie, of er menselijke goedkeuring is vereist voordat deze wordt uitgevoerd. Dit wordt gedaan door het AIFunction exemplaar in een ApprovalRequiredAIFunction instantie te verpakken.

Hier volgt een voorbeeld van een eenvoudig hulpmiddel voor functies dat doet alsof het het weer voor een bepaalde locatie ophaalt.

using System;
using System.ComponentModel;
using System.Linq;
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 15°C.";

Als u een AIFunction en vervolgens in een ApprovalRequiredAIFunctionwilt verpakken, kunt u het volgende doen:

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

Wanneer u de agent creëert, kunt u nu de functie voor goedkeuring vereisend hulpprogramma aan de agent verschaffen door een lijst met hulpmiddelen door te geven aan de AsAIAgent methode.

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

Warning

DefaultAzureCredential is handig voor ontwikkeling, maar vereist zorgvuldige overwegingen in de productieomgeving. Overweeg in productie een specifieke referentie te gebruiken (bijvoorbeeld ManagedIdentityCredential) om latentieproblemen, onbedoelde referentieprobing en potentiële beveiligingsrisico's van terugvalmechanismen te voorkomen.

Omdat u nu een functie hebt waarvoor goedkeuring is vereist, kan de agent reageren met een aanvraag voor goedkeuring in plaats van de functie rechtstreeks uit te voeren en het resultaat te retourneren. U kunt de antwoordinhoud voor alle ToolApprovalRequestContent exemplaren controleren, wat aangeeft dat de agent goedkeuring van de gebruiker voor een functie vereist.

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

var toolApprovalRequests = response.Messages
    .SelectMany(x => x.Contents)
    .OfType<ToolApprovalRequestContent>()
    .ToList();

Als er aanvragen voor functiegoedkeuring zijn, is de functie-aanroep inclusief de naam en argumenten beschikbaar vanuit de ToolCall eigenschap op het ToolApprovalRequestContent exemplaar. Dit kan worden weergegeven aan de gebruiker, zodat hij of zij kan bepalen of de functieaanroep moet worden goedgekeurd of geweigerd. In dit voorbeeld wordt ervan uitgegaan dat er één aanvraag is.

ToolApprovalRequestContent requestContent = toolApprovalRequests.First();
var functionCall = (FunctionCallContent)requestContent.ToolCall;
Console.WriteLine($"We require approval to execute '{functionCall.Name}'");

Zodra de gebruiker zijn invoer heeft verstrekt, gebruikt u de methode CreateResponse op ToolApprovalRequestContent om het goedkeuringsantwoord te maken. Geef true door om de functie-aanroep goed te keuren of false om deze af te wijzen.

De antwoordinhoud kan vervolgens worden doorgegeven aan de agent in een nieuw UserChatMessagesessieobject, samen met hetzelfde sessieobject om het resultaat van de agent terug te krijgen.

var approvalMessage = new ChatMessage(ChatRole.User, [requestContent.CreateResponse(true)]);
Console.WriteLine(await agent.RunAsync(approvalMessage, session));

Wanneer u functietools gebruikt met menselijke goedkeuringen in de cyclus, moet u nagaan op ToolApprovalRequestContent exemplaren in het antwoord na elke agentuitvoering, totdat alle functieaanroepen zijn goedgekeurd of geweigerd.

Tip

Zie de .NET Agents Stap 01: Functiehulpprogramma's gebruiken met Goedkeuringen voor een compleet en uitvoerbaar voorbeeld.

In deze zelfstudie leert u hoe u functiehulpprogramma's gebruikt waarvoor goedkeuring door een mens met behulp van een agent vereist is.

Wanneer agents gebruikersinvoer nodig hebben, bijvoorbeeld om een functieaanroep goed te keuren, wordt dit een human-in-the-loop-patroon genoemd. Een agentuitvoering waarvoor gebruikersinvoer is vereist, wordt voltooid met een antwoord dat aangeeft welke invoer van de gebruiker is vereist, in plaats van een definitief antwoord te voltooien. De aanroeper van de agent is vervolgens verantwoordelijk voor het ophalen van de vereiste invoer van de gebruiker en het aan de agent doorgeven ervan als onderdeel van een nieuwe agent-uitvoering.

Prerequisites

Zie de stap Een eenvoudige agent maken en uitvoeren in deze zelfstudie voor vereisten en het installeren van Python-pakketten.

Maak de agent met functionaliteiten waarvoor goedkeuring is vereist

Wanneer u functies gebruikt, is het mogelijk om aan te geven voor elke functie, of er menselijke goedkeuring is vereist voordat deze wordt uitgevoerd. Dit wordt bereikt door de approval_mode parameter op "always_require" te zetten wanneer de @tool decorator wordt gebruikt.

Hier volgt een voorbeeld van een eenvoudig hulpmiddel voor functies dat doet alsof het het weer voor een bepaalde locatie ophaalt.

from typing import Annotated
from agent_framework import tool

@tool
def get_weather(location: Annotated[str, "The city and state, e.g. San Francisco, CA"]) -> str:
    """Get the current weather for a given location."""
    return f"The weather in {location} is cloudy with a high of 15°C."

Als u een functie wilt maken waarvoor goedkeuring is vereist, kunt u de approval_mode parameter gebruiken:

@tool(approval_mode="always_require")
def get_weather_detail(location: Annotated[str, "The city and state, e.g. San Francisco, CA"]) -> str:
    """Get detailed weather information for a given location."""
    return f"The weather in {location} is cloudy with a high of 15°C, humidity 88%."

Wanneer u de agent maakt, kunt u nu de functiehulpprogramma's die goedkeuring vereisen aan de agent toewijzen door een lijst met hulpprogramma's door te geven aan de Agent constructor.

from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient

async with Agent(
    client=OpenAIChatClient(),
    name="WeatherAgent",
    instructions="You are a helpful weather assistant.",
    tools=[get_weather, get_weather_detail],
) as agent:
    # Agent is ready to use
    pass

Omdat u nu een functie hebt waarvoor goedkeuring is vereist, kan de agent reageren met een aanvraag voor goedkeuring in plaats van de functie rechtstreeks uit te voeren en het resultaat te retourneren. U kunt het antwoord controleren op aanvragen voor gebruikersinvoer. Dit geeft aan dat de agent goedkeuring van de gebruiker voor een functie vereist.

result = await agent.run("What is the detailed weather like in Amsterdam?")

if result.user_input_requests:
    for user_input_needed in result.user_input_requests:
        if user_input_needed.function_call is None:
            continue
        print(f"Function: {user_input_needed.function_call.name}")
        print(f"Arguments: {user_input_needed.function_call.arguments}")

Als er aanvragen voor functiegoedkeuring zijn, kunt u de details van de functieaanroep, inclusief naam en argumenten, vinden in de function_call eigenschap van de invoeraanvraag van de gebruiker. Dit kan worden weergegeven aan de gebruiker, zodat hij of zij kan bepalen of de functieaanroep moet worden goedgekeurd of geweigerd.

Zodra de gebruiker zijn invoer heeft opgegeven, kunt u een antwoord maken met behulp van de to_function_approval_response methode voor de invoeraanvraag van de gebruiker. Geef True door om de functie-aanroep goed te keuren of False om deze af te wijzen.

Het antwoord kan vervolgens worden doorgegeven aan de agent in een nieuwe Message, om het resultaat van de agent terug te ontvangen.

from agent_framework import Message

# Get user approval (in a real application, this would be interactive)
user_approval = True  # or False to reject

# Create the approval response
approval_message = Message(
    role="user",
    contents=[user_input_needed.to_function_approval_response(user_approval)]
)

# Continue the conversation with the approval
final_result = await agent.run([
    "What is the detailed weather like in Amsterdam?",
    Message(role="assistant", contents=[user_input_needed]),
    approval_message
])
print(final_result.text)

Goedkeuringen verwerken in een lus

Wanneer u werkt met meerdere functie-aanroepen waarvoor goedkeuring is vereist, moet u mogelijk goedkeuringen in een lus verwerken totdat alle functies zijn goedgekeurd of geweigerd:

async def handle_approvals(query: str, agent) -> str:
    """Handle function call approvals in a loop."""
    current_input = query

    while True:
        result = await agent.run(current_input)

        if not result.user_input_requests:
            # No more approvals needed, return the final result
            return result.text

        # Build new input with all context
        new_inputs = [query]

        for user_input_needed in result.user_input_requests:
            if user_input_needed.function_call is None:
                continue
            print(f"Approval needed for: {user_input_needed.function_call.name}")
            print(f"Arguments: {user_input_needed.function_call.arguments}")

            # Add the assistant message with the approval request
            new_inputs.append(Message(role="assistant", contents=[user_input_needed]))

            # Get user approval (in practice, this would be interactive)
            user_approval = True  # Replace with actual user input

            # Add the user's approval response
            new_inputs.append(
                Message(role="user", contents=[user_input_needed.to_function_approval_response(user_approval)])
            )

        # Continue with all the context
        current_input = new_inputs

# Usage
result_text = await handle_approvals("Get detailed weather for Seattle and Portland", agent)
print(result_text)

Wanneer u functietools met menselijke goedkeuringen in de controlelus gebruikt, vergeet niet te controleren op gebruikersinvoer aanvragen in de reactie, nadat elke agent run is voltooid, totdat alle functieaanroepen zijn goedgekeurd of geweigerd.

Volledig voorbeeld

# Copyright (c) Microsoft. All rights reserved.

import asyncio
from random import randrange
from typing import TYPE_CHECKING, Annotated, Any

from agent_framework import Agent, AgentResponse, Message, tool
from agent_framework.openai import OpenAIChatClient

if TYPE_CHECKING:
    from agent_framework import SupportsAgentRun

"""
Demonstration of a tool with approvals.

This sample demonstrates using AI functions with user approval workflows.
It shows how to handle function call approvals without using threads.
"""

conditions = ["sunny", "cloudy", "raining", "snowing", "clear"]


# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(location: Annotated[str, "The city and state, e.g. San Francisco, CA"]) -> str:
    """Get the current weather for a given location."""
    # Simulate weather data
    return f"The weather in {location} is {conditions[randrange(0, len(conditions))]} and {randrange(-10, 30)}°C."


# Define a simple weather tool that requires approval
@tool(approval_mode="always_require")
def get_weather_detail(location: Annotated[str, "The city and state, e.g. San Francisco, CA"]) -> str:
    """Get the current weather for a given location."""
    # Simulate weather data
    return (
        f"The weather in {location} is {conditions[randrange(0, len(conditions))]} and {randrange(-10, 30)}°C, "
        "with a humidity of 88%. "
        f"Tomorrow will be {conditions[randrange(0, len(conditions))]} with a high of {randrange(-10, 30)}°C."
    )


async def handle_approvals(query: str, agent: "SupportsAgentRun") -> AgentResponse:
    """Handle function call approvals.

    When we don't have a thread, we need to ensure we include the original query,
    the approval request, and the approval response in each iteration.
    """
    result = await agent.run(query)
    while len(result.user_input_requests) > 0:
        # Start with the original query
        new_inputs: list[Any] = [query]

        for user_input_needed in result.user_input_requests:
            print(
                f"\nUser Input Request for function from {agent.name}:"
                f"\n  Function: {user_input_needed.function_call.name}"
                f"\n  Arguments: {user_input_needed.function_call.arguments}"
            )

            # Add the assistant message with the approval request
            new_inputs.append(Message("assistant", [user_input_needed]))

            # Get user approval
            user_approval = await asyncio.to_thread(input, "\nApprove function call? (y/n): ")

            # Add the user's approval response
            new_inputs.append(
                Message("user", [user_input_needed.to_function_approval_response(user_approval.lower() == "y")])
            )

        # Run again with all the context
        result = await agent.run(new_inputs)

    return result


async def handle_approvals_streaming(query: str, agent: "SupportsAgentRun") -> None:
    """Handle function call approvals with streaming responses.

    When we don't have a thread, we need to ensure we include the original query,
    the approval request, and the approval response in each iteration.
    """
    current_input: str | list[Any] = query
    has_user_input_requests = True
    while has_user_input_requests:
        has_user_input_requests = False
        user_input_requests: list[Any] = []

        # Stream the response
        async for chunk in agent.run(current_input, stream=True):
            if chunk.text:
                print(chunk.text, end="", flush=True)

            # Collect user input requests from the stream
            if chunk.user_input_requests:
                user_input_requests.extend(chunk.user_input_requests)

        if user_input_requests:
            has_user_input_requests = True
            # Start with the original query
            new_inputs: list[Any] = [query]

            for user_input_needed in user_input_requests:
                print(
                    f"\n\nUser Input Request for function from {agent.name}:"
                    f"\n  Function: {user_input_needed.function_call.name}"
                    f"\n  Arguments: {user_input_needed.function_call.arguments}"
                )

                # Add the assistant message with the approval request
                new_inputs.append(Message("assistant", [user_input_needed]))

                # Get user approval
                user_approval = await asyncio.to_thread(input, "\nApprove function call? (y/n): ")

                # Add the user's approval response
                new_inputs.append(
                    Message("user", [user_input_needed.to_function_approval_response(user_approval.lower() == "y")])
                )

            # Update input with all the context for next iteration
            current_input = new_inputs


async def run_weather_agent_with_approval(stream: bool) -> None:
    """Example showing AI function with approval requirement."""
    print(f"\n=== Weather Agent with Approval Required ({'Streaming' if stream else 'Non-Streaming'}) ===\n")

    async with Agent(
        client=OpenAIChatClient(),
        name="WeatherAgent",
        instructions=("You are a helpful weather assistant. Use the get_weather tool to provide weather information."),
        tools=[get_weather, get_weather_detail],
    ) as agent:
        query = "Can you give me an update of the weather in LA and Portland and detailed weather for Seattle?"
        print(f"User: {query}")

        if stream:
            print(f"\n{agent.name}: ", end="", flush=True)
            await handle_approvals_streaming(query, agent)
            print()
        else:
            result = await handle_approvals(query, agent)
            print(f"\n{agent.name}: {result}\n")


async def main() -> None:
    print("=== Demonstration of a tool with approvals ===\n")

    await run_weather_agent_with_approval(stream=False)
    await run_weather_agent_with_approval(stream=True)


if __name__ == "__main__":
    asyncio.run(main())

Goedkeuring van tools

U kunt menselijke goedkeuring vereisen voordat een hulpprogramma wordt uitgevoerd door het te verpakken met tool.ApprovalRequiredFunc:

import "github.com/microsoft/agent-framework-go/tool"

approvedWeatherTool := tool.ApprovalRequiredFunc(weatherTool)

a := foundryprovider.NewAgent(endpoint, token, foundryprovider.ModelDeployment(model), foundryprovider.AgentConfig{
    Instructions: "You are a helpful assistant.",
    Config: agent.Config{
        Tools: []tool.Tool{approvedWeatherTool},
    },
})

Wanneer het model een aanroep van een hulpprogramma aanvraagt, onderschept het framework het en wacht op goedkeuring voordat het wordt uitgevoerd. De goedkeuringsstroom wordt verwerkt via middleware.

Goedkeuring voor tools gebruiken met Harness Agent

Eenvoudige/handmatige samenstelling vereist een hulpmiddel met goedkeuringsmarkering en een feedbacklus voor goedkeuring. Een Harness Agent maakt gebruik van dezelfde door goedkeuring gemarkeerde hulpprogramma's en antwoordinhoud, maar installeert ook middleware voor aanvragen in de wachtrij, permanente 'altijd goedkeuren'-regels en optionele heuristische automatische goedkeuring.

Verpakken functies waarvoor goedkeuring ApprovalRequiredAIFunctionis vereist en voeg ze vervolgens toe via HarnessAgentOptions.ChatOptions.Tools:

using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;

var weatherTool = new ApprovalRequiredAIFunction(
    AIFunctionFactory.Create(GetWeather));

AIAgent agent = chatClient.AsHarnessAgent(new HarnessAgentOptions
{
    ChatOptions = new ChatOptions
    {
        Instructions = "You are a helpful assistant.",
        Tools = [weatherTool],
    },
});

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

DisableToolAutoApproval is standaard ingesteld op false, dus het harnas voegt ToolApprovalAgent toe. Met de standaardinstelling ToolApprovalAgentOptionsworden er geen heuristische regels geconfigureerd. Niet-overeenkomende ToolApprovalRequestContent items worden nog steeds teruggezet naar de aanroeper voor goedkeuring. Om vertrouwde callbacks voor automatische goedkeuring toe te voegen, stelt u ToolApprovalAgentOptions.AutoApprovalRules in.

Wanneer u DisableToolAutoApproval = true instelt, wordt alleen de middleware voor automatische goedkeuring op basis van permanente regels, wachtrijen en heuristiek verwijderd. De goedkeuringsvereiste wordt niet verwijderd uit een ApprovalRequiredAIFunction. Binding van goedkeuringsreacties en het omzeilen van hulpprogramma's waarvoor geen goedkeuring is vereist, blijven ook standaard ingeschakeld; hun afzonderlijke opt-outs zijn DisableApprovalResponseBinding en DisableApprovalNotRequiredFunctionBypassing.

Markeer het gereedschap met approval_mode="always_require" en geef het door aan create_harness_agent:

from agent_framework import create_harness_agent, tool

@tool(approval_mode="always_require")
def get_weather_detail(location: str) -> str:
    """Get detailed weather information for a location."""
    return f"The weather in {location} is cloudy with a high of 15°C."

agent = create_harness_agent(
    client=client,
    agent_instructions="You are a helpful weather assistant.",
    tools=get_weather_detail,
)

session = agent.create_session()
result = await agent.run(
    "What is the detailed weather like in Amsterdam?",
    session=session,
)

disable_tool_auto_approval=False voegt standaard toe ToolApprovalMiddleware . De middleware vereist hetzelfde AgentSession gedurende goedkeuringsrondes, zet meerdere verzoeken in de wachtrij, past doorlopende goedkeuringen uit eerdere gebruikersreacties toe en evalueert auto_approval_rules voordat een verzoek naar de aanroeper wordt teruggestuurd. Met auto_approval_rules=None keurt geen enkele heuristische callback automatisch een oproep goed.

Door disable_tool_auto_approval=True in te stellen, wordt die harness-middleware verwijderd, maar verandert de approval_mode van de tool niet; het normale result.user_input_requests-goedkeuringsproces blijft van toepassing.

Een verpakt Go-harnas is momenteel niet beschikbaar. Verpak hulpprogramma's waarvoor goedkeuring is vereist met tool.ApprovalRequiredFunc en stel de goedkeuringsmiddleware rechtstreeks samen.

Volgende stappen