Apresentação
🔌 APIs e Backend para AI
AI Engineers constroem serviços, não apenas modelos. A API é a interface entre o sistema de AI e os consumidores.
🎯 Frase que impressiona
Quando desenho APIs de AI, penso em três coisas: contratos claros com Pydantic, streaming para casos de uso sensíveis à latência, e degradação graciosa quando o LLM subjacente falha.
Estrutura típica de uma API de AI
Client → API Gateway / Load Balancer → FastAPI Backend
↓
Auth / Rate Limit
↓
/v1/chat (streaming)
/v1/embed (batch)
/v1/ingest (async)
↓
LLM Service | Embedding Service | Queue
1️⃣ Frameworks — FastAPI vs Flask
| FastAPI | Flask | |
|---|---|---|
| Async | Nativo | Síncrono (ou gevent) |
| Validação | Pydantic automático | Manual |
| OpenAPI | /docs, /redoc gerados | Add-on |
| Performance | Melhor para I/O bound (LLM calls) | Adequado para load baixo |
Para LLMs: FastAPI — chamadas a APIs externas são I/O bound; async aproveita melhor.
2️⃣ Endpoints típicos para AI
POST /v1/chat— Chat completo; suporta streaming (SSE ou chunked)POST /v1/embed— Embedding; aceita batch (array de textos)POST /v1/ingest— Ingestão de documentos; async, retorna job_idGET /v1/health— Liveness: está vivo? Readiness: consegue servir? (DB, LLM API)
3️⃣ Validação com Pydantic
class ChatRequest(BaseModel):
messages: list[dict]
model: str = "gpt-4o-mini"
temperature: float = Field(ge=0, le=2)
max_tokens: int = Field(ge=1, le=4096)
class ChatResponse(BaseModel):
content: str
usage: TokenUsage
Validação automática: 422 se formato errado. Schemas no OpenAPI para clientes.
4️⃣ Streaming — Server-Sent Events (SSE)
Para LLMs: devolver tokens à medida que o modelo gera. Melhor UX (TTFT).
from fastapi.responses import StreamingResponse
async def stream_chat(request: ChatRequest):
async def generate():
async for token in llm.astream(request.messages):
yield f"data: {json.dumps({'token': token})}\n\n"
return StreamingResponse(generate(), media_type="text/event-stream")
Alternativa: StreamingResponse com text/plain e chunked encoding. Cliente processa linha a linha.
5️⃣ Dependency Injection
def get_llm() -> LLM:
return llm_client # singleton ou pool
@app.post("/chat")
async def chat(req: ChatRequest, llm: LLM = Depends(get_llm)):
return await llm.ainvoke(req.messages)
Uso: Injetar DB, auth, config, serviços externos. Facilita testes (mock do Depends).
6️⃣ Background Tasks vs Queue
| BackgroundTasks | Queue (Celery, Kafka) | |
|---|---|---|
| Quando | Tarefas rápidas (<30s) | Tarefas longas, retry |
| Onde | Mesmo processo | Worker separado |
| Retry | Manual | Automático |
| Escala | Limitado ao processo | Escala workers |
Exemplo: Ingestão de documento → Queue. Logging pós-response → BackgroundTasks.
7️⃣ Conceitos essenciais
- Idempotência:
POSTcom idempotency key; retry = mesmo resultado. - Rate limiting: Token bucket ou sliding window por user/API key. Redis para estado distribuído.
- Autenticação: JWT, API keys (header
X-API-Key), OAuth2. - Paginação: Cursor-based (
?cursor=xxx&limit=20) melhor que offset para listas grandes. - CORS: Configurar
CORSMiddlewarese o frontend está noutro domínio.
8️⃣ Timeouts e Retries para LLM APIs
- Timeout: 30-60s para geração; 5-10s para embedding.
- Retry: Só em 429, 503, timeout. Exponential backoff: 1s, 2s, 4s. Max 3 retries.
- Circuit breaker: Após N falhas, falhar rápido; half-open para testar recuperação.
9️⃣ Health Checks
/health/live— Liveness: processo está vivo. K8s usa para restart./health/ready— Readiness: DB conectado? LLM API acessível? K8s usa para traffic.
Se readiness falha, o pod deixa de receber tráfego mas não é morto.
🔟 Versionamento de API
- URL:
/v1/chat,/v2/chat— comum, explícito. - Header:
Accept-Version: 2— menos intrusivo. - Para LLMs: Permite evoluir schemas de prompts, adicionar campos, sem quebrar clientes antigos.
1️⃣1️⃣ Error Handling
- 400 — Bad request (validação falhou)
- 401 — Unauthorized
- 429 — Rate limit exceeded
- 500 — Erro interno (não expor detalhes ao cliente)
- 503 — Service unavailable (LLM API down)
Custom exception handlers para respostas consistentes.
1️⃣2️⃣ Logging e Observabilidade
- Request ID: Gerar em middleware; propagar a todos os logs.
- Log estruturado: JSON com request_id, user_id, latency, tokens_used.
- Métricas: Latência p50/p99, taxa de erro, tokens/request.
Ferramentas
- FastAPI — framework principal
- Pydantic — validação, schemas
- Tenacity / backoff — retry com backoff
- Starlette — base do FastAPI (middleware, responses)
Zona de prática
Sem perguntas. Clica em Editar para adicionar.