Оркестрация передачи

Это важно

Функции оркестрации агентов во фреймворке агентов находятся на стадии эксперимента. Они находятся в активной разработке и могут значительно измениться до перехода к стадии предварительной версии или кандидата на выпуск.

Оркестрация передачи позволяет агентам передавать управление друг другу в зависимости от контекста или запроса пользователя. Каждый агент может "передать" беседу другому агенту с соответствующим опытом, гарантируя, что правильный агент обрабатывает каждую часть задачи. Это особенно полезно для поддержки клиентов, экспертных систем или любого сценария, требующего динамического делегирования.

Дополнительные сведения о шаблоне, например о том, когда следует использовать шаблон или когда избежать шаблона в рабочей нагрузке, см. в разделе "Оркестрация передачи".

Распространенные варианты использования

Агент службы поддержки клиентов обрабатывает общий запрос, а затем передает техническому эксперту для устранения неполадок или агенту по работе с выставлением счетов, если это необходимо.

диаграмма

Цели обучения

  • Как определить агентов и их отношения взаимодействия при передаче
  • Настройка оркестрации передачи для динамической маршрутизации агентов
  • Как включить человека в цикл беседы

Определение специализированных агентов

Каждый агент отвечает за определенную область. В этом примере мы определим агент сортировки, агент возврата средств, агент отслеживания заказа и агент возврата товара. Некоторые агенты используют подключаемые модули для обработки определенных задач.

Подсказка

Используется 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.

Подсказка

Полный пример кода доступен здесь.

Замечание

Оркестрация агентов пока недоступна в пакете SDK для Java.

Дальнейшие шаги