Project 01 | AI Backend Engineering
A small API with real engineering underneath. βοΈπΏ
AI Playground API is a FastAPI backend built to establish the first foundation of an AI-powered backend system.
Instead of stopping at:
Client β LLM β Response
the project introduces the backend engineering around that interaction:
Client
β
FastAPI
β
Validation
β
AI Service
β
OpenAI Responses API
β
Usage + Cost
β
Clean API Response
The goal is simple:
Make communication with an LLM behave like a proper backend service.
| Capability | Included |
|---|---|
| π€ LLM generation | β |
| π§© Structured AI output | β |
| ποΈ Reasoning control | β |
| π’ Token usage | β |
| π° Cost estimation | β |
| π‘οΈ Provider error handling | β |
| π Application logging | β |
| π Environment secrets | β |
| π§ͺ Automated testing | β |
| βοΈ GitHub Actions CI | β |
Basic service response.
Returns the application's health status and version.
Generates a normal LLM response.
Example request:
{
"prompt": "Explain dependency injection in FastAPI.",
"model": "gpt-5.6-luna",
"reasoning_effort": "low",
"max_output_tokens": 300
}Example response shape:
{
"text": "Dependency injection in FastAPI...",
"model": "gpt-5.6-luna",
"usage": {
"input_tokens": 12,
"output_tokens": 95,
"total_tokens": 107,
"reasoning_tokens": 0
},
"estimated_cost": 0.000116
}Instead of relying on arbitrary model text, the endpoint returns data through a Pydantic schema.
class StructuredAIResponse(BaseModel):
answer: str
summary: strExample:
{
"answer": "An API allows software systems to communicate.",
"summary": "APIs provide structured software communication."
}This creates a predictable boundary between model output and backend data.
The request schema supports:
model
reasoning_effort
max_output_tokens
Valid reasoning levels:
none
low
medium
high
xhigh
max
Input constraints are enforced before requests reach the provider.
External services fail.
This project treats those failures as part of the API design.
Provider Timeout
β
AIServiceTimeoutError
β
504 Gateway Timeout
Rate Limit
β
AIServiceRateLimitError
β
429 Too Many Requests
Connection / Provider Failure
β
Application Exception
β
502 Bad Gateway
Provider-specific exceptions are translated into application-level errors instead of leaking implementation details to API consumers.
Every normal generation response exposes token usage:
Input Tokens
Output Tokens
Total Tokens
Reasoning Tokens
The service also calculates an estimated request cost from input and output token usage.
Cost calculation is isolated in:
app/utils/cost.py
The returned cost is an estimate, not a billing statement.
Important AI service events are logged:
Request
β
Provider call
β
Provider response
β
Usage calculation
β
API response
Errors are logged without exposing API credentials.
Logging configuration is centralized in:
app/logging_config.py
βββββββββββββββββ
β Client β
βββββββββ¬ββββββββ
β
βββββββββββββββββ
β FastAPI β
βββββββββ¬ββββββββ
β
βββββββββββββββββ
β Pydantic β
β Validation β
βββββββββ¬ββββββββ
β
βββββββββββββββββ
β AI Service β
βββββββββ¬ββββββββ
β
βββββββββββββββββ
β OpenAI β
β Responses API β
βββββββββββββββββ
The main separation is:
HTTP Layer
β
Service Layer
β
Provider Layer
This keeps API routing separate from AI-provider communication.
AI-Playground-API/
β
βββ app/
β βββ exceptions/
β β βββ custom_exceptions.py
β β βββ handlers.py
β β
β βββ services/
β β βββ ai_services.py
β β
β βββ utils/
β β βββ cost.py
β β
β βββ config.py
β βββ logging_config.py
β βββ main.py
β βββ schemas.py
β
βββ tests/
β βββ test_ai_service_errors.py
β βββ test_ai_service_request.py
β βββ test_ai_structured_response_errors.py
β βββ test_cost.py
β βββ test_exception_handlers.py
β βββ test_generate.py
β βββ test_structured_response.py
β βββ test_validation.py
β
βββ .github/
β βββ workflows/
β βββ ci.yml
β
βββ .env.example
βββ .gitignore
βββ LICENSE
βββ pytest.ini
βββ README.md
βββ requirements.txt
Create a local .env file:
OPENAI_API_KEY=your_api_key_hereThe real .env file is excluded from version control.
A safe template is provided:
.env.example
Never commit real API credentials.
Run the complete local test suite:
python -m pytest -qCurrent result:
19 passed
The real provider test is explicitly marked:
@pytest.mark.integrationRun without external provider access:
python -m pytest -q -m "not integration"Current CI result:
18 passed
1 deselected
Run the integration test separately when a valid local API key is available:
python -m pytest -q -m integrationGitHub Actions runs automatically on:
push
pull_request
Pipeline:
Checkout
β
Python Setup
β
Install Dependencies
β
Run Tests
β
β
Pass
External integration tests are excluded from CI.
CI uses a non-secret placeholder:
OPENAI_API_KEY=ci-test-placeholder
No real provider credential is stored in the workflow.
python -m venv .venvsource .venv/bin/activatepython -m pip install -r requirements.txtOPENAI_API_KEY=your_api_key_herepython -m fastapi dev app/main.pyThen explore the generated FastAPI documentation.
Service layer: keeps provider communication out of route handlers.
Custom exceptions: creates a stable application-level error boundary.
Structured output: turns model output into validated application data.
No database: this project has no persistence requirement.
No Docker: containerization is intentionally deferred because this single-service project has no infrastructure need for it yet.
Synchronous provider client: deeper async provider integration is reserved for workloads where concurrency and streaming actually matter.
This project intentionally does not include:
Database
Authentication
Streaming
Redis
File Processing
Embeddings
Vector Search
RAG
Agents
Tool Calling
Production Deployment
Nothing here is accidentally missing.
The project solves its current problem without adding infrastructure for problems it does not have yet.
Core API β
LLM Integration β
Structured Output β
Validation β
Error Handling β
Logging β
Usage Tracking β
Cost Estimation β
Testing β
CI β
Secret Protection β
Documentation β
License β
The playground started with one simple question:
Can an LLM become a reliable backend dependency instead of just an API call?
This project answers that question with a working, tested, documented service and a clean foundation for everything built on top of it.
Project 01 shipped. βοΈπ§ πΏ