Add Azure OpenAI chat completions to your existing Python FastAPI app in minutes.
- Prerequisites
- Step 1: Provision Azure Resources
- Step 2: Install Dependencies
- Step 3: Add the ChatClient to Your App
- Step 4: Verify It Works
- Before & After
- API Reference
- Configuration Options
- Common Pitfalls
- Next Steps
| Requirement | Check |
|---|---|
| Python 3.10+ | python --version |
| Azure CLI | az --version |
| Azure Developer CLI (azd) | azd version |
| Azure subscription with OpenAI access | Apply here if needed |
| Existing FastAPI project | Has main.py + requirements.txt |
# Log in to Azure (needed for keyless auth)
az login
azd auth login# From your project root
azd add chat
azd provisionThis provisions:
- Azure OpenAI account (Cognitive Services, kind: OpenAI)
- Chat model deployment (gpt-4o-mini, 10K TPM)
- RBAC role assignment (Cognitive Services OpenAI User)
- Copy
blocks/chat/infra/chat.bicepinto your project'sinfra/directory - Add the module to your
main.bicep:
module chat 'chat.bicep' = {
name: 'chat'
scope: resourceGroup
params: {
location: location
principalId: principalId
tags: tags
}
}
// Wire outputs to environment variables
output AZURE_OPENAI_ENDPOINT string = chat.outputs.endpoint
output AZURE_OPENAI_CHAT_DEPLOYMENT string = chat.outputs.chatDeploymentName
output AZURE_OPENAI_API_VERSION string = chat.outputs.apiVersion- Run
azd provision
Verify your environment variables are set:
azd env get-values | grep AZURE_OPENAIYou should see:
AZURE_OPENAI_ENDPOINT="https://<name>.openai.azure.com"
AZURE_OPENAI_CHAT_DEPLOYMENT="gpt-4o-mini"
AZURE_OPENAI_API_VERSION="2024-12-01-preview"
# Add to your existing requirements.txt
echo "openai>=1.50.0" >> requirements.txt
echo "azure-identity>=1.15.0" >> requirements.txt
# Install
pip install -r requirements.txtOr install directly:
pip install openai>=1.50.0 azure-identity>=1.15.0# Copy into your source directory (adjust the target to match your project structure)
# If your app is at app/main.py:
cp blocks/chat/code/python/chat_client.py app/
# If your app is at src/main.py:
cp blocks/chat/code/python/chat_client.py src/
# Flat structure (main.py at project root):
cp blocks/chat/code/python/chat_client.py .Note: The import path depends on your project structure. Use
from chat_client import ChatClientfor flat structures, orfrom app.chat_client import ChatClientfor package structures.
Add the following to your FastAPI app:
# src/main.py
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
from chat_client import ChatClient
app = FastAPI()
# Initialize the client — reads config from environment variables.
# The system_prompt is optional but recommended.
chat = ChatClient(
system_prompt="You are a helpful assistant for our product catalog."
)
class ChatRequest(BaseModel):
message: str
class ChatResponse(BaseModel):
response: str
@app.post("/chat", response_model=ChatResponse)
async def chat_endpoint(request: ChatRequest):
"""Chat with Azure OpenAI."""
response = chat.complete([
{"role": "user", "content": request.message}
])
return ChatResponse(response=response)
@app.post("/chat/stream")
async def chat_stream(request: ChatRequest):
"""Stream a chat response token by token."""
return StreamingResponse(
chat.stream([{"role": "user", "content": request.message}]),
media_type="text/event-stream",
)
@app.get("/health")
async def health():
"""Health check — verifies Azure OpenAI connectivity."""
return chat.health_check()Create a .env file (or sync from azd):
# Sync from azd (recommended)
azd env get-values > .envOr create manually:
AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com
AZURE_OPENAI_CHAT_DEPLOYMENT=gpt-4o-mini
AZURE_OPENAI_API_VERSION=2024-12-01-previewLoad .env in your app (add python-dotenv to requirements.txt):
from dotenv import load_dotenv
load_dotenv()# Start your app
uvicorn src.main:app --reload
# Test the health endpoint
curl http://localhost:8000/health
# Test the chat endpoint
curl -X POST http://localhost:8000/chat \
-H "Content-Type: application/json" \
-d '{"message": "What is Azure OpenAI?"}'
# Test streaming
curl -X POST http://localhost:8000/chat/stream \
-H "Content-Type: application/json" \
-d '{"message": "Explain cloud computing in 3 sentences."}'Expected health check response:
{
"status": "ok",
"block": "chat",
"message": "Azure OpenAI is reachable and the model deployment is responding.",
"details": {
"endpoint": "https://your-resource.openai.azure.com",
"deployment": "gpt-4o-mini",
"api_version": "2024-12-01-preview",
"model": "gpt-4o-mini"
}
}# src/main.py — BEFORE
from fastapi import FastAPI
app = FastAPI()
@app.get("/products")
async def list_products():
return [{"id": 1, "name": "Widget", "price": 9.99}]
@app.get("/products/{product_id}")
async def get_product(product_id: int):
return {"id": product_id, "name": "Widget", "price": 9.99}# src/main.py — AFTER (additions highlighted with comments)
from fastapi import FastAPI
from pydantic import BaseModel # ← NEW
from chat_client import ChatClient # ← NEW
app = FastAPI()
# ── New: AI chat client ──────────────────────────
chat = ChatClient(
system_prompt="You are a helpful product assistant."
)
class ChatRequest(BaseModel): # ← NEW
message: str
@app.post("/chat") # ← NEW
async def chat_endpoint(request: ChatRequest):
response = chat.complete([
{"role": "user", "content": request.message}
])
return {"response": response}
@app.get("/health") # ← NEW
async def health():
return chat.health_check()
# ── End new ───────────────────────────────────────
@app.get("/products")
async def list_products():
return [{"id": 1, "name": "Widget", "price": 9.99}]
@app.get("/products/{product_id}")
async def get_product(product_id: int):
return {"id": product_id, "name": "Widget", "price": 9.99}What changed:
- Added
chat_client.py(1 file) - Added 2 dependencies to
requirements.txt - Added ~15 lines of code to
main.py - The existing endpoints are untouched
| Parameter | Type | Default | Description |
|---|---|---|---|
endpoint |
str | None |
$AZURE_OPENAI_ENDPOINT |
Azure OpenAI URL |
deployment |
str | None |
$AZURE_OPENAI_CHAT_DEPLOYMENT |
Model deployment name |
api_version |
str | None |
$AZURE_OPENAI_API_VERSION |
API version |
system_prompt |
str | None |
None |
Default system message |
credential |
Any | None |
DefaultAzureCredential() |
Azure credential |
Returns the assistant's complete response.
Yields response tokens as they arrive.
Returns {"status": "ok", ...} or {"status": "error", "message": "..."}.
| Variable | Required | Default | Description |
|---|---|---|---|
AZURE_OPENAI_ENDPOINT |
Yes | — | Azure OpenAI resource URL |
AZURE_OPENAI_CHAT_DEPLOYMENT |
Yes | — | Deployment name |
AZURE_OPENAI_API_VERSION |
Yes | — | API version |
| Parameter | Default | Description |
|---|---|---|
modelName |
gpt-4o-mini |
Model to deploy |
modelVersion |
2024-07-18 |
Model version |
deploymentCapacity |
10 |
TPM capacity (thousands) |
location |
resource group location | Azure region |
Override via azd:
azd env set AZURE_OPENAI_MODEL gpt-4o
azd env set AZURE_OPENAI_DEPLOYMENT_CAPACITY 30
azd provisionBased on real-world error research. See TROUBLESHOOTING.md for full details.
Cause: Not logged in to Azure CLI.
Fix:
az login
# For multi-tenant: az login --tenant <tenant-id>Cause: Missing RBAC role. Having Contributor on the resource group is NOT enough.
Fix:
az role assignment create \
--assignee $(az ad signed-in-user show --query id -o tsv) \
--role "Cognitive Services OpenAI User" \
--scope <azure-openai-resource-id>The Bicep module creates this role assignment automatically. If you get 403, it may take up to 5 minutes for RBAC to propagate after provisioning.
Cause: Not all models are in all regions. gpt-4o-mini is broadly available but not everywhere.
Fix:
azd env set AZURE_LOCATION swedencentral # or eastus, westus3, etc.
azd provisionCause: Subscription TPM limit reached for this model in this region.
Fix: The block defaults to 10K TPM (conservative). If even that fails:
azd env set AZURE_OPENAI_DEPLOYMENT_CAPACITY 5
azd provisionOr request a quota increase in the Azure Portal.
Cause: Old openai or azure-identity package installed.
Fix:
pip install --upgrade openai>=1.50.0 azure-identity>=1.15.0The ChatClient validates SDK versions at import time and will print a clear error if they're too old.
Cause: Environment variables not synced after provisioning.
Fix:
azd env get-values > .env
# Then restart your app- Add RAG:
azd add rag— Add semantic search over your app's data - Customize the model: Change
AZURE_OPENAI_MODELto use GPT-4o or other models - Add conversation history: Store messages in a list and pass the full history to
complete() - Add content safety: Layer Azure AI Content Safety on top (coming soon as a block)
- Deploy:
azd deploypushes your app to Azure with managed identity already configured