AgentChat 中探索代理协作

重要

此功能处于实验阶段。 此阶段的功能仍处于开发阶段,在升级到预览版或候选发布阶段之前可能会更改。

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

代理当前在 Java 中不可用。

什么是 AgentChat

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

作为抽象类,可以对 AgentChat 进行子类化以支持自定义方案。

此类子类 AgentGroupChat提供了 AgentChat的具体实现,方法是使用基于策略的方法来管理聊天动态。

创建 AgentGroupChat

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

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

使用 AgentGroupChat创建 Agent

// 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 中不可用。

Agent 添加到 AgentGroupChat

// 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

AgentChat 支持两种作模式:Single-TurnMulti-Turn。 在 single-turn中,指定特定代理来提供响应。 在 multi-turn中,会话中的所有代理都会轮流响应,直到满足终止条件。 在这两种模式下,代理可以通过相互响应来实现定义的目标进行协作。

提供输入

将输入消息添加到 AgentChat 遵循与 ChatHistory 对象相同的模式。

AgentGroupChat chat = new();

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

await chat.add_chat_message(message="<message content>")

代理当前在 Java 中不可用。

单轮次代理调用

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

代理通过单轮调用参与AgentChat后,会将它添加到代理集,使其有资格进行多轮调用。

// 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 中不可用。

访问聊天历史记录

AgentChat 会话历史记录始终可访问,即使消息是通过调用模式传递的。 这确保了过去的交流在整个对话过程中始终可用。

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

// 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 中不可用。

由于不同的代理类型或配置可以维护其自己的会话历史记录版本,因此代理特定的历史记录也可以通过指定代理来使用。 (例如:OpenAIAssistantChatCompletionAgent。)

// 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 中不可用。

定义 AgentGroupChat 行为

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

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

代理选择

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

如果已知,可以指定一个初始代理始终由其执行第一轮。 使用基于KernelFunction策略时,还可以使用历史化简器来限制令牌使用。

.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(
    kernel=kernel,
    name=REVIEWER_NAME,
    instructions="<instructions>",
)

agent_writer = ChatCompletionAgent(
    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 中不可用。

聊天终止

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

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

.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(
    kernel=kernel,
    name=REVIEWER_NAME,
    instructions="<instructions>",
)

agent_writer = ChatCompletionAgent(
    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 中不可用。

重置聊天完成状态

无论使用单轮还是多轮方法调用 AgentGroupChat,一旦满足终止条件,AgentGroupChat 的状态将被更新,以表明它是 完成。 这可确保系统在会话完全结束时识别出这一点。 若要在 AgentGroupChat 状态后继续使用 实例,必须重置此状态才能进一步交互。 如果不重置,将无法进行其他交互或代理响应。

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

// 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 中不可用。

清除整个对话的状态

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

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

// 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 中不可用。

操作说明

有关使用 AgentGroupChat 进行 Agent 协作的端到端示例,请参阅: