Deploying a Real Python AI Application
Every project in this series has run on a local machine so far. This part covers what genuinely changes moving GreenDesk's real FastAPI service (parts 6 and 7) into an actual, deployed production environment.
Real, production-appropriate secrets management
Local development (this series so far): a real, local .env file,
loaded by python-dotenv
Real production: environment variables set directly by the hosting
platform's own real secrets management — NOT a .env file deployed
alongside the codeThis is a genuinely important, real distinction: a .env file is a real, practical local-development convenience, but shipping it as part of a real deployment (even if technically excluded from git, per part 1's .gitignore) risks it ending up somewhere it shouldn't. Real, production platforms (a real cloud provider's dashboard, a container orchestration secret store) provide their own, genuinely more secure mechanism for injecting the same ANTHROPIC_API_KEY environment variable at runtime.
A real, production-shaped Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]Containerizing GreenDesk's real FastAPI service is a genuinely common, practical real deployment path — the ANTHROPIC_API_KEY environment variable gets injected at real container runtime by the hosting platform, never baked into the image itself, keeping the real secret out of the container image entirely.
Notice .env is never copied into this real image — COPY . . would include it if it existed in the build context and wasn't excluded, which is exactly why a real, production .dockerignore file (mirroring part 1's .gitignore) needs to exclude .env explicitly, as a genuine, additional safeguard beyond just keeping it out of git.
Real, production process management
Local development: uvicorn main:app --reload (auto-restarts on code
changes — genuinely useful locally, never appropriate in production)
Real production: uvicorn main:app --workers 4 (multiple real worker
processes handling concurrent requests, no --reload)Running multiple real worker processes directly connects back to part 18's caching discussion — this is exactly why a shared, external cache (Redis) matters in a genuine, multi-worker production deployment, while lru_cache's single-process limitation becomes a real, practical problem the moment more than one worker process is actually running.
Real, environment-specific configuration
import os
ENVIRONMENT = os.environ.get("ENVIRONMENT", "development")
if ENVIRONMENT == "production":
RATE_LIMIT = "10/minute"
LOG_LEVEL = "warning"
else:
RATE_LIMIT = "100/minute" # genuinely more permissive for real local testing
LOG_LEVEL = "debug"A real, explicit ENVIRONMENT variable, checked at startup, is what lets the exact same real codebase behave appropriately differently in local development versus production — part 7's real rate limiting, for instance, genuinely should allow more requests during real local testing than it does once serving actual, real GreenDesk customer traffic.
Real, production monitoring for AI-specific concerns
import logging
logger = logging.getLogger("ai_api")
def qualify_lead(request: LeadQualificationRequest, api_key: str = Depends(verify_api_key)):
response = client.messages.create(...)
logger.info(
"lead_qualification_call",
extra={
"input_tokens": response.usage.input_tokens,
"output_tokens": response.usage.output_tokens,
},
)
# ...Logging real, actual token usage per request — directly available on the API response object per the AI Fundamentals series' own token coverage — is a genuinely important, AI-specific monitoring practice beyond standard real application logging, since it's what lets GreenDesk's real team track actual, ongoing API cost trends over time, not just whether requests are succeeding.
A real, practical pre-deployment checklist
[ ] Real secrets set via the hosting platform, not a shipped .env file
[ ] .dockerignore excludes .env, venv/, __pycache__/
[ ] Rate limiting (part 7) tuned for real production traffic
[ ] Shared cache (part 18) configured, not lru_cache, if running
multiple real workers
[ ] Real token-usage logging in place for ongoing cost visibility
[ ] Mocked test suite (part 19) passing in real CI before deployNext: common mistakes building AI-powered Python apps — a direct, honest roundup of the real gaps this series flagged individually, brought together in one place.