在代理聊天探索代理协作 (实验性)

警告

语义内核代理框架是实验性的,仍在开发中,可能会更改。

有关此讨论的详细 API 文档在以下位置提供:

代理当前在 Java 中不可用。

什么是 代理聊天

代理聊天 提供了一个框架,用于实现多个代理之间的交互,即使它们属于不同类型的代理。 这使得聊天完成代理和 Open AI 助手代理可以在同一对话中协同工作。 代理聊天 还定义了用于启动代理之间的协作的入口点,无论是通过多个响应还是单个代理响应。

作为抽象类, 可以分类代理聊天 来支持自定义方案。

此类子类(代理群聊)使用基于策略的方法管理聊天动态,提供代理聊天的具体实现

创建 代理群组聊天

若要创建 代理群组聊天,可以指定参与代理或创建空聊天,然后添加代理参与者。 配置聊天设置策略也会在代理群聊初始化期间执行。 这些设置定义会话动态在组中的运行方式。

注意:默认 的聊天设置 会导致限制为单个响应的对话。 有关配置_Chat设置的详细信息,请参阅 代理聊天 行为

使用代理创建代理群组聊天

// Define agents
ChatCompletionAgent agent1 = ...;
OpenAIAssistantAgent agent2 = ...;

// Create chat with participating agents.
AgentGroupChat chat = new(agent1, agent2);
# Define agents
agent1 = ChatCompletionAgent(...)
agent2 = OpenAIAssistantAgent(...)

# Create chat with participating agents
chat = AgentGroupChat(agents=[agent1, agent2])

代理当前在 Java 中不可用。

将代理添加到代理群组聊天

// Define agents
ChatCompletionAgent agent1 = ...;
OpenAIAssistantAgent agent2 = ...;

// Create an empty chat.
AgentGroupChat chat = new();

// Add agents to an existing chat.
chat.AddAgent(agent1);
chat.AddAgent(agent2);
# Define agents
agent1 = ChatCompletionAgent(...)
agent2 = OpenAIAssistantAgent(...)

# Create an empty chat
chat = AgentGroupChat()

# Add agents to an existing chat
chat.add_agent(agent=agent1)
chat.add_agent(agent=agent2)

代理当前在 Java 中不可用。

使用 代理群组聊天

代理聊天 支持两种操作模式: 单轮 次和 多轮次。 在单轮次,将指定特定代理来提供响应。 在 多轮次中,会话中的所有代理都会轮流响应,直到满足终止条件。 在这两种模式下,代理可以通过相互响应来实现定义的目标进行协作。

提供输入

将输入消息添加到 代理聊天 遵循与惠特 聊天历史记录 对象相同的模式。

AgentGroupChat chat = new();

chat.AddChatMessage(new ChatMessageContent(AuthorRole.User, "<message content>"));
chat = AgentGroupChat()

await chat.add_chat_message(ChatMessageContent(role=AuthorRole.USER, content="<message content>"))

代理当前在 Java 中不可用。

单轮次代理调用

在多轮调用中,系统必须决定下一步响应哪个代理以及会话何时结束。 相比之下,单轮调用只是返回来自指定代理的响应,从而允许调用方直接管理代理参与。

代理通过单轮调用参与代理聊天后,会将其添加到有资格进行多轮调用的代理

// Define an agent
ChatCompletionAgent agent = ...;

// Create an empty chat.
AgentGroupChat chat = new();

// Invoke an agent for its response
ChatMessageContent[] messages = await chat.InvokeAsync(agent).ToArrayAsync();
# Define an agent
agent = ChatCompletionAgent(...)

# Create an empty chat
chat = AgentGroupChat()

# Invoke an agent for its response(s)
async for message in chat.invoke(agent)
    # process message response(s)

代理当前在 Java 中不可用。

多轮次代理调用

虽然代理协作要求必须建立一个系统,不仅确定哪个代理应在每个轮次期间做出响应,而且还会评估会话何时达到其预期目标,启动多轮次协作仍然非常简单。

代理响应在生成时异步返回,从而允许聊天实时展开。

注意:在以下部分中, 代理选择聊天终止详细介绍执行设置 。 默认 执行设置 采用顺序或轮循机制选择,并将代理参与限制为单个轮次。

.NET 执行设置 API: AgentGroupChatSettings

// Define agents
ChatCompletionAgent agent1 = ...;
OpenAIAssistantAgent agent2 = ...;

// Create chat with participating agents.
AgentGroupChat chat =
  new(agent1, agent2)
  {
    // Override default execution settings
    ExecutionSettings =
    {
        TerminationStrategy = { MaximumIterations = 10 }
    }
  };

// Invoke agents
await foreach (ChatMessageContent response in chat.InvokeAsync())
{
  // Process agent response(s)...
}
# Define agents
agent1 = ChatCompletionAgent(...)
agent2 = OpenAIAssistantAgent(...)

# Create chat with participating agents
chat = AgentGroupChat(
    agents=[agent1, agent2],
    termination_strategy=DefaultTerminationStrategy(maximum_iterations=10),
)

async for response in chat.invoke():
    # process agent response(s)

代理当前在 Java 中不可用。

访问聊天历史记录

代理聊天对话历史记录始终可访问,即使消息通过调用模式传递。 这可确保过去交换在整个对话中保持可用。

注意:首先提供最新的消息(降序:最新到最早)。

// Define and use a chat
AgentGroupChat chat = ...;

// Access history for a previously utilized AgentGroupChat
ChatMessageContent[] history = await chat.GetChatMessagesAsync().ToArrayAsync();
# Define a group chat
chat = AgentGroupChat(...)

# Access history for a previously utilized AgentGroupChat
history = await chat.get_chat_messages()

代理当前在 Java 中不可用。

