Spaces:
Running
Running
Guilherme Favaron
Major update: Add hybrid search, reranking, multiple LLMs, and UI improvements
1b447de
| """ | |
| Expansão de Queries (Multi-Query Retrieval) | |
| Gera múltiplas variações de uma query para melhorar cobertura da busca. | |
| """ | |
| import re | |
| from typing import List, Dict, Any, Optional | |
| from src.generation import GenerationManager | |
| class QueryExpander: | |
| """Expande queries em múltiplas variações para melhor retrieval""" | |
| def __init__(self, generation_manager: GenerationManager): | |
| """ | |
| Args: | |
| generation_manager: Gerenciador de geração de texto | |
| """ | |
| self.generation_manager = generation_manager | |
| def expand_query( | |
| self, | |
| query: str, | |
| num_variations: int = 3, | |
| method: str = "llm" | |
| ) -> List[str]: | |
| """ | |
| Expande query em múltiplas variações | |
| Args: | |
| query: Query original | |
| num_variations: Número de variações a gerar | |
| method: Método de expansão ("llm", "template", "paraphrase") | |
| Returns: | |
| Lista com query original + variações | |
| """ | |
| if method == "llm": | |
| return self._expand_with_llm(query, num_variations) | |
| elif method == "template": | |
| return self._expand_with_templates(query, num_variations) | |
| elif method == "paraphrase": | |
| return self._expand_with_paraphrase(query, num_variations) | |
| else: | |
| return [query] | |
| def _expand_with_llm(self, query: str, num_variations: int) -> List[str]: | |
| """ | |
| Usa LLM para gerar variações da query | |
| Estratégia: Pede ao LLM para reformular a pergunta de formas diferentes | |
| """ | |
| prompt = f"""Você é um assistente que ajuda a reformular perguntas para melhorar buscas. | |
| Pergunta original: "{query}" | |
| Gere {num_variations} reformulações diferentes desta pergunta. Cada reformulação deve: | |
| - Manter o mesmo significado e intenção | |
| - Usar palavras e estruturas diferentes | |
| - Ser igualmente específica | |
| Formato de saída (uma por linha): | |
| 1. [primeira reformulação] | |
| 2. [segunda reformulação] | |
| 3. [terceira reformulação] | |
| Reformulações:""" | |
| try: | |
| response = self.generation_manager.generate( | |
| prompt=prompt, | |
| max_tokens=200, | |
| temperature=0.7 | |
| ) | |
| # Extrai variações do response | |
| variations = self._parse_llm_variations(response) | |
| # Garante que temos pelo menos a query original | |
| if not variations: | |
| variations = [query] | |
| elif query not in variations: | |
| variations.insert(0, query) | |
| return variations[:num_variations + 1] # +1 para incluir original | |
| except Exception as e: | |
| print(f"Erro ao expandir query com LLM: {e}") | |
| return [query] | |
| def _parse_llm_variations(self, response: str) -> List[str]: | |
| """ | |
| Extrai variações do response do LLM | |
| Procura por linhas numeradas ou bullets | |
| """ | |
| variations = [] | |
| # Tenta extrair linhas numeradas: "1. texto", "2. texto" | |
| pattern = r'^\d+\.\s*(.+)$' | |
| for line in response.split('\n'): | |
| line = line.strip() | |
| match = re.match(pattern, line) | |
| if match: | |
| variation = match.group(1).strip() | |
| if variation: | |
| variations.append(variation) | |
| # Se não encontrou numeradas, tenta bullets: "- texto", "* texto" | |
| if not variations: | |
| pattern = r'^[-*]\s*(.+)$' | |
| for line in response.split('\n'): | |
| line = line.strip() | |
| match = re.match(pattern, line) | |
| if match: | |
| variation = match.group(1).strip() | |
| if variation: | |
| variations.append(variation) | |
| return variations | |
| def _expand_with_templates(self, query: str, num_variations: int) -> List[str]: | |
| """ | |
| Usa templates fixos para expandir query | |
| Útil quando LLM não está disponível ou para casos simples | |
| """ | |
| templates = [ | |
| query, # Original | |
| f"Explique sobre {query}", | |
| f"O que é {query}?", | |
| f"Como funciona {query}?", | |
| f"Qual a definição de {query}?", | |
| f"Informações sobre {query}", | |
| ] | |
| return templates[:num_variations + 1] | |
| def _expand_with_paraphrase(self, query: str, num_variations: int) -> List[str]: | |
| """ | |
| Usa paraphrasing simples baseado em sinônimos | |
| Nota: Implementação básica. Para produção, considere usar | |
| modelo de paraphrase como T5 ou BART | |
| """ | |
| # Implementação simplificada com algumas variações comuns | |
| variations = [query] | |
| # Substituições comuns em português | |
| substitutions = [ | |
| ("o que é", "qual é"), | |
| ("como funciona", "qual o funcionamento de"), | |
| ("explique", "descreva"), | |
| ("diferença entre", "distinção entre"), | |
| ("vantagens", "benefícios"), | |
| ] | |
| for old, new in substitutions: | |
| if old in query.lower(): | |
| variation = query.lower().replace(old, new).capitalize() | |
| if variation not in variations: | |
| variations.append(variation) | |
| if len(variations) > num_variations: | |
| break | |
| return variations[:num_variations + 1] | |
| def get_expansion_info(self, method: str) -> Dict[str, Any]: | |
| """ | |
| Retorna informações sobre método de expansão | |
| Args: | |
| method: Nome do método | |
| Returns: | |
| Dicionário com informações | |
| """ | |
| info = { | |
| "llm": { | |
| "name": "LLM-based", | |
| "description": "Usa modelo de linguagem para gerar variações contextuais", | |
| "pros": "Variações de alta qualidade, contextuais", | |
| "cons": "Mais lento, requer LLM disponível", | |
| "best_for": "Queries complexas e conceituais" | |
| }, | |
| "template": { | |
| "name": "Template-based", | |
| "description": "Usa templates fixos para reformular queries", | |
| "pros": "Rápido, determinístico, sem dependências", | |
| "cons": "Variações genéricas, pode não preservar nuances", | |
| "best_for": "Queries simples, prototipação rápida" | |
| }, | |
| "paraphrase": { | |
| "name": "Paraphrase-based", | |
| "description": "Usa substituições de sinônimos e paráfrases", | |
| "pros": "Balanceado, mantém estrutura original", | |
| "cons": "Limitado por dicionário de sinônimos", | |
| "best_for": "Queries médias, quando LLM não está disponível" | |
| } | |
| } | |
| return info.get(method, { | |
| "name": method, | |
| "description": "Método desconhecido", | |
| "pros": "N/A", | |
| "cons": "N/A", | |
| "best_for": "N/A" | |
| }) | |