Stack completa de RAG conversacional 100% on-premise — embeddings + reranking sem chamada de API externa.
Extraído de implementação real em produção (~1.300 execuções/dia, dados anonimizados).
Construir RAG sem depender de OpenAI/Cohere pra embeddings é trivial em PoC e dolorido em produção. Você precisa resolver:
- Custo previsível — cada chamada de embedding externo escala linear, batch processing fica caro
- Latência sub-segundo — round-trip pra API externa adiciona 200-800ms por consulta
- Soberania de dados — saúde, jurídico, financeiro, gov: muitos verticais não podem mandar conteúdo sensível pra serviço externo
- Reranking — vector search puro tem precisão baixa; precisa de reranker, mas reranker externo dobra a latência
Stack open-source orquestrada em Docker Swarm + Traefik:
- Embeddings: Hugging Face TEI rodando
BAAI/bge-m3localmente (multilíngue, 8192 tokens, ~600 docs/s em CPU) - Reranker: TEI rodando
BAAI/bge-reranker-base(precisão >90% no MTEB pra PT-BR) - Vector DB: PostgreSQL com extensão
pgvector(pg16) — sem precisar de Weaviate/Pinecone/Qdrant separado - Orquestração de fluxo: n8n em modo queue (1 editor + 3 webhooks + 3 workers + Redis)
- Canal: Chatwoot v4.8+ (WhatsApp/web widget/Telegram)
- Painel admin: Next.js consumindo Claude API pra geração final (o RAG resolve o "o que buscar", LLM externo só compõe resposta)
- Reverse proxy + TLS: Traefik v3 com Let's Encrypt automático
flowchart TB
A[Usuário<br/>WhatsApp / web widget] --> B[Chatwoot]
B --> C[n8n webhook<br/>3 réplicas]
C --> D[n8n worker<br/>3 réplicas]
D --> E[Embed query<br/>TEI BGE-M3]
E --> F[Vector search<br/>pgvector top-50]
F --> G[Rerank<br/>TEI bge-reranker-base]
G --> H[Top-5 contexto]
H --> I{Precisa de<br/>geração?}
I -- sim --> J[LLM externo<br/>Claude/OpenAI]
I -- não --> K[Resposta direta<br/>do KB]
J --> L[Resposta]
K --> L
L --> B
B --> A
subgraph Self-hosted
E
G
F
M[(pgvector pg16<br/>knowledge_base)]
end
F -.-> M
N[Painel admin<br/>Next.js] -.gestão KB.-> M
N -.gestão fluxo.-> C
style E fill:#FF6F61,color:#fff
style G fill:#FF6F61,color:#fff
style M fill:#3FCF8E,color:#000
style J fill:#D97757,color:#fff
| Camada | Tecnologia | Self-hosted? |
|---|---|---|
| Embeddings | HF TEI + BGE-M3 | ✅ |
| Reranking | HF TEI + bge-reranker-base | ✅ |
| Vector DB | PostgreSQL 16 + pgvector | ✅ |
| Orquestração | n8n (modo queue) | ✅ |
| Canal | Chatwoot v4.8 | ✅ |
| Painel admin | Next.js 14 + Prisma | ✅ |
| LLM geração | Claude / OpenAI (configurável) | |
| Proxy + TLS | Traefik v3 + Let's Encrypt | ✅ |
| Cluster | Docker Swarm (1+ node) | ✅ |
| Backup | pg_dump cron + volume snapshot | ✅ |
.
├── stacks/
│ ├── 00-network.yml # rede overlay Swarm
│ ├── 01-traefik.yml # proxy + ACME
│ ├── 02-postgres.yml # pgvector pg16 (KB) + pg14 (n8n queue)
│ ├── 03-redis.yml # Redis pra n8n queue + Chatwoot
│ ├── 04-tei-embedder.yml # TEI BGE-M3
│ ├── 05-tei-reranker.yml # TEI bge-reranker-base
│ ├── 06-n8n.yml # editor + webhooks + workers (modo queue)
│ ├── 07-chatwoot.yml # app + sidekiq
│ ├── 08-portainer.yml # gestão Swarm
│ └── 09-admin-board.yml # painel Next.js (template)
├── sql/
│ ├── 001_pgvector.sql # CREATE EXTENSION + schema KB
│ ├── 002_seed_kb.sql # exemplo de docs com embedding
│ └── 003_indexes.sql # HNSW + ivfflat
├── workflows/
│ ├── 01-busca-kb.json # workflow n8n de busca
│ ├── 02-handoff-humano.json # protocolo de handoff
│ └── 03-orquestrador.json # roteador principal
├── admin-board/
│ ├── README.md # painel Next.js completo
│ ├── prisma/ # schema + migrations
│ └── ...
├── scripts/
│ ├── bootstrap.sh # provisiona Swarm + secrets + stacks
│ ├── ingest-docs.py # CLI pra ingestar PDFs/MD na KB
│ └── rotate-secrets.sh # rotação Swarm secrets
├── docs/
│ ├── why-self-hosted.md
│ ├── bge-m3-vs-openai-embeddings.md
│ ├── reranker-rationale.md
│ └── operations.md
├── docker-compose.dev.yml # dev local (single-node)
└── README.md
git clone https://github.com/LufeDigitalWave/self-hosted-rag-stack
cd self-hosted-rag-stack
# dev single-node (sem Swarm)
docker compose -f docker-compose.dev.yml up -d
docker compose -f docker-compose.dev.yml exec postgres psql -U postgres -f /sql/001_pgvector.sql
# popular KB de exemplo
python scripts/ingest-docs.py --dir ./samples --table knowledge_base
# testar embedding
curl -X POST http://localhost:8080/embed -d '{"inputs":"qual é a política de cancelamento?"}'
# testar fluxo completo via Chatwoot widget
open http://localhost:3000Pra deploy em Docker Swarm (1+ nodes):
./scripts/bootstrap.sh init manager-node-1
for f in stacks/*.yml; do docker stack deploy -c "$f" "$(basename "$f" .yml)"; doneenv: direto no compose. Esse repo usa:
docker secret createpra LLM API keys, Postgres password, GitHub PAT- Mount em
/run/secrets/*(read-only, 0400) - Script
scripts/rotate-secrets.shfaz rotação sem downtime .env.examplemostra estrutura, nunca.envreal no Git
Ver docs/operations.md.
| Métrica | Valor |
|---|---|
| Execuções n8n/dia | ~1.300 |
| Latência média RAG (embed → rerank → top-5) | < 600ms |
| Custo embeddings | $0 (vs ~$0.0001/1k tokens OpenAI) |
| Recall@5 (validação manual amostra de 200) | ~91% |
| Uptime últimos 5 meses | > 99.8% |
| Hardware | 1 node, 8 vCPU + 32GB RAM (AMD EPYC) |
- ✅ Busca KB — embed → vector search → rerank → top-5
- ✅ Handoff humano — detecta intenção → pausa bot → notifica time
- ✅ Orquestrador — roteia entre qualificação, FAQ, transação, escalação
- ✅ Ingestão — CLI Python pra subir PDF/MD/CSV com chunking semântico
- ✅ Reports — agregação Postgres → painel admin
- docs/why-self-hosted.md — quando vale a pena e quando não
- docs/bge-m3-vs-openai-embeddings.md — benchmark PT-BR
- docs/reranker-rationale.md — por que reranker é não-negociável
- docs/operations.md — backup, restore, rotação, scaling
Seja honesto:
- ❌ Volume < 10k consultas/mês — chamar OpenAI sai mais barato que rodar TEI
- ❌ Equipe sem alguém confortável com Docker Swarm — gerencia overhead
- ❌ Catálogo de documentos < 1k — pgvector com KNN exato resolve, sobra TEI
- ❌ Requisito de compliance que exige certificações cloud (SOC2/HIPAA managed)
Pra esses casos, RAG SaaS (Pinecone + OpenAI) ou Supabase pgvector resolvem com menos atrito.
MIT.