다음을 통해 공유


핸드오프 오케스트레이션

중요합니다

에이전트 프레임워크의 에이전트 오케스트레이션 기능은 실험적 단계에 있습니다. 현재 개발 중이며 미리 보기 또는 릴리스 후보 단계로 넘어가기 전에 크게 변경될 수 있습니다.

핸드오프 오케스트레이션을 사용하면 에이전트가 컨텍스트 또는 사용자 요청에 따라 서로 제어를 전송할 수 있습니다. 각 에이전트는 적절한 전문 지식을 갖춘 다른 에이전트에게 대화를 "전달"하여 올바른 에이전트가 작업의 각 부분을 처리하도록 할 수 있습니다. 이는 고객 지원, 전문가 시스템 또는 동적 위임이 필요한 시나리오에서 특히 유용합니다.

패턴을 사용하는 시기 또는 워크로드에서 패턴을 피해야 하는 경우와 같은 패턴에 대한 자세한 내용은 핸드오프 오케스트레이션을 참조하세요.

일반 사용 예

고객 지원 에이전트는 일반 문의를 처리한 다음, 문제 해결을 위해 기술 전문가 에이전트 또는 필요한 경우 청구 에이전트에게 전달합니다.

다이어그램

학습 내용

  • 에이전트 및 해당 핸드오프 관계를 정의하는 방법
  • 동적 에이전트 라우팅을 위한 핸드오프 오케스트레이션을 설정하는 방법
  • 대화 루프에 인간을 참여시키는 방법

특수 에이전트 정의

각 에이전트는 특정 영역을 담당합니다. 이 예제에서는 심사 에이전트, 환불 에이전트, 주문 상태 에이전트 및 주문 반환 에이전트를 정의합니다. 일부 에이전트는 플러그 인을 사용하여 특정 작업을 처리합니다.

팁 (조언)

여기서 ChatCompletionAgent 는 사용되지만 모든 에이전트 유형을 사용할 수 있습니다.

using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Agents.Orchestration;
using Microsoft.SemanticKernel.Agents.Orchestration.Handoff;
using Microsoft.SemanticKernel.Agents.Runtime.InProcess;
using Microsoft.SemanticKernel.ChatCompletion;

// Plugin implementations
public sealed class OrderStatusPlugin {
    [KernelFunction]
    public string CheckOrderStatus(string orderId) => $"Order {orderId} is shipped and will arrive in 2-3 days.";
}
public sealed class OrderReturnPlugin {
    [KernelFunction]
    public string ProcessReturn(string orderId, string reason) => $"Return for order {orderId} has been processed successfully.";
}
public sealed class OrderRefundPlugin {
    [KernelFunction]
    public string ProcessReturn(string orderId, string reason) => $"Refund for order {orderId} has been processed successfully.";
}

// Helper function to create a kernel with chat completion
public static Kernel CreateKernelWithChatCompletion(...)
{
    ...
}

ChatCompletionAgent triageAgent = new ChatCompletionAgent {
    Name = "TriageAgent",
    Description = "Handle customer requests.",
    Instructions = "A customer support agent that triages issues.",
    Kernel = CreateKernelWithChatCompletion(...),
};

ChatCompletionAgent statusAgent = new ChatCompletionAgent {
    Name = "OrderStatusAgent",
    Description = "A customer support agent that checks order status.",
    Instructions = "Handle order status requests.",
    Kernel = CreateKernelWithChatCompletion(...),
};
statusAgent.Kernel.Plugins.Add(KernelPluginFactory.CreateFromObject(new OrderStatusPlugin()));

ChatCompletionAgent returnAgent = new ChatCompletionAgent {
    Name = "OrderReturnAgent",
    Description = "A customer support agent that handles order returns.",
    Instructions = "Handle order return requests.",
    Kernel = CreateKernelWithChatCompletion(...),
};
returnAgent.Kernel.Plugins.Add(KernelPluginFactory.CreateFromObject(new OrderReturnPlugin()));

