Quby: RAG, agentes de texto e voz num único stack
Este texto é nota de estudo, não material comercial. Descreve como montei e conectei o Quby, um laboratório multi-tenant de IA para atendimento: RAG (retrieval-augmented generation), agentes de texto em vários canais e agentes de voz para suporte ao vivo.
Onde testar (links do estudo):
- Só agentes de voz: https://demo.quby.com.br — escolha um modelo no catálogo e inicie a chamada no navegador.
- Landing do produto: https://quby.com.br — contexto comercial e formulário para demo completa da Quby.
- Produto autenticado:
app.quby.com.br— dashboard, upload de conhecimento e inbox multicanal.
O que o Quby tenta demonstrar
O Quby junta três ideias que costumam ficar em repositórios separados:
1. Respostas ancoradas — usar PDFs, tabelas de preço, FAQs e processos da empresa, não memória genérica do modelo. 2. Agentes com trilho — qualificação, handoff para humano e roteamento devem sobreviver a troca de modelo e de canal. 3. O mesmo “cérebro” no chat e na voz — WhatsApp, webchat, e-mail, SMS e telefone compartilham leads, histórico e RAG quando faz sentido.
A stack roda em Kubernetes: PostgreSQL guarda dados transacionais, histórico de conversas e embeddings pgvector para RAG. Apache Kafka no cluster leva trabalho assíncrono (follow-up, outbound, enriquecimento, eventos de integração) para não bloquear HTTP e voz. Clerk para auth multi-tenant; OpenAI para embeddings e chat. Voz com Vapi e as mesmas tools de RAG do texto. Observabilidade com New Relic e Datadog (traces, métricas e visibilidade de webhooks e workers).
Arquitetura em uma visão
Canais (webchat, worker WhatsApp, e-mail, SMS, voz Vapi)
│
▼
Route handlers / webhooks ──► conversations + messages (PostgreSQL)
│
├── caminho sync: /api/ai/process (orquestrador)
│ ├── máquina de estados
│ ├── OpenAI Assistants opcional por org
│ ├── RAG: buildKnowledgeContextBlock → prompt
│ └── handoff / roteamento
│
└── caminho async: publicação no Kafka (Kubernetes)
├── follow-up e nurture
├── dispatch SMS / WhatsApp / e-mail
└── enriquecimento e integrações
│
▼
Leads, orçamentos, inbox (dashboard)
│
▼
New Relic + Datadog (traces, métricas, latência de webhook)Multi-tenancy: tudo escopado por organization_id. Chunks, assistentes e credenciais de canal são por org. Isso torna o estudo um padrão reutilizável, não um chatbot single-tenant.
RAG: ingestão, índice, recuperação
O módulo (lib/org-knowledge.ts) é pequeno e explícito.
Ingestão
- Upload de PDF, Markdown ou texto via
POST /api/knowledge/upload. - PDF no servidor com
unpdf(evita APIs de PDF que exigem DOM em serverless). - Texto bruto em
org_knowledge_documentscom status de indexação.
Chunks e embeddings
- Chunks ~2,4k caracteres, corte em parágrafo, overlap ~200 caracteres.
- Embeddings OpenAI
text-embedding-3-small(1536 dimensões). - Vetores em
org_knowledge_chunks. - Reindex apaga chunks antigos do documento (idempotente).
Busca
- Query embedada com o mesmo modelo.
- Busca por similaridade no PostgreSQL (pgvector + função SQL escopada, ex.:
search_org_knowledge), com limiar padrão 0,55. - Hits com título, tipo de fonte, conteúdo e score.
Montagem do prompt
buildKnowledgeContextBlock vira bloco limitado de “fontes internas” usado no orquestrador, webchat do tenant, geração de orçamento, etc.
Lição do estudo: uma função de retrieval, vários consumidores.
Trabalho assíncrono no Kafka (Kubernetes)
Nem todo efeito colateral cabe na request que respondeu ao cliente. Follow-up estilo cron, outreach proativo e passos pesados de integração viram eventos no Kafka, consumidos por workers no mesmo cluster da API.
Padrão do estudo:
1. O caminho síncrono persiste intenção no PostgreSQL (lead, rascunho de orçamento, estado da conversa). 2. A API ou um scheduler publica no tópico (chave por org quando possível). 3. O consumer aplica com idempotência: outbound, webhook ERP, segunda passada de LLM, etc.
Webchat e tools Vapi ficam dentro de timeout apertado; o backlog escala nos consumers. Processamento at-least-once com retry no consumer.
Observabilidade (New Relic e Datadog)
Agentes quebram de forma banal: retrieval lento, cron duplicado, auth de webhook, lag no Kafka. O estudo usa New Relic e Datadog de forma complementar:
- Traces em
/api/ai/process, upload de conhecimento e tools Vapi (knowledge-search, ticket). - Métricas de lag, duração de batch de embedding e erro em tools de voz.
- Logs correlacionados por
organization_ide id de conversa quando a política permite.
Agentes de texto: máquina de estados + LLM
Deixar o modelo decidir o funil quebra CRM. O Quby inverte isso.
lib/conversation-state-machine.ts define perfis e estados (IDENTIFY_INTENT, COLLECT_BUDGET, CREATE_LEAD, HANDOFF_OR_CLOSE, …). O backend escolhe o próximo estado; o LLM redige o passo atual e usa RAG em perguntas de domínio.
POST /api/ai/process carrega estado, lead, blocos RAG e histórico cross-channel, decide handoff/roteamento e chama Chat Completions ou runOpenAIAssistantTurn quando a org usa Assistants.
Lição: agente aqui é fluxo com pele de LLM, não um prompt único fingindo ser CRM.
Agentes de voz: Vapi + mesmo RAG
POST /api/webhook/vapi recebe ciclo de vida da chamada.
A tool search_knowledge posta em POST /api/webhook/vapi/knowledge-search: autentica, resolve a org, chama searchOrgKnowledge, devolve texto curto para o modelo de voz resumir em uma ou duas frases. Schema em lib/vapi-knowledge-search-tool.ts.
POST /api/webhook/vapi/ticket cria lead (create_quby_lead) no mesmo pipeline do webchat.
Lição: voz não é outra base; é RAG como function call sob latência de telefone.
Catálogo público de voz (demo)
O estudo expõe um sandbox só de voz em demo.quby.com.br. A página testa apenas agentes de voz: selecione um modelo à esquerda, abra o painel de chamada e converse no browser. É o caminho mais rápido para sentir latência, tools e personas sem login no produto.
| Agente | Papel no estudo | |--------|------------------| | Atendimento (Bob) | Concessionária: vendas, locação, serviço e peças | | Status de frota | Operação interna: coleta e atualização de status de ativos | | Renovação de locação (Bob) | Fluxo executivo: renovação e oferta de buyout do equipamento | | Prospecção ativa (Sarah) | Vendas proativa: qualificar lead e propor equipamento |
Para a plataforma completa (webchat, inbox, base de conhecimento, setup por org), a landing em quby.com.br leva ao formulário de demo comercial; a URL de voz acima fica propositalmente estreita para testar agentes isolados.
Inbox multicanal
| Canal | Entrada | Observação | |--------|---------|------------| | Webchat | stream + widget | RAG no site do cliente | | WhatsApp | worker + webhook | thread unificada | | E-mail | Gmail OAuth + push | mesmas conversas | | SMS | Twilio | número por org | | Voz | Vapi | tools RAG + lead |
lib/multichannel-ai-autoresponse.ts e lib/cross-channel-context.ts alinham autoresposta e histórico entre canais.
Operar o estudo com segurança
- Segredos só no servidor.
- Sem hit útil no RAG → oferecer retorno humano, não inventar.
- Orçamento como rascunho; envio com revisão humana.
- Busca sempre filtrada por
organization_idno Postgres e no RAG.
O que testar nos demos
1. Voz: abra https://demo.quby.com.br, escolha Atendimento ou Prospecção ativa e pergunte algo que deveria acionar search_knowledge (preço, garantia, processo).
2. Produto completo: veja https://quby.com.br para posicionamento e formulário de demo guiada.
3. Operação: login em app.quby.com.br para subir PDFs na base da org e ver o mesmo RAG nos canais de texto da inbox.
Checks mentais:
- Mesma fronteira de org no RAG, seja webchat ou chamada Vapi.
- Criação de lead após qualificação na voz (
create_quby_lead) alinhada ao funil do webchat, mesmo com UI diferente.
Encerramento
O Quby, neste estudo, é plataforma de laboratório para RAG, orquestração de agentes e tools de voz num stack multi-tenant. O núcleo é retrieval compartilhado, estado de funil determinístico e adaptadores de canal na mesma fronteira de org.
Para desenhar algo parecido, comece por searchOrgKnowledge e buildKnowledgeContextBlock como espinha dorsal; depois pendure chat, voz e orçamentos desse eixo.