群聊编排

重要

代理框架中的代理编排功能处于实验阶段。 它们处于积极开发阶段,在升级到预览版或候选发布阶段之前可能会发生重大变化。

群组聊天编排为代理之间的协作对话建模,还可以选择包括人类参与者。 群组聊天管理器协调流,确定下一个代理应响应以及何时请求人工输入。 这种模式非常适用于模拟会议、辩论或协作解决问题的会议。

常见用例

不同部门的代表人讨论一项业务建议,中间由一位经理代表主持对话,并在必要时引入人工干预。

图解

学习内容

  • 如何为群组聊天定义具有不同角色的代理
  • 如何使用群组聊天管理器控制聊天流
  • 如何使人类参与者参与对话
  • 如何观察对话并收集最终结果

定义你的代理

群聊中的每个代理都有一个特定角色。 在此示例中,我们定义一个文案撰稿人和一个审阅者。

小窍门

在此,使用了 ChatCompletionAgent,但您可以使用任何 代理类型

using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Agents.Orchestration;
using Microsoft.SemanticKernel.Agents.Orchestration.GroupChat;
using Microsoft.SemanticKernel.Agents.Runtime.InProcess;

// Create a kernel with an AI service
Kernel kernel = ...;

ChatCompletionAgent writer = new ChatCompletionAgent {
    Name = "CopyWriter",
    Description = "A copy writer",
    Instructions = "You are a copywriter with ten years of experience and are known for brevity and a dry humor. The goal is to refine and decide on the single best copy as an expert in the field. Only provide a single proposal per response. You're laser focused on the goal at hand. Don't waste time with chit chat. Consider suggestions when refining an idea.",
    Kernel = kernel,
};

ChatCompletionAgent editor = new ChatCompletionAgent {
    Name = "Reviewer",
    Description = "An editor.",
    Instructions = "You are an art director who has opinions about copywriting born of a love for David Ogilvy. The goal is to determine if the given copy is acceptable to print. If so, state that it is approved. If not, provide insight on how to refine suggested copy without example.",
    Kernel = kernel,
};

可选:观察代理响应

可以创建一个回调,以在序列通过 ResponseCallback 属性进行时捕获代理响应。

ChatHistory history = [];

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

设置群组聊天编排

创建一个 GroupChatOrchestration 对象,传入代理、一个群组聊天管理器(在此为 RoundRobinGroupChatManager)和响应回调。 经理控制流——在这里,轮流的方式进行,每轮交替进行一定次数的轮次。

GroupChatOrchestration orchestration = new GroupChatOrchestration(
    new RoundRobinGroupChatManager { MaximumInvocationCount = 5 },
    writer,
    editor)
{
    ResponseCallback = responseCallback,
};

启动运行时

需要运行时才能管理代理的执行。 在这里,我们在调用业务流程之前使用 InProcessRuntime 并启动它。

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

调用编排

使用初始任务调用业务流程(例如,“为新的电动 SUV 创建口号...”)。 代理将轮流响应,优化结果。

var result = await orchestration.InvokeAsync(
    "Create a slogan for a new electric SUV that is affordable and fun to drive.",
    runtime);

收集结果

等待编排完成并获取最终输出。

string output = await result.GetValueAsync(TimeSpan.FromSeconds(60));
Console.WriteLine($"\n# RESULT: {text}");
Console.WriteLine("\n\nORCHESTRATION HISTORY");
foreach (ChatMessageContent message in history)
{
    this.WriteAgentChatMessage(message);
}

可选:停止运行时

处理完成后,停止运行时以清理资源。

await runtime.RunUntilIdleAsync();

示例输出

# RESULT: “Affordable Adventure: Drive Electric, Drive Fun.”


ORCHESTRATION HISTORY

# Assistant - CopyWriter: “Charge Ahead: Affordable Thrills, Zero Emissions.”

# Assistant - Reviewer: The slogan is catchy but it could be refined to better ...

# Assistant - CopyWriter: “Electrify Your Drive: Fun Meets Affordability.”

# Assistant - Reviewer: The slogan captures the essence of electric driving and ...

# Assistant - CopyWriter: “Affordable Adventure: Drive Electric, Drive Fun.”

小窍门

此处提供了完整的示例代码

定义你的代理