由于不同的代理类型或配置可能会维护其自己的会话历史记录版本,因此代理特定的历史记录也可以通过指定代理来使用。 (例如: 打开 AI 助手聊天完成代理

// Agents to participate in chat
ChatCompletionAgent agent1 = ...;
OpenAIAssistantAgent agent2 = ...;

// Define a group chat
AgentGroupChat chat = ...;

// Access history for a previously utilized AgentGroupChat
ChatMessageContent[] history1 = await chat.GetChatMessagesAsync(agent1).ToArrayAsync();
ChatMessageContent[] history2 = await chat.GetChatMessagesAsync(agent2).ToArrayAsync();
# Agents to participate in a chat
agent1 = ChatCompletionAgent(...)
agent2 = OpenAIAssistantAgent(...)

# Define a group chat
chat = AgentGroupChat(...)

# Access history for a previously utilized AgentGroupChat
history1 = await chat.get_chat_messages(agent=agent1)
history2 = await chat.get_chat_messages(agent=agent2)

代理当前在 Java 中不可用。

定义 代理群组聊天 行为

代理之间的协作来解决复杂的任务是一种核心代理模式。 若要有效地使用此模式,必须建立一个系统,不仅确定哪个代理应在每个轮次期间做出响应,而且还会评估会话何时达到其预期目标。 这需要管理代理选择并建立明确的对话终止标准,确保代理之间实现解决方案的无缝合作。 这两个方面都受 执行设置 属性的约束。

以下部分( 代理选择聊天终止)将详细介绍这些注意事项。

代理选择

在多轮次调用中,代理选择由 选择策略指导。 此策略由可扩展的基类定义,以实现根据特定需求定制的自定义行为。 为方便起见,还提供了两个预定义的具体 选择策略 ,提供现成的方法用于在对话期间处理代理选择。

如果已知,可以指定初始代理以始终执行第一轮。 使用基于 内核函数的策略时,还可以使用历史记录化简器来限制令牌使用。

.NET 选择策略 API:

// Define the agent names for use in the function template
const string WriterName = "Writer";
const string ReviewerName = "Reviewer";

// Initialize a Kernel with a chat-completion service
Kernel kernel = ...;

// Create the agents
ChatCompletionAgent writerAgent =
    new()
    {
        Name = WriterName,
        Instructions = "<writer instructions>",
        Kernel = kernel
    };

ChatCompletionAgent reviewerAgent =
    new()
    {
        Name = ReviewerName,
        Instructions = "<reviewer instructions>",
        Kernel = kernel
    };

// Define a kernel function for the selection strategy
KernelFunction selectionFunction =
    AgentGroupChat.CreatePromptFunctionForStrategy(
        $$$"""
        Determine which participant takes the next turn in a conversation based on the the most recent participant.
        State only the name of the participant to take the next turn.
        No participant should take more than one turn in a row.

        Choose only from these participants:
        - {{{ReviewerName}}}
        - {{{WriterName}}}

        Always follow these rules when selecting the next participant:
        - After {{{WriterName}}}, it is {{{ReviewerName}}}'s turn.
        - After {{{ReviewerName}}}, it is {{{WriterName}}}'s turn.

        History:
        {{$history}}
        """,
        safeParameterNames: "history");

// Define the selection strategy
KernelFunctionSelectionStrategy selectionStrategy = 
  new(selectionFunction, kernel)
  {
      // Always start with the writer agent.
      InitialAgent = writerAgent,
      // Parse the function response.
      ResultParser = (result) => result.GetValue<string>() ?? WriterName,
      // The prompt variable name for the history argument.
      HistoryVariableName = "history",
      // Save tokens by not including the entire history in the prompt
      HistoryReducer = new ChatHistoryTruncationReducer(3),
  };   

// Create a chat using the defined selection strategy.
AgentGroupChat chat =
    new(writerAgent, reviewerAgent)
    {
        ExecutionSettings = new() { SelectionStrategy = selectionStrategy }
    };
REVIEWER_NAME = "Reviewer"
WRITER_NAME = "Writer"

agent_reviewer = ChatCompletionAgent(
    service_id=REVIEWER_NAME,
    kernel=kernel,
    name=REVIEWER_NAME,
    instructions="<instructions>",
)

agent_writer = ChatCompletionAgent(
    service_id=WRITER_NAME,
    kernel=kernel,
    name=WRITER_NAME,
    instructions="<instructions>",
)

selection_function = KernelFunctionFromPrompt(
    function_name="selection",
    prompt=f"""
    Determine which participant takes the next turn in a conversation based on the the most recent participant.
    State only the name of the participant to take the next turn.
    No participant should take more than one turn in a row.

    Choose only from these participants:
    - {REVIEWER_NAME}
    - {WRITER_NAME}

    Always follow these rules when selecting the next participant:
    - After user input, it is {WRITER_NAME}'s turn.
    - After {WRITER_NAME} replies, it is {REVIEWER_NAME}'s turn.
    - After {REVIEWER_NAME} provides feedback, it is {WRITER_NAME}'s turn.

    History:
    {{{{$history}}}}
    """,
)

chat = AgentGroupChat(
    agents=[agent_writer, agent_reviewer],
    selection_strategy=KernelFunctionSelectionStrategy(
        function=selection_function,
        kernel=_create_kernel_with_chat_completion("selection"),
        result_parser=lambda result: str(result.value[0]) if result.value is not None else COPYWRITER_NAME,
        agent_variable_name="agents",
        history_variable_name="history",
    ),
)

代理当前在 Java 中不可用。

聊天终止

多轮次 调用中 ,终止策略 决定最终轮次何时发生。 此策略可确保对话在适当的时间点结束。

此策略由可扩展的基类定义,以实现根据特定需求定制的自定义行为。 为方便起见,还提供了服务器预定义的具体选择策略,提供现成的方法,用于定义代理聊天对话的终止条件。

.NET 选择策略 API:

// Initialize a Kernel with a chat-completion service
Kernel kernel = ...;

// Create the agents
ChatCompletionAgent writerAgent =
    new()
    {
        Name = "Writer",
        Instructions = "<writer instructions>",
        Kernel = kernel
    };

ChatCompletionAgent reviewerAgent =
    new()
    {
        Name = "Reviewer",
        Instructions = "<reviewer instructions>",
        Kernel = kernel
    };

// Define a kernel function for the selection strategy
KernelFunction terminationFunction =
    AgentGroupChat.CreatePromptFunctionForStrategy(
        $$$"""
        Determine if the reviewer has approved.  If so, respond with a single word: yes

        History:
        {{$history}}
        """,
        safeParameterNames: "history");

// Define the termination strategy
KernelFunctionTerminationStrategy terminationStrategy = 
  new(selectionFunction, kernel)
  {
      // Only the reviewer may give approval.
      Agents = [reviewerAgent],
      // Parse the function response.
      ResultParser = (result) => 
        result.GetValue<string>()?.Contains("yes", StringComparison.OrdinalIgnoreCase) ?? false,
      // The prompt variable name for the history argument.
      HistoryVariableName = "history",
      // Save tokens by not including the entire history in the prompt
      HistoryReducer = new ChatHistoryTruncationReducer(1),
      // Limit total number of turns no matter what
      MaximumIterations = 10,
};

// Create a chat using the defined termination strategy.
AgentGroupChat chat =
    new(writerAgent, reviewerAgent)
    {
        ExecutionSettings = new() { TerminationStrategy = terminationStrategy }
    };

REVIEWER_NAME = "Reviewer"
WRITER_NAME = "Writer"

agent_reviewer = ChatCompletionAgent(
    service_id=REVIEWER_NAME,
    kernel=kernel,
    name=REVIEWER_NAME,
    instructions="<instructions>",
)

agent_writer = ChatCompletionAgent(
    service_id=WRITER_NAME,
    kernel=kernel,
    name=WRITER_NAME,
    instructions="<instructions>",
)

termination_function = KernelFunctionFromPrompt(
    function_name="termination",
    prompt="""
    Determine if the copy has been approved.  If so, respond with a single word: yes

    History:
    {{$history}}
    """,
)

chat = AgentGroupChat(
    agents=[agent_writer, agent_reviewer],
    termination_strategy=KernelFunctionTerminationStrategy(
        agents=[agent_reviewer],
        function=termination_function,
        kernel=_create_kernel_with_chat_completion("termination"),
        result_parser=lambda result: str(result.value[0]).lower() == "yes",
        history_variable_name="history",
        maximum_iterations=10,
    ),
)

代理当前在 Java 中不可用。

重置聊天完成状态

无论代理群聊是使用单轮还是多轮次方法调用,代理群聊的状态都会更新,以指示在满足终止条件后已完成 这可确保系统在会话完全结束时识别。 若要在代理群聊实例达到“已完成”状态后继续使用该实例,必须重置此状态才能进一步交互。 如果不重置,将无法进行其他交互或代理响应。

对于达到最大轮次限制的多轮次调用,系统将停止代理调用,但不会将实例 标记为已完成。 这允许扩展会话的可能性,而无需重置 完成 状态。

// Define an use chat
AgentGroupChat chat = ...;

// Evaluate if completion is met and reset.
if (chat.IsComplete) 
{
  // Opt to take action on the chat result...

  // Reset completion state to continue use
  chat.IsComplete = false;
}
# Define a group chat
chat = AgentGroupChat()

# Evaluate if completion is met and reset
if chat.is_complete:
    # Reset completion state to continue use
    chat.is_complete = False

代理当前在 Java 中不可用。

清除完整对话状态

使用参与 Open AI 助手的代理聊天后,可能需要删除与助手关联的远程线程。 代理聊天 支持重置或清除整个聊天状态,包括删除任何远程 线程 定义。 这可确保聊天结束后,不会将剩余聊天数据链接到助手。

完全重置不会删除已加入代理聊天的代理,并将代理聊天保留为可以重复使用的状态。 这样就可以继续与同一代理的交互,而无需重新初始化它们,从而使将来的对话更高效。

// Define an use chat
AgentGroupChat chat = ...;

// Clear the all conversation state
await chat.ResetAsync();
# Define a group chat
chat = AgentGroupChat()

# Clear the conversation state
await chat.reset()

代理当前在 Java 中不可用。

操作说明

有关使用 代理群组聊天 进行 代理 协作的端到端示例,请参阅: