Implementar agentes de IA usando o SDK do GitHub Copilot

Concluído

Esta unidade aborda os principais padrões de implementação para criar um agente de IA usando o SDK do GitHub Copilot. Esses padrões se aplicam a qualquer cenário de agente. Os exemplos de código usam C# e .NET, que é a plataforma usada no exercício do módulo.

Configurar o cliente do SDK do GitHub Copilot

A primeira etapa é criar uma CopilotClient instância que gerencia a conexão com o servidor da CLI do Copilot. Normalmente, você registra o cliente como um serviço singleton em seu aplicativo.

Instalar pacotes necessários

Adicione o SDK do GitHub Copilot e o pacote Microsoft.Extensions.AI (usado para definições de ferramenta) ao seu projeto:

dotnet add package GitHub.Copilot.SDK
dotnet add package Microsoft.Extensions.AI

Configurar o cliente

Crie um CopilotClient com CopilotClientOptions que controla o comportamento de inicialização e o registro em log:

var client = new CopilotClient(new CopilotClientOptions
{
    AutoStart = true,
    LogLevel = "info"
});

A opção AutoStart informa ao SDK que deve iniciar o processo de servidor da CLI do Copilot automaticamente quando a primeira sessão for criada. A opção LogLevel controla a verbosidade da saída de diagnóstico do SDK.

Depois de criar o cliente, inicie-o:

await client.StartAsync();

Esse código estabelece a conexão com o servidor da CLI e prepara o cliente para a criação da sessão.

Definir ferramentas do agente

As ferramentas dão ao agente a capacidade de interagir com os serviços de back-end do aplicativo. No SDK do GitHub Copilot para .NET, você define as ferramentas do pacote Microsoft.Extensions.AI usando AIFunctionFactory.Create.

Criar um serviço de ferramentas

Um padrão comum é criar uma classe de serviço dedicada que contenha todos os métodos de ferramenta que seu agente possa chamar. Cada método representa uma ação que o agente pode executar:

public class SupportAgentTools
{
    public async Task<string> GetOrderDetailsAsync(int orderId)
    {
        // Query the database for order information
        var order = await _dbContext.Orders.FindAsync(orderId);
        return order != null
            ? $"Order {orderId}: {order.ProductName}, Status: {order.Status}"
            : "Order not found.";
    }

    public async Task<string> ProcessReturnAsync(int orderId, string reason)
    {
        // Business logic to process the return
        var order = await _dbContext.Orders.FindAsync(orderId);
        order.Status = "Return Initiated";
        await _dbContext.SaveChangesAsync();
        return $"Return initiated for order {orderId}.";
    }
}

Registrar ferramentas com o SDK

Converta seus métodos de serviço em definições de ferramenta que o SDK pode usar. Cada ferramenta precisa de um nome, descrição e descrições de parâmetro para que o modelo de IA entenda quando e como usá-lo:

var toolService = new SupportAgentTools(dbContext);

var tools = new List<AIFunction>
{
    AIFunctionFactory.Create(
        async ([Description("The order ID number")] int orderId) =>
            await toolService.GetOrderDetailsAsync(orderId),
        "get_order_details",
        "Look up the status and details of a specific order."),

    AIFunctionFactory.Create(
        async ([Description("The order ID")] int orderId,
               [Description("The reason for the return")] string reason) =>
            await toolService.ProcessReturnAsync(orderId, reason),
        "process_return",
        "Process a return request for an order.")
};

Cada AIFunctionFactory.Create chamada usa três argumentos:

  1. Uma função lambda que encapsula seu método de serviço, com [Description] atributos em cada parâmetro.
  2. Um nome de ferramenta que o modelo de IA usa para fazer referência à ferramenta.
  3. Uma descrição que ajuda o modelo a entender quando chamar a ferramenta.

Os [Description] atributos nos parâmetros são importantes: eles informam ao modelo de IA o que cada parâmetro representa, o que ajuda o modelo a fornecer valores precisos ao chamar a ferramenta.

Criar e configurar uma sessão

As sessões representam conversas individuais ou contextos de tarefa. Você configura uma sessão com o modelo, o prompt do sistema, as ferramentas e outras configurações.

Configurar a sessão

Use SessionConfig para especificar como a sessão deve se comportar:

var config = new SessionConfig
{
    Model = "gpt-4.1",
    SystemMessage = new SystemMessageConfig
    {
        Mode = SystemMessageMode.Replace,
        Content = @"You are a customer support agent for an e-commerce company.

CAPABILITIES:
- Look up order details
- Process returns

RULES:
- Only assist with order-related inquiries
- Always verify order details before taking action
- Be polite and professional"
    },
    Tools = tools,
    InfiniteSessions = new InfiniteSessionConfig
    {
        Enabled = false
    }
};

Opções de configuração de chave:

  • Modelo: especifica qual modelo de IA usar para esta sessão.
  • SystemMessage: define a função e o comportamento do agente. O Mode determina se o prompt substitui a mensagem do sistema padrão (Replace) ou acrescenta à mensagem (Append).
  • Ferramentas: a lista de definições de ferramenta que o agente pode usar.
  • InfiniteSessions: controla a compactação automática de contexto para conversas longas. Quando habilitado, você pode ajustar e para controlar quando ocorrer a compactação.

Criar a sessão

Crie uma sessão do cliente usando sua configuração:

var session = await client.CreateSessionAsync(config);

Manipular respostas com eventos

O SDK do GitHub Copilot usa um modelo controlado por eventos para comunicação. Depois de enviar uma mensagem, você assina eventos para receber respostas e detectar quando o processamento é concluído.