群聊中的每个代理都有一个特定角色。 在本示例中:

  • 编写者:根据反馈创建和编辑内容。
  • 审阅者:评审内容并提供改进反馈。

小窍门

此处 ChatCompletionAgent 与 Azure OpenAI 一起使用,但可以使用任何 代理类型模型服务

from semantic_kernel.agents import Agent, ChatCompletionAgent
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion

def get_agents() -> list[Agent]:
    writer = ChatCompletionAgent(
        name="Writer",
        description="A content writer.",
        instructions=(
            "You are an excellent content writer. You create new content and edit contents based on the feedback."
        ),
        service=AzureChatCompletion(),
    )
    reviewer = ChatCompletionAgent(
        name="Reviewer",
        description="A content reviewer.",
        instructions=(
            "You are an excellent content reviewer. You review the content and provide feedback to the writer."
        ),
        service=AzureChatCompletion(),
    )
    return [writer, reviewer]

观察代理响应

可以定义一个回调,以在对话进行时打印每个代理的消息。

from semantic_kernel.contents import ChatMessageContent

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

设置群组聊天编排

创建一个 GroupChatOrchestration 对象,传入代理、群组聊天管理器(在本例中为 RoundRobinGroupChatManager),以及响应回调。 经理控制流——在这里,轮流的方式进行,每轮交替进行一定次数的轮次。

from semantic_kernel.agents import GroupChatOrchestration, RoundRobinGroupChatManager

agents = get_agents()
group_chat_orchestration = GroupChatOrchestration(
    members=agents,
    manager=RoundRobinGroupChatManager(max_rounds=5),  # Odd number so writer gets the last word
    agent_response_callback=agent_response_callback,
)

启动运行时

启动运行时以管理代理执行。

from semantic_kernel.agents.runtime import InProcessRuntime

runtime = InProcessRuntime()
runtime.start()

调用编排

使用初始任务调用业务流程(例如,“为新的电动 SUV 创建口号...”)。 代理将轮流响应,优化结果。

orchestration_result = await group_chat_orchestration.invoke(
    task="Create a slogan for a new electric SUV that is affordable and fun to drive.",
    runtime=runtime,
)

收集结果

等待编排完成。

value = await orchestration_result.get()
print(f"***** Final Result *****\n{value}")

可选:停止运行时

处理完成后,停止运行时以清理资源。

await runtime.stop_when_idle()

示例输出

**Writer**
"Drive Tomorrow: Affordable Adventure Starts Today!"
**Reviewer**
This slogan, "Drive Tomorrow: Affordable Adventure Starts Today!", effectively communicates the core attributes...
**Writer**
"Embrace the Future: Your Affordable Electric Adventure Awaits!"
**Reviewer**
This revised slogan, "Embrace the Future: Your Affordable Electric Adventure Awaits!", further enhances the message...
**Writer**
"Feel the Charge: Adventure Meets Affordability in Your New Electric SUV!"
***** Result *****
"Feel the Charge: Adventure Meets Affordability in Your New Electric SUV!"

小窍门

此处提供了完整的示例代码。

注释

代理编排在 Java SDK 中尚不可用。

自定义群组聊天管理器

可以通过实现自己的 GroupChatManager来自定义群聊流。 这样,你可以控制结果的筛选方式、下一个代理的选择方式,以及何时请求用户输入或终止聊天。

例如,可以通过继承 GroupChatManager 和重写其抽象方法来创建自定义管理器:

using Microsoft.SemanticKernel.Agents.Orchestration.GroupChat;
using Microsoft.SemanticKernel.ChatCompletion;
using System.Threading;
using System.Threading.Tasks;

public class CustomGroupChatManager : GroupChatManager
{
    public override ValueTask<GroupChatManagerResult<string>> FilterResults(ChatHistory history, CancellationToken cancellationToken = default)
    {
        // Custom logic to filter or summarize chat results
        return ValueTask.FromResult(new GroupChatManagerResult<string>("Summary") { Reason = "Custom summary logic." });
    }

    public override ValueTask<GroupChatManagerResult<string>> SelectNextAgent(ChatHistory history, GroupChatTeam team, CancellationToken cancellationToken = default)
    {
        // Randomly select an agent from the team
        var random = new Random();
        int index = random.Next(team.Members.Count);
        string nextAgent = team.Members[index].Id;
        return ValueTask.FromResult(new GroupChatManagerResult<string>(nextAgent) { Reason = "Custom selection logic." });
    }

