在有人参与的审批循环中使用函数工具

本教程步骤介绍如何使用需要人工审批的函数工具,该代理是在 Azure OpenAI 聊天完成服务上构建的。

当代理需要任何用户输入(例如批准函数调用)时,这称为人机循环模式。 需要用户输入的代理运行完成时将提供说明用户需要输入哪些内容的响应,而不是提供最终答案。 然后,代理的调用方负责从用户获取所需的输入,并在新代理运行过程中将其传回代理。

先决条件

有关先决条件和安装 NuGet 包,请参阅本教程中的 “创建并运行简单代理 ”步骤。

使用函数工具创建代理

使用函数时,可以为每个函数指示它是否需要人工批准才能执行。 这是通过在AIFunction实例中包装ApprovalRequiredAIFunction实例来完成的。

下面是一个简单的函数工具示例,该工具用于模拟获取给定位置的天气。

using System;
using System.ComponentModel;
using System.Linq;
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using OpenAI;

[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.";

若要创建一个 AIFunction 并将其包装在一个 ApprovalRequiredAIFunction 中,可以执行以下步骤:

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

创建代理时,现在可以通过将一个包含工具的列表传递给 CreateAIAgent 方法,向代理提供需要审批功能的工具。

AIAgent agent = new AzureOpenAIClient(
    new Uri("https://<myresource>.openai.azure.com"),
    new AzureCliCredential())
     .GetChatClient("gpt-4o-mini")
     .CreateAIAgent(instructions: "You are a helpful assistant", tools: [approvalRequiredWeatherFunction]);

由于现在有一个需要审批的函数,因此代理可能会响应审批请求,而不是直接执行函数并返回结果。 可以检查任何 FunctionApprovalRequestContent 实例的响应内容,指示代理需要用户批准函数。

AgentThread thread = agent.GetNewThread();
AgentRunResponse response = await agent.RunAsync("What is the weather like in Amsterdam?", thread);

var functionApprovalRequests = response.Messages
    .SelectMany(x => x.Contents)
    .OfType<FunctionApprovalRequestContent>()
    .ToList();

如果有任何函数审批请求,可以在实例的属性FunctionCall中找到FunctionApprovalRequestContent函数调用的详细信息,包括名称和参数。 这可以向用户显示,以便他们可以决定是批准还是拒绝函数调用。 对于此示例,假设有一个请求。

FunctionApprovalRequestContent requestContent = functionApprovalRequests.First();
Console.WriteLine($"We require approval to execute '{requestContent.FunctionCall.Name}'");

用户提供输入后,可以在FunctionApprovalResponseContent上使用CreateResponse方法创建一个FunctionApprovalRequestContent实例。 传递 true 以批准函数调用,或 false 拒绝它。

然后,响应内容可以传递到新的UserChatMessage中,并且将相同的线程对象传递给代理,以便从代理中获取结果。

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

每当使用包含人类介入的审批流程的功能工具时,请记住在每次代理运行后检查 FunctionApprovalRequestContent 响应中的实例,直到所有功能调用都获得批准或拒绝。

本教程步骤展示如何使用需要人工批准并与代理配合的函数工具。

当代理需要任何用户输入(例如批准函数调用)时,这称为人机循环模式。 需要用户输入的代理运行完成时将提供说明用户需要输入哪些内容的响应,而不是提供最终答案。 然后,代理的调用方负责从用户获取所需的输入,并在新代理运行过程中将其传回代理。

先决条件

有关先决条件和安装 Python 包,请参阅本教程中的 “创建并运行简单代理 ”步骤。

使用需要审批的函数工具创建代理

使用函数时,可以为每个函数指示它是否需要人工批准才能执行。 通过使用@ai_function修饰器时,将approval_mode参数设置为"always_require"来完成此操作。

下面是一个简单的函数工具示例,该工具用于模拟获取给定位置的天气。

from typing import Annotated
from agent_framework import ai_function

@ai_function
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."

若要创建需要审批的函数,可以使用 approval_mode 参数:

@ai_function(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%."

现在,在创建代理时,您可以通过将包含审批功能的工具列表传递给ChatAgent构造函数,为代理提供此工具。

from agent_framework import ChatAgent
from agent_framework.openai import OpenAIResponsesClient

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

由于现在有一个需要审批的函数,因此代理可能会响应审批请求,而不是直接执行函数并返回结果。 可以检查任何用户输入请求的响应,这表示代理需要用户批准函数。

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:
        print(f"Function: {user_input_needed.function_call.name}")
        print(f"Arguments: {user_input_needed.function_call.arguments}")

如果有任何函数审批请求,可以在用户输入请求的属性中找到 function_call 函数调用的详细信息,包括名称和参数。 这可以向用户显示,以便他们可以决定是批准还是拒绝函数调用。

用户提供输入后,您可以使用create_response方法在用户输入请求上创建响应。 传递 True 以批准函数调用,或 False 拒绝它。

然后,可以通过新的 ChatMessage将响应传递到代理,以便从代理中获取结果。

from agent_framework import ChatMessage, Role

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

# Create the approval response
approval_message = ChatMessage(
    role=Role.USER, 
    contents=[user_input_needed.create_response(user_approval)]
)

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

在循环中处理审批

使用需要审批的多个函数调用时,可能需要在一个循环中处理审批,直到所有函数获得批准或拒绝:

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:
            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(ChatMessage(role=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(
                ChatMessage(role=Role.USER, contents=[user_input_needed.create_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)

每当使用具有人工审核流程的函数工具时,请记住在每次代理执行后,在响应中检查用户输入请求,直到所有函数调用都获得批准或被拒绝。

后续步骤