Assinar eventos de sessão

Use o session.On método com correspondência de padrões para lidar com diferentes tipos de evento:

var responseBuilder = new StringBuilder();
var tcs = new TaskCompletionSource<string>();

session.On(evt =>
{
    switch (evt)
    {
        case AssistantMessageEvent msg:
            responseBuilder.Append(msg.Data.Content);
            break;

        case SessionIdleEvent:
            tcs.SetResult(responseBuilder.ToString());
            break;

        case SessionErrorEvent err:
            tcs.SetException(
                new Exception($"Agent error: {err.Data.Message}"));
            break;
    }
});

Cada tipo de evento serve a uma finalidade específica:

  • AssistantMessageEvent: contém uma parte do texto de resposta do agente. Você acumula essas partes de mensagem para criar a resposta completa.
  • SessionIdleEvent: sinaliza que o agente terminou o processamento, incluindo todas as chamadas de ferramenta. Esse evento indica que a resposta está concluída.
  • SessionErrorEvent: indica que ocorreu um erro durante o processamento. A Data.Message propriedade contém a descrição do erro.

Enviar uma mensagem e aguardar a resposta

Use SendAsync com um MessageOptions objeto para enviar o prompt do usuário ao agente:

await session.SendAsync(new MessageOptions
{
    Prompt = "What is the status of order 12345?"
});

// Wait for the response with a timeout
var response = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(30));

O padrão TaskCompletionSource mostrado aqui permite que você integre o modelo do SDK evento-dirigido com código async/await. Quando SessionIdleEvent é acionado, ele conclui a tarefa com o texto de resposta acumulado.

Práticas recomendadas de tratamento de erros

O tratamento robusto de erros é essencial para agentes de produção.

Erros do manipulador de ferramentas

Coloque os manipuladores de ferramenta em blocos try-catch e retorne mensagens de erro significativas em vez de gerar exceções. Quando uma ferramenta retorna uma mensagem de erro, o modelo de IA pode interpretá-la e fornecer uma resposta útil ao usuário:

AIFunctionFactory.Create(
    async ([Description("The order ID")] int orderId) =>
    {
        try
        {
            return await toolService.GetOrderDetailsAsync(orderId);
        }
        catch (Exception ex)
        {
            return $"Error retrieving order: {ex.Message}";
        }
    },
    "get_order_details",
    "Look up the status and details of a specific order.")

Tratamento de erros no nível da sessão

Use o SessionErrorEvent para capturar erros durante o processamento do agente. Você também pode configurar o gancho de sessão OnErrorOccurred, que retorna um valor ErrorHandling para controlar como o agente responde a erros.

  • Repetir: Repetir a operação com falha novamente.
  • Ignorar: prossiga com o processamento sem o resultado com falha.
  • Abortar: interromper o processamento e revelar o erro.

Tempos limite

Sempre defina um tempo limite ao aguardar respostas. O exemplo anterior usa WaitAsync(TimeSpan.FromSeconds(30)) para evitar espera indefinida se o agente encontrar um problema inesperado.

Design de prompt do sistema

O prompt do sistema é uma das decisões de configuração mais importantes. Ele define quem é o agente, o que ele pode fazer e como ele deve se comportar. Um prompt de sistema bem estruturado normalmente inclui:

  • Definição de função: o que o agente representa (por exemplo, "Você é um agente de suporte ao cliente da ContosoShop").
  • Funcionalidades: quais ferramentas estão disponíveis e o que elas fazem.
  • Diretrizes de fluxo de trabalho: como o agente deve abordar as tarefas (por exemplo, "Sempre verifique os detalhes do pedido antes de processar um retorno").
  • Regras e restrições: limites que o agente deve seguir (por exemplo, "Discutir apenas tópicos relacionados a pedidos" ou "Escalonar solicitações de reembolso acima de US$ 100").

Mantenha o prompt do sistema focado e específico. Instruções vagas levam a um comportamento imprevisível, enquanto regras excessivamente restritivas podem tornar o agente inútil.

Transmitir respostas com eventos delta

Para aplicativos interativos, como as interfaces do usuário de chat, você pode transmitir o token por token da resposta do agente em vez de aguardar a mensagem completa. Utilize AssistantMessageDeltaEvent para capturar cada token parcial à medida que chega:

session.On(evt =>
{
    switch (evt)
    {
        case AssistantMessageDeltaEvent delta:
            // Render each token as it arrives
            Console.Write(delta.Data.DeltaContent);
            break;

        case SessionIdleEvent:
            Console.WriteLine();
            tcs.SetResult("Done");
            break;

        case SessionErrorEvent err:
            tcs.SetException(
                new Exception($"Agent error: {err.Data.Message}"));
            break;
    }
});

A DeltaContent propriedade contém o fragmento de texto incremental. O streaming fornece uma experiência mais responsiva porque os usuários veem a resposta conforme ela se forma, em vez de esperar que o modelo gere a mensagem inteira.

Resumo

O SDK do GitHub Copilot fornece uma estrutura poderosa para implementar agentes de IA que podem raciocinar, usar ferramentas e manter o contexto. Ao definir os recursos do agente por meio de ferramentas, configurar sessões com prompts claros do sistema e lidar com respostas com eventos, você pode criar agentes sofisticados que fornecem valor comercial real. Uma robusta gestão de erros e um design cuidadoso de prompts são fundamentais para garantir que seu agente opere de forma confiável e eficaz em cenários de produção. Na próxima unidade, você verá como aplicar esses padrões de implementação para criar um agente de suporte ao cliente de exemplo usando o SDK do GitHub Copilot.