Skip to content

Knowledge Base (FAQ customizado por Affiliate)

Mecanismo que permite responder perguntas de FAQ usando uma base de conhecimento própria de cada affiliate (documentos indexados em vetores no Qdrant), em vez do FAQ genérico e hardcoded da plataforma iFriend.

Duas partes: ingestão e consulta

Este documento descreve o mecanismo completo, dividido em dois componentes deployáveis distintos dentro deste mesmo monorepo (ifriend-agents):

  1. Ingestão (apps/knowledge-base-service/ + runtime/workers/knowledge_base/) — o Knowledge Base Service: API de upload (Cloud Run) + worker de indexação (Cloud Function Gen2, via Pub/Sub). Recebe o documento do affiliate, faz parse/chunking/embedding e grava no Qdrant. Ver Arquitetura do Knowledge Base Service.
  2. Consulta (runtime "Trip", este pacote ifriend_agent/) — o que este documento detalha a partir daqui: knowledge_base_agent/knowledge_base_tool.py consultam o Qdrant em tempo de chat.

A API de ingestão já suporta gerenciamento, não só upload: listar os documentos de um affiliate, remover um documento específico, e resetar a KB inteira — ver Endpoints para quem for construir o front no Site.

[Knowledge Base Service — apps/knowledge-base-service + runtime/workers/knowledge_base]
Affiliate faz upload (JWT) → API valida e sobe pro GCS → cria job (Firestore)
   → publica no Pub/Sub → worker baixa, faz parse/chunk/embedding
   → grava no Qdrant, collection `affiliate_<id>_kb`
   → PATCH /affiliates/{id}/root_agent na iFriend API (knowledgeBaseCollection)

[Runtime "Trip" — ifriend_agent/]
JWT/message_metadata resolve affiliate_id
   → affiliate_config já carrega knowledgeBaseCollection (mecanismo existente,
     ver Affiliate → Configuração)
   → knowledge_base_agent (AgentTool, sempre presente se ENABLE_KNOWLEDGE_BASE=true)
      → knowledge_base_tool: embed(pergunta) + busca no Qdrant
      → chunks relevantes (score >= threshold) → responde
      → nada relevante → sentinel NO_KB_MATCH → orquestrador usa faq_agent genérico

Write-back do knowledgeBaseCollection

Ao concluir a indexação, o worker chama a iFriend API para associar a collection ao affiliate:

PATCH {IFRIEND_API_BASE_URL}/affiliates/{affiliate_id}/root_agent
Authorization: Bearer <JWT sistêmico>
{"knowledgeBaseCollection": "affiliate_<id>_kb"}
  • Autenticação: sistêmica (admin), via runtime/workers/knowledge_base/ifriend_api_auth.py — mesmo padrão de AuthTokenManager já usado no agente principal (POST /authentication_token com IFRIEND_API_EMAIL/IFRIEND_API_PASSWORD, token cacheado ~55min, retry automático em 401).
  • Kill-switch: IFRIEND_API_KB_WRITEBACK_ENABLED (padrão false) — habilitar explicitamente por ambiente; o endpoint foi liberado primeiro em dev, confirmar antes de habilitar em produção.
  • Falha não bloqueia o job: indexação e busca já funcionam independentemente do resultado deste passo. O worker registra writeback_status (success/failed, + writeback_error se falhou) no documento do job no Firestore, sem alterar o status geral (que reflete o resultado da indexação em si) — ver runtime/workers/knowledge_base/affiliate_api.py e job_status.py.

Contrato compartilhado entre ingestão e consulta

Como a leitura (ifriend_agent/tools/knowledge_base_tool.py) e a escrita (runtime/workers/knowledge_base/) são componentes deployáveis diferentes, a compatibilidade entre eles depende inteiramente de manter estes valores idênticos nos dois lados:

Item Valor Onde é usado
QDRANT_URL / QDRANT_API_KEY idênticos nos dois serviços mesma instância Qdrant compartilhada
KB_EMBEDDING_MODEL idêntico (sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 por padrão) knowledge_base_tool.py e runtime/workers/knowledge_base/embedder.py — vetores precisam ser comparáveis
Nome da collection affiliate_<id>_kb gerado por qdrant_writer.collection_name_for_affiliate(), lido via knowledgeBaseCollection
Distance metric COSINE KB_SIMILARITY_THRESHOLD=0.75 do lado de leitura assume isso
Payload do ponto {"text": <chunk>, "document_id": <job_id>, ...} knowledge_base_tool.py lê a chave text; document_id é usado pelos endpoints de remoção (DELETE /kb/documents/{job_id})

Restrição de arquitetura

