Pular para o conteúdo

Busca Hibrida

O pipeline de busca do Valter combina cinco estrategias em um unico fluxo de consulta: match lexical BM25, similaridade de vetores semanticos, boost de knowledge graph, query expansion via LLM e cross-encoder reranking. O endpoint e POST /v1/retrieve.

A formula central e:

score_final(d, q) = w_bm25 * norm(BM25) + w_sem * norm(cosine) + w_kg * kg_boost

Pesos padrao: BM25 = 0.5, semantico = 0.4, KG = 0.1.

Toda requisicao de busca passa por 8 estagios. Cada estagio e mensuravel de forma independente e a maioria pode ser ativada/desativada via parametros da requisicao.

O retriever calcula uma chave de cache a partir do hash do texto da consulta, filtros, estrategia e feature flags. Se existir uma resposta em cache no Redis (TTL de 180s), ela e retornada imediatamente sem executar o pipeline.

Um cache hit define cache_hit: true na resposta e registra a latencia apenas como o tempo de consulta ao cache. Este e o caminho mais rapido pelo sistema.

Quando expand_query esta habilitado, o LLMQueryExpander gera ate 3 variantes da consulta usando um Groq LLM. O prompt de expansao e especifico para busca juridica brasileira:

# From core/query_expander.py
# Rules for expansion:
# 1. Legal synonyms (e.g., "dano moral" -> "dano extrapatrimonial")
# 2. Procedural equivalents (e.g., "recurso especial" -> "REsp")
# 3. Thesis/statute reformulations (e.g., "prazo prescricional" -> "prescricao quinquenal art. 206 CC")

O expander tem um timeout configuravel (padrao 3.0s). Em caso de timeout ou falha, a expansao retorna uma lista vazia e o pipeline continua apenas com a consulta original. As variantes expandidas sao incluidas na resposta como expansion_queries.

A consulta original e quaisquer variantes de expansao sao codificadas em vetores densos usando o modelo de embedding definido por VALTER_EMBEDDING_MODEL (padrao: rufimelo/Legal-BERTimbau-sts-base, 768 dimensoes).

Dois backends de encoder estao disponiveis:

  • Local: SentenceTransformerEncoder — carrega o modelo no processo
  • Remoto: RailwayEncoder — envia requisicoes HTTP para um servico GPU dedicado no Railway

BM25 e busca semantica rodam concorrentemente usando asyncio.gather para otimizacao de latencia.

  • BM25: Usa a biblioteca rank_bm25 (BM25Okapi) sobre documentos tokenizados do PostgreSQL. O indice e construido na inicializacao a partir dos campos ementa, tese e razoes_decidir de todos os documentos.
  • Semantico: Realiza busca por similaridade de cosseno no Qdrant usando o vetor da consulta codificada. Quando query expansion esta ativa, todos os vetores de variantes sao buscados e os resultados sao mesclados.

Ambos os caminhos de retrieval buscam ate top_k * 3 candidatos (limitado a 100) para garantir diversidade suficiente antes do merge.

Os candidatos do BM25 e da busca semantica sao combinados usando uma de duas estrategias, selecionavel via parametro strategy da requisicao:

  • weighted (padrao): Normaliza os scores de BM25 e semantico independentemente, depois os combina usando pesos configuraveis. O dataclass SearchWeights tem como padrao bm25=0.5, semantic=0.4, kg=0.1.
  • rrf (Reciprocal Rank Fusion): Merge baseado em posicao usando a formula 1 / (k + rank) com k=60. Essa abordagem e menos sensivel a diferencas na distribuicao de scores entre retrievers.

Se um retriever retornar resultados vazios, a estrategia automaticamente recorre apenas aos resultados do outro retriever.

Filtros pos-retrieval sao aplicados a lista mesclada de candidatos. Filtros disponiveis em SearchFilters:

FiltroTipoComportamento
ministrostringNormalizado para maiusculas para matching case-insensitive
data_iniciostring (YYYYMMDD)Data minima da decisao
data_fimstring (YYYYMMDD)Data maxima da decisao
tipos_recursolist[string]Extraido do formato do numero do processo
resultadostringFiltro de resultado da decisao

Quando include_kg esta habilitado e o graph store Neo4j esta disponivel, cada resultado recebe um boost de relevancia baseado nas suas conexoes no grafo.

O calculo do KG boost (compute_kg_boost_from_entities em stores/graph.py) avalia tres tipos de entidade para cada decisao:

  • Criterios — criterios juridicos conectados a decisao, ponderados por um multiplicador qualitativo peso
  • Fatos — elementos factuais vinculados no grafo
  • Provas — entidades de evidencia

As queries de boost rodam concorrentemente com concorrencia configuravel (VALTER_KG_BOOST_MAX_CONCURRENCY, padrao 20). O score de boost e combinado com o score de busca usando o peso de KG (padrao 0.1).

Quando rerank esta habilitado e um reranker esta configurado, os melhores resultados sao reordenados por um modelo cross-encoder que pontua pares consulta-documento por relevancia.

Dois backends de reranker estao disponiveis:

  • Local: CrossEncoderReranker — roda o modelo cross-encoder no processo
  • Remoto: RailwayReranker — envia requisicoes HTTP para um servico GPU dedicado

O reranking tipicamente adiciona 200-500ms de latencia, mas melhora a precisao dos resultados do topo.

O retriever dual-vector (DualVectorRetriever em core/dual_vector_retriever.py) usa uma abordagem diferente: em vez de um unico vetor de consulta, ele codifica fatos e tese juridica separadamente e busca o corpus com cada um.

Endpoint: POST /v1/factual/dual-search

O relatorio de divergencia classifica os resultados em tres categorias:

CategoriaSignificado
fact_onlyFactualmente similar mas juridicamente diferente
thesis_onlyJuridicamente similar mas factualmente diferente
overlapSimilar em ambas as dimensoes factual e juridica

Essa separacao e valiosa para identificar casos em que os mesmos fatos levaram a raciocinio juridico diferente, ou em que a mesma tese juridica foi aplicada a cenarios factuais diferentes.

O feature search oferece filtragem estruturada sobre 21 campos extraidos por IA (gerados por classificacao via Groq LLM).

Endpoint: POST /v1/search/features

Nove filtros combinaveis com semantica AND (exceto categorias que usa OR/ANY):

FiltroTipo de Match
categoriasSemantica OR/ANY entre as categorias listadas
dispositivo_normaMatch exato (ex.: “CDC”, “CC/2002”)
resultadoExato, case-sensitive
unanimidadeBooleano
tipo_decisaoExato, case-sensitive
tipo_recursoExato, case-sensitive
ministro_relatorExato, case-sensitive
argumento_vencedorParcial ILIKE, case-insensitive
argumento_perdedorParcial ILIKE, case-insensitive

Principais variaveis de ambiente que controlam o pipeline de busca:

VariavelPadraoFinalidade
VALTER_EMBEDDING_MODELrufimelo/Legal-BERTimbau-sts-baseModelo de embedding para encoding
VALTER_EMBEDDING_DIMENSION768Dimensao do vetor
VALTER_KG_BOOST_BATCH_ENABLEDtrueHabilitar KG boost em batch
VALTER_KG_BOOST_MAX_CONCURRENCY20Maximo de queries concorrentes ao Neo4j para KG boost
VALTER_QUERY_EXPANSION_MAX_VARIANTS3Maximo de variantes de query expansion