ChatCompletionAgent refundAgent = new ChatCompletionAgent {
    Name = "OrderRefundAgent",
    Description = "A customer support agent that handles order refund.",
    Instructions = "Handle order refund requests.",
    Kernel = CreateKernelWithChatCompletion(...),
};
refundAgent.Kernel.Plugins.Add(KernelPluginFactory.CreateFromObject(new OrderRefundPlugin()));

핸드오프 관계를 설정하기

OrchestrationHandoffs를 사용하여 어떤 에이전트가 어떤 경우에 누구에게 업무를 넘길 수 있는지를 지정합니다.

var handoffs = OrchestrationHandoffs
    .StartWith(triageAgent)
    .Add(triageAgent, statusAgent, returnAgent, refundAgent)
    .Add(statusAgent, triageAgent, "Transfer to this agent if the issue is not status related")
    .Add(returnAgent, triageAgent, "Transfer to this agent if the issue is not return related")
    .Add(refundAgent, triageAgent, "Transfer to this agent if the issue is not refund related");

에이전트 응답 관찰

속성을 통해 대화가 진행됨에 따라 에이전트 응답을 캡처하는 콜백을 ResponseCallback 만들 수 있습니다.

ChatHistory history = [];

ValueTask responseCallback(ChatMessageContent response)
{
    history.Add(response);
    return ValueTask.CompletedTask;
}

휴먼 인 더 루프

핸드오프 오케스트레이션의 주요 기능은 사람이 대화에 참여할 수 있는 기능입니다. 이는 에이전트가 사용자의 입력을 필요로 할 때마다 호출되는 InteractiveCallback을 제공하여 달성됩니다. 실제 애플리케이션에서는 사용자에게 입력하라는 메시지가 표시됩니다. 샘플에서 응답 큐를 사용할 수 있습니다.

// Simulate user input with a queue
Queue<string> responses = new();
responses.Enqueue("I'd like to track the status of my order");
responses.Enqueue("My order ID is 123");
responses.Enqueue("I want to return another order of mine");
responses.Enqueue("Order ID 321");
responses.Enqueue("Broken item");
responses.Enqueue("No, bye");

ValueTask<ChatMessageContent> interactiveCallback()
{
    string input = responses.Dequeue();
    Console.WriteLine($"\n# INPUT: {input}\n");
    return ValueTask.FromResult(new ChatMessageContent(AuthorRole.User, input));
}

핸드오프 오케스트레이션 설정

에이전트, 핸드오프 관계 및 콜백을 전달하여 HandoffOrchestration 객체를 만듭니다.

HandoffOrchestration orchestration = new HandoffOrchestration(
    handoffs,
    triageAgent,
    statusAgent,
    returnAgent,
    refundAgent)
{
    InteractiveCallback = interactiveCallback,
    ResponseCallback = responseCallback,
};

런타임 시작

에이전트 실행을 관리하려면 런타임이 필요합니다. 여기서는 오케스트레이션을 호출하기 전에 InProcessRuntime를 사용하고 시작합니다.

InProcessRuntime runtime = new InProcessRuntime();
await runtime.StartAsync();

오케스트레이션 호출

초기 작업(예: "내 주문에 도움이 필요한 고객")을 사용하여 오케스트레이션을 호출합니다. 에이전트는 필요에 따라 대화를 라우팅하고 필요한 경우 인간과 연결합니다.

string task = "I am a customer that needs help with my orders";
var result = await orchestration.InvokeAsync(task, runtime);

결과 수집

오케스트레이션이 완료되고 최종 출력을 가져올 때까지 기다립니다.

string output = await result.GetValueAsync(TimeSpan.FromSeconds(300));
Console.WriteLine($"\n# RESULT: {output}");
Console.WriteLine("\n\nORCHESTRATION HISTORY");
foreach (ChatMessageContent message in history)
{
    // Print each message
    Console.WriteLine($"# {message.Role} - {message.AuthorName}: {message.Content}");
}

선택 사항: 런타임 중지

처리가 완료되면 런타임을 중지하여 리소스를 정리합니다.

await runtime.RunUntilIdleAsync();

샘플 출력

