Amazon Bedrock para desenvolvedores .NET: por onde começar

Rodar um modelo de linguagem por conta própria significa lidar com GPU, escalonamento, latência de cold start e uma conta de infraestrutura que cresce rápido. Amazon Bedrock existe para tirar essa camada do caminho: acesso gerenciado a modelos de diferentes provedores através de uma API só, sem provisionar servidor nenhum.

Um catálogo de modelos, uma API comum

Bedrock reúne modelos de múltiplos provedores sob o mesmo serviço gerenciado: Claude, da Anthropic, Llama, da Meta, e os modelos da própria família Amazon Nova, que hoje ocupa o espaço que antes era do Titan para geração de texto (o Titan segue disponível principalmente como gerador de embeddings). A vantagem prática de reunir provedores diferentes atrás do mesmo serviço é poder trocar de modelo, ou usar mais de um lado a lado, sem reconstruir a infraestrutura de acesso a cada troca.

A lista exata de modelos habilitados e seus identificadores muda com alguma frequência, então vale sempre conferir o catálogo atual diretamente no console do Bedrock antes de fixar um ModelId específico em código.

A API Converse do Bedrock existe justamente para isso: uma interface única de conversação que funciona com qualquer modelo do catálogo que suporte mensagens, incluindo Claude, Llama e a família Nova, então o código de chamada não muda ao trocar de modelo, só o identificador do modelo passado na requisição.

Chamando o Bedrock a partir do .NET

O SDK oficial expõe isso via Amazon.BedrockRuntime, com AmazonBedrockRuntimeClient como ponto de entrada:

var client = new AmazonBedrockRuntimeClient(RegionEndpoint.USEast1);

var request = new ConverseRequest
{
    ModelId = "<id-do-modelo-no-catalogo-do-bedrock>",
    Messages = new List<Message>
    {
        new Message
        {
            Role = ConversationRole.User,
            Content = new List<ContentBlock> { new ContentBlock { Text = "Explique o que é idempotência em uma frase." } }
        }
    }
};

var response = await client.ConverseAsync(request);
Console.WriteLine(response.Output.Message.Content[0].Text);

Trocar ModelId para o identificador de um modelo Llama ou Nova mantém o restante do código igual, porque a estrutura de Messages e ContentBlock é a mesma para qualquer modelo compatível com a API Converse.

Streaming quando a resposta não pode esperar inteira

Para respostas mais longas, esperar o texto inteiro antes de mostrar qualquer coisa prejudica a experiência. ConverseStreamAsync devolve a resposta em pedaços conforme ela é gerada:

var streamResponse = await client.ConverseStreamAsync(request);

await foreach (var evento in streamResponse.Stream)
{
    if (evento is ContentBlockDeltaEvent delta)
        Console.Write(delta.Delta.Text);
}

Cada evento do stream representa um pedaço incremental da resposta, permitindo exibir o texto progressivamente em vez de esperar a geração inteira terminar.

Autenticação via IAM, não chave de API solta

Diferente de chamar diretamente a API de um provedor de LLM com uma chave estática, o acesso ao Bedrock passa pelo modelo de permissão do IAM da AWS. Isso significa conceder à role ou ao usuário que executa a aplicação permissão explícita para invocar os modelos necessários (a ação bedrock:InvokeModel ou bedrock:InvokeModelWithResponseStream, dependendo do caso), em vez de espalhar uma chave de API por variável de ambiente. Para quem já opera na AWS, isso integra naturalmente com o restante do controle de acesso já existente na conta, sem outro segredo separado para gerenciar.

Por onde realmente começar

O primeiro passo prático, antes de qualquer código, é habilitar o acesso aos modelos desejados no console do Bedrock, já que cada modelo do catálogo precisa ser ativado explicitamente na conta antes de poder ser chamado. Depois disso, a API Converse com AmazonBedrockRuntimeClient já é suficiente para uma primeira integração funcional, deixando otimizações como streaming, cache de prompt ou seleção fina de parâmetros de geração para depois que o fluxo básico já estiver funcionando de ponta a ponta.