Apresentação
🏗️ System Design para AI — Arquitetura em Escala
Eles valorizam arquitetura. Saber desenhar sistemas de AI para produção diferencia candidatos.
🎯 Frase que impressiona
Penso no design de sistemas de AI em camadas: fluxo de pedidos, computação, armazenamento e resiliência. Cada camada tem características diferentes de escalabilidade e custo.
Arquitetura de Alto Nível (Fluxo de Pedidos)
User → API Gateway → Load Balancer → AI Backend (stateless)
↓
┌───────────────┼───────────────┐
↓ ↓ ↓
Cache (Redis) Embedding Svc LLM Gateway
↓ ↓ ↓
hit → return Vector DB (OpenAI/Claude/vLLM)
miss → LLM RAG retrieval
Caminho síncrono (chat): Request → Cache check → (miss) → Embedding → Vector search → Context build → LLM → Response
Caminho assíncrono (ingestão): Event → Kafka/SQS → Worker (chunk, embed) → Vector DB
1️⃣ API Gateway — Primeira Linha de Defesa
- Rate limiting: Token bucket ou sliding window por user/API key. Redis para estado distribuído.
- Authentication: JWT, API keys — validar antes de chegar ao backend.
- Request validation: Schema do payload (Pydantic) antes de processar.
- Logging: Request ID para tracing; log de custo (tokens) por request.
- Prompt injection básico: Sanitizar input, detetar padrões suspeitos, guardrails antes do LLM.
2️⃣ Escala para Milhões de Users
API Gateway → Load Balancer → Autoscaling AI Backend → LLM Service
Componentes críticos:
- Autoscaling: HPA no K8s baseado em CPU, memória ou custom metrics (queue depth, latency).
- Async processing: Tarefas pesadas (ingestão, batch) via Kafka/RabbitMQ — não bloquear request path.
- Message queues: Buffer de picos, retry automático, desacoplamento.
- Distributed vector DB: Qdrant, Pinecone, Weaviate — cluster para alta leitura.
- Stateless backend: Qualquer réplica serve qualquer request. Session em Redis ou client.
Ferramentas: Kubernetes, Kafka/RabbitMQ/SQS, Redis, vector DB (Qdrant, Pinecone, pgvector).
3️⃣ Reduzir Custos LLM — Estratégias Prioritárias
- Caching (maior impacto):
- Semantic cache: embedding da query → busca similaridade → hit devolve resposta; miss → LLM.
- Exact cache: hash do prompt → hit instantâneo.
- Cache de embeddings: queries repetidas não re-embedam.
- Model routing: Queries simples (classificação, intent) → modelo pequeno (GPT-4o-mini, Llama 3.2 3B). Complexas → modelo maior.
- RAG: Retrieval before generation — menos tokens no contexto, menos "invenção".
- Batching: Agrupar requests (embedding API aceita batch) para melhor throughput.
- Token optimization: Prompts curtos, output limits, structured outputs para evitar verbosidade.
- Speculative decoding: Modelo pequeno "adivinha" tokens, modelo grande confirma — menos calls ao modelo grande.
4️⃣ Microservices — Decomposição para AI
| Serviço | Responsabilidade | Escala independente |
|---|---|---|
| API | Routing, auth, validation | Por traffic |
| Embedding Service | Text → vector | Por volume de ingestão + queries |
| LLM Gateway | Proxy para OpenAI/Claude/vLLM, routing | Por LLM load |
| Vector DB | Storage, similarity search | Por index size |
| Ingestion Worker | Processar docs, chunk, embed | Por throughput |
Benefício: Cada serviço escala conforme a sua carga. Embedding pode ter 10 réplicas, LLM gateway 2.
5️⃣ Sistemas Orientados a Eventos
Sync vs Async:
- Sync: Chat, respostas imediatas. User espera.
- Async: Ingestão de docs, batch embedding, reportes. Event → Queue → Worker.
Event-driven ingestão:
Doc criado/alterado → Event (Kafka/SQS) → Worker → Chunk → Embed → Vector DB
Desacoplamento, retry automático, reprocessar sem re-enviar.
6️⃣ Caching — Três Níveis
| Nível | O quê | TTL | Impacto | |-------|------|-----| | Exact | Hash(prompt) → response | 24h+ | Latência, custo | | Semantic | Embedding(query) → similar → response | 1–24h | Custo (queries similares) | | Embedding | Query text → vector | 7d+ | Custo em embedding calls |
Redis: Keys com TTL. Semantic cache usa vector similarity ou approx (ex: GPTCache, Semantic Cache).
7️⃣ Model Routing
Ideia: Enviar cada pedido para o modelo adequado.
- Queries simples (Yes/No, classificação) → modelo barato (GPT-4o-mini, ~$0.15/1M input).
- Raciocínio complexo, código → modelo maior (GPT-4o, Claude Opus).
Implementação:
- Heurística: tamanho do prompt, keywords, histórico.
- LLM router: pequeno modelo classifica intent → escolhe modelo.
- A/B test para validar que qualidade não cai.
8️⃣ Graceful Degradation e Resilência
- Retry com backoff: 429, 503, timeout → exponential backoff. Max 3 retries.
- Circuit breaker: Após N falhas consecutivas → abrir circuito, falhar rápido. Half-open para testar recuperação.
- Fallback: LLM principal falha → modelo menor, resposta cached, ou "Temporariamente indisponível".
- Queue para reprocessar: Request falhou → re-enviar para queue, worker reprocessa.
Sempre ter plano B.
9️⃣ Latência — TTFT e Tokens/sec
- TTFT (Time To First Token): Crítico para UX. Utilizador vê que algo acontece.
- Tokens/sec: Velocidade de geração. Streaming melhora perceived latency.
- Otimizações: Modelos menores, caching, speculative decoding, prompt caching (OpenAI), prefetch.
🔟 Idempotency e Consistência
- Idempotency keys: Operações retryable (processar doc, criar recurso). Cliente envia key → servidor devolve resultado cached em retry. Evita duplicação.
- At-least-once vs exactly-once: Queues normalmente at-least-once. Idempotency no consumer para exactly-once semântico.
Ferramentas Resumidas
| Categoria | Ferramentas |
|---|---|
| Orchestration | Kubernetes, Docker |
| Queues | Kafka, RabbitMQ, SQS, Celery |
| Cache | Redis, Memcached |
| Vector DB | Qdrant, Pinecone, Weaviate, pgvector |
| Observability | Langfuse, LangSmith, Prometheus, Datadog |
| LLM APIs | OpenAI, Anthropic, vLLM (self-hosted) |
1️⃣1️⃣ Segurança em Sistemas de AI
- Prompt injection: Sanitizar input, separator tokens, instruções claras no system prompt. Guardrails (NeMo, open source) para detetar/bloquear.
- Rate limiting: Evitar abuso, controlar custos de API externa. Por user e por tenant.
- Dados sensíveis: Não logar prompts completos em produção. Mascarar PII antes de enviar ao LLM. Dados on-prem se regulado.
- Output validation: Validar structured output do LLM antes de executar ações (tool calling).
1️⃣2️⃣ Capacity Planeamento — Estimar Carga
Perguntas a responder:
- QPS (queries por segundo) em pico?
- Latência alvo (p50, p99)?
- Cache hit rate esperado?
Cálculo aproximado: 1M queries/mês ≈ 0.4 QPS média. Pico 3-5×. Com 30% cache hit: ~0.3 QPS ao LLM. 1 réplica GPT-4o-mini pode servir ~1-2 QPS (latência 2-5s). Ajustar réplicas consoante.
Perguntas de Follow-up Comuns
- Onde colocarias rate limiting? → API Gateway, antes do backend. Por user/tenant.
- Como garantirias que o vector DB não é bottleneck? → Sharding, réplicas de leitura, caching de queries frequentes.
- Como estimarias custo para 1M queries/mês? → Breakdown: embeddings + LLM (input+output) × $/1K tokens. Aplicar cache hit rate. Vector DB e infra separados.
- Como lidarias com prompt injection? → Sanitização, guardrails, output validation antes de tool execution.
Zona de prática
Sem perguntas. Clica em Editar para adicionar.