# RESULT: Handled order return for order ID 321 due to a broken item, and successfully processed the return.

ORCHESTRATION HISTORY

# Assistant - TriageAgent: Could you please specify what kind of help you need with your orders? Are you looking to check the order status, return an item, or request a refund?

# Assistant - OrderStatusAgent: Could you please tell me your order ID?

# Assistant - OrderStatusAgent: Your order with ID 123 has been shipped and will arrive in 2-3 days. Anything else I can assist you with?

# Assistant - OrderReturnAgent: I can help you with that. Could you please provide the order ID and the reason you'd like to return it?

# Assistant - OrderReturnAgent: Please provide the reason for returning the order with ID 321.

# Assistant - OrderReturnAgent: The return for your order with ID 321 has been successfully processed due to the broken item. Anything else I can assist you with?

팁 (조언)

전체 샘플 코드는 여기에서 사용할 수 있습니다.

특수 에이전트 정의

각 에이전트는 특정 영역을 담당합니다. 다음은 그 예입니다.

  • TriageAgent: 초기 고객 요청을 처리하고 관련 전문가를 결정합니다.
  • RefundAgent: 환불 요청을 처리합니다.
  • OrderStatusAgent: 주문 상태를 확인합니다.
  • OrderReturnAgent: 주문 반환을 처리합니다.

플러그 인

먼저 에이전트에서 사용할 플러그 인을 정의해야 합니다. 이러한 플러그 인에는 특정 작업을 처리하기 위한 논리가 포함됩니다.

from semantic_kernel.functions import kernel_function

class OrderStatusPlugin:
    @kernel_function
    def check_order_status(self, order_id: str) -> str:
        """Check the status of an order."""
        # Simulate checking the order status
        return f"Order {order_id} is shipped and will arrive in 2-3 days."


class OrderRefundPlugin:
    @kernel_function
    def process_refund(self, order_id: str, reason: str) -> str:
        """Process a refund for an order."""
        # Simulate processing a refund
        print(f"Processing refund for order {order_id} due to: {reason}")
        return f"Refund for order {order_id} has been processed successfully."


class OrderReturnPlugin:
    @kernel_function
    def process_return(self, order_id: str, reason: str) -> str:
        """Process a return for an order."""
        # Simulate processing a return
        print(f"Processing return for order {order_id} due to: {reason}")
        return f"Return for order {order_id} has been processed successfully."

요원

다음으로, 이러한 플러그 인을 사용할 에이전트를 정의합니다.

팁 (조언)

ChatCompletionAgent 여기서는 Azure OpenAI와 함께 사용되지만 에이전트 유형 또는 모델 서비스를 사용할 수 있습니다.

from semantic_kernel.agents import ChatCompletionAgent
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion

support_agent = ChatCompletionAgent(
    name="TriageAgent",
    description="A customer support agent that triages issues.",
    instructions="Handle customer requests.",
    service=OpenAIChatCompletion(),
)

refund_agent = ChatCompletionAgent(
    name="RefundAgent",
    description="A customer support agent that handles refunds.",
    instructions="Handle refund requests.",
    service=OpenAIChatCompletion(),
    plugins=[OrderRefundPlugin()],
)

order_status_agent = ChatCompletionAgent(
    name="OrderStatusAgent",
    description="A customer support agent that checks order status.",
    instructions="Handle order status requests.",
    service=OpenAIChatCompletion(),
    plugins=[OrderStatusPlugin()],
)

order_return_agent = ChatCompletionAgent(
    name="OrderReturnAgent",
    description="A customer support agent that handles order returns.",
    instructions="Handle order return requests.",
    service=OpenAIChatCompletion(),
    plugins=[OrderReturnPlugin()],
)

핸드오프 관계 정의

OrchestrationHandoffs를 사용하여 어떤 에이전트가 어떤 경우에 누구에게 업무를 넘길 수 있는지를 지정합니다.

from semantic_kernel.agents import OrchestrationHandoffs

