Pular para conteúdo

Escalabilidade

O padrão atual funciona para clínicas pequenas a médias (até ~10 médicos, ~100 procedimentos). Além disso, rachaduras aparecem.

Limites observáveis

Dimensão Limite confortável Quebra acima de
Médicos por clínica 5-10 ~12 (ambiguidade de nome)
Procedimentos por clínica ~150 ~300 (prompt gigante)
Convênios ~20
Mensagens/minuto por instância ~30 ~100 (fila Postgres)
Clínicas por servidor ~5 ~10 (memória Postgres + LLM concorrente)
Tamanho do system prompt ~50k tokens ~100k (custo estoura)

Ponto #1 — resolução de médico

Coberto em primeiro nome do doutor. É o primeiro gargalo. Qualquer clínica com 12+ médicos vai encontrar duplicação de nome.

Mitigação: adotar slug / menu numerado antes de passar dos 10 médicos.

Ponto #2 — tamanho do system prompt

No Medcenter, o prompt tem ~660 linhas, ~30k tokens. Com 12 médicos e 200 procedimentos, estima-se ~60k tokens. Custos:

Tokens input × turnos Custo com gpt-4.1 (~$2.50/1M)
30k × 10 turnos $0.75
60k × 10 turnos $1.50
100k × 10 turnos $2.50

Mil sessões/mês com prompt de 100k = $2500/mês só em input. Não sustentável.

Mitigação:

  1. Mover preços, horários, telefones para tools.
  2. Paginar lista de procedimentos — o LLM pergunta "qual especialidade?" primeiro e a tool devolve só os procedimentos daquela área.
  3. Usar context caching da OpenAI (prompt fixo é cacheado; só o histórico de chat conta como novo).

Ponto #3 — fila Postgres como mensageria

n8n_fila_mensagens_* serve até ~100 INSERTs/segundo confortavelmente. Se virar 500/s (ex: clínica com 50 atendentes paralelos), o índice telefone começa a ter contenção.

Mitigação: migrar para Redis (LPUSH/BRPOP) — latência baixa e compatível com debounce por padrão.

Ponto #4 — conexão única do PostgresSaver

_conn = psycopg.connect(DATABASE_URL, autocommit=True)

Uma conexão por processo. Em caso de LLM concorrente alto (~20 sessões simultâneas rodando invoke), pode ter contenção em escrita de checkpoint.

Mitigação: psycopg_pool.ConnectionPool(min_size=5, max_size=20) + PostgresSaver via pool.

Ponto #5 — 1 container = 1 clínica

Estratégia atual: cada clínica tem seu docker compose up separado. Na prática, até ~5 clínicas em uma VM de 4 vCPU / 8 GB.

Mitigação para >10 clínicas:

  • VM por cliente (isolamento máximo, preço alto).
  • K8s namespace por clínica (médio — mais complexo mas compartilha infra).
  • Multi-tenant em 1 container (mais barato, mas requer refatorar config por request e isolar checkpointer por clínica. Não recomendado hoje).

Ponto #6 — PostgresSaver ilimitado

Chat history nunca expira. Uma sessão de 3 meses acumula milhares de mensagens. O próximo invoke carrega tudo.

Mitigação: implementar truncamento via CONTEXT_WINDOW_LENGTH (variável existente mas não usada nos projetos atuais). Quando histórico > N mensagens, resumir as mais antigas e injetar o resumo.

Ponto #7 — OpenAI rate limits

gpt-4.1 tier 1 = 500 req/min. Se a clínica tem 20 atendentes paralelos e cada sessão gera 5 invokes/min, pico de 100 req/min — ok. Duas clínicas assim: 200 req/min. Cinco: chega perto do limite.

Mitigação:

  • Subir tier na OpenAI (requer histórico de consumo).
  • Implementar retry com backoff em caso de 429.

Roteiro recomendado conforme cresce

  1. Até 3 clínicas / 10 médicos cada: padrão atual é suficiente.
  2. 3-10 clínicas: externalizar config (YAML/DB), adotar pool Postgres, implementar CONTEXT_WINDOW_LENGTH.
  3. 10+ clínicas: multi-tenant (um container, vários thread_id prefixados com clínica), K8s para orquestração, fila Redis.
  4. Grande volume (>1000 sessões/dia por clínica): LLM router (perguntas triviais → modelo mais barato, só complexas → gpt-4.1).

Custos — ordem de grandeza

Cenário (mensal) Custo aproximado
1 clínica, 500 sessões/mês, 5 turnos, 30k prompt ~$50
1 clínica, 2000 sessões/mês, idem ~$200
5 clínicas × 2000 sessões/mês ~$1000

Mídia (Gemini + Whisper) adiciona 10-20% a isso, dependendo do perfil.