Capacitação Microsoft AI — Aula 3: Microsoft Foundry, do recurso ao SDK com streaming

Este é o terceiro de oito artigos que acompanham as aulas da Capacitação Microsoft AI 2026, que Otávio Lourenço da Silva e eu ministramos ao vivo entre agosto e setembro. As gravações continuam no ar; os artigos existem para quem prefere ler, revisar ou copiar o código com calma.

O que a aula cobriu

A terceira aula é a aula da plataforma. Passamos pela arquitetura do Microsoft Foundry — a diferença entre recurso e projeto, os papéis de acesso (RBAC), as conexões com AI Search, Storage e Key Vault, o deploy de um modelo pelo portal e a escolha entre Standard e PTU — e depois voltamos ao código para fechar um ciclo que começou na aula 1. O programa desta aula usa o mesmo modelo, a mesma identidade, o mesmo SDK e o mesmo IChatClient da aula de Fundamentos, com uma única diferença: a resposta chega token a token, em vez de inteira, de uma vez só.

Três ideias para levar

1. Recurso, projeto e papel: a plataforma antes do código

No Foundry, o recurso é a unidade de infraestrutura — é nele que os modelos são implantados e que as conexões com outros serviços do Azure são registradas. O projeto é a unidade de trabalho, com endpoint próprio, e é a ele que a aplicação se conecta: o FOUNDRY_ENDPOINT de todas as aulas termina em /api/projects/<projeto>. E o papel que a sua identidade precisa ter é o Foundry User, atribuído no recurso: ser Owner da subscription concede Actions (criar e apagar), mas chamar o modelo exige DataActions. Quem aprende essa separação uma vez para de esbarrar em 403 Forbidden.

2. Streaming é uma troca de método, não de arquitetura

O setup é idêntico ao da aula 1 — AIProjectClient autenticado por DefaultAzureCredential, cliente de Responses para o deployment e conversão em IChatClient. A diferença cabe no laço final: GetResponseAsync vira GetStreamingResponseAsync, que devolve um IAsyncEnumerable<ChatResponseUpdate>. Cada atualização já traz o texto em .Text, sem testar tipo nenhum, e o mesmo laço funcionaria contra qualquer outro provedor.

ChatOptions options = new();

await foreach (ChatResponseUpdate update
    in chatClient.GetStreamingResponseAsync(prompt, options))
{
    Console.Write(update.Text);              // pedaço de texto

    if (update.ConversationId is not null)
    {
        options.ConversationId = update.ConversationId;   // elo da próxima pergunta
    }
}

Vale rodar esta demo e a de Fundamentos lado a lado, com a mesma pergunta: a percepção de latência muda sem que nada além do método chamado tenha mudado.

3. O contexto continua no serviço — e chega junto com o fluxo

Como na aula 1, o programa não guarda histórico: guarda apenas o ConversationId e o serviço cuida do resto. A sutileza do streaming é que esse id chega junto com as atualizações e só é definitivo no fim, por isso o código guarda o último valor não nulo em vez de assumir que ele veio na primeira. Comparado com a aula 2, onde o histórico vive numa lista no cliente, fica claro que a decisão de quem guarda o contexto é independente da decisão de como a resposta é consumida.

Antes de rodar

  • .NET SDK 10 e Azure CLI instalados, com az login --tenant <tenant-id> feito no tenant certo.
  • Um recurso Foundry com um modelo implantado e o papel Foundry User atribuído à sua conta — ser Owner da subscription não basta.
  • As variáveis FOUNDRY_ENDPOINT (endpoint do projeto, terminando em /api/projects/<projeto>) e FOUNDRY_MODEL (nome do deployment) no seu launchSettings.json. Um único arquivo serve as três primeiras aulas — basta trocar o nome do perfil.
  • Não altere as versões dos pacotes. O projeto converge para o pivô OpenAI 2.9.1; dotnet add package OpenAI, o Azure.AI.Extensions.OpenAI em prerelease ou o Microsoft.Extensions.AI.OpenAI sem versão compilam sem aviso e quebram em tempo de execução com MissingMethodException. O NoWarn de OPENAI001 no .csproj também não é opcional.

Se você está na trilha Python

A mesma aula existe em Python 3.12+: AIProjectClient com DefaultAzureCredential, cliente OpenAI obtido do projeto, stream=True para a resposta token a token e contexto no serviço via previous_response_id. A versão Python vai um pouco além: retry exponencial em erros transientes (429 e 5xx) com tenacity, contagem local de tokens com tiktoken para estimar custo antes de rodar em lote, e saída formatada com rich. As versões ficam fixadas no requirements.txt.

Próximo passo

Faça um diff entre o Program.cs desta aula e o da aula 1: as seções de setup são idênticas e a diferença cabe no laço final. Depois, se quiser ver o problema de versões ao vivo, rode dotnet add package OpenAI, compile com sucesso, veja o erro em tempo de execução e desfaça — ensina mais sobre grafo de dependências do que qualquer slide. Na aula 4 entramos em RAG, embeddings e Azure AI Search: como dar ao modelo o contexto da sua empresa sem treinar nada.

Dúvidas ou algo que não funcionou? Deixe nos comentários ou abra uma issue no repositório.

Comentários

Deixe um comentário