handoffs = (
    OrchestrationHandoffs()
    .add_many(    # Use add_many to add multiple handoffs to the same source agent at once
        source_agent=support_agent.name,
        target_agents={
            refund_agent.name: "Transfer to this agent if the issue is refund related",
            order_status_agent.name: "Transfer to this agent if the issue is order status related",
            order_return_agent.name: "Transfer to this agent if the issue is order return related",
        },
    )
    .add(    # Use add to add a single handoff
        source_agent=refund_agent.name,
        target_agent=support_agent.name,
        description="Transfer to this agent if the issue is not refund related",
    )
    .add(
        source_agent=order_status_agent.name,
        target_agent=support_agent.name,
        description="Transfer to this agent if the issue is not order status related",
    )
    .add(
        source_agent=order_return_agent.name,
        target_agent=support_agent.name,
        description="Transfer to this agent if the issue is not order return related",
    )
)

에이전트 응답 관찰

대화가 진행됨에 따라 각 에이전트의 메시지를 인쇄하는 콜백을 정의할 수 있습니다.

from semantic_kernel.contents import ChatMessageContent

def agent_response_callback(message: ChatMessageContent) -> None:
    print(f"{message.name}: {message.content}")

휴먼 인 더 루프

핸드오프 오케스트레이션의 주요 기능은 사람이 대화에 참여할 수 있는 기능입니다. 이는 에이전트가 사용자의 입력을 human_response_function 필요로 할 때마다 호출되는 콜백을 제공하여 수행됩니다.

from semantic_kernel.contents import AuthorRole, ChatMessageContent

def human_response_function() -> ChatMessageContent:
    user_input = input("User: ")
    return ChatMessageContent(role=AuthorRole.USER, content=user_input)

핸드오프 오케스트레이션 설정

에이전트, 핸드오프 관계 및 콜백을 전달하여 HandoffOrchestration 객체를 만듭니다.

from semantic_kernel.agents import HandoffOrchestration

handoff_orchestration = HandoffOrchestration(
    members=[
        support_agent,
        refund_agent,
        order_status_agent,
        order_return_agent,
    ],
    handoffs=handoffs,
    agent_response_callback=agent_response_callback,
    human_response_function=human_response_function,
)

런타임 시작

런타임을 시작하여 에이전트 실행을 관리합니다.

from semantic_kernel.agents.runtime import InProcessRuntime

runtime = InProcessRuntime()
runtime.start()

오케스트레이션 호출

초기 작업(예: "고객이 줄에 있습니다.")을 사용하여 오케스트레이션을 호출합니다. 에이전트는 필요에 따라 대화를 라우팅하고 필요한 경우 인간과 연결합니다.

orchestration_result = await handoff_orchestration.invoke(
    task="A customer is on the line.",
    runtime=runtime,
)

결과 수집

오케스트레이션이 완료되기를 기다립니다.

value = await orchestration_result.get()
print(value)

선택 사항: 런타임 중지

처리가 완료되면 런타임을 중지하여 리소스를 정리합니다.

await runtime.stop_when_idle()

샘플 출력

TriageAgent: Hello! Thank you for reaching out. How can I assist you today?
User: I'd like to track the status of my order
OrderStatusAgent: Sure, I can help you with that. Could you please provide me with your order ID?
User: My order ID is 123
OrderStatusAgent: Your order with ID 123 has been shipped and is expected to arrive in 2-3 days. Is there anything else I can assist you with?
User: I want to return another order of mine
OrderReturnAgent: I can help you with returning your order. Could you please provide the order ID for the return and the reason you'd like to return it?
User: Order ID 321
OrderReturnAgent: Please provide the reason for returning the order with ID 321.
User: Broken item
OrderReturnAgent: The return for your order with ID 321 has been successfully processed due to the broken item. Is there anything else I can assist you with?
User: No, bye
Task is completed with summary: Handled order return for order ID 321 due to a broken item, and successfully processed the return.

팁 (조언)

전체 샘플 코드는 여기에서 사용할 수 있습니다.

비고

에이전트 오케스트레이션은 Java SDK에서 아직 사용할 수 없습니다.

다음 단계