Desenvolvendo um chatbot com Azure AI Foundry e Azure OpenAI no Cloud Shell, do zero ao “funcionou”
Introdução
Existe um tipo de aprendizado que só acontece quando você coloca a mão na massa e encara o que o tutorial não prevê. Foi exatamente isso que aconteceu neste lab de desenvolver um aplicativo de IA com o SDK do Microsoft Foundry. A proposta é simples e poderosa: criar um app de chat que conversa com um modelo implantado no Azure, mantendo histórico de mensagens e rodando direto no Azure Cloud Shell. Na prática, porém, aparecem detalhes que fazem toda a diferença, como o tipo de endpoint que você está usando, o método de autenticação mais confiável no ambiente do Cloud Shell e as versões das bibliotecas que conversam entre si.
O que você vai construir aqui
Ao final, você terá um chatbot de terminal que pergunta, responde, mantém contexto e encerra quando você digitar quit. Você vai conseguir reproduzir todo o ambiente do zero, com todos os comandos, sem depender de editor “pesado”, e com um código final que realmente conversa com o deployment do seu modelo.
Antes de começar, entenda o ponto que mais derruba gente
O Azure AI Foundry trabalha com o conceito de Projeto e existe um endpoint do projeto que parece correto à primeira vista. Só que o endpoint do projeto não é o endpoint do Azure OpenAI. Quando você tenta chamar rotas de chat completion usando o host do projeto, a chance de receber 404 é enorme, porque a rota que o SDK do OpenAI espera não existe naquele host. O host que serve as rotas de chat completions é o do recurso Azure OpenAI, com domínio openai.azure.com. Quando você separa isso com clareza, metade dos erros some.
Ambiente do lab no Azure Cloud Shell
O Cloud Shell é ótimo porque já vem com várias coisas prontas, mas tem duas pegadinhas: a sessão é efêmera e a experiência muda dependendo se você está no PowerShell ou no Bash. Aqui eu vou assumir o PowerShell, que é o que costuma aparecer para muita gente no lab.
Crie uma pasta para o projeto e entre nela.
cd ~
mkdir ai102-chat -Force
cd ai102-chat
Criando um ambiente virtual opcional, mas recomendado
Se você quiser isolar dependências e evitar conflito com pacotes do sistema, crie um virtualenv. Se você já está com um ambiente como labenv ativo, mantenha. Se não estiver, crie e ative.
python -m venv labenv
No Cloud Shell, o ambiente virtual em Linux costuma ser ativado assim, mesmo dentro do PowerShell.
source labenv/bin/activate
Se aparecer (labenv) no início da linha do terminal, você está dentro do venv. A partir daqui, um detalhe importante: dentro do venv você não usa --user no pip.
Instalando as dependências do chatbot
Atualize o pip e instale as bibliotecas necessárias para autenticar com Azure AD e chamar o Azure OpenAI.
python -m pip install --upgrade pip
python -m pip install --upgrade azure-identity openai
Se o lab pedir requirements.txt e você quiser manter o padrão, crie o arquivo assim.
@'
azure-identity
openai
'@ | Set-Content -Encoding utf8 requirements.txt
E instale por ele.
python -m pip install -r requirements.txt
Confirmando que os imports funcionam
Esse é um teste simples que evita você perder tempo depois com erro de módulo.
python -c "from azure.identity import DeviceCodeCredential; from openai import AzureOpenAI; print('OK')"
Coletando as informações do Azure do jeito certo
Aqui entra o ponto central. Você pode ter um Project endpoint do Foundry com cara de endpoint “principal”, mas para chat completions você precisa do endpoint do recurso Azure OpenAI. O endpoint do Azure OpenAI é aquele que termina com openai.azure.com.
Se você já tem o endpoint do Azure OpenAI, ótimo. Se quiser puxar via CLI para evitar erro de digitação, use o comando abaixo, ajustando nome do recurso e resource group.
az account set --subscription "<SUBSCRIPTION_ID>"
$endpoint = az cognitiveservices account show `
--name "<NOME_DO_RECURSO_AZURE_OPENAI>" `
--resource-group "<RESOURCE_GROUP>" `
--query properties.endpoint -o tsv
$endpoint
Agora você define as variáveis de ambiente que o código vai ler. A primeira é o endpoint do Azure OpenAI e a segunda é o nome do deployment do modelo.
$env:AZURE_OPENAI_ENDPOINT="https://<seu-recurso>.openai.azure.com/"
$env:MODEL_DEPLOYMENT="gpt-4o"
Se você ainda não tiver certeza do nome do deployment, liste os deployments do recurso. O nome que importa é a coluna Name.
az cognitiveservices account deployment list `
--name "<NOME_DO_RECURSO_AZURE_OPENAI>" `
--resource-group "<RESOURCE_GROUP>" `
-o table
Por que escolher Device Code no Cloud Shell
No mundo ideal, DefaultAzureCredential resolve tudo. No mundo real do Cloud Shell, ele pode tentar várias estratégias e falhar em cadeia, ou depender do Azure CLI ser invocável por dentro do Python, o que nem sempre acontece. O Device Code é simples, previsível e funciona bem para labs porque você autentica pelo navegador quando o script pede e segue o jogo.
Criando o chatbot completo, pronto para rodar
Agora vem a parte boa: criar o arquivo chat-app.py completo sem depender do nano. Esse comando sobrescreve o arquivo e já deixa tudo pronto.
@'
import os
import sys
from azure.identity import DeviceCodeCredential, get_bearer_token_provider
from openai import AzureOpenAI
TENANT_ID = "<SEU_TENANT_ID>"
SCOPE = "https://cognitiveservices.azure.com/.default"
def main():
endpoint = os.getenv("AZURE_OPENAI_ENDPOINT")
deployment = os.getenv("MODEL_DEPLOYMENT")
if not endpoint:
print("ERROR: AZURE_OPENAI_ENDPOINT não definido.", flush=True)
print("Defina no PowerShell: $env:AZURE_OPENAI_ENDPOINT='https://<recurso>.openai.azure.com/'", flush=True)
sys.exit(1)
if not deployment:
print("ERROR: MODEL_DEPLOYMENT não definido.", flush=True)
print("Defina no PowerShell: $env:MODEL_DEPLOYMENT='gpt-4o'", flush=True)
sys.exit(1)
credential = DeviceCodeCredential(tenant_id=TENANT_ID)
token_provider = get_bearer_token_provider(credential, SCOPE)
client = AzureOpenAI(
azure_endpoint=endpoint,
api_version="2024-10-21",
azure_ad_token_provider=token_provider
)
messages = [
{"role": "system", "content": "You are a helpful AI assistant that answers questions."}
]
print("Chat pronto. Para sair, digite: quit", flush=True)
while True:
user_text = input("You: ").strip()
if user_text.lower() == "quit":
print("Saindo...", flush=True)
break
if not user_text:
continue
messages.append({"role": "user", "content": user_text})
print("Assistant: thinking...", flush=True)
resp = client.chat.completions.create(
model=deployment,
messages=messages
)
answer = resp.choices[0].message.content
print(f"Assistant: {answer}", flush=True)
messages.append({"role": "assistant", "content": answer})
if __name__ == "__main__":
main()
'@ | Set-Content -Encoding utf8 chat-app.py
Repare que TENANT_ID precisa ser preenchido. Se você já sabe o tenant, coloque. Se não souber, você consegue ver via CLI.
az account show --query tenantId -o tsv
Copie o resultado e substitua no arquivo na variável TENANT_ID. Se você quiser evitar abrir editor, dá para reescrever o arquivo com o tenant já colado, ou usar um replace simples, mas a forma mais clara no lab é colocar manualmente uma vez.
Executando o chatbot
Agora é a melhor parte. Rode o script.
python chat-app.py
Ele vai imprimir a instrução para autenticação por device code. Você autentica e, depois disso, o chat passa a responder. A primeira pergunta já serve como teste de ponta a ponta. Quando você perguntar qualquer coisa, ele deve imprimir Assistant: thinking… e em seguida retornar a resposta.
Como transformar isso em um chatbot utilizável, e não só um teste
Um detalhe que faz diferença na sensação de chatbot é manter o histórico, porque ele passa a entender o contexto do que você perguntou antes. Neste código, isso acontece porque a lista messages cresce com as entradas do usuário e as respostas do assistente. Se você quiser controlar o tamanho do histórico para não gastar tokens em conversas muito longas, a evolução natural é limitar quantas mensagens ficam salvas. Você pode, por exemplo, manter sempre o system prompt e as últimas dez interações. Isso deixa o bot mais “leve” e mais previsível em custo.
O que eu aprendi na prática com esse lab
Existe uma diferença grande entre “o lab diz para fazer” e “o ambiente real responde como”. O Cloud Shell é prático, mas muda algumas regras do jogo, especialmente no assunto credenciais. A maior armadilha aqui foi confundir o endpoint do projeto com o endpoint do Azure OpenAI. Quando você usa o endpoint certo, o erro 404 desaparece e o fluxo fica bem mais lógico. Quando você escolhe um método de autenticação robusto para o ambiente, como o Device Code, você para de brigar com detalhes de invocação do CLI e foca no que interessa, que é o app.
Fechamento
No fim, esse lab entrega muito mais do que um simples chat no terminal. Ele te força a entender a anatomia do Azure AI na prática: recurso, endpoint, deployment, credencial, versão de API, dependências e execução em ambiente efêmero. E quando finalmente funciona, você ganha algo valioso para a prova e para a vida real: a capacidade de diagnosticar. Porque construir é bom, mas saber por que quebrou e como ajustar é o que realmente acelera sua curva.