O root_agent é montado uma vez por processo (AgentBuilder.build()), não por request — não é possível ligar/desligar agentes por affiliate na composição. Por isso knowledge_base_agent é registrado como um AgentTool sempre presente (como faq_tool), controlado por dois níveis independentes:

  • Kill-switch global: ENABLE_KNOWLEDGE_BASE (env var) — decide se o tool existe no deployment.
  • Gate por affiliate: dentro da própria tool, lendo affiliate_config.get("knowledgeBaseCollection") em runtime — decide se aquele affiliate tem KB configurada.

Campo em affiliate_config

Campo Tipo Descrição
knowledgeBaseCollection str Nome da collection no Qdrant para este affiliate (ex.: affiliate_11522_kb). Ausência do campo = affiliate sem KB, cai direto no faq_agent.

Este campo é de propriedade do backend externo — ver ressalva em Estendendo a Configuração do Agente.

Decisão de relevância é determinística, não do LLM

knowledge_base_tool.py aplica um threshold de similaridade (KB_SIMILARITY_THRESHOLD, padrão 0.75) sobre o score do melhor resultado do Qdrant antes de qualquer chamada ao LLM do knowledge_base_agent. Se não passar do threshold, a tool já retorna None — evitando gastar uma chamada de síntese de LLM "à toa" para affiliates sem conteúdo relevante para aquela pergunta.

Embedding: modelo local gratuito

A pergunta do usuário é embeddada em processo via fastembed (ONNX Runtime, sem PyTorch, sem custo por chamada), modelo configurável via KB_EMBEDDING_MODEL (padrão sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2, multilíngue).

Coordenação obrigatória com a indexação

O worker de indexação (runtime/workers/knowledge_base/embedder.py) precisa gerar os vetores com exatamente o mesmo modelo configurado para a consulta. Modelos diferentes entre indexação e consulta produzem vetores incomparáveis — a busca simplesmente não funciona. Isso não é uma sugestão, é um requisito de compatibilidade — os dois cloudbuild-*.yaml devem apontar KB_EMBEDDING_MODEL para o mesmo valor.

Troca de modelo (2026-08-24) — reindexação pendente

intfloat/multilingual-e5-small (modelo anterior) foi removido do catálogo de modelos suportados pelo fastembed numa versão mais recente da lib — fastembed foi fixado em ==0.8.0 em ambos os requirements.txt (consulta e indexação) e o modelo trocado para paraphrase-multilingual-MiniLM-L12-v2 (mesma dimensão, 384D).

Isso não é compatível com collections já indexadas com o modelo antigo. Toda collection por afiliado indexada antes desta mudança tem vetores do e5-small — comparar contra queries do modelo novo produz resultados incomparáveis (relevância quebrada silenciosamente, não um erro visível). Não fazer deploy deste código em produção antes de reindexar as collections existentes (ferramenta de reindexação ainda não existe — precisa ser construída: não há endpoint de reindexação hoje, só upload/status/delete; o arquivo original de cada documento só persiste no GCS se o documento/afiliado nunca foi deletado).

Cache

Ver detalhes na seção "Performance e Cache" do design original — resumo:

  • affiliate_config (com knowledgeBaseCollection) já é cacheado pelo IFriendAPIClient (ResponseCache, TTL 5 min) e por sessão.
  • Embedding da pergunta e resultado da busca no Qdrant têm cache dedicado em memória (KB_CACHE_TTL, padrão 10 min), por instância do processo — ver ifriend_agent/tools/knowledge_base_tool.py.
  • Sem cache compartilhado entre instâncias (Redis) nesta primeira versão — reavaliar apenas se a taxa de cache-miss em produção justificar.

Arquivos principais

Consulta (runtime "Trip"):

  • ifriend_agent/tools/knowledge_base_tool.py — busca vetorial + caches + threshold.
  • ifriend_agent/agents/knowledge_base_agent.py — agente que consome a tool.
  • ifriend_agent/agent_builder.py — registro condicional via ENABLE_KNOWLEDGE_BASE.
  • ifriend_agent/prompts/orchestrator_prompt.py — roteamento condicional (FAQ_SECTION_WITH_KNOWLEDGE_BASE).
  • ifriend_agent/config/feature_flags.py — flag ENABLE_KNOWLEDGE_BASE.

Ingestão (Knowledge Base Service) — ver detalhes em Arquitetura do Knowledge Base Service:

  • apps/knowledge-base-service/ — API de upload e status (Cloud Run).
  • runtime/workers/knowledge_base/ — worker de parse/chunk/embedding/Qdrant (Cloud Function Gen2).
  • cloudbuild-knowledge-base-api.yaml / cloudbuild-knowledge-base-worker.yaml.

Ver também