    public override ValueTask<GroupChatManagerResult<bool>> ShouldRequestUserInput(ChatHistory history, CancellationToken cancellationToken = default)
    {
        // Custom logic to decide if user input is needed
        return ValueTask.FromResult(new GroupChatManagerResult<bool>(false) { Reason = "No user input required." });
    }

    public override ValueTask<GroupChatManagerResult<bool>> ShouldTerminate(ChatHistory history, CancellationToken cancellationToken = default)
    {
        // Optionally call the base implementation to check for default termination logic
        var baseResult = base.ShouldTerminate(history, cancellationToken).Result;
        if (baseResult.Value)
        {
            // If the base logic says to terminate, respect it
            return ValueTask.FromResult(baseResult);
        }

        // Custom logic to determine if the chat should terminate
        bool shouldEnd = history.Count > 10; // Example: end after 10 messages
        return ValueTask.FromResult(new GroupChatManagerResult<bool>(shouldEnd) { Reason = "Custom termination logic." });
    }
}

然后,可以在编排过程中使用自定义管理器:

GroupChatOrchestration orchestration = new (new CustomGroupChatManager { MaximumInvocationCount = 5 }, ...);

小窍门

此处提供了自定义群组聊天管理器的完整示例

可以通过实现自己的 GroupChatManager来自定义群聊流。 这样,你可以控制结果的筛选方式、下一个代理的选择方式,以及何时请求用户输入或终止聊天。

例如,可以通过继承 GroupChatManager 和重写其抽象方法来创建自定义管理器:

from semantic_kernel.agents import GroupChatManager, BooleanResult, StringResult, MessageResult
from semantic_kernel.contents import ChatMessageContent, ChatHistory

class CustomGroupChatManager(GroupChatManager):
    async def filter_results(self, chat_history: ChatHistory) -> MessageResult:
        # Custom logic to filter or summarize chat results
        summary = "Summary of the discussion."
        return MessageResult(result=ChatMessageContent(role="assistant", content=summary), reason="Custom summary logic.")

    async def select_next_agent(self, chat_history: ChatHistory, participant_descriptions: dict[str, str]) -> StringResult:
        # Randomly select an agent from the participants
        import random
        next_agent = random.choice(list(participant_descriptions.keys()))
        return StringResult(result=next_agent, reason="Custom selection logic.")

    async def should_request_user_input(self, chat_history: ChatHistory) -> BooleanResult:
        # Custom logic to decide if user input is needed
        return BooleanResult(result=False, reason="No user input required.")

    async def should_terminate(self, chat_history: ChatHistory) -> BooleanResult:
        # Optionally call the base implementation to check for default termination logic
        base_result = await super().should_terminate(chat_history)
        if base_result.result:
            return base_result
        # Custom logic to determine if the chat should terminate
        should_end = len(chat_history.messages) > 10  # Example: end after 10 messages
        return BooleanResult(result=should_end, reason="Custom termination logic.")

然后,可以在编排过程中使用自定义管理器:

from semantic_kernel.agents import GroupChatOrchestration

group_chat_orchestration = GroupChatOrchestration(manager=CustomGroupChatManager(max_rounds=5), ...)

小窍门

此处提供了自定义群组聊天管理器的完整示例

注释

代理编排在 Java SDK 中尚不可用。

群组聊天管理器函数调用的顺序

组织群组聊天时,将按照特定顺序在每轮对话中调用群组聊天管理员的方法。

  1. ShouldRequestUserInput:检查下一个代理说话之前是否需要用户(人工)输入。 如果为 true,则业务流程暂停以等待用户输入。 然后,用户输入将添加到管理器的聊天历史记录中,并发送到所有代理。
  2. ShouldTerminate:确定群聊是否应结束(例如,如果达到最大轮数或满足自定义条件)。 如果为 true,业务流程将继续执行结果筛选。
  3. FilterResults:仅在聊天终止时调用,以汇总或处理对话的最终结果。
  4. SelectNextAgent:如果聊天未终止,请选择下一个客服人员来继续对话。

此顺序可确保在推进会话之前检查用户输入和终止条件,并且结果仅在末尾进行筛选。 可以通过重写自定义群聊管理器中的相应方法来定制每个步骤的逻辑。

后续步骤