Learn how to scale AI services when your real constraint is the API rate limit, not traffic — using queues, caches, and back-off strategies instead of more servers.
Quando implantei a plataforma de IA clínica em um Mac Mini, esperava que o tráfego fosse meu problema de escalonamento. Não era.
Na primeira vez que alguns usuários concorrentes acessaram o sistema ao mesmo tempo, a latência saltou de aproximadamente 2 segundos para mais de 6. O próprio servidor mal se moveu — a CPU estava ociosa. O problema estava acima: cada requisição do usuário disparava uma chamada separada à API Claude, e o limite de requisições da API já estava saturado.
Uma fila é uma sala de espera educada — melhor do que todos correndo para a porta ao mesmo tempo. Esse único insight mudou completamente como pensei sobre escalonamento de um serviço de IA solo.
A mudança fundamental: Engenheiros solo de IA não precisam de mais servidores. Precisam de uso mais inteligente da única API que estão chamando.
As três alavancas que importam:
Este módulo percorre cada alavanca com padrões TypeScript funcionais que você pode inserir em uma rota de API Next.js ou um serviço em background.
Para quem é este módulo: Você está rodando um serviço de IA em uma única máquina ou um VPS pequeno. Você chama a API Claude (ou outra API de LLM). Você já recebeu um erro 429 em produção, ou está preocupado que vai receber.
A Anthropic aplica limites de requisições em duas dimensões simultaneamente:
Quando qualquer limite é excedido, a API retorna HTTP 429 Too Many Requests junto com um cabeçalho Retry-After que informa quanto tempo esperar.
Atingir um limite pode esconder o outro. Se você adicionar tentativas apenas para 429s e seu loop de tentativas disparar muito rápido, você pode esgotar seu orçamento de RPM antes que seu orçamento de TPM se recupere. Sempre faça back-off em ambas as dimensões.
Imagine um serviço de automação de suporte onde cada ticket de entrada aciona uma chamada à API Claude. Em baixo volume (um ticket por minuto) tudo parece bem. Mas quando cinco tickets chegam em trinta segundos:
O serviço não está sobrecarregado — o Mac Mini está ocioso. Mas da perspectiva da API, o contrato de concorrência foi violado.
Prompt de reflexão: Pense no seu próprio serviço de IA (atual ou planejado). Qual é o pior caso de burst de usuários concorrentes que você esperaria em uma janela de cinco minutos? Como isso se compara ao limite RPM do seu nível?
A chamada de API mais barata é aquela que você nunca faz. Para serviços de IA, o cache tem um valor incomumente alto porque:
Um simples cache LRU (Least Recently Used) em memória lida com o caso mais comum — prompts repetidos exatos ou quase exatos.
Notas de design que vale a pena internalizar:
Map preserva a ordem de inserção, então keys().next().value é sempre a chave mais antiga."o que é RAG?" e "o que é RAG?" compartilham a mesma entrada de cache. Adicione mais normalização (letras minúsculas, remoção de pontuação) se seus prompts são digitados pelo usuário.Comece aqui antes de qualquer outra coisa. O cache é a otimização de maior ROI disponível. No meu trabalho de automação de suporte, uma fração significativa das chamadas à API durante uma sessão eram variações de perguntas já respondidas anteriormente na mesma conversa. O cache eliminou essas chamadas completamente.
O cache ajuda com requisições repetidas. Mas e em relação a um burst de requisições novas — que todas precisam de uma chamada ao vivo da API?
Sem controle de concorrência, todas essas chamadas disparam simultaneamente e a API limita suas requisições. A solução é um semáforo: um contador simples que limita quantas chamadas podem estar em voo ao mesmo tempo.
Pense em um semáforo como um restaurante com um número fixo de mesas. Novos clientes esperam na porta se todas as mesas estiverem ocupadas — eles não tentam se espremer todos de uma vez e derrubar as mesas.
O valor maxConcurrent depende do seu limite de RPM de nível e do seu tempo de resposta alvo. Um padrão conservador para um serviço de produção solo é 3–5 chamadas concorrentes. Se sua chamada média leva 2 segundos e você permite 3 concorrentes, você está limitado a aproximadamente 90 RPM — confortavelmente abaixo da maioria dos limites de nível.
Profundidade da fila vs. timeout. O semáforo acima enfileira requisições indefinidamente. Em um fluxo voltado ao usuário, adicione um prazo: se uma requisição esperar mais de alguns segundos, rejeite-a com uma mensagem graciosa em vez de fazer o usuário esperar indefinidamente.
Mesmo com um semáforo, você pode ocasionalmente receber um 429 — talvez seu serviço e outro app compartilhem a mesma chave de API, ou haja um burst na inicialização. A resposta correta é back-off exponencial com jitter.
Envolva a chamada real à API dentro de withBackoff para obter comportamento automático de tentativas:
Às vezes a resposta certa é falhar rapidamente em vez de tentar novamente. Se um usuário está esperando por uma resposta interativa e a API está saturada, enfileirá-lo por 30 segundos é pior do que retornar uma mensagem amigável imediatamente.
Quando falhar rapidamente:
Quando enfileirar e esperar:
Não engula erros silenciosamente. Quando você retornar um fallback, registre o evento 429 com timestamp e o contexto da requisição. Um pico repentino em fallbacks é um sinal de que você precisa aumentar seu nível de API ou reduzir a configuração maxConcurrent no seu semáforo.
Aqui está como cache, semáforo e back-off se encaixam em uma rota de API de produção:
flowchart TD
A[Incoming Request] --> B{Cache hit?}
B -- Yes --> C[Return cached response]
B -- No --> D{Semaphore slot open?}
D -- No --> E[Wait in queue]
E --> F[Slot acquired]
D -- Yes --> F
F --> G[Call Claude API]
G -- Success --> H[Store in cache]
H --> I[Return response]
G -- 429 --> J{Retries left?}
J -- Yes --> K[Exponential back-off]
K --> G
J -- No --> L[Return fallback or error]
Escalar um serviço de IA solo não é sobre adicionar hardware. É sobre respeitar as restrições da API externa da qual você depende:
maxConcurrent previne que tráfego em burst dispare muitas chamadas paralelas.Esses padrões não custam nada para implementar e muitas vezes são a diferença entre um serviço estável e um que fica inesperadamente indisponível em uma noite movimentada.
Test your understanding of API rate-limit management, caching, and back-off strategies for solo AI services.
1. Your Next.js API route calls Claude once per user request. You suddenly notice latency tripling and a spike in 429 errors after a feature launch. What is the most likely root cause?
2. Which combination of optimizations delivers the highest ROI for a solo AI service under rate-limit pressure?
3. An LRU cache with a 1-hour TTL will always serve stale responses to users after a model update.
True or False question
Correct Answer: FALSE
False. Stale responses are only served if the same prompt is repeated within the TTL window. You can also invalidate the cache on model updates by adding a model-version prefix to the cache key or clearing the cache explicitly.
4. You set a semaphore to maxConcurrent=5 and your average Claude API call takes 2 seconds. Roughly how many requests per minute can your service handle at steady state?
5. Why does exponential back-off need jitter (randomized delay) in addition to exponential growth?
6. A user submits a form that triggers an LLM call. The semaphore is full and the user would wait 20+ seconds. What is the best response?