Explorando a colaboração de agentes no AgentChat
Importante
Esse recurso está em estágio experimental. Os recursos nesta etapa ainda estão em desenvolvimento e estão sujeitos a alterações antes de avançar para a versão de pré-visualização ou de candidato a lançamento.
A documentação detalhada da API relacionada a esta discussão está disponível em:
No momento, os agentes não estão disponíveis em Java.
O que é AgentChat
?
AgentChat
fornece uma estrutura que permite a interação entre vários agentes, mesmo que sejam de tipos diferentes. Isso possibilita que um ChatCompletionAgent
e um OpenAIAssistantAgent
trabalhem juntos na mesma conversa.
AgentChat
também define pontos de entrada para iniciar a colaboração entre agentes, seja por meio de várias respostas ou de uma resposta de agente único.
Como uma classe abstrata, AgentChat
pode ser subclassificada para dar suporte a cenários customizados.
Uma dessas subclasses, AgentGroupChat
, oferece uma implementação concreta de AgentChat
, usando uma abordagem baseada em estratégia para gerenciar a dinâmica da conversa.
Criando um AgentGroupChat
Para criar um AgentGroupChat
, você pode especificar os agentes participantes ou criar um chat vazio e, em seguida, adicionar os agentes participantes. A configuração das Configurações de Chat e Estratégias também é realizada durante a inicialização AgentGroupChat
. Essas configurações definem como a dinâmica da conversa funcionará dentro do grupo.
Observação: as configurações de bate-papo padrão resultam em uma conversa limitada a uma única resposta. Consulte o
AgentChat
Comportamento para obter detalhes sobre como ajustar as Configurações de _Chat.
Criando um AgentGroupChat
com um 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])
No momento, os agentes não estão disponíveis em Java.
Adicionando um Agent
a um 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)
No momento, os agentes não estão disponíveis em Java.
Usando AgentGroupChat
AgentChat
dá suporte a dois modos de operação: Single-Turn
e Multi-Turn
. Em single-turn
, um agente específico é designado para fornecer uma resposta. Em multi-turn
, todos os agentes da conversa se revezam para responder até que um critério de término seja atingido. Em ambos os modos, os agentes podem colaborar respondendo uns aos outros para atingir uma meta definida.
Fornecendo informações
Adicionar uma mensagem de entrada a um AgentChat
segue o mesmo padrão de um objeto ChatHistory
.
AgentGroupChat chat = new();
chat.AddChatMessage(new ChatMessageContent(AuthorRole.User, "<message content>"));
chat = AgentGroupChat()
await chat.add_chat_message(message="<message content>")
No momento, os agentes não estão disponíveis em Java.
Invocação de agente de turno único
Em uma invocação de vários turnos, o sistema deve decidir qual agente responde em seguida e quando a conversa deve terminar. Por outro lado, uma invocação de turno único simplesmente retorna uma resposta do agente especificado, permitindo que o chamador gerencie diretamente a participação do agente.
Depois que um agente participa do AgentChat
por meio de uma invocação de turno único, ele é adicionado ao conjunto de agentes qualificados para invocação de múltiplos turnos.
// 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)
No momento, os agentes não estão disponíveis em Java.
Invocação de agente de vários turnos
Embora a colaboração do agente exija que haja um sistema que não apenas determine qual agente deve responder durante cada turno, mas também avalie quando a conversa atingiu o objetivo pretendido, iniciar a colaboração em vários turnos permanece simples.
As respostas do agente são retornadas de forma assíncrona à medida que são geradas, permitindo que a conversa se desdobre em tempo real.
Observação: nas seções a seguir, Seleção de Agente e Encerramento de Bate-papo serão detalhados nas Configurações de Execução em detalhes. As configurações de execução padrão empregam seleção sequencial ou round-robin e limitam a participação do agente a um único turno.
API de configurações de execução do .NET: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)
No momento, os agentes não estão disponíveis em Java.
Acessando o histórico de bate-papo
O AgentChat
histórico de conversas é sempre acessível, mesmo que as mensagens sejam entregues por meio do padrão de invocação. Isso garante que as trocas anteriores permaneçam disponíveis durante toda a conversa.
Observação: a mensagem mais recente é fornecida primeiro (ordem decrescente: mais recente para a mais antiga).
// 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()
No momento, os agentes não estão disponíveis em Java.
Como diferentes tipos de agente ou configurações podem manter sua própria versão do histórico de conversas, o histórico específico do agente também está disponível especificando um agente. (Por exemplo: OpenAIAssistant
versus ChatCompletionAgent
.)
// 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)
No momento, os agentes não estão disponíveis em Java.
Definindo o comportamento do AgentGroupChat
A colaboração entre agentes para resolver tarefas complexas é um padrão agêntico central. Para usar esse padrão de forma eficaz, deve haver um sistema que não apenas determine qual agente deve responder durante cada turno, mas também avalie quando a conversa atingiu o objetivo pretendido. Isso requer o gerenciamento da seleção de agentes e o estabelecimento de critérios claros para o encerramento da conversa, garantindo uma cooperação perfeita entre os agentes em direção a uma solução. Ambos os aspectos são regidos pela propriedade Configurações de Execução .
As seções a seguir, Seleção de Agente e Encerramento de Chat, se aprofundarão nessas considerações em detalhes.
Seleção de Agente
Na invocação de vários turnos, a seleção de agentes é guiada por uma Estratégia de Seleção. Essa estratégia é definida por uma classe base que pode ser estendida para implementar comportamentos personalizados adaptados a necessidades específicas. Por conveniência, duas estratégias de seleção concretas predefinidas também estão disponíveis, oferecendo abordagens prontas para uso para lidar com a seleção de agentes durante as conversas.
Se conhecido, um agente inicial pode ser especificado para sempre jogar na primeira rodada. Um redutor de histórico também pode ser empregado para limitar o uso de tokens ao utilizar uma estratégia baseada em um KernelFunction
.
API de estratégia de seleção do .NET:
SelectionStrategy
SequentialSelectionStrategy
KernelFunctionSelectionStrategy
Microsoft.SemanticKernel.Agents.History
// 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",
),
)
No momento, os agentes não estão disponíveis em Java.
Encerramento do bate-papo
Na invocação de vários turnos, a Estratégia de Terminação determina quando o turno final ocorre. Essa estratégia garante que a conversa termine no ponto apropriado.
Essa estratégia é definida por uma classe base que pode ser estendida para implementar comportamentos personalizados adaptados a necessidades específicas. Por conveniência, vária s estratégias de seleção concretas predefinidas também estão disponíveis, oferecendo abordagens prontas para uso para definir critérios de encerramento para uma AgentChat
conversas.
API de estratégia de seleção do .NET:
TerminationStrategy
RegexTerminationStrategy
KernelFunctionSelectionStrategy
KernelFunctionTerminationStrategy
AggregatorTerminationStrategy
Microsoft.SemanticKernel.Agents.History
// 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,
),
)
No momento, os agentes não estão disponíveis em Java.
Redefinindo o estado de conclusão do bate-papo
Independentemente de AgentGroupChat
ser invocado usando a abordagem de turno único ou de múltiplos turnos, o estado do AgentGroupChat
é atualizado para indicar que está concluído depois que os critérios de término são atendidos. Isso garante que o sistema reconheça quando uma conversa foi totalmente concluída. Para continuar usando uma instância de AgentGroupChat
depois de atingir o estado Concluído, esse estado deve ser redefinido para permitir interações adicionais. Sem redefinir, interações adicionais ou respostas do agente não serão possíveis.
No caso de uma invocação de vários turnos que atinja o limite máximo de turnos, o sistema interromperá a invocação do agente, mas não marcará a instância como concluída. Isso permite a possibilidade de estender a conversa sem a necessidade de redefinir o estado de conclusão .
// 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
No momento, os agentes não estão disponíveis em Java.
Limpar estado completo da conversa
Quando terminar de usar um AgentChat
em que um OpenAIAssistant
participou, talvez seja necessário excluir o thread remoto associado ao assistente .
AgentChat
oferece suporte para redefinir ou limpar todo o estado da conversa, incluindo a exclusão de qualquer definição de thread em remoto. Isso garante que nenhum dado residual da conversa permaneça vinculado ao assistente após a conclusão do bate-papo.
Uma redefinição completa não remove os agentes que ingressaram no AgentChat
e deixa o AgentChat
em um estado em que ele pode ser reutilizado. Isso permite a continuação das interações com os mesmos agentes sem a necessidade de reinicializá-los, tornando as conversas futuras mais eficientes.
// 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()
No momento, os agentes não estão disponíveis em Java.
Instruções
Para um exemplo completo do uso de AgentGroupChat
para a colaboração Agent
, consulte: