<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[Busca híbrida - Elasticsearch Labs]]></title>
    <description><![CDATA[Articles and tutorials from the Search team at Elastic]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[Busca híbrida - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/pt/search-labs/blog/category/hybrid-search</link>
    </image>
    <link>https://www.elastic.co/pt/search-labs/blog/category/hybrid-search</link>
    <atom:link href="https://www.elastic.co/pt/search-labs/rss/category/hybrid-search.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[pt]]></language>
    <lastBuildDate>Mon, 28 Sep 2026 16:09:10 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Banco de dados vetorial do Elasticsearch: envie em minutos, redimensione de forma acessível para centenas de bilhões]]></title>
    <description><![CDATA[As partes mais difíceis da recuperação híbrida, já prontas, com padrões otimizados, modelos de terceiros e nativos da Jina AI e inferência em GPU gerenciada, tudo pronto para uso. Crie apps de IA rápidos e escaláveis, não infraestrutura.]]></description>
    <content:encoded><![CDATA[<p>O Elasticsearch é uma das plataformas mais implantadas do mundo para cargas de trabalho vetoriais, potencializando a busca semântica, a Retrieval-Augmented Generation (RAG) e recomendações para empresas como GitHub, Docusign, Seismic e muitas outras. Hoje, estamos anunciando o Banco de dados vetorial do Elasticsearch, uma nova oferta sem servidor otimizada para aplicações baseadas em vetores. Você fornece seus documentos e suas consultas, e nós cuidamos dos embeddings, do ajuste de índices e da infraestrutura. Além disso, mantemos tudo econômico e escalável. </p><p>Para novos usuários, esta é a maneira mais rápida de colocar a busca vetorial de alta qualidade em funcionamento. Se você já usa o Elasticsearch, a nova oferta é a busca vetorial na plataforma onde seus dados já estão, sem nenhum novo sistema para adotar. O Elasticsearch Vector Database oferece suporte a uma variedade de cenários, desde a fundamentação de um grande modelo de linguagem (LLM) e o fornecimento de recuperação e memória para um agente de IA até o atendimento de centenas de bilhões de vetores. <a href="https://cloud.elastic.co/registration?onboarding_token=vector">Crie um novo projeto</a> e comece em minutos.</p><h2>Um motor, todos os casos de uso vetoriais</h2><p>O banco de dados vetorial do Elasticsearch foi desenvolvido para qualquer pessoa que crie aplicativos usando vetores:</p><ul><li><p><strong>RAG:</strong> recupere o contexto certo para o seu LLM com a recuperação de vetores densos e esparsos, ou opte pela busca híbrida combinando a recuperação vetorial e lexical. A qualidade da sua geração melhora com a qualidade da sua recuperação.</p></li><li><p><strong>Agentes de IA:</strong> forneça aos agentes recuperação rápida e filtrada de documentos e memória de conversação, com as baixas latências que loops de agentes em várias etapas exigem.</p></li><li><p><strong>Busca semântica:</strong> faça a correspondência por significado, não por palavras-chave, com um tipo de campo e zero código de pipeline.</p></li><li><p><strong>Recomendações e similaridade:</strong> encontre vizinhos mais próximos em produtos, imagens ou qualquer conteúdo que você tenha, em escala.</p></li></ul><h2>Tudo o que sua carga de trabalho vetorial precisa, otimizado e pronto para uso</h2><p>Criar uma aplicação baseada em vetores significa conectar várias partes separadas: configurar e hospedar modelos de embedding, fazer a indexação dos seus documentos por meio deles, armazenar os vetores com eficiência, aplicar o modelo de embedding a cada consulta, fazer a correspondência com o armazenamento de vetores e, por fim, recuperar os documentos por trás das correspondências. O Elasticsearch Vector Database cuida de tudo isso para você, sem necessidade de configuração ou setup adicional.</p><h3>Indexação de vetores com o modo de índice vectordb_document</h3><p>O modo de índice <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/dense-vector#dense-vector-vectordb-document-mode">vectordb_document</a>, uma nova configuração de índice desenvolvida especificamente para cargas de trabalho que priorizam vetores, vem ativado por padrão, para que você obtenha as configurações que os especialistas escolheriam. Veja o que ele ativa:</p><ul><li><p><strong>bfloat16 por padrão:</strong> os vetores são armazenados com metade do tamanho do float32 com impacto insignificante no recall, reduzindo o consumo de disco aproximadamente pela metade antes mesmo de a quantização entrar em cena.</p></li><li><p><strong>Vetores de origem excluídos:</strong> no Elasticsearch, seus embeddings já residem nas estruturas de índice usadas para busca; manter uma segunda cópia bruta no _source apenas infla o armazenamento e desacelera a recuperação de resultados. Excluímos a duplicata para que as respostas retornem mais rápido e você armazene menos.</p></li><li><p><strong>Os arquivos certos pré-carregados no cache:</strong> as estruturas de dados que as consultas vetoriais acessam primeiro são carregadas na memória antecipadamente, para que sua primeira consulta (e também a milésima) seja ultrarrápida.</p></li><li><p><strong>Mesclagem paralela:</strong> a mesclagem consolida segmentos em estruturas de vetores mais bem organizadas, o que melhora o recall e reduz a latência, e executar essas mesclagens com várias threads significa que você chega lá mais rápido.</p></li></ul><h3>Armazenamento de vetores, compressão e ajuste automático</h3><ul><li><p>Seus vetores são compactados automaticamente.<a href="https://www.elastic.co/pt/search-labs/blog/better-binary-quantization-lucene-elasticsearch"> O Better Binary Quantization (BBQ)</a> reduz o consumo de memória dos vetores em até 32x enquanto preserva o recall, e o DiskBBQ reduz ainda mais os requisitos de memória para cargas de trabalho em grande escala.<a href="https://www.elastic.co/pt/search-labs/blog/vector-quantization-auto-calibration-diskbbq"> </a></p></li><li><p>Opte pela<a href="https://www.elastic.co/pt/search-labs/blog/vector-quantization-auto-calibration-diskbbq"> calibração automática</a>, que ajusta a quantização de cada segmento aos seus dados e a reajusta a cada mesclagem conforme os dados sofrem desvios. Quando testado em 18 conjuntos de dados, o número de consultas por segundo (QPS) melhorou em uma média de 16,7%, com ganhos de recall na maioria deles.</p></li></ul><h3>Embeddings em inferência gerenciada por GPU</h3><ul><li><p>Gere embeddings com os <a href="https://www.elastic.co/pt/jina-search-models">modelos nativos de embedding e reranking da Jina AI</a>, ou traga modelos de terceiros, tudo em GPUs gerenciadas via <a href="https://www.elastic.co/docs/explore-analyze/elastic-inference/eis">Elastic Inference Service (EIS)</a>, sem precisar operar servidores de modelos. Ou faça a auto-hospedagem, se preferir usar seu próprio modelo.</p></li><li><p>O tipo de campo <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/semantic-text"><strong>semantic_text</strong></a> lida automaticamente com o particionamento e a geração de embeddings, além de consultas, o caminho mais simples para a busca semântica no mercado. </p></li></ul><h3>Busca híbrida e busca vetorial filtrada</h3><ul><li><p>A <a href="https://www.elastic.co/pt/elasticsearch/hybrid-search">busca híbrida</a> é integrada, combinando a recuperação de texto completo e de vetores em uma única consulta. Combine os resultados com reciprocal rank fusion (RRF) ou qualquer outro mecanismo de combinação que você quiser. A busca vetorial normalmente é a parte mais difícil de configurar bem na busca híbrida. Com o banco de dados vetorial do Elasticsearch, você tem tudo sob controle e toda a sua stack híbrida fica ainda melhor. </p></li><li><p>Com a <a href="https://www.elastic.co/pt/search-labs/blog/filtered-hnsw-knn-search">busca vetorial filtrada</a>, aplique filtros de metadados como parte da própria recuperação vetorial, e não como uma etapa adicionada posteriormente que prejudica o recall.</p></li></ul><h3>Empresarial desde o primeiro dia</h3><p>Você também conta com controle de acesso baseado em funções (RBAC), logging de auditoria e as certificações de conformidade que geralmente faltam nos bancos de dados exclusivamente vetoriais.</p><h2>Acessível em escala e previsível</h2><p>O banco de dados vetorial do Elasticsearch foi desenvolvido para continuar acessível à medida que você cresce: a compressão com BBQ e DiskBBQ, que mantém o armazenamento linear e o uso de memória baixo, significa que redimensionar para centenas de bilhões de vetores não faz sua conta disparar. E o que você paga é calculado com base em números que já conhece: a quantidade de dados que armazena e indexa, além da capacidade de busca de que precisa. Estime a quantidade de documentos e as dimensões dos vetores, além da carga de consultas, e você poderá calcular o que vai pagar antes de criar o projeto. Você também pode entender sua conta linha por linha no fim do mês. Não há unidades de computação opacas nem cobranças surpresa por operações em segundo plano.</p><h2>Como começar com o banco de dados vetorial do Elasticsearch</h2><h3>Crie um projeto de banco de dados vetorial serverless</h3><p>Crie um novo <a href="https://cloud.elastic.co/registration?onboarding_token=vector">projeto serverless de banco de dados vetorial no Elastic Cloud</a>. Aponte seus dados para o endpoint, e você estará pronto para indexar.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt556cbdfba551f248/6aa10b4332b53038406d321a/image1.png" alt="Elastic Cloud Serverless project types: Elasticsearch, Vector Database, Observability and Security" /><h3>Criar um índice usando semantic_text</h3><p>O modo de índice vetorial gerencia a configuração do vetor. Usar semantic_text significa que a configuração de embeddings e particionamento, assim como a configuração do índice, é gerenciada para você com inferência gerenciada por GPU, sem a necessidade de criar um pipeline de embeddings.</p>PUT my-vectors
{
"mappings": {
"properties": {
"description": { "type": "semantic_text" }
    }
  }
}<h3>Ingerir documentos</h3><p>Indexe texto, e os embeddings são gerados para você.</p>POST /my-vectors/_doc
{
  "id": "park_rocky-mountain",
  "title": "Rocky Mountain",
  "description": "Bisected north to south by the Continental Divide, this portion of the Rockies has ecosystems varying from over 150 riparian lakes to montane and subalpine forests to treeless alpine tundra."
}<h3>Execute uma consulta de busca semântica</h3><p>Consulte o mesmo campo semântico que você acabou de criar:</p>GET /my-vectors/_search
{
  "query": {
    "semantic": {
      "field": "description",
      "query": "a mountain range in the middle of north america"
    }
  }
}<p>E você recebe os resultados de volta:</p>{
  "took": 80,
  "hits": {
    "max_score": 0.7792325,
    "hits": [
      {
        "_index": "my-vectors",
        "_score": 0.7792325,
        "_source": {
          "id": "park_rocky-mountain",
          "title": "Rocky Mountain",
          "description": "Bisected north to south by the Continental Divide, ..."
        }
      }
    ]
  }
}<p>A busca semântica é apenas o começo. Execute consultas totalmente textuais ou combine os dois tipos em consultas híbridas. Você pode até criar suas próprias consultas vetoriais para ter controle total. Siga o <a href="https://www.elastic.co/docs/solutions/vector-database/vector-full-text-search">guia de início rápido da busca semântica</a> na documentação para obter as instruções completas.</p><h2>O que vem por aí para a busca vetorial no Elasticsearch</h2><p>Já estamos trabalhando nas próximas melhorias:</p><ul><li><p><strong>Melhor gerenciamento multitenant:</strong> se os seus dados precisarem permanecer separados por tenant, vamos oferecer uma maneira de fazer isso mais rápido e com menos código.</p></li><li><p><strong>Otimização automática de índice:</strong> de "índice novo em folha" a "totalmente otimizado", com o mínimo de ajustes possível.</p></li><li><p><strong>Melhorias contínuas de infraestrutura:</strong> ajuste contínuo das configurações e da infraestrutura do banco de dados vetorial para que você tenha sempre a melhor taxa de transferência e as respostas mais rápidas.</p></li></ul><h2>Experimente o banco de dados vetorial do Elasticsearch no Elastic Cloud Serverless</h2><p>Vá de um projeto vazio a uma consulta vetorial híbrida e filtrada em minutos, com padrões de nível de produção fazendo o ajuste para você. Crie apps de IA rápidos e escaláveis, não infraestrutura.</p><p>Comece no <a href="https://cloud.elastic.co/registration?onboarding_token=vector">Elastic Cloud Serverless</a>, ou mergulhe na <a href="https://www.elastic.co/docs/solutions/vector-database">documentação completa </a>e na <a href="https://www.elastic.co/docs/api/doc/elastic-cloud-serverless/group/endpoint-vectordb-projects">referência da API.</a></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/vector-database-rag-serverless</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/vector-database-rag-serverless</guid>
    <category><![CDATA[Banco de dados vetorial]]></category>
    <category><![CDATA[Elastic Cloud Serverless]]></category>
    <category><![CDATA[Busca híbrida]]></category>
    <dc:creator><![CDATA[Dustin Coates]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4def84aae6aff861/6aa10ab1ee57e53d9b05253c/cover.png" length="0" type="image/png"/>
    <pubDate>Wed, 09 Sep 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Como medir e melhorar o recall das buscas no Elasticsearch: de 0,43 a 0,75 com a busca híbrida]]></title>
    <description><![CDATA[Aprenda a medir e melhorar o recall das buscas no Elasticsearch combinando a busca léxica BM25 com embeddings vetoriais do Jina AI, usando a API rank_eval para validar a melhoria com números reais.]]></description>
    <content:encoded><![CDATA[<p><a href="https://www.elastic.co/docs/solutions/search/full-text">A busca lexical</a> usando o <a href="https://www.elastic.co/blog/practical-bm25-part-1-how-shards-affect-relevance-scoring-in-elasticsearch">algoritmo de classificação BM25</a> é barata, rápida e muito eficaz para uma ampla gama de consultas. Mas ela tem um ponto cego: consultas que não compartilham tokens com seus documentos. Neste artigo, você vai medir exatamente onde a BM25 falha. Usaremos a <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/search-rank-eval">API de avaliação de classificação</a> do Elasticsearch (<code>rank_eval</code>) e preencheremos essa lacuna adicionando <a href="https://www.elastic.co/search-labs/es/blog/jina-embeddings-v3-elastic-inference-service">Jina AI embeddings</a> via <a href="https://www.elastic.co/docs/explore-analyze/elastic-inference/eis">Elastic Inference Service</a> (EIS). Você verá a pontuação de recall variar de <code>0.43</code> para <code>0.75</code> e saberá o porquê.</p><h2>O que é recall?</h2><p><a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/search-rank-eval#k-recall">O recall</a> mede em uma escala de <code>0</code> a <code>1</code> quantos dos documentos que seus usuários realmente querem aparecem em algum lugar dos seus resultados de busca. Se uma consulta aparecer em três produtos e sua busca devolver apenas dois deles entre os 10 primeiros, <code>recall@10 = 0.67</code> nessa consulta. É uma métrica baseada em conjuntos: ela não se importa com a posição dos documentos relevantes dentro desses <em>k</em> resultados. Um documento relevante na posição 10 conta o mesmo que um na posição 1. Ter um recall alto significa que você não está perdendo resultados relevantes.</p><p>
</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5ffd147b13705680/6a170a6fe8fbce11a539fc22/b13af2a5d0ca055535d8bfe3dfe4b3d1093ee6da-1457x796.png" alt="Diagrama de Venn ilustrando como o Recall@10 é calculado, mostrando a sobreposição entre todos os documentos relevantes e os 10 principais resultados recuperados pelo BM25, resultando em uma pontuação de Recall@10 igual a 0,40." /><p>O diagrama mostra dois conjuntos: todos os documentos relevantes (à esquerda) e o que o BM25 realmente recuperou (top 10, à direita). Apenas a interseção conta para a recuperação, <code>prod_1</code> e <code>prod_2</code> foram encontrados, enquanto <code>prod_3</code>, <code>prod_4</code> e <code>prod_6</code> foram completamente perdidos. Resultado: <code>Recall@10 = 2/5 = </code><strong><code>0.40</code></strong>.</p><h2>Pré-requisitos</h2><p>Vamos direto ao ponto para entender melhor como o recall funciona. Esta demonstração usa Python. Você pode acompanhar no notebook complementar (<a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/relevance-tuning-improving-recall-adding-vectors/notebook.ipynb">notebook.ipynb</a>), onde cada bloco de código é uma célula pronta para ser executada.</p><p>O código fornecido utiliza o seguinte:</p><ul><li><p>Elasticsearch 9.3+</p></li><li><p>Python 3.10+</p></li></ul>pip install elasticsearch pandas plotly python-dotenv<ul><li><p>Um arquivo <code>.env</code> com suas credenciais do Elasticsearch</p></li></ul>ELASTICSEARCH_URL=https://your-cluster-url
ELASTICSEARCH_API_KEY=your-api-key<h2>O conjunto de dados</h2><p>Usaremos um catálogo de produtos com 1.000 produtos, abrangendo categorias como calçados, eletrônicos, ferramentas e outros.</p><p>Cada documento tem quatro campos:</p><p>Campo</p><p>Tipo</p><p>`title`</p><p>texto</p><p>`description`</p><p>texto</p><p>`marca`</p><p>palavra-chave</p><p>`category`</p><p>palavra-chave</p><p>O conjunto de dados é carregado a partir de <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/relevance-tuning-improving-recall-adding-vectors/dataset.csv"><code>dataset.csv</code></a>.</p><h2>O poder e os limites da busca lexical</h2><p>BM25 é o algoritmo padrão de ranqueamento no Elasticsearch e na maioria dos mecanismos de busca. Ele classifica os documentos de acordo com a frequência com que seus termos de consulta aparecem neles, ajustados ao tamanho do documento e à frequência desses termos em todo o índice. Você tem <a href="https://www.elastic.co/docs/reference/text-analysis/analyzer-reference">analisadores</a> na parte superior: normalização de letras minúsculas, stemming e retirada de stopwords. Uma busca por "tênis de corrida" retornará resultados como "Tênis de corrida" e provavelmente também "correr".</p><p>Isso funciona bem para uma grande classe de consultas:</p><ul><li><p>"tênis de corrida" faz a correspondência imediata dos produtos com esses tokens exatos no título.</p></li><li><p>"alto-falante Bluetooth" destaca produtos de áudio portáteis porque os tokens aparecem literalmente.</p></li></ul><p>Os resultados são determinísticos e explicáveis: um documento tem classificação alta porque os termos de consulta aparecem nele. Depurar a relevância é simples.</p><h3>Onde ocorre a falha</h3><p>Agora, vamos testar essas consultas no mesmo catálogo:</p><ul><li><p><strong>"rotina de cuidados com a pele":</strong> a palavra "rotina" não aparece em nenhum título de produto. O BM25 pode corresponder parcialmente com "cuidados com a pele", mas séruns faciais, óleos corporais e hidratantes são descritos usando termos como "vitamina C", "retinol" ou "iluminador", nenhum dos quais se sobrepõe à consulta. Produtos que formam uma rotina completa de cuidados com a pele ficam espalhados pelo índice, sem nenhum token compartilhado para ancorá-los.</p></li></ul>ID: B06XX6DS3P, Score: 9.0552, Title: Replenix Retinol Smooth + Tighten Body Lotion - Collagen-Boosting, Regenerating Anti-Aging Body Cream, Reduces Appearance of Stretch Marks, 6.7 oz.

  ID: B08XMPKJ1L, Score: 5.2699, Title: Bio-Oil Skincare Body Oil (Natural) Serum for Scars and Stretchmarks, Face and Body Moisturizer Hydrates Skin, with Organic Jojoba Oil and Vitamin E, For All Skin Types, 6.7 oz

  ID: B01CY764KQ, Score: 5.0057, Title: Nike Up Or Down Men Deodorant - Pack of 2 | Long-Lasting Fragrance, Body Spray Combo for Men | Deodorant for Active Living | Nike Men's Deo Set | Ultimate Odor Protection | Grooming Essentials | Signature Nike Scent | High-Performance Men's Deodorant<ul><li><p><strong>"acessórios de viagem para pets":</strong> é um agrupamento de casos de uso, não uma categoria de produto. Um sling para cães, uma cadeirinha para pets e uma caixa de viagem são todos relevantes, mas as descrições falam sobre portabilidade, segurança e conforto, em vez de "acessórios de viagem". O BM25 corresponde amplamente a palavra "pet", mas não tem sinal para distinguir produtos específicos para viagens do restante do catálogo de pets.</p></li></ul>ID: B0BVV7BKTW, Score: 7.4371, Title: Large Foldable Travel Duffel Bag with Shoes Compartment

ID: B07TNPHYNV, Score: 6.6455, Title: 40 Pieces Christmas Bronze Jingle Bells Craft Small Bells

ID: B08R8FRW53, Score: 6.6335, Title: CUBY Dog and Cat Sling Carrier
ID: B08QMCQYGM, Score: 6.5259, Title: YTFGGY Whiteboard Pinstripe Tape 6 Rolls 1/8"
ID: B0CP3LQSWM, Score: 6.2994, Title: Portable Dog Water Bottle 32 Oz<p>Esse é um <strong>problema de recall</strong>. Os documentos relevantes existem no seu índice. O BM25 simplesmente não os encontra porque as palavras do usuário e as do documento não coincidem o suficiente.</p><p>Adicionar sinônimos ajuda em casos conhecidos. Mas não dá para enumerar todas as formas como o usuário pode expressar uma intenção. É aí que entram os vetores.</p><h2>Por que medir o recall</h2><p>Antes de corrigir um problema, você precisa quantificá-lo.</p><p><a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/search-rank-eval#k-recall"><strong>Recall@k</strong></a> mede quantos documentos que seus usuários realmente desejam aparecem nos resultados de busca. Formalmente:</p>Recall@k = (relevant documents found in top k) / (total relevant documents)<p><a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/search-rank-eval#k-precision"><strong>Precision@k</strong></a> mede os k principais resultados e quantos são realmente relevantes:</p>Precision@k = (relevant documents in top k) / k<p>Alta precisão mostra que os resultados que você retorna são bons. No comércio eletrônico, perder um produto relevante (baixo recall) geralmente é pior do que mostrar um resultado um pouco imperfeito (menor precisão), porque o produto oculto é venda perdida.</p><p>A API <code>rank_eval</code> do Elasticsearch permite medir os dois de forma sistemática. Você fornece uma lista de consultas, cada uma com um conjunto de documentos avaliados, e o Elasticsearch calcula as métricas para você em todas elas.</p><h2>Configuração da avaliação</h2><p>A API <code>rank_eval</code> precisa de um <strong>conjunto de dados de avaliações</strong>: um mapeamento das consultas para os documentos relevantes para cada um, junto com uma nota de relevância (0 = não relevante, 1 = relevante, 2 = altamente relevante).</p><p>No bloco de notas, esta é a <a href="https://www.elastic.co/docs/solutions/search/ranking/learning-to-rank-ltr#learning-to-rank-judgement-list">lista de julgamentos</a>:</p>judgments = [
    # Query 1: "running shoes" BM25 handles well (tokens appear in product titles) 
    {"query_id": "q1", "doc_id": "B09NQJFRW6", "grade": 2, "query": "running shoes"},
    {"query_id": "q1", "doc_id": "B08JMD4LMM", "grade": 2, "query": "running shoes"},
    {"query_id": "q1", "doc_id": "B08VRJ6F2Q", "grade": 2, "query": "running shoes"},
    {"query_id": "q1", "doc_id": "B07S8NRRWR", "grade": 2, "query": "running shoes"},
    {"query_id": "q1", "doc_id": "B01HD620I8", "grade": 2, "query": "running shoes"},
    {"query_id": "q1", "doc_id": "B07DX86321", "grade": 2, "query": "running shoes"},
    {"query_id": "q1", "doc_id": "B0968YVLQ8", "grade": 1, "query": "running shoes"},
    {"query_id": "q1", "doc_id": "B093QJ39ZS", "grade": 1, "query": "running shoes"},
    {"query_id": "q1", "doc_id": "B096FGSC39", "grade": 1, "query": "running shoes"},
    {"query_id": "q1", "doc_id": "B01GVQWVV2", "grade": 1, "query": "running shoes"},

    # Query 2: "skincare routine" intent-based, "routine" never appears in product titles
    {"query_id": "q2", "doc_id": "B08XMPKJ1L", "grade": 2, "query": "skincare routine"},
    {"query_id": "q2", "doc_id": "B0BN3WQB92", "grade": 2, "query": "skincare routine"},
    {"query_id": "q2", "doc_id": "B0BT7B7P5T", "grade": 2, "query": "skincare routine"},
    {"query_id": "q2", "doc_id": "B00NPA2WEY", "grade": 2, "query": "skincare routine"},
    {"query_id": "q2", "doc_id": "B06XX6DS3P", "grade": 1, "query": "skincare routine"},
    {"query_id": "q2", "doc_id": "B07PDRD1KT", "grade": 1, "query": "skincare routine"},
    {"query_id": "q2", "doc_id": "B074J7869B", "grade": 1, "query": "skincare routine"},
    {"query_id": "q2", "doc_id": "B08JV31QW4", "grade": 1, "query": "skincare routine"},
    {"query_id": "q2", "doc_id": "B00K3TVJMQ", "grade": 1, "query": "skincare routine"},

    # Query 3: "study desk setup" intent-based, products are desks/stands/organizers
    {"query_id": "q3", "doc_id": "B08CS35J2T", "grade": 2, "query": "study desk setup"},
    {"query_id": "q3", "doc_id": "B09B3LFDXJ", "grade": 2, "query": "study desk setup"},
    {"query_id": "q3", "doc_id": "B07W58LMND", "grade": 1, "query": "study desk setup"},
    {"query_id": "q3", "doc_id": "B0CHYDX91L", "grade": 1, "query": "study desk setup"},

    # Query 4: "pet travel accessories" use-case grouping, products are carriers/crates/seats
    {"query_id": "q4", "doc_id": "B08R8FRW53", "grade": 2, "query": "pet travel accessories"},
    {"query_id": "q4", "doc_id": "B01MYUYX33", "grade": 2, "query": "pet travel accessories"},
    {"query_id": "q4", "doc_id": "B003C5RKE4", "grade": 2, "query": "pet travel accessories"},
    {"query_id": "q4", "doc_id": "B09GF8GBF6", "grade": 1, "query": "pet travel accessories"},
    {"query_id": "q4", "doc_id": "B0CP3LQSWM", "grade": 1, "query": "pet travel accessories"},
]<p>A combinação é intencional: <code>q1</code> é uma consulta que o BM25 lida bem (tokens exatos nos títulos dos produtos), enquanto <code>q2</code>, <code>q3</code> e <code>q4</code> são consultas orientadas à intenção, nas quais a intenção do usuário é expressa como um conceito, não como palavras-chave específicas de produto.</p><h2>Medindo o recall de base do BM25</h2><p>Primeiro, configure o cliente do Elasticsearch e indexe os dados de texto bruto:</p>import os
import json
import pandas as pd
import plotly.graph_objects as go
from elasticsearch import Elasticsearch, helpers
from dotenv import load_dotenv

load_dotenv()

es = Elasticsearch(
    os.getenv("ELASTICSEARCH_URL"),
    api_key=os.getenv("ELASTICSEARCH_API_KEY")
)

INDEX_NAME = "ecommerce-products"<p>Agora, crie a solicitação <code>rank_eval</code> para o BM25. Cada solicitação na lista combina uma consulta com as classificações correspondentes:</p>judgments_df = pd.DataFrame(judgments)

bm25_requests = []
for query_id, query_text in (
    judgments_df[["query_id", "query"]].drop_duplicates().values
):
    relevant_docs = judgments_df[judgments_df["query_id"] == query_id]
    ratings = [
        {"_index": INDEX_NAME, "_id": row["doc_id"], "rating": row["grade"]}
        for _, row in relevant_docs.iterrows()
    ]

    bm25_requests.append({
        "id": query_id,
        "request": {
            "query": {
                "multi_match": {
                    "query": query_text,
                    "fields": ["title", "description"]
                }
            }
        },
        "ratings": ratings,
    })

bm25_eval = {
    "requests": bm25_requests,
    "metric": {"recall": {"k": 10, "relevant_rating_threshold": 1}},
}

bm25_result = es.rank_eval(index=INDEX_NAME, body=bm25_eval)
print("BM25 Recall@10:", bm25_result.body["metric_score"])<p>Resultado:</p>BM25 Recall@10: 0.43<p><code>0.43</code> significa que, em todas as quatro consultas, o BM25 encontra apenas 43% dos documentos que deveria. A deficiência se concentra nas consultas baseadas na intenção: "rotina de cuidados com a pele" não inclui séruns faciais e óleos corporais, pois "rotina" nunca aparece nos títulos dos produtos. Já "acessórios de viagem para pets" retorna produtos para pets fora do tópico, enquanto não inclui transportadoras e caixas de transporte descritas em termos de portabilidade e segurança, em vez de "acessórios de viagem".</p><p>Esta é a nossa linha de base. Agora, temos um número a superar.</p><h2>Adicionando busca vetorial com embeddings do Jina</h2><p><a href="https://www.elastic.co/docs/solutions/search/vector"><code>Vector search</code></a> codifica documentos e consultas como vetores de alta dimensão, tipo de vetor composto por centenas ou milhares de valores numéricos, cada um codificando um recurso específico dos dados que representa. Documentos com significado semelhante acabam próximos uns dos outros no espaço vetorial, mesmo que não compartilhem palavras. "Equipamento de ginástica" e "conjunto de halteres" ficam próximos porque os conceitos estão relacionados. Escolhi o Elasticsearch como meu banco de dados vetorial porque ele faz busca híbrida, oferecendo compreensão semântica e precisão de palavras-chave prontas para uso.</p><p><a href="https://www.elastic.co/docs/explore-analyze/elastic-inference/eis">EIS</a> inclui suporte pronto para uso de modelos via <a href="https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-inference">API de inferência</a>.</p><h3>Passo 1: usando embeddings Jina v5 como endpoint de inferência</h3>INFERENCE_ENDPOINT_ID = ".jina-embeddings-v5-text-small"<p>Se seu cluster tem recursos de GPU (disponíveis no Elastic Cloud e Elasticsearch 9.3+), as incorporações são geradas na GPU, o que é bem mais rápido do que a inferência da CPU e elimina o tradeoff de desempenho que historicamente encarecia os vetores em larga escala.</p><p>Por que as incorporações Jina especificamente? <a href="https://www.elastic.co/search-labs/blog/jina-embeddings-v5-text">jina-embeddings-v5-text</a> é um modelo multilíngue (mais de 119 idiomas) com uma janela de contexto de 32 mil tokens e suporte para <a href="https://arxiv.org/abs/2106.09685">adaptadores de Adaptação de Baixa Ordem (LoRA)</a> específicos para cada tarefa. Ele funciona bem para descrições curtas de produtos, prontamente utilizável. Saiba mais sobre o modelo <code>jina-embeddings-v5-text</code> <a href="https://huggingface.co/jinaai/jina-embeddings-v5-text-small">aqui</a>.</p><h3>Passo 2: criar o índice com um campo semântico</h3>index_mappings = {
    "mappings": {
        "properties": {
            "title": {"type": "text", "copy_to": "semantic_field"},
            "description": {"type": "text", "copy_to": "semantic_field"},
            "brand": {"type": "keyword"},
            "category": {"type": "keyword"},
            "semantic_field": {
                "type": "semantic_text",
                "inference_id": INFERENCE_ENDPOINT_ID,
            },
        }
    }
}

if not es.indices.exists(index=INDEX_NAME):
    es.indices.create(index=INDEX_NAME, body=index_mappings)
    print(f"Created index: {INDEX_NAME}")<p>O tipo de campo <a href="https://www.elastic.co/docs/solutions/search/semantic-search/semantic-search-semantic-text"><code>semantic_text</code></a> é essencial aqui. É uma abstração de nível mais alto sobre <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/dense-vector"><code>dense_vector</code></a>: você aponta para um endpoint de inferência, e o Elasticsearch cuida de gerar automaticamente os embeddings.</p><p>A propriedade <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/copy-to"><code>copy_to</code></a> em <code>title</code> e <code>description</code> significa que o conteúdo de ambos os campos flui para <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/semantic-text"><code>semantic_field</code></a> para incorporação, de modo que um único vetor captura a representação completa do produto.</p><h3>Passo 3: indexar os produtos</h3>def bulk_index(products, index_name):
    actions = []
    for product in products:
        doc_id = product.get("_id")
        source = {k: v for k, v in product.items() if k != "_id"}
        action = {"_index": index_name, "_source": source}
        if doc_id:
            action["_id"] = doc_id
        actions.append(action)

    success, failed = helpers.bulk(es, actions, raise_on_error=False)
    if failed:
        for error in failed:
            print(f"Error: {error}")
    else:
        print(f"Successfully indexed {success} documents")

bulk_index(products, INDEX_NAME)<p>No momento do índice, o Elasticsearch chama o endpoint de inferência para cada documento e armazena a incorporação resultante em <code>semantic_field</code>. Sem código extra do seu lado.</p><h2>Busca híbrida: combinando BM25 e vetores com RRF</h2><p>Adicionar vetores melhora a recuperação, mas usar vetores sozinhos pode prejudicar a precisão em consultas de correspondência exata; "tênis de corrida" ainda deve priorizar correspondências exatas. A busca híbrida mantém o componente léxico especificamente para preservar essa precisão.</p><p>A busca híbrida com <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion">Fusão de Classificação Recíproca</a> (RRF) mantém o melhor dos dois mundos:</p><ul><li><p>O BM25 lida com consultas exatas e quase exatas com alta precisão.</p></li><li><p>A busca semântica processa consultas baseadas em intenção e multilíngues com alta precisão.</p></li><li><p>O RRF combina as duas listas classificadas em uma única classificação.</p></li></ul><p>A fórmula RRF atribui a cada documento uma pontuação baseada em sua classificação em cada lista de resultados:</p>score = sum(1 / (rank_constant + rank))<p>Um documento bem classificado em ambas as listas recebe uma pontuação combinada maior. O <code>rank_constant</code> controla quanto peso documentos de menor classificação recebem.</p>hybrid_requests = []

for query_id, query_text in (
    judgments_df[["query_id", "query"]].drop_duplicates().values
):
    relevant_docs = judgments_df[judgments_df["query_id"] == query_id]
    ratings = [
        {"_index": INDEX_NAME, "_id": row["doc_id"], "rating": row["grade"]}
        for _, row in relevant_docs.iterrows()
    ]

    hybrid_requests.append({
        "id": query_id,
        "request": {
            "retriever": {
                "rrf": {
                    "retrievers": [
                        {
                            "standard": {
                                "query": {
                                    "multi_match": {
                                        "query": query_text,
                                        "fields": ["title", "description"],
                                    }
                                }
                            }
                        },
                        {
                            "standard": {
                                "query": {
                                    "match": {
                                        "semantic_field": {"query": query_text}
                                    }
                                }
                            }
                        },
                    ],
                    "rank_window_size": 50,
                    "rank_constant": 5,
                }
            }
        },
        "ratings": ratings,
    })

hybrid_eval = {
    "requests": hybrid_requests,
    "metric": {"recall": {"k": 10, "relevant_rating_threshold": 1}},
}

hybrid_result = es.rank_eval(index=INDEX_NAME, body=hybrid_eval)
print("Hybrid Recall@10:", hybrid_result.body["metric_score"])<p>Resultado:</p>Hybrid Recall@10: 0.75<p>O Hybrid melhora substancialmente em relação ao BM25 (<code>0.43</code>) e preserva a precisão para consultas de correspondência exata como "tênis de corrida".</p><h2>Resultados: Antes e depois</h2><p>Eis a comparação completa entre as três abordagens:</p>methods = {
    "BM25 (Lexical)": bm25_requests,
    "Hybrid (BM25 + Vectors)": hybrid_requests,
}

recall_metric = {"recall": {"k": 10, "relevant_rating_threshold": 1}}

comparison_data = []
for method_name, requests in methods.items():
    result = es.rank_eval(
        index=INDEX_NAME,
        body={"requests": requests, "metric": recall_metric}
    )
    comparison_data.append({
        "method": method_name,
        "recall@10": result.body["metric_score"]
    })

comparison_df = pd.DataFrame(comparison_data)
print(comparison_df.to_string(index=False))<p>Resultado:</p><p>Método</p><p>Recall@10</p><p>BM25 (Léxico)</p><p>0,43</p><p>Híbrido (BM25 + Vetores)</p><p>0,75</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5a1d72b57056fe64/6a170a71c1e8a56c58f882ab/e49f6c10516b0a48a0ad75962c6590ee07311407-700x500.png" alt="Gráfico de barras comparando Recall@10 entre a busca lexical BM25 e a busca híbrida combinando BM25 com vetores, mostrando que a busca híbrida alcança uma recordação significativamente maior." /><p>Analisando por consulta:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt871347f754c866d0/6a170a73839dfa40abdcfeb4/40e36dcb7b34cbf4649c512bcb60cef60f1778a6-700x500.png" alt="Gráfico de barras agrupadas comparando o Recall@10 entre a busca lexical e a busca híbrida do BM25 em quatro consultas de produtos, mostrando que a busca híbrida supera consistentemente a busca lexical em cada consulta." /><h2>Conclusão</h2><p>Ao longo deste artigo, vimos que a busca léxica do BM25 é confiável quando os usuários digitam consultas exatas, mas perde a capacidade de recuperação quando buscam por intenção em vez de palavras-chave. Usando <code>rank_eval</code>, estabelecemos uma linha base reprodutível para medir essa lacuna com números reais. A partir daí, adicionamos um campo <code>semantic_text</code> alimentado por embeddings Jina e rodamos a avaliação novamente. O resultado: a buscar híbrida melhorou a capacidade de recuperação de <code>0.43</code> para <code>0.75</code> enquanto preservava a precisão nas consultas de correspondência exata, embora a margem real dependa da sua mistura de consultas.</p><p>O padrão se estende além deste exemplo: colete julgamentos das consultas reais de seus usuários, execute <code>rank_eval</code> como linha de base, adicione <code>semantic_text</code> e meça novamente. Você saberá exatamente o que melhorou e em quanto.</p><h2>Próximas etapas</h2><ul><li><p>Aprofunde-se no recall e na busca vetorial: <a href="https://www.elastic.co/search-labs/blog/recall-vector-search-quantization">quantização de busca vetorial e recall</a>, de Jeff Vestal</p></li><li><p>Adicione o reranking para melhorar ainda mais a precisão nos resultados principais</p></li><li><p>Consulte a <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/rrf.html">documentação de busca híbrida do Elasticsearch</a></p></li><li><p>Leia mais sobre a <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-rank-eval.html"><code>rank_eval</code></a><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-rank-eval.html"> API</a></p></li></ul>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-relevance-tuning-improve-recall</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-relevance-tuning-improve-recall</guid>
    <category><![CDATA[Busca híbrida]]></category>
    <category><![CDATA[Banco de dados vetorial]]></category>
    <dc:creator><![CDATA[Jeffrey Rengifo]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt37c9d2971b5a2db3/6a170a75cf4f254223b2d149/492c9b5432a2b9e40cebb3b60f0df019a8c7bf6d-1280x720.png" length="0" type="image/png"/>
    <pubDate>Mon, 04 May 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Resolução de entidades com Elasticsearch, parte 4: O desafio definitivo]]></title>
    <description><![CDATA[Resolvendo e avaliando desafios de resolução de entidades em um conjunto de dados de desafio definitivo altamente diversificado, projetado para evitar atalhos.]]></description>
    <content:encoded><![CDATA[<p>Agora vimos a resolução inteligente de entidades implementada de duas maneiras. Ambas as abordagens começam da mesma forma: preparação e extração de entidades, seguidas pela recuperação de candidatos com Elasticsearch. A partir daí, avaliamos esses candidatos usando um grande modelo de linguagem (LLM), seja por meio de geração de JSON baseada em prompt ou chamada de funções, e exigimos que o modelo forneça uma explicação transparente para seu julgamento.</p><p>Como vimos na <a href="https://www.elastic.co/search-labs/blog/elasticsearch-entity-resolution-llm-function-calling">postagem anterior</a>, a consistência proporcionada pela chamada de função não é apenas uma mera otimização; é essencial. Uma vez removidos os erros estruturais do ciclo de avaliação, os resultados em cenários padrão (como os do conjunto de dados de nível 4) melhoraram significativamente.</p><p>No entanto, há uma pergunta óbvia a ser respondida:</p><p><em>Essa abordagem ainda funciona quando as coisas realmente ficam confusas?</em></p><p>A resolução de entidades no mundo real raramente falha por causa de casos simples. Ela falha quando nomes cruzam línguas, culturas, sistemas de escrita, períodos de tempo e fronteiras organizacionais. Ela falha quando as pessoas são referenciadas por títulos em vez de nomes, quando as empresas mudam de nome, quando as transliterações não são consistentes e quando o contexto (não a ortografia) é a única coisa que vincula uma menção a uma entidade do mundo real.</p><p>Então, para o post final desta série, colocamos o sistema no que chamamos de <strong>desafio definitivo</strong>.</p><h2>O que faz disso o desafio definitivo?</h2><p>Em avaliações anteriores, testamos o sistema usando conjuntos de dados cada vez mais complexos. Quando chegamos ao nível 4, discutido no post anterior, já estávamos lidando com uma mistura de apelidos, títulos, nomes multilíngues e referências semânticas. Esses testes mostraram que a arquitetura em si era sólida, mas que problemas de confiabilidade, especialmente JSON malformado, estavam prejudicando o recall.</p><p>Com a chamada de função implementada, finalmente tivemos uma base estável. Isso nos deu a oportunidade de fazer uma pergunta mais interessante:</p><p><em>Um único pipeline unificado consegue lidar </em><em><strong>com vários tipos diferentes</strong></em><em> de problemas de resolução de entidades simultaneamente?</em></p><p>O conjunto de dados de desafio definitivo foi projetado para explorar precisamente essa dimensão.</p><p>Em vez de se concentrar em uma única dificuldade (como apelidos ou transliteração), este conjunto de dados combina <strong>mais de 50 tipos de desafios distintos</strong>, incluindo:</p><ul><li><p>Convenções culturais de nomeação.</p></li><li><p>Referências baseadas em títulos.</p></li><li><p>Relações comerciais e mudanças históricas de nome.</p></li><li><p>Menções multilíngues e em diferentes sistemas de escrita.</p></li><li><p>Desafios complexos que misturam vários dos itens acima.</p></li></ul><p>O mais importante é que isso não se trata de otimizar para um caso de uso específico. Trata-se de testar se o <em>padrão de design</em> se sustenta quando as regras mudam de entidade para entidade.</p><h2>Visão geral do conjunto de dados</h2><p>O conjunto de dados de desafio definitivo consiste em:</p><ul><li><p><strong>50 entidades</strong>, abrangendo pessoas, organizações e instituições.</p></li><li><p><strong>Cerca de 60 artigos</strong>, com estrutura e complexidade linguística variadas.</p></li><li><p><strong>51 categorias distintas de desafios</strong>, agrupadas de forma ampla em:</p><ul><li><p>Convenções culturais de nomeação.</p></li><li><p>Títulos e o contexto profissional.</p></li><li><p>Relacionamentos empresariais e organizacionais.</p></li><li><p>Desafios multilíngues e de transliteração.</p></li><li><p>Cenários combinados e casos limite.</p></li></ul></li></ul><p>No início da série, vimos que usar IA generativa (GenAI) para criar conjuntos de dados pode ser uma faca de dois gumes. Sem ele, reunir dados de teste suficientemente grandes e diversos seria extremamente difícil. Mas, se não for controlado, o modelo tende a simplificar demais as coisas.</p><p>Em uma etapa inicial de geração, por exemplo, descobrimos que o modelo incluía frases como "o presidente russo" como apelidos explícitos para Vladimir Putin. Isso pode parecer razoável hoje, mas anula o propósito de testar a resolução contextual. O que acontece se o artigo estiver discutindo a Rússia nos anos 1990? O sistema deve inferir a entidade correta a partir do contexto, não depender de um alias fixo.</p><p>Por esse motivo, este conjunto de dados foi deliberadamente projetado para que <strong>os atalhos não funcionem</strong>. Os pseudônimos não são explicitamente listados quando se espera que o sistema deduza o significado. Frases descritivas não são vinculadas previamente a entidades. As correspondências corretas frequentemente dependem do contexto em nível de artigo, não apenas do texto local.</p><p><strong>Observação importante:</strong> embora demonstremos os recursos do sistema em diversos cenários, este ainda é um protótipo educacional. Os sistemas de produção que lidam com o monitoramento real de entidades sob sanção exigiriam validação adicional, verificações de conformidade, trilhas de auditoria e tratamento especializado para casos de uso sensíveis.</p><h2>Por que esses cenários são difíceis?</h2><p>No primeiro post desta série, apresentamos um exemplo simples, mas ambíguo: "A nova atualização do Swift chegou!" O desafio é que "Swift" pode corresponder a múltiplas entidades do mundo real, dependendo do contexto. Esse exemplo captura uma verdade mais ampla: a linguagem natural é inerentemente ambígua.</p><p>A resolução de entidades, portanto, não é apenas um problema de correspondência de strings. As pessoas normalmente se baseiam normalmente em conhecimento compartilhado, normas culturais e contexto situacional para resolver referências, e raramente percebemos que estamos fazendo isso.</p><p>Considere alguns casos comuns:</p><ul><li><p>Um título como “o presidente” não tem significado sem contexto geopolítico e temporal.</p></li><li><p>O nome de uma empresa pode se referir a uma controladora, uma subsidiária ou uma marca anterior, dependendo de quando o artigo foi escrito.</p></li><li><p>O nome de uma pessoa pode aparecer em diferentes ordens, sistemas de escrita ou transliterações, dependendo da língua e da cultura.</p></li><li><p>A mesma frase pode se referir legitimamente a diferentes entidades em diferentes contextos, e o sistema deve ser capaz de <em>rejeitar</em> correspondências com a mesma confiança com que as aceita.</p></li></ul><p>Não existe um conjunto único de regras que lide com tudo isso de forma clara. É por isso que este protótipo separa as responsabilidades de forma tão clara:</p><ul><li><p>O Elasticsearch reduz o conjunto de candidatos de forma eficiente e transparente.</p></li><li><p>O LLM é usado apenas quando o julgamento é necessário e é obrigado a se explicar.</p></li><li><p>Recuperação e raciocínio continuam sendo etapas distintas.</p></li></ul><p>Essa separação se torna ainda mais importante à medida que a diversidade de tipos de desafios aumenta.</p><h2>Como o sistema lida com a diversidade sem exceções específicas</h2><p>Um dos resultados mais interessantes desta avaliação é o que <em>não</em> mudou:</p><ul><li><p><strong>Não</strong> adicionamos lógica especial para nomes japoneses.</p></li><li><p>Não <strong>adicionamos</strong> regras personalizadas para patronímicos árabes.</p></li><li><p><strong>Não</strong> adicionamos mapeamentos fixos para nomes históricos de empresas.</p></li></ul><p>Em vez disso, o sistema se baseou nos mesmos elementos centrais apresentados anteriormente na série:</p><ul><li><p>Entidades enriquecidas por contexto indexadas para busca semântica.</p></li><li><p>Recuperação híbrida (exata, alias e semântica) no Elasticsearch.</p></li><li><p>Um pequeno e bem definido conjunto de correspondências candidatas.</p></li><li><p>Julgamento de LLM restrito por chamada de função e esquemas mínimos.</p></li></ul><p>Isso sugere que a flexibilidade do sistema vem da <strong>representação e da arquitetura</strong>, não de uma coleção de regras em constante crescimento.</p><p>Quando o sistema tem sucesso, é porque os candidatos certos são recuperados e o LLM tem contexto suficiente para explicar por que uma referência corresponde (ou não) a uma entidade específica.</p><h2>Resultados: Como foi o desempenho?</h2><p>No conjunto de dados de desafio definitivo, o sistema produziu os seguintes resultados gerais:</p><ul><li><p><strong>Precisão:</strong> ~91%</p></li><li><p><strong>Recall:</strong> ~86%</p></li><li><p><strong>Pontuação F1:</strong> ~89%</p></li><li><p><strong>Taxa de aceitação em LLM:</strong> ~72%</p></li></ul><h3>Desempenho em diferentes tipos de desafio</h3><p>A análise dos resultados por tipo de desafio revela pontos fortes e limitações:</p><p><strong>O desempenho mais forte (100% na pontuação F1)</strong> foi observado em áreas como:</p><ul><li><p>Correspondência de entidades entre sistemas de escrita (cirílico, coreano e chinês).</p></li><li><p>Cenários hebraicos (patronímicos, títulos profissionais, títulos religiosos, transliteração).</p></li><li><p>Hierarquias de negócios (aeroespacial, manufatura diversificada, corporações multidivisionais).</p></li><li><p>Títulos profissionais (acadêmicos, militares, políticos, religiosos).</p></li><li><p>Cenários combinados em japonês envolvendo múltiplos sistemas de escrita.</p></li></ul><p><strong>Forte desempenho (pontuação F1 de 80–99%)</strong> incluiu:</p><ul><li><p>Figuras políticas internacionais (98%).</p></li><li><p>Alterações históricas de nome (90%).</p></li><li><p>Hierarquias empresariais complexas (89%).</p></li><li><p>Nomes de empresas japonesas (93%).</p></li><li><p>Transliteração entre escrituras (86%).</p></li><li><p>Patrônimos árabes (86%).</p></li></ul><p><strong>Áreas mais desafiadoras</strong> incluíram:</p><ul><li><p>Transliteração avançada (chinês, coreano): 0% de pontuação F1.</p></li><li><p>Certos cenários japoneses (honoríficos, ordem dos nomes, variação do sistema de escrita): ~67% F1.</p></li><li><p>Alguns cenários árabes (nomes de empresas, referências institucionais): ~40% F1.</p></li></ul><p>O que é importante aqui é <em>por que</em> o sistema teve dificuldades nesses casos. As falhas não foram causadas por problemas na abordagem geral, mas por limitações em componentes específicos, especialmente o modelo vetorial denso usado para busca semântica em determinados cenários multilíngues.</p><p>Como recuperação e julgamento estão claramente separados, melhorar o desempenho não exige reescrever o sistema. A substituição por um modelo de embeddings multilíngue mais capaz, o enriquecimento do contexto da entidade ou o refinamento das estratégias de recuperação melhoraria os resultados nessas categorias sem alterar a arquitetura central.</p><p>Do ponto de vista arquitetônico, essa é a verdadeira métrica de sucesso.</p><h2>O que isso nos diz sobre o design</h2><p>Olhando para trás na série, alguns padrões se destacam:</p><ul><li><p><strong>A preparação é mais importante do que a combinação inteligente. </strong>Enriquecer entidades com contexto desde o início reduz drasticamente a ambiguidade depois.</p></li><li><p><strong>Os LLMs são mais valiosos como juízes, não como recuperadores. </strong>Pedir <em>que expliquem por que</em> uma combinação faz sentido é muito mais poderoso do que pedir que busquem.</p></li><li><p><strong>A confiabilidade possibilita precisão. </strong>A chamada de funções não apenas limpou o JSON; ela revelou o recall que já estava latente na etapa de recuperação.</p></li><li><p><strong>A generalização supera a especialização. </strong>Um pequeno número de abstrações bem definidas lidou com dezenas de tipos de desafios sem lógica personalizada.</p></li></ul><p>Por isso, o protótipo é intencionalmente nativo do Elasticsearch e conservador na forma como utiliza LLMs. O objetivo não é substituir a busca; é tornar a busca explicável em situações onde o significado importa.</p><h2>Conclusão</h2><p>O desafio final não era buscar métricas perfeitas; era sobre responder a uma pergunta mais fundamental:</p><p><em>Uma arquitetura transparente, orientada para busca e assistida por LLM, pode lidar com a ambiguidade de entidades no mundo real sem se limitar a regras ou caixas-pretas?</em></p><p>Para este protótipo educacional, a resposta é sim, com claras ressalvas sobre robustez para produção, conformidade, monitoramento e qualidade dos dados. Se você estiver criando sistemas que precisem justificar <em>por que</em> foi feita uma correspondência de entidade, vale a pena considerar seriamente esse padrão. Espero que esta série tenha mostrado que a resolução de entidades não precisa ser algo misterioso. Com a separação certa das preocupações, torna-se algo sobre o qual você pode refletir, medir e melhorar.</p><p>Este trabalho também sugere um padrão arquitetônico mais amplo. O que surge é uma leve, mas importante, evolução da Retrieval-Augmented Generation (RAG). Em vez de permitir que a recuperação alimente diretamente a geração, introduzimos uma etapa explícita de avaliação. O LLM é usado primeiro para avaliar e verificar a consistência dos candidatos recuperados, e apenas os resultados aprovados podem ampliar a geração. Você pode pensar nisso como Retrieval-Augmented Generation com Avaliação, ou GARAGE, porque quem não gosta de uma boa sigla.</p><p>Quais outros casos de uso poderiam se beneficiar desse padrão? Sistemas que exigem confiança, transparência e raciocínio defensável são candidatos naturais. Trabalhos futuros nessa área devem ser tão interessantes quanto os resultados que vimos aqui, e estou entusiasmado para ver para onde a comunidade vai levar isso a seguir.</p><h2>Próximos passos: Experimente por conta própria</h2><p>Quer ver o desafio definitivo em ação? Confira o <a href="https://github.com/jesslm/entity-resolution-lab-public/tree/main/notebooks#:~:text=5%20minutes%20ago-,05_ultimate_challenge_v3.ipynb,-Initial%20public%20lab"><strong>Notebook do desafio definitivo</strong></a> para ver um passo a passo completo, com implementações reais, explicações detalhadas e exemplos práticos.</p><p>O pipeline completo de resolução de entidades demonstra os conceitos centrais e a arquitetura necessários para uso em produção. Você pode usá-lo como base para construir sistemas que monitorem artigos de notícias, rastreiem menções de entidades e respondam a perguntas sobre quais entidades aparecem em quais artigos, tudo isso mantendo transparência e explicabilidade.
</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/entity-resolution-elasticsearch-llm-challenges</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/entity-resolution-elasticsearch-llm-challenges</guid>
    <category><![CDATA[AI]]></category>
    <category><![CDATA[Busca híbrida]]></category>
    <dc:creator><![CDATA[Jessica Moszkowicz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc58be329ffebcd60/6a17043e47d49c0bc62d88ab/70fb0ff949f6db9ac9b8a28ecb4329ab915ebf46-720x420.png" length="0" type="image/png"/>
    <pubDate>Fri, 13 Mar 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Resolução de entidades com Elasticsearch & LLMs, Parte 2: Correspondência de entidades com julgamento LLM e busca semântica]]></title>
    <description><![CDATA[Uso de busca semântica e julgamento transparente de LLM para a resolução de entidades no Elasticsearch.]]></description>
    <content:encoded><![CDATA[<p>Na<a href="https://www.elastic.co/search-labs/blog/entity-resolution-llm-elasticsearch"> Parte 1</a>, preparamos nossa lista de monitoramento e extraímos as menções às entidades. Agora, estamos prontos para responder à pergunta difícil: a qual entidade uma menção realmente se refere? Vamos voltar ao exemplo do primeiro blog desta série, que explica por que precisamos de resolução de entidades: "A atualização Swift chegou!" Imagine que esta manchete vem acompanhada de um pouco mais de contexto:</p><ol><li><p>A nova atualização do Swift chegou! Os desenvolvedores estão ansiosos para experimentar os novos recursos.</p></li><li><p>A nova atualização do Swift chegou! O novo álbum será lançado no próximo mês.</p></li></ol><p>Com esse contexto adicional, devemos conseguir resolver o nome "Swift" para a entidade correta.</p><p>Na <a href="https://www.elastic.co/search-labs/blog/entity-resolution-llm-elasticsearch">postagem anterior</a>, configuramos nossa lista de observação e enriquecemos as entidades com contexto adicional. Olhando nossos exemplos acima, precisamos ter pelo menos as seguintes duas entidades na lista: Taylor Swift e Swift Programming Language. Também abordamos como extraímos menções a entidades do texto. Ambos os exemplos extrairiam "Swift". Com esses ingredientes prontos, a lista de observação enriquecida e as entidades extraídas, finalmente estamos prontos para apresentar a estrela do show: a correspondência de entidades.</p><p><strong>Lembre-se:</strong> este é um protótipo educacional projetado para ensinar conceitos de correspondência de entidades. Os sistemas de produção podem usar diferentes modelos de linguagem grande (LLMs), regras de correspondência personalizadas, pipelines de julgamento especializados ou abordagens de conjunto que combinam várias estratégias de correspondência.</p><h2>O problema: por que a correspondência é difícil</h2><p>A linguagem humana é algo extraordinário. Uma das propriedades mais interessantes é sua criatividade infinita. Podemos gerar e entender um número infinito de novas frases. Será que é de se estranhar, então, que correspondências exatas na resolução das entidades sejam raras? Autores se esforçam para ser criativos quando podem. Ficaria bastante cansativo se tivéssemos que escrever e ler nomes completos sempre que uma entidade fosse mencionada. Portanto, embora as correspondências exatas sejam fáceis, a realidade é que precisamos de uma abordagem mais sofisticada para a resolução de entidades: uma que seja robusta o suficiente para lidar com pelo menos parte da criatividade ilimitada de autores humanos. Por isso, dividimos o problema em duas etapas: usar o Elasticsearch para recuperar candidatos plausíveis em larga escala, e depois usar um LLM para julgar se esses candidatos realmente se referem à mesma entidade do mundo real.</p><h2>A solução: correspondência em três etapas com julgamento transparente do LLM</h2><p>Estamos no meio de uma mudança de paradigma na forma como usamos computadores. Assim como a ascensão da Internet nos levou da computação localizada para uma rede conectada globalmente, a IA generativa (GenAI) está mudando fundamentalmente a forma como o conteúdo, o código e as informações são criados. Na verdade, o protótipo educacional que acompanha essa série foi quase exclusivamente "codificado por vibração" usando um LLM, com orientação cuidadosa do autor. Isso não quer dizer que os LLMs tenham ou que alcançarão o tipo de produtividade inerente à linguagem humana, mas significa que agora temos um recurso poderoso para ajudar na resolução de entidades.</p><p>Um padrão comum que usamos com GenAI é a retrieval augmented generation (RAG). Aqui, <em>retrieval</em> significa recuperar entidades candidatas (não gerar respostas), e o LLM é usado estritamente para avaliação e explicação da correspondência. Embora <em>pudéssemos</em> pedir a um LLM para nos ajudar com a resolução de entidades de ponta a ponta, essa abordagem é dispendiosa, tanto em termos de tempo quanto de dinheiro. A RAG ajuda os LLMs a realizar seu trabalho usando maneiras mais eficientes de fornecer contexto ao LLM, capacitando-o a auxiliar de forma eficiente na resolução de entidades.</p><p>Para a parte de recuperação do RAG, voltamos novamente ao Elasticsearch. Primeiro, encontramos possíveis correspondências usando uma combinação de correspondência exata, correspondência com aliases e busca híbrida, que combina busca semântica e por palavra-chave. Assim que encontramos essas possíveis correspondências, as enviamos para um LLM para julgamento. O LLM atua como avaliador final de correspondência. Também fazemos o LLM explicar seu raciocínio, um diferenciador importante em relação a outros sistemas de resolução de entidades. Sem essas explicações, a resolução de entidades é uma caixa preta; com elas, podemos ver por nós mesmos por que uma correspondência faz sentido.</p><h2>Conceitos-chave: correspondência em três etapas, busca híbrida e julgamento transparente de LLM</h2><p><strong>O que é a correspondência em três etapas?</strong> No início deste projeto, hipotetizamos que a busca semântica será uma parte crucial do sistema, mas nem toda correspondência exige uma busca tão sofisticada. Para encontrar correspondências de forma eficiente, adotamos uma abordagem progressiva ao problema. Primeiro, verificamos correspondências exatas usando busca por palavras-chave. Se encontrarmos essa correspondência, nosso trabalho estará feito e poderemos seguir em frente. Se a correspondência exata falhar, recorremos à correspondência de alias. No protótipo, a correspondência de alias também é feita usando correspondência exata com palavras-chave, para simplificar. Na produção, você pode expandir essa etapa com normalização, regras de transliteração, correspondência fuzzy ou tabelas de alias curadas. Se ainda não encontramos uma possível correspondência nas duas primeiras etapas, é hora de introduzir a busca semântica por meio da busca híbrida do Elasticsearch com fusão recíproca de classificação (RRF).</p><p><strong>O que é busca híbrida?</strong> No Elasticsearch, podemos usar a busca semântica para encontrar correspondências significativas que levem em conta o contexto. O Elasticsearch é amplamente utilizado para busca vetorial e recuperação híbrida. A semelhança semântica é poderosa para o significado, mas não substitui a filtragem estruturada (por exemplo, por intervalos de tempo, locais ou identificadores) e geralmente é desnecessária quando uma correspondência exata está disponível. O Elasticsearch se destacou com a busca lexical, que é ótima em tarefas onde a busca semântica não se encaixa. Para aproveitar ao máximo ambas as abordagens, usamos a busca lexical junto com a busca semântica em uma única consulta híbrida. Depois, juntamos os resultados para encontrar as correspondências mais prováveis usando o RRF. No protótipo, os dois melhores resultados tornam-se correspondências potenciais que podem ser enviadas para avaliação do LLM.</p><p><strong>Por que julgamento de LLM?</strong> Julgamentos e explicações de LLM permitem que nosso sistema trate ambiguidade e contexto de forma transparente. Isso é vital para casos como "o presidente", que pode se referir a múltiplas entidades, dependendo do contexto, mas também faz com que apelidos e variações culturais funcionem bem no sistema. Finalmente, quando consideramos tarefas de missão crítica, como identificar entidades a partir de listas de sanções, precisamos saber por que uma combinação foi aceita para confiar no sistema. Crucialmente, o LLM não busca o corpus completo; ele avalia apenas o pequeno conjunto de candidatos retornados pelo Elasticsearch.</p><h2>Resultados do mundo real: correspondência com raciocínio de LLM</h2><p>Um dos principais desafios de qualquer tarefa de processamento de linguagem natural é a criação de um documento de referência, um "gabarito" que nos diga quais são os resultados esperados. Sem isso, é praticamente impossível avaliar o desempenho de um sistema em uma tarefa, mas criar um documento desse tipo pode ser um processo trabalhoso. Para o protótipo de resolução de entidades, recorremos novamente à GenAI para nos ajudar a configurar os dados que pudéssemos usar para os testes.</p><p>Primeiro, definimos vários tipos de desafios, como apelidos e transliteração, e então pedimos ao LLM para criar uma coleção em camadas de conjuntos de dados que se tornariam progressivamente maiores e mais desafiadores para o sistema. A criação dos conjuntos de dados foi menos simples do que se esperava. O LLM tinha uma forte propensão para "trapacear" ao tornar muito fácil obter a resposta certa. Por exemplo, um dos tipos de desafio focou no contexto semântico. Este tipo incluiu coisas como resolver "autor russo" para "Liev Tolstói". O LLM incorretamente colocou "autor russo" como um alias para "Leo Tolstoy", o que negou a necessidade de uma busca híbrida para encontrar a correspondência.</p><p>Após várias refatorações para corrigir problemas como esse, tínhamos cinco níveis de conjunto de dados para trabalhar. Os níveis 1 a 4 eram progressivamente maiores, com mais tipos de desafio. O Tier 5 era o conjunto de dados do "desafio supremo", composto pelos exemplos mais difíceis de todos os tipos de desafio. Todos os dados dos testes estão disponíveis no <a href="https://github.com/jesslm/entity-resolution-lab-public/tree/main/comprehensive_evaluation">diretório de avaliação completo</a>.</p><p>Para avaliar nossa abordagem de resolução de entidades baseada em prompts, focamos nossa atenção no conjunto de dados de nível 4. Um ponto importante é que a avaliação foi realizada como um experimento controlado para que pudéssemos focar na qualidade da correspondência de entidades. Os dados da lista de observação foram pré-enriquecidos com contexto, e as entidades foram extraídas do artigo antecipadamente. Isso garantiu que a avaliação fosse focada em correspondência, e não na precisão da extração. Isso isola a qualidade da correspondência; o desempenho de ponta a ponta também dependeria da qualidade do recall e do enriquecimento da extração.</p><h3>Conjunto de dados de avaliação</h3><p>O conjunto de dados de avaliação de nível 4 fornece um teste abrangente das capacidades do sistema:[1]</p><ul><li><p><strong>Entidades da lista de observação:</strong> 66 entidades de diversos tipos (pessoas, organizações, locais).</p></li><li><p><strong>Artigos de teste:</strong> 69 artigos que abrangem cenários reais de resolução de entidades.</p></li><li><p><strong>Correspondências esperadas:</strong> 206 correspondências de entidades esperadas em todos os artigos.</p></li><li><p><strong>Tipos de desafio: </strong>15 tipos diferentes de desafio que testam vários aspectos da resolução de entidades.</p></li></ul><p>Os tipos de desafios incluídos no conjunto de dados são:</p><ul><li><p><strong>Apelidos:</strong> "Bob Smith" → "Robert Smith" (sete artigos).</p></li><li><p><strong>Títulos e honoríficos:</strong> "Dr. Sarah Williams" → "Sarah Williams" (cinco artigos).</p></li><li><p><strong>Contexto semântico:</strong> "autor russo" → "Liev Tolstói" (oito artigos).</p></li><li><p><strong>Nomes multilíngues:</strong> manuseio de nomes em diferentes scripts (seis artigos).</p></li><li><p><strong>Entidades empresariais:</strong> variações de nome corporativo (sete artigos).</p></li><li><p><strong>Referências executivas: </strong>"CEO da Microsoft" → "Satya Nadella" (cinco artigos).</p></li><li><p><strong>Líderes políticos:</strong> referências baseadas em títulos (cinco artigos).</p></li><li><p><strong>Iniciais:</strong> "J. Smith" → "John Smith" (três artigos).</p></li><li><p><strong>Variações na ordem dos nomes:</strong> diferentes convenções de ordenação de nomes (três artigos).</p></li><li><p><strong>Nomes truncados:</strong> correspondências parciais de nomes (três artigos).</p></li><li><p><strong>Divisão de nomes:</strong> nomes divididos no texto (três artigos).</p></li><li><p><strong>Falta de espaços/hífens:</strong> variações de formatação (dois artigos).</p></li><li><p><strong>Transliteração:</strong> correspondência de nomes entre escrituras (dois artigos).</p></li><li><p><strong>Desafios combinados:</strong> Vários desafios em um único artigo (seis artigos).</p></li><li><p><strong>Negócios complexos:</strong> relações comerciais hierárquicas (cinco artigos).</p></li></ul><p>Vamos ver como a resolução de entidades baseada em prompts foi realizada.</p><h3>Desempenho geral</h3><p>Os resultados mostram que a avaliação de correspondência baseada no LLM é muito promissora, mas também revelam um problema significativo de confiabilidade. Como cada par de candidatos deve ser avaliado pelo LLM, falhas na saída estruturada podem suprimir a aceitação e a recuperação, mesmo quando a recuperação está funcionando bem.</p><p>Métrica</p><p>Valor</p><p>Precisão</p><p>83,8%</p><p>Recall</p><p>62,6%</p><p>Pontuação F1</p><p>71,7%</p><p>Total de correspondências encontradas</p><p>344</p><p>Taxa de aceitação do LLM</p><p>44,8%</p><p>Taxa de erro</p><p>30,2%</p><h3>O problema da taxa de erro</h3><p>Lembre-se de que o primeiro passo que damos no protótipo é criar potenciais pares de correspondência usando o Elasticsearch. Cada uma dessas possíveis correspondências precisa ser avaliada pelo LLM. Para processar eficientemente todas essas correspondências, agrupamos as chamadas de LLM em lote. Isso reduz os custos da API e a latência, mas também há um risco aumentado de obter JSON malformado na saída. À medida que o tamanho do lote aumenta, o JSON se torna mais longo e complexo, tornando mais provável que o LLM gere JSON inválido. É daí que decorre a taxa de erro de 30%. Na avaliação, usamos um tamanho de lote de cinco correspondências por solicitação. Mesmo com este tamanho de lote conservador, ainda vemos falhas na análise JSON, o que distorce significativamente os resultados da avaliação.</p><h2>O que vem a seguir: otimização da integração com LLMs</h2><p>Agora que combinamos entidades usando busca semântica e julgamento de LLM, temos um pipeline completo de resolução de entidades. Essa abordagem introduz um novo modo de falha, no entanto, quando o julgamento do modelo está correto, mas sua saída não é utilizável. Podemos otimizar a integração do LLM para maior confiabilidade e eficiência de custos. No próximo post, exploraremos como usar o chamado de função para saída estruturada, que garante estrutura e segurança de tipos, ao mesmo tempo em que reduz erros e custos.</p><h2>Experimente você mesmo</h2><p>Quer ver a correspondência de entidades em ação? Confira o <a href="https://github.com/jesslm/entity-resolution-lab-public/tree/main/notebooks#:~:text=5%20minutes%20ago-,03_entity_matching_v3.ipynb,-Initial%20public%20lab">notebook do Entity Matching</a> para ver um passo a passo completo com implementações reais, explicações detalhadas e exemplos práticos. O caderno mostra exatamente como combinar entidades usando busca em três etapas, busca híbrida com RRF e julgamento baseado em LLM com raciocínio.</p><p><strong>Lembre-se:</strong> este é um protótipo educacional projetado para ensinar os conceitos. Ao construir sistemas de produção, considere fatores adicionais, como seleção de modelos, otimização de custos, requisitos de latência, validação de qualidade, tratamento de erros e monitoramento, que não são abordados neste protótipo focado em aprendizado.</p><h2>Notas</h2><ol><li><p>Esses conjuntos de dados são sintéticos e projetados para educação; eles se aproximam de desafios reais, mas não representam nenhum domínio de produção específico.</p></li></ol>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-entity-resolution-llm-semantic-search</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-entity-resolution-llm-semantic-search</guid>
    <category><![CDATA[AI]]></category>
    <category><![CDATA[Busca híbrida]]></category>
    <dc:creator><![CDATA[Jessica Moszkowicz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltefc59243d9990405/6a17056ab339d5778f769ebf/473ca4357c7d60f690edbd2a844acda169aca9c3-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Thu, 26 Feb 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Garantindo precisão semântica com pontuação mínima]]></title>
    <description><![CDATA[Melhore a precisão semântica empregando limiares mínimos de pontuação. O artigo inclui exemplos concretos de busca semântica e híbrida. ]]></description>
    <content:encoded><![CDATA[<p>A busca semântica abriu um mundo de oportunidades para a relevância da busca. Modelos esparsos e densos de alta qualidade, como ELSER, E5 e Jina Embedding v4, retornam resultados relevantes com base no significado das palavras, em vez da correspondência de palavras-chave. No entanto, a busca semântica às vezes retorna resultados irrelevantes na cauda final ou para consultas que não apresentam resultados relevantes no índice. Essa propriedade dos modelos esparsos e densos pode confundir os usuários ou desperdiçar tokens preciosos para grandes modelos de linguagem (LLMs).</p><p>Neste artigo, você aprenderá como usar o parâmetro de pontuação mínima para aumentar a precisão dos seus resultados de busca semânticos. Se você quiser testar os exemplos fornecidos neste post do blog, <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/ensuring-semantic-precision-with-minimum-score/ensuring_semantic_precision_with_minimum_score.ipynb">acesse o caderno Jupyter associado</a>.</p><h2>Contexto: Precisão e recall</h2><p>Na relevância da pesquisa, a <em>precisão </em>e a <em>recall </em>são conceitos-chave. Qualquer leitor que ainda não esteja familiarizado é altamente incentivado a pesquisar sobre eles. Segue abaixo um resumo.</p><ul><li><p><strong>Precisão: </strong>a fração dos resultados de busca retornados que são relevantes para o usuário.</p></li><li><p><strong>Recall: </strong>a fração de todos os documentos relevantes no corpus que estão incluídos no conjunto de resultados de busca.</p></li></ul><p>Ou, em outras palavras, a precisão retorna <strong>apenas </strong>resultados relevantes e o recall retorna <strong>todos </strong>os resultados relevantes. Como você pode imaginar, esses são requisitos frequentemente concorrentes. A busca semântica tende a ter uma memória muito alta, mas pode ter dificuldades com precisão. Continue lendo para saber como se locomover por esta propriedade.</p><h2>Apresentando o parâmetro de pontuação mínima</h2><p>O parâmetro ‘min_score’ nos permite melhorar a precisão ao definir uma pontuação mínima, que truncará o conjunto de resultados removendo quaisquer correspondências com uma pontuação inferior ao limite definido. Aqui está um exemplo simples:</p>GET search-movies/_search
{
  "retriever": {
    "linear": {
      "min_score": 4,
      "retrievers": [
        ...
      ]
    }
  }
}<h2>Normalização da pontuação</h2><p>Definir uma pontuação mínima é muito bom; no entanto, nem todos os modelos semânticos retornam uma pontuação adequada para um limite estático. ELSER, por exemplo, retorna uma pontuação que é ilimitada. <a href="https://huggingface.co/intfloat/e5-small#faq">Algumas</a> pontuações de modelos densos estão fortemente agrupadas e só fazem sentido no contexto da consulta específica.</p><p>Para a maioria dos casos de busca semântica, recomendamos usar uma abordagem de normalização antes de aplicar o 'min_score'. A normalização garante que a pontuação do documento esteja dentro de um intervalo definido. Os recuperadores Elasticsearch fornecem dois desses <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrievers/linear-retriever#linear-retriever-normalizers">normalizadores</a>, 'l2_norm' e 'minmax'. O mais comumente usado é o 'minmax', pois é fácil de entender e funciona bem em muitos cenários. As principais propriedades do 'minmax' incluem:</p><ul><li><p>As pontuações dos documentos são distribuídas entre 0 e 1.</p></li><li><p>O documento com maior pontuação é sempre pontuado como 1.</p></li><li><p>O documento com menor pontuação sempre é pontuado como 0.</p><ul><li><p>Isso pode torná-lo menos adequado para buscar palavras-chave. Consulte a seção “Busca híbrida” para uma discussão mais aprofundada.</p></li></ul></li></ul><p>A seguir está um exemplo de consulta semântica normalizada com <code>min_score</code>. O tamanho da janela de classificação foi aumentado para 500 para permitir que possamos retornar uma lista maior de resultados de busca, começando em 100.</p>GET search-movies/_search
{
  "size": 100,
  "_source": [
    "title", "overview"
  ],
  "retriever": {
    "linear": {
      "rank_window_size": 500,
      "min_score": 0.25,
      "retrievers": [
        {
          "normalizer": "minmax",
          "retriever": {
            "standard": {
              "query": {
                "semantic": {
                  "field": "overview_vector",
                  "query": "superhero movie"
                }
              }
            }
          }
        }
      ]
    }
  }
}<p>O tamanho foi ajustado para um valor maior do que o normalmente visto na produção. Isso é para que possamos inspecionar a qualidade dos resultados de busca e ajustar os resultados.</p><h2>Busca híbrida usando o recuperador linear</h2><p>Para busca híbrida, a abordagem mais simples é normalizar todas as pontuações, atribuir pesos e aplicar uma pontuação mínima. Note que, ao escolher pesos cuja soma seja 1, você mantém a pontuação total dentro de um intervalo de 0 a 1. Isso facilita entender as pontuações finais e afinar <code>min_score</code>. A seguir está um exemplo:</p>GET search-movies/_search
{
  "size": 100,
  "_source": ["title", "overview","keywords"],
  "retriever": {
    "linear": {
      "rank_window_size": 500,
      "min_score": 0.25,
      "retrievers": [
        {
          "weight": 0.6,
          "normalizer": "minmax",
          "retriever": {
            "standard": {
              "query": {
                "semantic": {
                  "field": "overview_vector",
                  "query": "superhero movie"
                }
              }
            }
          }
        },
        {
          "weight": 0.4,
          "normalizer": "minmax",
          "retriever": {
            "standard": {
              "query": {
                "multi_match": {
                  "query": "superhero movie",
                  "fields": ["overview","keywords", "title"],
                  "type": "cross_fields",
                  "minimum_should_match": "2"
                }
              }
            }
          }
        }
      ]
    }
  }
}<h2>Busca híbrida usando o RRF</h2><p>Com o BM25, muitas vezes controlamos a precisão por outros meios, como usando o operador <code>AND</code> ou <code>minimum_should_match</code>. Além disso, consultas compostas por termos únicos, precisos e raros naturalmente causam resultados de busca com poucos resultados, muitas vezes todos altamente relevantes. Isso pode resultar em:</p><ul><li><p>Os resultados mais distantes na lista recebem uma pontuação normalizada baixa no recuperador BM25, mesmo que a pontuação absoluta do BM25 esteja próxima das pontuações mais altas.</p></li><li><p>Ao adicionar uma pontuação BM25 muito baixa à pontuação semântica, o total pode ser aproximado como a pontuação semântica.</p></li><li><p>A falta de contribuição da pontuação BM25 pode fazer com que o documento seja descartado pelo <code>min_score threshold</code>.</p></li></ul><p>Como solução, podemos usar a fusão de classificação recíproca (RRF) para combinar os resultados BM25 e semânticos. O RRF contorna o desafio de comparar pontuações de diferentes algoritmos de busca focando na posição em cada conjunto de resultados. Nesse cenário, o <code>min_score</code> é aplicado apenas ao recuperador semântico.</p>GET search-movies/_search
{
  "_source": ["title", "overview","keywords"],
  "retriever": {
    "rrf": {
      "rank_window_size": 500,
      "retrievers": [
        {
          "linear": {
            "rank_window_size": 500,
            "min_score": 0.25,
            "retrievers": [
              {
                "normalizer": "minmax",
                "retriever": {
                  "standard": {
                    "query": {
                      "semantic": {
                        "field": "overview_vector",
                        "query": "superhero movie"
                      }
                    }
                  }
                }
              }
            ]
          }
        },
        {
          "standard": {
            "query": {
              "multi_match": {
                "query": "superhero movie",
                "fields": ["overview", "keywords","title"],
                "type": "cross_fields",
                "minimum_should_match": "2"
              }
            }
          }
        }
      ]
    }
  }
}<h2>Conclusão</h2><p>Usando <code>min_score</code>, mostramos como podemos reduzir o número de falsos positivos em nossos conjuntos de resultados causados pela alta recordação de algoritmos de busca semântica. Para saber mais sobre recuperadores, consulte este <a href="https://www.elastic.co/search-labs/blog/elasticsearch-retrievers">post do blog</a> e a <a href="https://www.elastic.co/docs/solutions/search/retrievers-overview">documentação do Elasticsearch</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/semantic-precision-minimum-score</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/semantic-precision-minimum-score</guid>
    <category><![CDATA[Relevância]]></category>
    <category><![CDATA[Busca híbrida]]></category>
    <dc:creator><![CDATA[Mattias Brunnert]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd4a3fba607900049/6a170e0fcdacbf8fe17d2a7a/8b3b5910abfe16d48d309341a0027008b16c4340-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Fri, 20 Feb 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Criar um conector do ChatGPT com o Elasticsearch para consultar problemas no GitHub]]></title>
    <description><![CDATA[Saiba como criar um conector ChatGPT personalizado e implantar um servidor Elasticsearch MCP que usa a pesquisa híbrida para buscar problemas internos do GitHub.]]></description>
    <content:encoded><![CDATA[<p>Recentemente, a OpenAI anunciou o recurso de <a href="https://help.openai.com/en/articles/11487775-connectors-in-chatgpt">conectores personalizados</a> para o ChatGPT nos planos Pro/Business/Empresarial e Edu. Além dos conectores prontos para uso para acessar dados no Gmail, GitHub, Dropbox etc. É possível criar conectores personalizados usando servidores MCP.</p><p>Os conectores personalizados permitem que você combine seus conectores ChatGPT existentes com fontes adicionais de dados, como o Elasticsearch, para obter respostas abrangentes.</p><p>Neste artigo, criaremos um servidor <a href="https://modelcontextprotocol.io/docs/getting-started/intro">MCP</a> que conecta o ChatGPT a um índice Elasticsearch contendo informações sobre problemas internos e solicitações de pull do GitHub. Isso permite que consultas em linguagem natural sejam respondidas usando os dados do seu Elasticsearch.</p><p>Implantaremos o servidor MCP usando o <a href="https://gofastmcp.com/getting-started/welcome">FastMCP</a> no Google Colab com ngrok para obter um URL público ao qual o ChatGPT possa se conectar, eliminando a necessidade de uma configuração de infraestrutura complexa.</p><p>Para uma visão geral do MCP e seu ecossistema, consulte <a href="https://www.elastic.co/search-labs/blog/mcp-current-state">O Estado Atual do MCP</a>.</p><h2>Pré-requisitos</h2><p>Antes de começar, você precisará de:</p><ul><li><p>Cluster do Elasticsearch (8.X ou superior)</p></li><li><p>Chave de API do Elasticsearch com acesso de leitura ao seu índice</p></li><li><p>Conta do Google (para o Google Colab)</p></li><li><p>Conta Ngrok (versão gratuita funciona)</p></li><li><p>Conta do ChatGPT com plano Pro/Empresarial/Business ou Edu</p></li></ul><h2>Entendendo os requisitos do conector MCP do ChatGPT</h2><p>Os conectores MCP do ChatGPT exigem a implementação de duas ferramentas: <code>search</code> e <code>fetch</code>. Para mais detalhes, consulte <a href="https://platform.openai.com/docs/mcp#create-an-mcp-server">OpenAI Docs</a>.</p><h3><a href="https://platform.openai.com/docs/mcp#search-tool">Ferramenta de busca</a></h3><p>Retorna uma lista de resultados relevantes do seu índice Elasticsearch com base em uma consulta do usuário.</p><h4>O que ele recebe:</h4><ul><li><p>Uma única string com a consulta de linguagem natural do usuário.</p></li><li><p>Exemplo: "Encontre problemas relacionados à migração do Elasticsearch."</p></li></ul><h4>O que ele retorna: </h4><ul><li><p>Um objeto com uma chave <code>result</code> contendo um array de objetos de resultado. Cada resultado inclui:</p><ul><li><p><code>id</code> - Identificador único do documento</p></li><li><p><code>title</code> - Título da issue ou do PR</p></li><li><p><code>url</code> - Link para o problema/PR</p></li></ul></li></ul><h4>Na nossa implementação:</h4>return {
    "results": [
        {
            "id": "PR-612",
            "title": "Fix memory leak in WebSocket notification service",
            "url": "https://internal-git.techcorp.com/pulls/612"
        },
        # ... more results
    ]
}<h3><a href="https://platform.openai.com/docs/mcp#fetch-tool">Ferramenta de recuperação</a></h3><p>Recupera o conteúdo completo de um documento específico.</p><h4>O que ele recebe:</h4><ul><li><p>Uma única string com o ID do documento Elasticsearch do resultado de busca</p></li><li><p>Exemplo: "Me dê os detalhes do PR-578."</p></li></ul><h4>O que ele retorna:</h4><ul><li><p>Um objeto de documento completo com:</p><ul><li><p><code>id</code> - Identificador único do documento</p></li><li><p><code>title</code> - Título da issue ou do PR</p></li><li><p><code>text</code> - Complete a descrição e os detalhes do problema/PR</p></li><li><p><code>url</code> - Link para o problema/PR</p></li><li><p><code>type</code> - Tipo de documento (issue, pull_request)</p></li><li><p><code>status</code> - Status atual (aberto, em_andamento, resolvido)</p></li><li><p><code>priority</code> - Nível de prioridade (baixo, médio, alto, crítico)</p></li><li><p><code>assignee</code> - Pessoa designada para o problema/PR</p></li><li><p><code>created_date</code> - Quando foi criado</p></li><li><p><code>resolved_date</code> - Quando foi resolvido (se aplicável)</p></li><li><p><code>labels</code> - Tags associadas ao documento</p></li><li><p><code>related_pr</code> - ID de pull request relacionado</p></li></ul></li></ul>return {
    "id": "PR-578",
    "title": "Security hotfix: Patch SQL injection vulnerabilities",
    "text": "Description: CRITICAL SECURITY FIX for ISSUE-1889. Patches SQL...",
    "url": "https://internal-git.techcorp.com/pulls/578",
    "type": "pull_request",
    "status": "closed",
    "priority": "critical",
    "assignee": "sarah_dev",
    "created_date": "2025-09-19",
    "resolved_date": "2025-09-19",
    "labels": "security, hotfix, sql",
    "related_pr": null
}<p><strong>Observação</strong>: este exemplo usa uma estrutura plana onde todos os campos estão no nível raiz. Os requisitos do OpenAI são flexíveis e também permitem objetos de metadados aninhados.</p><h2>Questões do GitHub e conjunto de dados PRs</h2><p>Para este tutorial, vamos usar um conjunto de dados interno do GitHub contendo problemas e solicitações de pull. Isso representa um cenário em que você deseja consultar dados privados e internos por meio do ChatGPT.</p><p>O conjunto de dados pode ser encontrado <a href="https://gist.github.com/TomasMurua/4e7bbdf7a7ebbdffaa663c43578d934a">aqui</a>. E atualizaremos o índice dos dados usando a <a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-bulk">bulk API</a>.</p><p>Esse conjunto de dados inclui:</p><ul><li><p>Problemas com descrições, status, prioridade e responsáveis</p></li><li><p>Solicitações de pull com alterações de código, revisões e informações de implantação</p></li><li><p>Relações entre problemas e PRs (por exemplo, PR-578 corrige o ISSUE-1889)</p></li><li><p>Rótulos, datas e outros metadados</p></li></ul><h3>Mapeamentos de índice</h3><p>O índice usa os seguintes <a href="https://www.elastic.co/docs/manage-data/data-store/mapping">mapeamentos</a> para permitir a pesquisa híbrida com o <a href="https://www.elastic.co/docs/explore-analyze/machine-learning/nlp/ml-nlp-elser">ELSER</a>. A <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/semantic-text">text_semantic</a> é usada para busca semântica, enquanto outros campos permitem a busca por palavras-chave.</p>{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "title": {
        "type": "text"
      },
      "text": {
        "type": "text"
      },
      "text_semantic": {
        "type": "semantic_text",
        "inference_id": ".elser-2-elasticsearch"
      },
      "url": {
        "type": "keyword"
      },
      "type": {
        "type": "keyword"
      },
      "status": {
        "type": "keyword"
      },
      "priority": {
        "type": "keyword"
      },
      "assignee": {
        "type": "keyword"
      },
      "created_date": {
        "type": "date",
        "format": "iso8601"
      },
      "resolved_date": {
        "type": "date",
        "format": "iso8601"
      },
      "labels": {
        "type": "keyword"
      },
      "related_pr": {
        "type": "keyword"
      }
    }
  }
}<h2>Construa o servidor MCP</h2><p>Nosso servidor MCP implementa duas ferramentas seguindo as especificações da OpenAI, usando busca híbrida para combinar correspondência semântica e de texto para obter melhores resultados.</p><h3>Ferramenta de busca</h3><p>Utiliza busca híbrida com <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion">RRF</a> (Reciprocal Rank Fusion), combinando buscar semântica com correspondência de texto:</p>@mcp.tool()
    async def search(query: str) -&gt; Dict[str, List[Dict[str, Any]]]:
        """
        Search for internal issues and PRs using hybrid search (semantic + text with RRF).
        Returns list with id, title, and url per OpenAI spec.
        """
        if not query or not query.strip():
            return {"results": []}

        logger.info(f"Searching for: '{query}'")

        try:
            # Hybrid search with RRF (Reciprocal Rank Fusion)
            response = es_client.search(
                index=ELASTICSEARCH_INDEX,
                size=10,
                source=["id", "title", "url", "type", "priority"],
                retriever={
                    "rrf": {
                        "retrievers": [
                            {
                                # Semantic search with ELSER
                                "standard": {
                                    "query": {
                                        "semantic": {
                                            "field": "text_semantic",
                                            "query": query
                                        }
                                    }
                                }
                            },
                            {
                                # Text search (BM25) for keyword matching
                                "standard": {
                                    "query": {
                                        "multi_match": {
                                            "query": query,
                                            "fields": [
                                                "title^3",
                                                "text^2",
                                                "assignee^2",
                                                "type",
                                                "labels",
                                                "priority"
                                            ],
                                            "type": "best_fields",
                                            "fuzziness": "AUTO"
                                        }
                                    }
                                }
                            }
                        ],
                        "rank_window_size": 50,
                        "rank_constant": 60
                    }
                }
            )

            results = []
            if response and 'hits' in response:
                for hit in response['hits']['hits']:
                    source = hit['_source']
                    results.append({
                        "id": source.get('id', hit['_id']),
                        "title": source.get('title', 'Unknown'),
                        "url": source.get('url', '')
                    })

            logger.info(f"Found {len(results)} results")
            return {"results": results}

        except Exception as e:
            logger.error(f"Search error: {e}")
            raise ValueError(f"Search failed: {str(e)}")<h3>Pontos principais:</h3><ul><li><p><strong>Busca híbrida com RRF:</strong> combina busca semântica (ELSER) e busca por texto (BM25) para melhores resultados.</p></li><li><p><strong>Consulta multi-correspondência:</strong> <a href="https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-multi-match-query">busca em múltiplos campos</a> com aumento de relevância (title^3, text^2, assignee^2). O símbolo de caret (^) multiplica as pontuações de relevância, priorizando as correspondências nos títulos em detrimento do conteúdo.</p></li><li><p><strong>Correspondência inexata:</strong> <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/common-options#fuzziness"><code>fuzziness: AUTO</code></a> lida com erros de digitação e ortografia, permitindo correspondências aproximadas.</p></li><li><p><strong>Ajuste dos parâmetros do RRF:</strong></p><ul><li><p><code>rank_window_size: 50</code> - Especifica quantos resultados principais de cada recuperador (semântico e textual) são considerados antes da mesclagem.</p></li><li><p><code>rank_constant: 60</code> - Esse valor determina quanta influência os documentos em conjuntos de resultados individuais têm sobre o resultado final classificado.</p></li></ul></li><li><p><strong>Retorna somente os campos obrigatórios:</strong> <code>id</code>, <code>title</code>, <code>url</code> de acordo com a especificação da OpenAI e evita a exposição desnecessária de campos adicionais.</p></li></ul><h3>Ferramenta de recuperação</h3><p>Recupera detalhes do documento pelo ID do documento, quando existe:</p>@mcp.tool()
    async def fetch(id: str) -&gt; Dict[str, Any]:
        """
        Retrieve complete issue/PR details by ID.
        Returns id, title, text, url.
        """
        if not id:
            raise ValueError("ID is required")

        logger.info(f"Fetching: {id}")

        try:
            # Search by the 'id' field (not _id) since IDs are stored as a field
            response = es_client.search(
                index=ELASTICSEARCH_INDEX,
                body={
                    "query": {
                        "term": {
                            "id": id  # Search by your custom 'id' field
                        }
                    },
                    "size": 1
                }
            )

            if not response or not response['hits']['hits']:
                raise ValueError(f"Document with id '{id}' not found")

            hit = response['hits']['hits'][0]
            source = hit['_source']

            result = {
                "id": source.get('id', id),
                "title": source.get('title', 'Unknown'),
                "text": source.get('text', ''),
                "url": source.get('url', ''),
                "type": source.get('type', ''),
                "status": source.get('status', ''),
                "priority": source.get('priority', ''),
                "assignee": source.get('assignee', ''),
                "created_date": source.get('created_date', ''),
                "resolved_date": source.get('resolved_date', ''),
                "labels": source.get('labels', ''),
                "related_pr": source.get('related_pr', '')
            }

            logger.info(f"Fetched: {result['title']}")
            return result

        except Exception as e:
            logger.error(f"Fetch error: {e}")
            raise ValueError(f"Failed to fetch '{id}': {str(e)}")<h3>Pontos principais:</h3><ul><li><p><strong>Buscar por campo de ID do documento:</strong> Utiliza consulta de termo no campo personalizado <code>id</code></p></li><li><p><strong>Retorna o documento completo:</strong> inclui o campo <code>text</code> completo com todo o conteúdo</p></li><li><p><strong>Estrutura plana:</strong> Todos os campos no nível da raiz, correspondendo à estrutura de documentos do Elasticsearch.</p></li></ul><h2>Implantar no Google Colab</h2><p>Usaremos o Google Colab para executar nosso servidor MCP e o ngrok para expô-lo publicamente, permitindo que o ChatGPT se conecte a ele.</p><h3>Etapa 1: Abra o notebook do Google Colab</h3><p>Acesse nosso notebook pré-configurado <a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/elasticsearch-chatgpt-connector">Elasticsearch MCP para ChatGPT</a>.</p><h3>Etapa 2: Configure suas credenciais</h3><p>Você precisará de três informações:</p><ul><li><p><strong>URL do Elasticsearch:</strong> seu <a href="https://www.elastic.co/docs/deploy-manage/deploy/cloud-enterprise/connect-elasticsearch">URL do cluster do Elasticsearch</a>.</p></li><li><p><strong>Chave da API do Elasticsearch:</strong> <a href="https://www.elastic.co/docs/deploy-manage/api-keys/elasticsearch-api-keys">Chave da API</a> com permissão de leitura do seu índice.</p></li><li><p><strong>Token de autenticação Ngrok:</strong> token grátis do <a href="https://ngrok.com/">ngrok</a>. Vamos usar o ngrok para expor a URL do MCP à internet para que o ChatGPT possa se conectar a ela.</p></li></ul><h4>Obter seu token ngrok</h4><ol><li><p>Cadastre-se para uma conta gratuita em <a href="https://ngrok.com/">ngrok</a></p></li><li><p>Acesse seu <a href="https://dashboard.ngrok.com/">painel do ngrok</a></p></li><li><p>Copie seu token de autenticação.</p></li></ol><h4>Adicionando segredos ao Google Colab</h4><p>No notebook do Google Colab:</p><ol><li><p>Clique no <strong>ícone de chave </strong>na barra lateral esquerda para abrir <strong>Secrets</strong>.</p></li><li><p>Adicione estes três segredos:</p></li></ol>ELASTICSEARCH_URL=https://your-cluster.elastic.com:443
ELASTICSEARCH_API_KEY=your-api-key
NGROK_TOKEN=your-ngrok-token<p>3. Habilitar o acesso ao notebook para cada segredo</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5acae97b386277f8/6a17f08f5ea30f74c964b6c2/d5dd6ac19fe816a562c6351fdb0f11369da0e877-609x321.jpg" alt="Adicionar segredos ao Google Collab" /><h3>Passo 3: Execute o notebook</h3><ol><li><p>Clique em <strong>Runtime</strong> e depois em <strong>Executar tudo</strong> para executar todas as células</p></li><li><p>Aguarde o servidor iniciar (cerca de 30 segundos)</p></li><li><p>Procure a saída mostrando seu URL público do ngrok</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdd11aacf2deab67c/6a17f091e8fbce81f13a1a41/f185100e8869624bc9e1c7b2b4eb32785e2d89e7-1189x283.png" alt="" /><p>4. A saída exibirá algo como:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8891d917fdbaaf48/6a17f092abe0f208c7dfeaf6/e02e625e91ed9136454e4401b184575fb03a336e-1052x465.jpg" alt="A saída da execução de um notebook no Google Collab" /><h2>Conectar-se ao ChatGPT</h2><p>Agora vamos conectar o servidor MCP à sua conta do ChatGPT.</p><ol><li><p>Abra o ChatGPT e vá para <strong>Configurações</strong>.</p></li><li><p>Navegue até <strong>Conectores. </strong>Se você estiver usando uma conta Pro, precisará ativar <a href="https://platform.openai.com/docs/guides/developer-mode">o modo de desenvolvedor</a> nos conectores.</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt95efdcb2c39307e7/6a17f094abe0f24d8edfeafa/32c02192912fc0e7e5a52e9399077ba7ae3b4901-739x715.png" alt="Conectando o servidor MPC a uma conta do ChatGPT" /><p><em>Se você está usando o ChatGPT em empresas ou negócios, precisa disponibilizar o conector para seu local de trabalho.</em></p><p>3. Clique em <strong>Criar</strong>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd4c8fc8dd6033918/6a17f095631730de19585b7b/15c53e5ccc381108a9dc0052cca05bf0fc97679a-755x683.png" alt="Adicionando um conector ao ChatGPT" /><p><em><strong>Observação</strong></em><em>: nos espaços de trabalho Business, Empresarial e Edu, somente os proprietários, administradores e usuários com a respectiva configuração ativada (para Empresarial/Edu) podem adicionar conectores personalizados. Usuários com a função de membro padrão não têm permissão para adicionar conectores personalizados.</em></p><p><em>Após um conector ser adicionado e habilitado por um proprietário ou usuário administrador, ele fica disponível para todos os membros do espaço de trabalho.</em></p><p>4. Insira as informações necessárias e sua URL ngrok que termina em <code>/sse/</code>. Repare no "/" após "sse". Não vai funcionar sem ele:</p><ul><li><p><strong>Nome:</strong> Elasticsearch MCP</p></li><li><p><strong>Descrição: </strong>MCP personalizado para pesquisar e recuperar informações internas do GitHub.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd716ad0beeeb1d35/6a17f09714d90c11cc79b6d7/162a85705cc8ac48a3f2f665551d513e0719f93d-479x684.png" alt="Criar um Conector MCP Elastic " /><p>5. Pressione <strong>Criar</strong> para salvar o MCP personalizado.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt857794237d7d3b5a/6a17f0983e03d729b74f2d54/97eb5fb0a32b86bfadfb35561f698616f217c049-913x629.png" alt="Salvar o conector MCP personalizado clicando em criar" /><p>A conexão será instantânea se seu servidor estiver em execução. Não é necessária autenticação adicional, pois a chave da API do Elasticsearch está configurada no seu servidor.</p><h2>Teste o servidor MCP</h2><p>Antes de fazer perguntas, você precisa selecionar qual conector o ChatGPT deve usar.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd1602c48878dc7a9/6a17f09a6df731cca90a0fff/77a6fc1eb263a0eb16aac64f2ecaca5f4ac12ec2-966x568.gif" alt="Selecionar qual conector o ChatGPT deve usar" /><h3>Prompt 1: Buscar por problemas</h3><p>Pergunte: "<strong>Encontre problemas relacionados à migração do Elasticsearch" </strong>e confirme a chamada da ferramenta de ações.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6c204ceacf897f61/6a17f09c9da390fb1de4657d/cfd781acbff8cd7c8095bbe29224f8b26d581f77-650x375.png" alt="Peça ao ChatGPT &quot;Encontre problemas relacionados à migração do Elasticsearch&quot; e confirme a chamada da ferramenta de ações." /><p>O ChatGPT chamará a ferramenta <code>search</code> com sua consulta. Você pode ver que ele está procurando as ferramentas disponíveis, se preparando para chamar a ferramenta Elasticsearch e confirma com o usuário antes de tomar qualquer medida em relação à ferramenta.</p><h4>Solicitação de chamada de ferramenta:</h4>{
  "query": "Elasticsearch migration issues"
}<h4>Resposta da ferramenta:</h4>{
  "results": [
    {
      "id": "PR-598",
      "title": "Elasticsearch 8.x migration - Application code changes",
      "url": "https://internal-git.techcorp.com/pulls/598"
    },
    {
      "id": "ISSUE-1712",
      "title": "Migrate from Elasticsearch 7.x to 8.x",
      "url": "https://internal-git.techcorp.com/issues/1712"
    },
    {
      "id": "RFC-045",
      "title": "Design Proposal: Microservices Migration Architecture",
      "url": "https://internal-git.techcorp.com/rfcs/045"
    }
    // ... 7 more results
  ]
}<p>O ChatGPT processa os resultados e os apresenta em um formato natural e conversacional.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1b4378e7d26b4ad0/6a17f09ddbb4ff4de1fb57bf/9d5b6cff85c7e54ccc2584b8ae96d45495fae8c1-923x1352.png" alt="Como o ChatGPT processa os resultados da solicitação de chamada da ferramenta e da resposta à chamada da ferramenta" /><h3>Nos bastidores</h3><h4>Prompt: "Encontrar problemas relacionados à migração do Elasticsearch"</h4><p>1. Chamadas do ChatGPT <code>search(“Elasticsearch migration”)</code></p><p>2. O Elasticsearch realiza uma busca híbrida</p><ul><li><p><strong>A busca semântica</strong> compreende conceitos como "atualização" e "<em>compatibilidade de versões"</em>.</p></li><li><p>A <strong>busca de texto</strong> encontra correspondências exatas para "<em>Elasticsearch</em>" e "migração".</p></li><li><p>O <strong>RRF</strong> combina e classifica os resultados de ambas as abordagens</p></li></ul><p>3. Retorna os 10 melhores eventos de correspondência com <code>id</code>, <code>title</code>, <code>url</code></p><p>4. O ChatGPT identifica "<em>ISSUE-1712: migrar do Elasticsearch 7.x para o 8.x</em>" como o resultado mais relevante</p><h3>Prompt 2: Obter todos os detalhes</h3><p>Perguntar: <em><strong>"Informe detalhes sobre o ISSUE-1889"</strong></em></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8d1a53db8bfe8326/6a17f09f445de966104d021a/5c0db5245535ce67a36056e61e135bddc97ce496-934x629.png" alt="O ChatGPT reconhece que você quer informações detalhadas sobre um problema específico, aciona a ferramenta fetch e confirma com o usuário antes de tomar qualquer medida em relação à ferramenta." /><p>O ChatGPT reconhece que você quer informações detalhadas sobre um problema específico e aciona a ferramenta <code>fetch</code>, confirmando com o usuário antes de tomar qualquer medida em relação à ferramenta.</p><h4>Solicitação de chamada de ferramenta:</h4>{
  "id": "ISSUE-1889"
}<h4>Resposta da ferramenta:</h4>{
  "id": "ISSUE-1889",
  "title": "SQL injection vulnerability in search endpoint",
  "text": "Description: Security audit identified SQL injection vulnerability in /api/v1/search endpoint. User input from query parameter is not properly sanitized before being used in raw SQL query. Severity: HIGH - Immediate action required Affected Code: - File: services/search/query_builder.py - Line: 145-152 - Issue: String concatenation used instead of parameterized queries Investigation: - @security_team_alice: Confirmed exploitable with UNION-based injection - @sarah_dev: Checking all other endpoints for similar patterns - @john_backend: Found 3 more instances in legacy codebase Remediation: - Rewrite using SQLAlchemy ORM or parameterized queries - Add input validation and sanitization - Implement WAF rules as additional layer - Security regression tests Comments: - @tech_lead_mike: Stop all other work, this is P0 - @sarah_dev: PR-578 ready with fixes for all 4 vulnerable endpoints - @alex_devops: Deployed hotfix to production 2025-09-19 at 14:30 UTC - @security_team_alice: Verified fix, conducting full pentest next week Resolution: All vulnerable endpoints patched. Added pre-commit hooks to catch raw SQL queries. Security training scheduled for team.",
  "url": "https://internal-git.techcorp.com/issues/1889",
  "type": "issue",
  "status": "closed",
  "priority": "critical",
  "assignee": "sarah_dev",
  "created_date": "2025-09-18",
  "resolved_date": "2025-09-19",
  "labels": "security, vulnerability, bug, sql",
  "related_pr": "PR-578"
}<p>O ChatGPT sintetiza as informações e as apresenta claramente.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt560958fa3bd212d0/6a17f0a0faa91355ba93c974/410f19f213e94fc4e3c47eeef6e04b69e0c86159-602x462.png" alt="Como o ChatGPT sintetiza as informações e as apresenta " /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcccf35a584e8373b/6a17f0a2505ac3471cad8c2e/54d8ffa117628a1e3afc317c3ab75d4f7731d7ab-767x1600.png" alt="Como o ChatGPT apresenta as informações" /><h3>Nos bastidores</h3><h4>Prompt: “Informe mais detalhes sobre ISSUE-1889”</h4><ol><li><p>Chamadas do ChatGPT <code>fetch(“ISSUE-1889”)</code></p></li><li><p>O Elasticsearch recupera o documento completo</p></li><li><p>Retorna um documento completo com todos os campos no nível raiz</p></li><li><p>O ChatGPT sintetiza as informações e responde com citações adequadas.</p></li></ol><h2>Conclusão</h2><p>Neste artigo, criamos um servidor MCP personalizado que conecta o ChatGPT ao Elasticsearch usando ferramentas MCP dedicadas de <strong>busca</strong> e <strong>recuperação</strong>, permitindo consultas em linguagem natural sobre dados privados.</p><p>Este padrão MCP funciona para qualquer índice Elasticsearch, documentação, produtos, log ou quaisquer outros dados que você queira consultar por meio de linguagem natural.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/chatgpt-connector-mcp-server-github-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/chatgpt-connector-mcp-server-github-elasticsearch</guid>
    <category><![CDATA[IA agêntica]]></category>
    <category><![CDATA[Busca híbrida]]></category>
    <dc:creator><![CDATA[Tomás Murúa]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd1602c48878dc7a9/6a17f09a6df731cca90a0fff/77a6fc1eb263a0eb16aac64f2ecaca5f4ac12ec2-966x568.gif" length="0" type="image/gif"/>
    <pubDate>Mon, 01 Dec 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Busca híbrida sem complicações: simplificando a busca híbrida com recuperadores.]]></title>
    <description><![CDATA[Descubra como simplificar a busca híbrida no Elasticsearch com um formato de consulta de múltiplos campos para recuperadores lineares e RRF, e crie consultas sem conhecimento prévio sobre seu índice do Elasticsearch.]]></description>
    <content:encoded><![CDATA[<p><a href="https://www.elastic.co/what-is/hybrid-search">A busca híbrida</a> é amplamente reconhecida como uma abordagem de busca poderosa, combinando a precisão e a velocidade da <a href="https://www.elastic.co/search-labs/blog/lexical-and-semantic-search-with-elasticsearch#lexical-search---sparse-retrieval">busca lexical</a> com os recursos de linguagem natural da <a href="https://www.elastic.co/what-is/semantic-search">busca semântica</a>. No entanto, aplicá-lo na prática pode ser complicado, muitas vezes exigindo conhecimento profundo sobre o índice e a construção de consultas verbosas com configurações complexas. Neste blog, exploraremos como o <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrievers#multi-field-query-format">formato de consulta com múltiplos campos para buscadores lineares e RRF</a> torna a busca híbrida mais simples e acessível, eliminando problemas comuns e permitindo que você aproveite todo o seu potencial com maior facilidade. Analisaremos também como o formato de consulta com vários campos permite realizar consultas de pesquisa híbridas sem conhecimento prévio sobre o índice.</p><h2>O problema da amplitude de pontuação</h2><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3521a6558cd477ca/6a17f174445de94d3c4d0225/c8b49153c47d2cdc233c0d2e440db04711d48ca5-1600x1600.jpg" alt="" /><p>Para contextualizar, vamos analisar um dos principais motivos pelos quais a busca híbrida pode ser difícil: a variação nos intervalos de pontuação. Nosso velho amigo <a href="https://www.elastic.co/elasticon/conf/2016/sf/improved-text-scoring-with-bm25">BM25</a> produz pontuações ilimitadas. Em outras palavras, o BM25 pode gerar pontuações que variam de perto de 0 até (teoricamente) o infinito. Em contraste, as consultas aos campos <code>dense_vector</code> produzirão pontuações limitadas entre 0 e 1. Exacerbando este problema, <code>semantic_text</code> ofusca o tipo de campo usado para indexar embeddings, portanto, a menos que você tenha conhecimento detalhado sobre a configuração do seu índice e endpoint de inferência, pode ser difícil dizer qual será o intervalo de pontuação da sua consulta. Isso representa um problema ao tentar intercalar resultados de busca lexical e semântica, já que os resultados lexicais podem ter precedência sobre os semânticos, mesmo que os resultados semânticos sejam mais relevantes. A solução geralmente aceita para esse problema é normalizar as pontuações antes de intercalar os resultados. O Elasticsearch possui duas ferramentas para isso: os recuperadores <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrievers/linear-retriever">lineares</a> e <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrievers/rrf-retriever">RRF</a> .
</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt09ed6bf3d25066bd/6a17f1750b0bedbd70dd3686/264481268c8b6ac259e3c257b85431b513f16672-1077x586.png" alt="Comparação dos resultados da pesquisa com linear/rrf versus sem linear/rrf." /><p>O recuperador <strong>RRF</strong> aplica o <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion">algoritmo RRF</a>, usando a classificação do documento como medida de relevância e descartando a pontuação. Como a pontuação não é considerada, as discrepâncias na faixa de pontuação não representam um problema.</p><p>O recuperador <strong>linear</strong> utiliza uma combinação linear para determinar a pontuação final de um documento. Isso envolve pegar a pontuação de cada consulta de componente para o documento, normalizá-la e somá-las para gerar a pontuação total. Matematicamente, a operação pode ser expressa como:</p>Total Score = 𝚺(N(Sx))<p>Onde <code>N</code> é a função de normalização e SX é a pontuação para a consulta X. A função de normalização é fundamental aqui, pois transforma a pontuação de cada consulta para usar o mesmo intervalo. Você pode aprender mais sobre o recuperador linear <a href="https://www.elastic.co/search-labs/blog/linear-retriever-hybrid-search">aqui</a>.</p><h2>Analisando detalhadamente</h2><p>Os usuários podem implementar uma busca híbrida eficaz com essas ferramentas, mas isso requer algum conhecimento sobre o seu índice. Vejamos um exemplo com o recuperador linear, onde consultaremos um índice com dois campos:</p>PUT linear_retriever_example
{
  "mappings": {
    "properties": {
      "semantic_text_field": { &lt;1&gt;
        "type": "semantic_text",
        "inference_id": ".multilingual-e5-small-elasticsearch"
      },
      "text_field": { &lt;2&gt;
        "type": "text"
      }
    }
  }
}<p>1. <code>semantic_text_field</code> é um campo <code>semantic_text</code> que usa <a href="https://www.elastic.co/docs/explore-analyze/machine-learning/nlp/ml-nlp-e5">E5</a>, um modelo de incorporação de texto.</p><p>2. <code>text_field</code> é um campo <code>text</code> padrão</p>GET linear_retriever_example/_search
{
  "retriever": {
    "linear": {
      "retrievers": [
        {
          "retriever": {
            "standard": {
              "query": {
                "match": { &lt;1&gt;
                  "semantic_text_field": "foo"
                }
              }
            }
          },
          "normalizer": "minmax"
        },
        {
          "retriever": {
            "standard": {
              "query": {
                "match": {
                  "text_field": "foo"
                }
              }
            }
          },
          "normalizer": "minmax"
        }
      ]
    }
  }
}<p>1. Usamos uma consulta <code>match</code> em nosso campo <code>semantic_text</code> , para o qual <a href="https://www.elastic.co/search-labs/blog/semantic-search-match-knn-sparse-vector#we-made-match-happen-in-semantic-search!">adicionamos suporte no Elasticsearch 8.18/9.0</a></p><p>
Ao construir a consulta, precisamos ter em mente que <code>semantic_text_field</code> usa um modelo de incorporação de texto, portanto, quaisquer consultas sobre ele gerarão uma pontuação entre 0 e 1. Precisamos também saber que <code>text_field</code> é um campo <code>text</code> padrão e, portanto, as consultas nele gerarão uma pontuação ilimitada. Para criar um conjunto de resultados com a relevância adequada, precisamos usar um mecanismo de recuperação que normalize as pontuações das consultas antes de combiná-las. Neste exemplo, usamos o recuperador linear com normalização <code>minmax</code> , que normaliza a pontuação de cada consulta para um valor entre 0 e 1.</p><p>A construção da consulta neste exemplo é bastante simples, pois envolve apenas dois campos. No entanto, a situação pode se complicar rapidamente à medida que mais campos, e de tipos variados, são adicionados. Isso demonstra como escrever uma consulta de pesquisa híbrida eficaz geralmente requer um conhecimento mais profundo do índice consultado, para que as pontuações das consultas componentes sejam devidamente normalizadas antes da combinação. Isso representa uma barreira para a adoção mais ampla da busca híbrida.</p><h3>Agrupamento de consultas</h3><p>Vamos expandir o exemplo: E se quiséssemos consultar um campo <code>text</code> e dois campos <code>semantic_text</code> ? Poderíamos construir uma consulta como esta:</p>GET linear_retriever_example/_search
{
  "retriever": {
    "linear": {
      "retrievers": [
        {
          "retriever": {
            "standard": {
              "query": {
                "semantic": {
                  "field": "semantic_text_field_1",
                  "query": "foo"
                }
              }
            }
          },
          "normalizer": "minmax"
        },
        {
          "retriever": {
            "standard": {
              "query": {
                "semantic": {
                  "field": "semantic_text_field_2",
                  "query": "foo"
                }
              }
            }
          },
          "normalizer": "minmax"
        },
        {
          "retriever": {
            "standard": {
              "query": {
                "match": {
                  "text_field": "foo"
                }
              }
            }
          },
          "normalizer": "minmax"
        }
      ]
    }
  }
}<p>Isso parece bom à primeira vista, mas existe um problema em potencial. Agora, as correspondências do campo <code>semantic_text</code> representam ⅔ da pontuação total:</p>Total Score = N(semantic_text_field_1 score) + N(semantic_text_field_2 score) + N(text_field score)<p>Provavelmente não é isso que você deseja, pois cria uma pontuação desequilibrada. Os efeitos podem não ser tão perceptíveis em um exemplo como este, com apenas 3 campos, mas tornam-se problemáticos quando mais campos são consultados. Por exemplo, a maioria dos índices contém muito mais campos lexicais do que semânticos (ou seja, <code>dense_vector</code>, <code>sparse_vector</code> ou <code>semantic_text</code>). E se estivéssemos consultando um índice com 9 campos lexicais e 1 campo semântico usando o padrão acima? As correspondências lexicais representariam 90% da pontuação, diminuindo a eficácia da busca semântica.</p><p>Uma forma comum de resolver isso é agrupar as consultas em categorias lexicais e semânticas e atribuir pesos iguais a ambas. Isso impede que qualquer uma das categorias domine a pontuação total.</p><p>Vamos colocar isso em prática. Como seria essa abordagem de consultas agrupadas neste exemplo ao usar o recuperador linear?</p>GET linear_retriever_example/_search
{
  "retriever": {
    "linear": {
      "retrievers": [
        {
          "retriever": {
            "linear": {
              "retrievers": [
                {
                  "retriever": {
                    "standard": {
                      "query": {
                        "semantic": {
                          "field": "semantic_text_field_1",
                          "query": "foo"
                        }
                      }
                    }
                  },
                  "normalizer": "minmax"
                },
                {
                  "retriever": {
                    "standard": {
                      "query": {
                        "semantic": {
                          "field": "semantic_text_field_2",
                          "query": "foo"
                        }
                      }
                    }
                  },
                  "normalizer": "minmax"
                }
              ]
            }
          },
          "normalizer": "minmax"
        },
        {
          "retriever": {
            "standard": {
              "query": {
                "match": {
                  "text_field": "foo"
                }
              }
            }
          },
          "normalizer": "minmax"
        }
      ]
    }
  }
}<p>Uau, isso está ficando prolixo! Você pode até ter precisado rolar a página para cima e para baixo várias vezes para examinar toda a consulta! Aqui, utilizamos dois níveis de normalização para criar os grupos de consulta. Matematicamente, pode ser expresso como:</p>Total Score = N(N(semantic_text_field_1 score) + N(semantic_text_field_2 score)) + N(text_field score)<p>Este segundo nível de normalização garante que as consultas aos campos <code>semantic_text</code> e <code>text</code> sejam ponderadas igualmente. Observe que omitimos a normalização de segundo nível para <code>text_field</code> neste exemplo, uma vez que há apenas um campo lexical, poupando-o de <em>ainda mais</em> verbosidade.</p><p>Essa estrutura de consulta já é complexa demais, e estamos consultando apenas três campos. À medida que se consultam mais campos, a tarefa torna-se cada vez mais difícil de gerir, mesmo para profissionais de pesquisa experientes.</p><h2>O formato de consulta com vários campos</h2><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5d9007d279f0da29/6a17f17714d90c39cf79b6f5/dd04e1686076a574b717c1460acfe4eb79299208-1600x1600.jpg" alt="" /><p>Adicionamos o <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrievers#multi-field-query-format">formato de consulta com vários campos</a> para os recuperadores lineares e RRF no Elasticsearch 8.19, 9.1 e <a href="https://www.elastic.co/cloud/serverless">serverless</a> para simplificar tudo isso. Agora você pode realizar a mesma consulta acima apenas com:</p>GET linear_retriever_example/_search
{
  "retriever": {
    "linear": {
      "fields": [ "semantic_text_field_1", "semantic_text_field_2", "text_field" ],
      "query": "foo",
      "normalizer": "minmax"
    }
  }
}<p>O que reduz a consulta de 55 linhas para apenas 9! O Elasticsearch usa automaticamente os mapeamentos de índice para:</p><ul><li><p>Determine o tipo de cada campo consultado.</p></li><li><p>Agrupe cada campo em uma categoria lexical ou semântica.</p></li><li><p>Dê o mesmo peso a cada categoria na pontuação final.</p></li></ul><p>Isso permite que qualquer pessoa execute uma consulta de pesquisa híbrida eficaz sem precisar saber detalhes sobre o índice ou os endpoints de inferência utilizados.</p><p>Ao usar o RRF, você pode omitir o <code>normalizer</code>, já que a classificação é usada como um indicador de relevância:</p>GET rrf_retriever_example/_search
{
  "retriever": {
    "rrf": {
      "fields": [ "semantic_text_field_1", "semantic_text_field_2", "text_field" ],
      "query": "foo"
    }
  }
}<h2>Aumento por campo</h2><p>Ao usar o recuperador linear, você pode aplicar um reforço por campo para ajustar a importância das correspondências em determinados campos. Por exemplo, digamos que você esteja consultando quatro campos: dois campos <code>semantic_text</code> e dois campos <code>text</code> :</p>GET linear_retriever_example/_search
{
  "retriever": {
    "linear": {
      "fields": [ "semantic_text_field_1", "semantic_text_field_2", "text_field_1", "text_field_2" ],
      "query": "foo",
      "normalizer": "minmax"
    }
  }
}<p>Por padrão, cada campo tem o mesmo peso em seu grupo (lexical ou semântico). A distribuição da pontuação é a seguinte:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdc6e197e5ff7b68d/6a17f179505ac32834ad8c46/ba31c76189e3a1e5b1638437ccf0528aafec2598-1600x549.png" alt="Comparação de grupos de consulta e pontuações de campo" /><p>Em outras palavras, cada área corresponde a 25% da pontuação total.</p><p>Podemos usar a sintaxe <code>field^boost</code> para adicionar um aumento por campo a qualquer campo. Vamos aplicar um aumento de 2 a <code>semantic_text_field_1</code> e <code>text_field_1</code>:</p>GET linear_retriever_example/_search
{
  "retriever": {
    "linear": {
      "fields": [ "semantic_text_field_1^2", "semantic_text_field_2", "text_field_1^2", "text_field_2" ]
      "query": "foo",
      "normalizer": "minmax"
    }
  }
}<p>Agora a distribuição da pontuação é a seguinte:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltccc9ed7d6e865a5e/6a17f17abe6086a31d004882/de20e555d52f914bf483a048d056f54f4fece757-1600x549.png" alt="Alteração no peso do campo com busca de referência e híbrida" /><p>Cada grupo de consultas ainda tem o mesmo peso, mas agora o peso dos campos dentro dos grupos foi alterado:</p><ul><li><p><code>semantic_text_field_1</code> representa 66% da pontuação do grupo de consultas semânticas e 33% da pontuação total.</p></li><li><p><code>text_field_1</code> representa 66% da pontuação do grupo de consulta lexical e 33% da pontuação total.</p></li></ul><p>ℹ️ Observe que o intervalo de pontuação total não será alterado quando um aumento por campo for aplicado. Este é um efeito colateral intencional da normalização de pontuação, que garante que as pontuações das consultas lexicais e semânticas permaneçam diretamente comparáveis entre si.</p><p>ℹ️ O reforço por campo também pode ser usado com o recuperador RRF no Elasticsearch 9.2+</p><h3>Resolução curinga</h3><p>Você pode usar o caractere curinga <code>*</code> no parâmetro <code>fields</code> para corresponder a vários campos. Continuando o exemplo acima, esta consulta é funcionalmente equivalente a consultar explicitamente s<code>emantic_text_field_1</code>, <code>semantic_text_field_2</code> e <code>text_field_1</code> :</p>GET linear_retriever_example/_search
{
  "retriever": {
    "linear": {
      "fields": [ "semantic_text_field_*", "*_field_1" ],
      "query": "foo",
      "normalizer": "minmax"
    }
  }
}<p>É interessante notar que o padrão <code>*_field_1</code> corresponde tanto <code>text_field_1</code> quanto a <code>semantic_text_field_1</code>. Isso é tratado automaticamente; a consulta será executada como se cada um dos campos tivesse sido consultado explicitamente. Também não há problema em que <code>semantic_text_field_1</code> corresponda a ambos os padrões; todas as correspondências de nomes de campos são desduplicadas antes da execução da consulta.</p><p>Você pode usar o caractere curinga de diversas maneiras:</p><ul><li><p>Correspondência de prefixo (ex: <code>*_text_field</code>)</p></li><li><p>Correspondência em linha (ex: <code>semantic_*_field</code>)</p></li><li><p>Correspondência de sufixo (ex: <code>semantic_text_field_*</code>)</p></li></ul><p>Você também pode usar vários curingas para aplicar uma combinação do acima, como <code>*_text_field_*</code>.</p><h3>Campos de consulta padrão</h3><p>O formato de consulta com vários campos também permite consultar um índice sobre o qual você não sabe nada. Se você omitir o parâmetro <code>fields</code> , a consulta abrangerá todos os campos especificados pela <a href="https://www.elastic.co/docs/reference/elasticsearch/index-settings/index-modules">configuração de índice index.query.default_field</a>:</p>GET linear_retriever_example/_search
{
  "retriever": {
    "linear": {
      "query": "foo",
      "normalizer": "minmax"
    }
  }
}<p>Por padrão, <code>index.query.default_field</code> é definido como <code>*</code>. Este caractere curinga será resolvido para todos os tipos de campo no índice que suportam consultas por termo, que são a maioria. As exceções são:</p><ul><li><p><code>dense_vector</code> campos</p></li><li><p><code>rank_vector</code> campos</p></li><li><p>Campos geométricos: <code>geo_point</code>, <code>shape</code></p></li></ul><p>Essa funcionalidade é especialmente útil quando você deseja realizar uma consulta de pesquisa híbrida em um índice fornecido por terceiros. O formato de consulta com vários campos permite executar uma consulta adequada de forma simples. Basta excluir o parâmetro <code>fields</code> e todos os campos aplicáveis serão consultados.</p><h2>Conclusão</h2><p>O problema do intervalo de pontuação pode tornar a implementação de uma busca híbrida eficaz bastante complexa, especialmente quando há pouca informação sobre o índice consultado ou os endpoints de inferência em uso. O formato de consulta com múltiplos campos para os mecanismos de recuperação linear e RRF atenua esse problema, integrando uma abordagem de busca híbrida automatizada, baseada em agrupamento de consultas, em uma API simples e acessível. Funcionalidades adicionais, como reforço por campo, resolução de curingas e campos de consulta padrão, ampliam a funcionalidade para abranger diversos casos de uso.</p><h2>Experimente o formato de consulta com vários campos hoje mesmo.</h2><p>Você pode conferir os mecanismos de recuperação linear e RRF com o formato de consulta de múltiplos campos em projetos Elasticsearch <a href="https://www.elastic.co/cloud/serverless">Serverless</a> totalmente gerenciados, com um <a href="https://www.elastic.co/docs/deploy-manage/deploy/elastic-cloud/create-serverless-project">período de avaliação gratuito</a>. Também está disponível em versões de pilha a partir das versões 8.19 e 9.1.</p><p>Comece em minutos no seu ambiente local com um único comando:</p>curl -fsSL https://elastic.co/start-local | sh<p></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/hybrid-search-multi-field-query-retrievers-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/hybrid-search-multi-field-query-retrievers-elasticsearch</guid>
    <category><![CDATA[Busca híbrida]]></category>
    <category><![CDATA[Relevância]]></category>
    <dc:creator><![CDATA[Mike Pellegrini]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt89e066372c549595/6a17f17c3e9e457c38ba1583/4494f98ae3958bbdbc6171df9677fc4d65ec5640-1536x1024.png" length="0" type="image/png"/>
    <pubDate>Thu, 27 Nov 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Você sabe, para contexto - Parte III: O poder da busca híbrida na engenharia de contexto]]></title>
    <description><![CDATA[Descubra como usar a engenharia de contexto e a busca híbrida para melhorar a precisão dos resultados da IA com agregações, RBAC e sinais não relacionados ao conteúdo.]]></description>
    <content:encoded><![CDATA[<p>Já discutimos a busca híbrida (<a href="https://www.elastic.co/search-labs/blog/context-engineering-hybrid-search-evolution-agentic-ai">Parte I</a>) e a engenharia de contexto (<a href="https://www.elastic.co/search-labs/blog/context-engineering-llm-evolution-agentic-ai">Parte II</a>); agora, vamos explorar como elas funcionam juntas para obter o máximo efeito no fornecimento de contexto direcionado para operações de RAG e IA agente.</p><h2>A busca não morreu, apenas mudou de lugar.</h2><p>Assim, tivemos essa mudança de uma abordagem que consistia principalmente em buscar contexto por meio de uma caixa de texto e usar as informações (o contexto) retornadas para construir as respostas nós mesmos, para agora usar a linguagem natural para dizer a um agente o que queremos e deixar que ele pesquise e compile automaticamente a resposta para nós. Muitos no mundo da tecnologia estão apontando para essa mudança e proclamando que "a busca está morta" (bem, o mundo do SEO e do AdWords está <a href="https://www.pewresearch.org/short-reads/2025/07/22/google-users-are-less-likely-to-click-on-links-when-an-ai-summary-appears-in-the-results/">definitivamente mudando</a>: alguém aí se lembra <a href="https://www.wired.com/story/goodbye-seo-hello-geo-brandlight-openai/">do GEO</a> ?), mas a busca ainda é absolutamente crucial para as operações de agentes — ela só é realizada, em grande parte, fora do campo de visão, por meio de ferramentas.</p><p>Anteriormente, os humanos eram os principais árbitros da relevância subjetiva: cada usuário tem seus próprios motivos para realizar a busca, e sua experiência pessoal influencia a precisão relativa dos resultados. Para confiarmos que os agentes podem chegar à mesma conclusão (ou melhor) que nós, precisamos garantir que as informações contextuais a que eles têm acesso sejam as mais próximas possíveis da nossa intenção subjetiva. Temos que estruturar o contexto que oferecemos aos mestrados em Direito (LLM) de forma a atingir esse objetivo!</p><h2>Geração de contexto com recuperação de pesquisa híbrida</h2><p>Só para relembrar, lá da Parte I, que a busca híbrida da Elastic combina os pontos fortes da busca tradicional baseada em palavras-chave (flexibilidade de sintaxe, precisão de palavras-chave e pontuação de relevância) com a compreensão semântica da busca por similaridade vetorial e oferece múltiplas técnicas de reclassificação. Essa sinergia (nunca se encontrou um uso mais preciso dessa palavra!) Permite resultados altamente relevantes, com consultas que podem ser muito mais específicas na forma como direcionam o conteúdo. Não se trata apenas de poder aplicar a relevância subjetiva como <em>uma</em> das etapas de recuperação; trata-se, na verdade, de que a recuperação na primeira etapa pode incluir a pontuação de relevância juntamente com todos os outros métodos simultaneamente.</p><h3>Precisão e eficiência superiores</h3><p>Utilizar uma plataforma de dados que possa fornecer busca, recuperação e reclassificação distribuídas como seu principal mecanismo de recuperação de contexto faz muito sentido. Você pode usar uma sintaxe de consulta avançada para adicionar o componente ausente da intenção subjetiva e filtrar o conteúdo que possa distrair ou obscurecer o valor das informações contextuais retornadas. Você pode selecionar qualquer uma das opções de sintaxe individuais disponíveis ou combinar modalidades em uma única pesquisa que visa cada tipo de dado da maneira que melhor o compreende e, em seguida, combiná-los/reordená-los com a reclassificação. Você pode filtrar a resposta para incluir apenas os campos/valores desejados, mantendo os dados irrelevantes afastados. Em termos de suporte aos agentes, essa flexibilidade de segmentação permite criar ferramentas extremamente precisas na forma como recuperam o contexto.</p><h3>Refinamento de contexto (agregações e sinais não relacionados ao conteúdo)</h3><p>As agregações podem ser especialmente úteis para moldar o conteúdo que uma ferramenta fornece à janela de contexto. As agregações fornecem naturalmente informações numéricas sobre o formato dos dados contextuais retornados, o que facilita e torna mais preciso o raciocínio dos Modelos de Aprendizagem Baseados em Leis (LLMs). Como as agregações podem ser hierarquicamente aninhadas, é uma maneira fácil de adicionar detalhes em vários níveis para o LLM, a fim de gerar uma compreensão mais matizada. As agregações também podem ajudar no gerenciamento do tamanho da janela de contexto — você pode facilmente reduzir o resultado de uma consulta de 100 mil documentos para algumas centenas de tokens de insights agregados.</p><p>Os sinais não relacionados ao conteúdo são os indicadores inerentes aos seus dados que fornecem uma visão mais ampla do que você está analisando; são as características adicionais dos resultados, como popularidade, atualidade, localização geográfica, categorias, diversidade de hospedagem ou faixas de preço. Essas informações podem ser úteis para orientar o agente na avaliação da importância do contexto recebido. Alguns exemplos simples podem ajudar a ilustrar isso melhor:</p><ul><li><p><strong>Impulsionando conteúdo popular e publicado recentemente</strong> - Imagine que você tenha uma base de conhecimento com artigos. Você deseja encontrar artigos relevantes para a consulta de um usuário, mas também quer priorizar artigos que sejam recentes e que tenham sido considerados úteis por outros usuários (por exemplo, que tenham um grande número de "curtidas"). Nesse cenário, podemos usar uma busca híbrida para encontrar artigos relevantes e, em seguida, reclassificá-los com base em uma combinação de sua data de publicação e popularidade.</p></li><li><p><strong>Busca em e-commerce com ajuste de vendas e estoque</strong> - Em um ambiente de e-commerce, você deseja mostrar aos clientes produtos que correspondam ao termo de busca, mas também promover produtos que estejam vendendo bem e disponíveis em estoque. Você também pode querer diminuir a classificação de produtos com baixo estoque para evitar a frustração do cliente.</p></li><li><p><strong>Priorizando problemas de alta gravidade em um sistema de rastreamento de bugs</strong> - Para uma equipe de desenvolvimento de software, ao procurar problemas, é crucial que os problemas de alta gravidade, alta prioridade e atualizados recentemente sejam exibidos primeiro. Você pode usar indicadores não-sinais, como "criticidade" e "mais discutido", para ponderar diferentes fatores de forma independente, garantindo que as questões mais críticas e ativamente discutidas cheguem ao topo.</p></li></ul><p>Essas consultas de exemplo e outras podem ser encontradas na <a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/you-know-for-context/">página de conteúdo</a> do Elasticsearch Labs que acompanha este artigo.</p><h3>aplicação das leis de segurança</h3><p>Uma vantagem crucial de utilizar uma camada de velocidade baseada em pesquisa, como o Elastic, para engenharia de contexto é sua estrutura de segurança integrada. A plataforma da Elastic garante que o contexto fornecido às operações de IA generativa e agente respeite e proteja informações confidenciais mantidas em sigilo por meio de controle de acesso baseado em funções (RBAC) e controle de acesso baseado em atributos (ABAC) granulares. Isso significa que não apenas as consultas são processadas com eficiência, mas também que os resultados são filtrados de acordo com as permissões específicas do agente ou do usuário que iniciou a solicitação.</p><p>Os agentes são executados como o usuário autenticado, portanto a segurança é aplicada implicitamente por meio dos recursos de segurança integrados à plataforma:</p><ul><li><p><strong>Permissões refinadas:</strong> Defina o acesso no nível do documento, do campo ou até mesmo do termo, garantindo que os agentes de IA recebam apenas os dados que estão autorizados a visualizar.</p></li><li><p><strong>Controle de acesso baseado em funções (RBAC):</strong> Atribua funções a agentes ou usuários, concedendo acesso a conjuntos de dados ou funcionalidades específicas com base em suas responsabilidades definidas.</p></li><li><p><strong>Controle de acesso baseado em atributos (ABAC):</strong> Implemente políticas de acesso dinâmicas com base em atributos dos dados, do usuário ou do ambiente, permitindo uma segurança altamente adaptável e contextualizada.</p></li><li><p><strong>Segurança em nível de documento (DLS) e segurança em nível de campo (FLS):</strong> Esses recursos garantem que, mesmo dentro de um documento recuperado, apenas as partes autorizadas sejam visíveis, impedindo que informações confidenciais sejam expostas.</p></li><li><p><strong>Integração com segurança corporativa:</strong> Integre-se perfeitamente com sistemas de gerenciamento de identidade existentes (como LDAP, SAML, OIDC) para aplicar políticas de segurança consistentes em toda a organização.</p></li></ul><p>Ao integrar essas medidas de segurança diretamente no mecanismo de recuperação de contexto, a Elastic atua como um guardião seguro, garantindo que os agentes de IA operem dentro de limites de dados definidos, evitando a exposição não autorizada de dados e mantendo a conformidade com as regulamentações de privacidade de dados. Isso é fundamental para construir confiança em sistemas de IA que lidam com informações confidenciais ou proprietárias.</p><p>Como benefício adicional, ao usar uma camada unificada de velocidade de dados sobre suas fontes de dados corporativas, você alivia as cargas inesperadas de consultas ad hoc nesses repositórios que as ferramentas de agentes criariam. Você obtém um local centralizado para pesquisar tudo em tempo quase real e um único lugar para aplicar controles de segurança e governança.</p><h2>Ferramentas híbridas baseadas em pesquisa</h2><p>Existem algumas funcionalidades essenciais (e <a href="https://www.elastic.co/blog/whats-new-elastic-9-2-0">outras estão sendo adicionadas constantemente</a>) da plataforma Elastic que impulsionam a busca pela engenharia de contexto. O principal aqui é que a plataforma oferece uma infinidade de maneiras de atingir objetivos, com a flexibilidade para adaptar, alterar e expandir os métodos à medida que o ecossistema de IA avança.</p><h3>Apresentando o Construtor de Agentes</h3><p>O Elastic <a href="https://www.elastic.co/elasticsearch/agent-builder">Agent Builder</a> é nossa primeira incursão no mundo das ferramentas de IA com agentes, criadas para interagir com os dados que você já armazena no Elastic. O Agent Builder oferece uma interface de chat que permite aos usuários criar e gerenciar seus próprios agentes e ferramentas dentro do Kibana. Ele vem com servidores MCP e A2A integrados, APIs programáticas e um conjunto de ferramentas de sistema pré-construídas para consultar e explorar índices do Elasticsearch, além de gerar consultas ES|QL a partir de linguagem natural. O Agent Builder permite criar ferramentas personalizadas que visam e moldam os dados contextuais retornados ao agente por meio de uma sintaxe de consulta <a href="https://www.elastic.co/docs/reference/query-languages/esql">ES|QL</a> expressiva.</p><p>Como o ES|QL realiza buscas híbridas, você pergunta? A funcionalidade principal é alcançada através da combinação do tipo de campo <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/semantic-text">semantic_text</a> e dos comandos <a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/fork">FORK</a>/<a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/fuse">FUSE</a> (o FUSE usa <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion">RRF</a> por padrão para mesclar os resultados de cada fork). Aqui está um exemplo simples de uma busca fictícia de produto:</p>FROM products
| FORK
  (MATCH description "high performance gaming laptop" | EVAL search_type = "bm25"),
  (MATCH description_semantic "high performance gaming laptop" | EVAL search_type = "semantic")
| FUSE 
| LIMIT 20
| KEEP product_name, description, _score, search_type<p>A cláusula <a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/eval">EVAL</a> incluída em cada um dos ramos FORK no exemplo acima não é estritamente necessária; ela está incluída apenas para demonstrar como você pode rastrear de qual modalidade de pesquisa um determinado resultado foi retornado.</p><h3>Modelos de pesquisa</h3><p>Digamos que você queira direcionar suas próprias ferramentas externas de gerenciamento de agentes para sua implantação do Elasticsearch. E em vez de ES|QL, você deseja usar recuperadores de vários estágios ou reutilizar a sintaxe DSL existente que você desenvolveu, e também deseja poder controlar as entradas que a consulta aceita, a sintaxe usada para executar a pesquisa e os campos retornados na saída. <a href="https://www.elastic.co/docs/solutions/search/search-templates">Os modelos de pesquisa</a> permitem que os usuários definam estruturas predefinidas para padrões de pesquisa comuns, melhorando a eficiência e a consistência na recuperação de dados. Isso é particularmente benéfico para ferramentas de agentes que interagem com APIs de busca, pois ajuda a padronizar o código repetitivo e permite uma iteração mais rápida na lógica de busca. E se alguma vez precisar ajustar algum desses fatores, basta atualizar o modelo de pesquisa e pronto, as alterações são implementadas. Se você procura um exemplo de modelos de pesquisa em ação com ferramentas agentivas, confira o blog do Elasticsearch Labs " <a href="https://www.elastic.co/search-labs/blog/mcp-intelligent-search">MCP para pesquisa inteligente</a>", que utiliza um modelo de pesquisa por trás de uma chamada de ferramenta de um servidor MCP externo.</p><h3>Fluxos de trabalho integrados (SIM!)</h3><p>Um dos aspectos mais difíceis de lidar em nosso novo mundo de IA com agentes é a natureza não determinística de agentes "racionais" semiautônomos e autodirigidos. A engenharia de contexto é uma disciplina crítica para a IA ativa: são as técnicas que ajudam a restringir as possíveis conclusões que nosso agente pode gerar ao que sabemos ser verdade fundamental. Mesmo com uma janela de contexto altamente precisa e relevante (quando saímos do âmbito dos fatos numéricos), ainda nos falta aquela garantia de que a resposta do agente seja totalmente repetível e confiável.</p><p>Ao executar a mesma solicitação para um agente várias vezes, as respostas podem ser <em>essencialmente</em> as mesmas, com <em>apenas uma pequena</em> diferença na forma como são enviadas. Isso geralmente funciona bem para consultas simples, talvez seja quase imperceptível, e podemos tentar moldar a saída com técnicas de engenharia de contexto. Mas, à medida que as tarefas que solicitamos aos nossos agentes se tornam mais complexas, aumenta a probabilidade de que uma ou mais subtarefas introduzam uma variação que altere ligeiramente o resultado final. É provável que a situação piore à medida que começarmos a depender mais da comunicação entre agentes, e essas variações se tornarão cumulativas. Isso reforça a ideia de que as ferramentas com as quais nossos agentes interagem precisam ser muito flexíveis e ajustáveis para direcionar com precisão os dados contextuais, e que devem responder em um formato de saída esperado. Isso também indica que, para muitos casos de uso, precisamos direcionar as interações entre agentes e ferramentas — é aí que os fluxos de trabalho entram em cena!</p><p>Em breve, a Elastic terá fluxos de trabalho totalmente personalizáveis integrados ao núcleo da plataforma. Esses fluxos de trabalho poderão operar com agentes e ferramentas de forma bidirecional, ou seja, os fluxos de trabalho poderão chamar agentes e ferramentas, e os agentes e ferramentas poderão chamar fluxos de trabalho. Ter essas funcionalidades totalmente integradas na mesma plataforma de IA de busca onde todos os seus dados residem será transformador; o potencial dos fluxos de trabalho é extremamente empolgante! Em breve, muito em breve!</p><h3>Elástico como banco de memória unificado</h3><p>Por ser uma plataforma de dados distribuída, criada para buscas quase em tempo real, a Elastic executa naturalmente as funções de memória de longo prazo para sistemas de IA com agentes. Com a experiência de chat integrada do Agent Builder, também temos rastreamento e gerenciamento da memória de curto prazo e do histórico de conversas. E como toda a plataforma é orientada a APIs, é extremamente fácil utilizar o Elastic como plataforma para persistir a saída contextual de uma ferramenta (e poder consultá-la posteriormente), o que poderia sobrecarregar a janela de contexto do agente; essa técnica às vezes é chamada de "<a href="https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents#:~:text=Agents%20can%20assemble%20understanding%20layer%20by%20layer%2C%20maintaining%20only%20what%27s%20necessary%20in%20working%20memory%20and%20leveraging%20note%2Dtaking%20strategies%20for%20additional%20persistence">anotações</a> " em círculos de engenharia de contexto.</p><p>Ter memória de curto e longo prazo na mesma plataforma de busca traz muitos benefícios intrínsecos: imagine poder usar históricos de bate-papo e respostas contextuais persistentes como parte dos influenciadores semânticos em interações futuras, ou para realizar análises de ameaças, ou para criar produtos de dados persistentes que são gerados automaticamente a partir de chamadas de ferramentas repetidas com frequência… As possibilidades são infinitas!</p><h2>Conclusão</h2><p>O surgimento de grandes modelos de linguagem mudou a forma como conseguimos relacionar conteúdo e os métodos que usamos para analisar nossos dados. Estamos nos afastando rapidamente do mundo atual, onde os humanos realizam a pesquisa, a análise contextual e o raciocínio lógico para responder às suas próprias perguntas, para um mundo onde essas etapas são amplamente automatizadas por meio de inteligência artificial ativa. Para que possamos confiar nas respostas geradas que recebemos, precisamos ter a garantia de que o agente considerou <em>todas</em> as informações <em>mais relevantes</em> (incluindo o fator de relevância subjetiva) ao gerar sua resposta. Nosso principal método para tornar a IA agente confiável é fundamentar as ferramentas que recuperam contexto adicional por meio de técnicas de RAG (Aleatorização, Atribuição e Geração de Respostas) e engenharia de contexto, mas a forma como essas ferramentas realizam a <em>recuperação inicial</em> pode ser crucial para a precisão da resposta.</p><p>A plataforma Elastic Search AI oferece a flexibilidade e a vantagem da busca híbrida, juntamente com diversos recursos integrados que auxiliam a IA agente em termos de precisão, desempenho e escalabilidade; em outras palavras, o Elastic é uma plataforma fantástica para vários aspectos da engenharia de contexto! Ao padronizar a recuperação de contexto por meio de uma plataforma de busca, simplificamos as operações das ferramentas de inteligência artificial em várias frentes — e, assim como diz o paradoxo "ir mais devagar para ir mais rápido", a simplicidade na camada de geração de contexto significa uma IA mais rápida e confiável.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/context-engineering-hybrid-search-agentic-ai-accuracy</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/context-engineering-hybrid-search-agentic-ai-accuracy</guid>
    <category><![CDATA[Busca híbrida]]></category>
    <category><![CDATA[IA agêntica]]></category>
    <dc:creator><![CDATA[Woody Walton]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt42a203a316f0e22e/6a170932b339d58ebc769f5f/b82ff25242e4229cc20b218d9cc91c60cfd680bc-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Thu, 20 Nov 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Sabe, para contexto - Parte I: A evolução da busca híbrida e da engenharia de contexto]]></title>
    <description><![CDATA[Explore como a busca híbrida e a engenharia de contexto evoluíram a partir de fundamentos lexicais para viabilizar a próxima geração de fluxos de trabalho de IA com agentes.]]></description>
    <content:encoded><![CDATA[<h2>Nosso novíssimo mundo de IA agente</h2><p>Como muitos de nós, me sinto ao mesmo tempo entusiasmado e surpreso com a velocidade com que as capacidades da IA estão evoluindo. Vimos pela primeira vez os grandes modelos de linguagem (LLMs) e a busca vetorial nos lançarem na revolução semântica, onde não precisávamos mais ficar procurando coisas com palavras-chave. Em seguida, os LLMs nos mostraram novas maneiras de interagir com nossos dados, usando interfaces de bate-papo para transformar solicitações em linguagem natural em respostas que destilam vastas bases de conhecimento em resumos facilmente assimiláveis. Nós agora (já!) Possuem os primórdios da lógica automatizada orientada por LLM na forma de fluxos de trabalho de "IA agente" que podem compreender semanticamente uma solicitação recebida, raciocinar sobre as etapas a serem seguidas e, em seguida, escolher entre as ferramentas disponíveis para executar iterativamente ações para atingir esses objetivos.</p><p>A promessa da IA agente está nos forçando a evoluir, deixando de usar principalmente a "engenharia de prompts" para moldar nossas interações generativas de IA, e passando a nos concentrar em como podemos ajudar as ferramentas agentes a obter as informações adicionais mais relevantes e eficientes que o LLM precisa considerar ao gerar suas respostas — a "engenharia de contexto" é a próxima fronteira. A busca híbrida é, de longe, o meio mais poderoso e flexível para revelar contexto relevante, e a plataforma Search AI da Elastic abre uma nova maneira de aproveitar os dados a serviço da engenharia de contexto. Neste artigo, discutiremos como os Modelos de Aprendizagem Baseados em Liderança (LLMs) transformaram o mundo da recuperação de informação sob duas perspectivas e, em seguida, como eles podem trabalhar em conjunto para alcançar melhores resultados. Há muito terreno a percorrer…</p><h2>Parte I: Como os LLMs mudaram a busca</h2><p>Vamos começar pela perspectiva de como os LLMs (mestrados em direito) mudaram a forma como acessamos e recuperamos informações.</p><h3>Nosso legado lexical</h3><p>Há muito tempo que vivemos num mundo de busca lexical um tanto limitado (ou quase, da melhor forma possível). A busca é a primeira ferramenta que utilizamos ao pesquisar ou iniciar um novo projeto e, até recentemente, dependia de nós formular nossas consultas de uma maneira que um mecanismo de busca lexical entendesse. A busca lexical baseia-se na correspondência de algum tipo de termo de consulta com palavras-chave encontradas em um conjunto de documentos — independentemente de o conteúdo ser estruturado ou não estruturado. Para que uma busca lexical retorne um documento como resultado, ele precisa ter correspondido àquela palavra-chave (ou ter um vocabulário controlado, como uma lista de sinônimos ou um dicionário, para fazer a conexão conceitual para nós).</p>POST my-index/_search
{
  "size": 10,
  "query": {
    "semantic": {
      "query": "machine learning applications",
      "field": "semantic-content-field"
    }
  }
}<p><em>Um exemplo de </em><a href="https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-multi-match-query"></a><em> consulta lexical de correspondência múltipla</em></p><p>Ao menos os mecanismos de busca têm a capacidade de retornar resultados com uma pontuação de relevância. Os mecanismos de busca oferecem uma ampla gama de opções de sintaxe de consulta para segmentar dados indexados de forma eficaz, além de algoritmos de relevância integrados que classificam os resultados de acordo com a intenção da sintaxe de consulta do usuário. Os mecanismos de busca se beneficiam de décadas de avanços em algoritmos de classificação por relevância, o que os torna uma plataforma eficiente de recuperação de dados, capaz de fornecer resultados pontuados e classificados de acordo com sua relevância para a consulta. Bancos de dados e outros sistemas que usam SQL como principal método para recuperar dados estão em desvantagem nesse aspecto: não existe o conceito de relevância em uma consulta de banco de dados; o máximo que podem fazer é classificar os resultados alfabeticamente ou numericamente. A boa notícia é que você obterá todos os resultados (recall) com essas palavras-chave, mas eles não estarão necessariamente em uma ordem útil em relação ao <em>motivo pelo qual</em> você os solicitou (precisão). Esse é um ponto importante, como veremos em breve…</p><h3>Entre o dragão (semântico)</h3><p>O potencial das representações vetoriais de informações como alternativa à busca por palavras-chave vem sendo pesquisado há <a href="https://www.elastic.co/search-labs/blog/introduction-to-vector-search">bastante tempo</a>. Os vetores são muito promissores porque nos libertam do modo de correspondência de conteúdo baseado apenas em palavras-chave — como são representações numéricas de termos e pesos, os vetores permitem que os conceitos sejam matematicamente próximos com base na compreensão do modelo de linguagem sobre como os termos se relacionam entre si no domínio de treinamento. A longa demora na busca por vetores de propósito geral se devia ao fato de os modelos serem, em sua maioria, limitados a domínios específicos; eles simplesmente não eram grandes o suficiente para compreender adequadamente os muitos conceitos diferentes que um termo poderia representar em diferentes contextos.</p><p>Foi somente com o surgimento dos Modelos de Linguagem de Grande Porte (LLMs, na sigla em inglês), há alguns anos, e sua capacidade de serem treinados com quantidades muito maiores de dados (usando <a href="https://en.wikipedia.org/wiki/Transformer_(deep_learning_architecture)">transformadores</a> e <a href="https://en.wikipedia.org/wiki/Attention_(machine_learning)">atenção</a>), que a busca vetorial se tornou viável — o tamanho e a profundidade dos LLMs finalmente permitiram que os vetores armazenassem nuances suficientes para, de fato, capturar o significado semântico. Esse aumento repentino na profundidade de compreensão permitiu que os LLMs (Learning Language Machines) passassem a desempenhar diversas funções de processamento de linguagem natural (PLN) que antes estavam bloqueadas, sendo talvez a mais impactante a capacidade de inferir o próximo termo mais provável em uma sequência, dado o contexto do que já estava presente na sequência. A inferência é o processo que confere à IA generativa sua capacidade quase humana de produzir texto. O texto gerado por IA é baseado na compreensão do LLM sobre como os termos se relacionam em seus dados de treinamento e também utiliza a formulação da solicitação para diferenciar os diversos contextos em que os termos podem aparecer.</p><p>Por mais mágica que seja a IA generativa, os LLMs <em>têm</em> limitações que causam erros de qualidade e precisão, comumente chamados de alucinações. As alucinações ocorrem quando o profissional de saúde mental não tem acesso à informação (ou não é guiado ao contexto correto) para basear sua resposta na verdade, então, na tentativa de ser prestativo, ele gera uma resposta confiante e plausível que, na verdade, é inventada. Parte da causa é que, embora os LLMs aprendam o uso da linguagem em grandes domínios de informações diversas, eles precisam interromper o treinamento em um determinado momento, portanto, há um fator de temporalidade em sua compreensão — o que significa que o modelo só pode saber o que era preciso até o momento em que o treinamento foi interrompido. Outro fator que contribui para as alucinações é que o modelo geralmente desconhece dados privados (dados não disponíveis na internet pública), e isso é especialmente significativo quando esses dados contêm termos e nomenclatura específicos.</p><h3>Bancos de dados vetoriais</h3><p>Os LLMs vetorizam o conteúdo para seu espaço de modelo usando uma técnica chamada incorporação de texto, que se refere à <a href="https://www.elastic.co/search-labs/blog/hybrid-search-multiple-embeddings">incorporação</a> ou mapeamento do significado semântico do conteúdo na visão de mundo do modelo com base no treinamento que ele recebeu. Existem algumas etapas envolvidas na preparação e no processamento de conteúdo para incorporação, incluindo <a href="https://www.elastic.co/search-labs/blog/chunking-strategies-elasticsearch">a segmentação</a> e a tokenização (e <a href="https://www.kaggle.com/code/danishmahdi/subword-tokenization-bpe-wordpiece-and-unigram">a tokenização de subpalavras</a>). O resultado é tipicamente um conjunto de vetores densos que representam a compreensão do modelo sobre o significado daquele trecho de conteúdo dentro de seu espaço vetorial. O chunking é um processo impreciso que visa ajustar o conteúdo às limitações de processamento de um modelo para gerar embeddings, tentando também agrupar textos relacionados em um chunk usando construções semânticas como indicadores de sentença e parágrafo.</p><p>A necessidade de fragmentação pode gerar alguma perda semântica em um documento incorporado, porque os fragmentos individuais não estão totalmente associados a outros fragmentos do mesmo documento. A opacidade inerente das redes neurais pode agravar essa perda de informação — um modelo de aprendizagem linear é verdadeiramente uma “caixa preta”, onde as conexões entre termos e conceitos feitas durante o treinamento não são determinísticas e não podem ser interpretadas por humanos. Isso acarreta problemas de explicabilidade, repetibilidade, viés inconsciente e, potencialmente, perda de confiança e precisão. No entanto, a capacidade de conectar ideias semanticamente, de não estar vinculado a palavras-chave específicas ao fazer buscas, é extremamente poderosa:</p>POST my-index/_search 
{
  "size": 10, 
  "query": {
    "semantic": {
      "query": "machine learning applications",
      "field": "semantic-content-field"
    }
  }
} <p><em>Um exemplo </em><a href="https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-semantic-query"><em>de</em></a><em> consulta semântica</em></p><p>Há ainda outra questão a considerar em relação às bases de dados vetoriais: elas não são motores de busca, são bases de dados! Quando uma <a href="https://www.elastic.co/search-labs/blog/introduction-to-vector-search">busca por similaridade vetorial</a> é realizada, os termos da consulta são codificados para encontrar um conjunto de coordenadas (de incorporação) dentro do espaço vetorial do modelo. Essas coordenadas são então usadas como o alvo para encontrar os documentos que são os "vizinhos mais próximos" do alvo — o que significa que a classificação de um documento (ou sua posição nos resultados) é determinada pela <em>distância</em> de similaridade calculada entre as coordenadas desse documento e as coordenadas da consulta. Em que direção a classificação deve ter prioridade? Qual dos contextos possíveis está mais próximo da intenção do usuário? A imagem que me vem à mente é uma cena do filme <a href="https://www.youtube.com/watch?v=x3h7xz558EY&amp;start=3&amp;end=86">Stargate</a>, onde temos os seis pontos de coordenadas que se cruzam para nos indicar o destino (o alvo), mas não conseguimos chegar lá sem conhecer o "sétimo símbolo" - as coordenadas do ponto de partida que representam a intenção subjetiva do usuário. Assim, em vez de a classificação relativa dos vetores ser baseada em uma esfera de similaridade cada vez maior e indiferenciada, ao considerarmos a intenção subjetiva da consulta por meio de sintaxe expressiva e pontuação de relevância, podemos obter algo semelhante a um <em>cilindro</em> de relevância subjetiva graduada.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb49ae330d3de1fc1/6a17053ee8fbce089639fb46/1ddfaae0c1496d08d7d30419e6d2aeaeacfc0ea2-1600x544.png" alt="Um cilindro de relevância subjetiva graduada." /><p>As capacidades de inferência de um LLM podem ajudar a identificar o contexto mais provável <em>para</em> a consulta, mas o problema é que <em>, sem essa ajuda,</em> as coordenadas da consulta recebida <em>só</em> podem ser determinadas pela forma como o modelo foi originalmente treinado.</p><p>De certa forma, pode-se dizer que a similaridade vetorial vai ao extremo oposto da correspondência estrita por palavras-chave — sua força reside na capacidade de superar os problemas de incompatibilidade de termos, mas <a href="https://medium.com/data-science/vector-embeddings-are-lossy-heres-what-to-do-about-it-4f9a8ee58bb7">quase em excesso</a>: os modelos de similaridade de palavras tendem a unificar conceitos relacionados em vez de diferenciá-los. A similaridade vetorial melhora nossa capacidade de combinar conteúdo semanticamente, mas não garante precisão, pois pode ignorar palavras-chave exatas e detalhes específicos que não são suficientemente desambiguados pelo modelo. A busca por similaridade vetorial é poderosa por si só, mas precisamos de maneiras de correlacionar os resultados que obtemos de um banco de dados vetorial com os resultados de outros métodos de recuperação.</p><h3>Técnicas de reclassificação</h3><p>Agora é um bom momento para mencionar uma técnica geral chamada reclassificação, que reavalia ou normaliza os conjuntos de resultados para uma ordem de classificação unificada. A necessidade de reclassificação pode ser devida a resultados de múltiplas fontes ou métodos de recuperação que possuem mecanismos de classificação/pontuação diferentes (ou nenhum, como no caso do SQL!), ou a reclassificação pode ser usada para alinhar semanticamente os resultados de fontes não semânticas à consulta do usuário. A reclassificação é uma operação de segunda etapa, ou seja, um conjunto de resultados que foram coletados por algum método <em>de recuperação inicial</em> (ou seja, Em seguida, os métodos de busca (SQL, busca lexical, busca vetorial) são reordenados com um método de pontuação diferente.</p><p>Existem diversas abordagens disponíveis, incluindo <a href="https://www.elastic.co/docs/solutions/search/ranking/learning-to-rank-ltr">Learning-To-Rank (LTR)</a> e <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion">Reciprocal Rank Fusion (RRF)</a> — o LTR é útil para capturar características dos resultados de pesquisa (curtidas, avaliações, cliques, etc.) e usá-las para pontuar e impulsionar ou influenciar os resultados. O RRF é perfeito para mesclar resultados retornados de diferentes modalidades de consulta (por exemplo, pesquisas lexicais e em bancos de dados vetoriais) juntas em uma única lista de resultados. O Elastic também oferece a flexibilidade de ajustar as pontuações usando métodos <a href="https://www.elastic.co/search-labs/blog/linear-retriever-hybrid-search">de reclassificação linear</a> .</p><p>Uma das técnicas de reclassificação mais eficazes, no entanto, é <a href="https://www.elastic.co/docs/solutions/search/ranking/semantic-reranking">a reclassificação semântica</a>, que utiliza a compreensão semântica de um modelo de aprendizado de máquina para analisar os vetores de incorporação da consulta e dos resultados em conjunto e, em seguida, aplicar a pontuação/repontuação de relevância para determinar a ordem final. A reclassificação semântica requer, obviamente, uma conexão com um modelo de reclassificação, e o Elasticsearch fornece uma <a href="https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-inference">API de Inferência</a> que permite criar endpoints <strong>de reclassificação</strong> que utilizam modelos integrados (<a href="https://www.elastic.co/docs/explore-analyze/machine-learning/nlp/ml-nlp-rerank">Elastic Rerank</a>), modelos de terceiros <a href="https://www.elastic.co/docs/reference/elasticsearch/clients/eland/machine-learning">importados</a> ou serviços hospedados externamente, como <a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put-cohere">Cohere</a> ou <a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put-googlevertexai">Google Vertex AI</a>. Em seguida, você pode realizar a reclassificação por meio da sintaxe de abstração de consulta <a href="https://www.elastic.co/docs/solutions/search/retrievers-overview">do recuperador</a> :</p>POST my-index/_search 
{
  "size": 10,
  "retriever": {
    "text_similarity_reranker": {
      "retriever": {
        "rrf": {
          "retrievers": [
            {
              "standard": {
                "query": {
                  "multi_match": {
                    "query": "machine learning applications",
                    "fields": ["title", "content"]
                  }
                }
              }
            },
            {
              "knn": {
                "field": "semantic-content-field",
                "k": 10,
                "num_candidates": 100,
                "query_vector_builder": {
                  "text_embedding": {
                    "model_id": "my-text-embedding-model",
                    "model_text": "machine learning applications"
                  }
                }
              }
            }
          ],
          "rank_window_size": 50,
          "rank_constant": 20
        }
      }
    },
    "field": "content",
    "inference_id": "my-reranker",
    "inference_text": "machine learning applications",
    "rank_window_size": 20
  }
}<p><em>Um exemplo de operação de reclassificação de recuperação em múltiplos estágios</em></p><p>Parece ótimo, não é? Podemos realizar uma reclassificação de resultados de fontes distintas e chegar perto de uma compreensão semântica de todos os tipos de conteúdo... A reclassificação semântica pode ser dispendiosa tanto em termos computacionais quanto de tempo de processamento, e por isso, só pode ser feita de forma viável em um número limitado de resultados, o que significa que <em>a forma como</em> esses resultados iniciais são obtidos é importante.</p><h3>O método de recuperação de contexto é importante.</h3><p>A intenção subjetiva é um fator importante para determinar a precisão de um resultado e avaliar sua relevância. Sem a possibilidade de considerar a intenção do usuário ao realizar a consulta (expressa por meio de sintaxe flexível ou por reclassificação em um segundo estágio), só podemos selecionar entre os contextos existentes já codificados no espaço do modelo. Normalmente, lidamos com essa falta de contexto por meio de técnicas como <a href="https://en.wikipedia.org/wiki/Retrieval-augmented_generation">a Geração de Aumento de Recuperação (RAG)</a>. O RAG funciona alterando as coordenadas da consulta ao incluir termos relacionados adicionais retornados de uma pré-consulta para obter dados contextualmente relevantes. Isso torna o mecanismo que fornece esse contexto adicional e <em>seu</em> método inicial de recuperação ainda mais importantes para a precisão do contexto!</p><p>Vamos analisar os diferentes métodos de recuperação de contexto e como eles podem ajudar ou prejudicar uma operação RAG:</p><ul><li><p><strong>A recuperação de pesquisa híbrida sem um mecanismo de busca ainda carece de relevância subjetiva.</strong> Se a plataforma que fornece o RAG for baseada principalmente em SQL (o que inclui a maioria das plataformas de "data lake"), ela não terá pontuação de relevância na fase inicial de recuperação. Muitas plataformas de data lake oferecem sua própria versão de recuperação híbrida (não busca), geralmente combinando técnicas de reclassificação como reclassificação semântica e RRF em seus resultados de recuperação baseados em SQL e em bancos de dados vetoriais. Uma simples ordenação é obviamente insuficiente para uma classificação subjetiva, mas mesmo quando usada como base para uma operação de reclassificação semântica de segundo estágio, o SQL como recuperação de primeiro estágio torna-se um problema quando a reclassificação semântica é realizada apenas nos "k melhores" resultados — sem alguma forma de pontuar os resultados na recuperação, que garantia temos de que os <em>melhores</em> resultados estão realmente entre os primeiros resultados?</p></li><li><p><strong>A similaridade vetorial por si só não é suficiente para o RAG</strong>. Na verdade, isso se deve a uma série de problemas que se acumulam: a perda de dados inerente ao processo de incorporação, juntamente com métodos ingênuos de segmentação, a forma como a similaridade é calculada e a ausência crucial do componente de intenção subjetiva. Um dos principais objetivos do RAG é fundamentar as interações da IA generativa na verdade objetiva, tanto para evitar alucinações quanto para informar o LLM sobre informações privadas que ele desconhecia durante o treinamento. Podemos usar o contexto adicional fornecido pelo RAG para restringir e direcionar os LLMs a considerarem as conexões e os detalhes que sabemos serem mais importantes para responder à questão em análise. Para isso, precisamos usar <em>abordagens</em> semânticas e lexicais.</p></li><li><p><strong>RAG baseado em grep/regex de arquivo.</strong> Há <a href="https://www.nicolasbustamante.com/p/the-rag-obituary-killed-by-agents">setores</a> do universo da IA agente que apontam para o uso de janelas de contexto vastamente ampliadas que acessam arquivos locais via grep e regex para RAG (Random Access Groups - Grupos de Acesso Aleatório) em vez de plataformas de recuperação externas. A ideia é que, com uma janela contextual muito maior disponível, os profissionais de Letras e Literatura (LLMs) poderão fazer conexões conceituais dentro de seu próprio espaço de pensamento, em vez de depender de fragmentos isolados e de múltiplos métodos/plataformas de recuperação de informações para coletar informações relevantes. Embora seja verdade, em teoria, que ter um documento inteiro forneça uma visão mais completa do que segmentos de um documento, isso só funciona em domínios de dados pequenos (ou, por exemplo, ao fornecer arquivos para <a href="https://en.wikipedia.org/wiki/Vibe_coding">vibecoding</a>) e, mesmo assim, o método de recuperação inicial é uma varredura de todos os documentos com correspondência apenas por palavra-chave.</p></li></ul><p><strong>A busca é mais do que a recuperação de informações.</strong></p><p>Os mecanismos de busca são projetados especificamente para tornar as consultas o mais rápidas e flexíveis possível. Internamente, utilizam estruturas de dados especializadas para armazenar e recuperar diferentes tipos de dados de maneiras que atendam às necessidades específicas de cada tipo de dado. O Elasticsearch oferece armazenamento e consulta otimizados para praticamente todos os tipos de dados, incluindo busca lexical em texto completo/não estruturado (correspondência, frase, proximidade, correspondência múltipla), correspondência e filtragem rápidas por palavra-chave (correspondência exata), intervalos numéricos, datas, endereços IP, e é muito flexível na forma como armazena estruturas de documentos (por exemplo, documentos aninhados ou achatados). O Elasticsearch também é um banco de dados vetorial nativo que pode armazenar e consultar tipos de vetores esparsos e densos, e continuamos a explorar maneiras inovadoras (por exemplo, <a href="https://www.elastic.co/search-labs/blog/better-binary-quantization-lucene-elasticsearch">Better Binary Quantization (BBQ)</a> e <a href="https://www.elastic.co/search-labs/blog/diskbbq-elasticsearch-introduction">DiskBBQ</a>) para manter a fidelidade da pesquisa, ao mesmo tempo que melhoramos a velocidade, a escalabilidade e os custos associados ao conteúdo vetorizado. A plataforma Elasticsearch também oferece resiliência de dados e alta disponibilidade integradas, e inclui recursos de gerenciamento do ciclo de vida dos dados, como <a href="https://www.elastic.co/docs/deploy-manage/tools/snapshot-and-restore/searchable-snapshots">Snapshots pesquisáveis</a> , que permitem manter dados acessados com pouca frequência ou com retenção de longo prazo em armazenamento de objetos econômico — mas ainda totalmente pesquisáveis.</p><h3>A busca híbrida oferece o melhor de todos os mundos.</h3><p><a href="https://www.elastic.co/what-is/hybrid-search">Busca híbrida</a> (e não apenas recuperação híbrida!) Combina os pontos fortes da busca lexical tradicional com a compreensão semântica dos Modelos de Aprendizagem Lógica (LLMs) e da busca por similaridade vetorial. Essa sinergia permite direcionar resultados altamente relevantes na fase <em>de recuperação</em> por meio de qualquer uma das opções flexíveis de sintaxe de consulta que um mecanismo de busca oferece: opções de sintaxe orientadas por intenção e pontuação de relevância, recuperação de dados multimodais, filtragem, agregações e direcionamento. Com sintaxes de busca como <a href="https://www.elastic.co/docs/reference/query-languages/esql">ES|QL</a> e <a href="https://www.elastic.co/docs/solutions/search/retrievers-overview">mecanismos de recuperação</a> em múltiplos estágios, podemos combinar de forma flexível a busca tradicional com a busca semântica, filtros e múltiplas técnicas de reclassificação, tudo em uma única requisição.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6ee9512910856ee3/6a17053fcdacbf2ea97d291e/f25180cb430414b99ae553d3b8eb161dbccea4d4-1920x1080.png" alt="Como funciona a busca híbrida" /><p>Uma das maiores vantagens da pesquisa híbrida é que suas consultas podem usar sintaxe especializada para vários tipos de dados diferentes simultaneamente. Essas diferentes sintaxes de consulta podem ser usadas não apenas para <em>encontrar</em> resultados, mas também como filtros ou agregações <em>nos</em> resultados. Por exemplo, um dos tipos de consulta mais comuns que frequentemente é combinado com outras sintaxes é <a href="https://www.elastic.co/docs/explore-analyze/geospatial-analysis">a análise geoespacial</a>. Você pode realizar ações como consultar resultados que possuam coordenadas geográficas dentro de uma distância específica de um ponto, solicitar agregações de seus resultados por região ou ainda agregações para rastrear e alertar sobre movimentos de entrada e saída de uma zona. Com a pesquisa híbrida, você tem a flexibilidade de combinar sintaxes para direcionar os resultados da maneira mais precisa, recuperando o conteúdo mais próximo do seu contexto.</p><h2>Intervalo</h2><p>Esta primeira parte conta a história de como a busca vetorial mudou a forma como conseguimos recuperar dados e prepara o terreno para as mudanças que os Modelos de Aprendizagem Baseados em Lógica (LLMs) trouxeram aos mecanismos de consulta que usamos para interagir com os dados. Vamos fingir que tivemos que dividir isso em várias partes para que os LLMs pudessem entender sem perder o contexto… ;-) Vamos aprender mais sobre <em>por que isso é importante</em> na <a href="https://www.elastic.co/search-labs/blog/context-engineering-llm-evolution-agentic-ai">Parte II: IA Agêntica e a necessidade de engenharia de contexto</a>, e na Parte III, retornaremos à nossa discussão sobre busca híbrida.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/context-engineering-hybrid-search-evolution-agentic-ai</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/context-engineering-hybrid-search-evolution-agentic-ai</guid>
    <category><![CDATA[Busca híbrida]]></category>
    <category><![CDATA[Relevância]]></category>
    <dc:creator><![CDATA[Woody Walton]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc49e39872984c8eb/6a1705410e2e49e42c419fd5/7e59a0671aa9ea32d68188a693936a66ebf48625-1000x628.png" length="0" type="image/png"/>
    <pubDate>Wed, 12 Nov 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Busca multimodal de picos de montanhas com Elasticsearch e SigLIP-2 ]]></title>
    <description><![CDATA[Aprenda como implementar buscas multimodais de texto para imagem e de imagem para imagem usando embeddings SigLIP-2 e busca vetorial kNN do Elasticsearch. Objetivo do projeto: encontrar fotos do pico do Monte Ama Dablam tiradas durante uma trilha no Everest.]]></description>
    <content:encoded><![CDATA[<p>Você já quis pesquisar seu álbum de fotos por significado? Experimente buscas como "mostre-me fotos minhas onde estou usando uma jaqueta azul e sentado em um banco", "mostre-me fotos do Monte Everest" ou "saquê e sushi". Pegue uma xícara de café (ou sua bebida favorita) e continue lendo. Neste blog, mostraremos como criar um aplicativo de busca híbrido multimodal. Multimodal significa que o aplicativo consegue entender e pesquisar em diferentes tipos de entrada — texto, imagens e áudio — e não apenas palavras. Híbrido significa que combina técnicas como correspondência de palavras-chave, busca vetorial kNN e geofencing para fornecer resultados mais precisos.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdfa1ec1ccd450e94/6a17da751d1b8308ee93e344/0ec6bbb45013846b59ee00d2bf73ee2182ee7392-1920x1080.gif" alt="Biblioteca de fotos de diferentes picos de montanhas da trilha até o Monte Everest." /><p>Para isso, utilizamos o SigLIP-2 do Google para gerar representações vetoriais tanto para imagens quanto para texto, e as armazenamos no banco de dados vetorial Elasticsearch. No momento da consulta, convertemos a entrada da pesquisa, seja texto ou imagem, em representações vetoriais (embeddings) e executamos buscas vetoriais kNN rápidas para recuperar os resultados. Essa configuração permite uma busca eficiente de texto para imagem e de imagem para imagem. A interface Streamlit UI dá vida a este projeto, fornecendo-nos um frontend que não só permite realizar buscas textuais para encontrar e visualizar as fotos correspondentes no álbum, como também nos permite identificar o pico da montanha na imagem carregada e visualizar outras fotos dessa montanha no álbum.
Abordamos também as medidas que tomamos para melhorar a precisão da pesquisa, juntamente com dicas e truques práticos. Para uma exploração mais aprofundada, disponibilizamos um <a href="https://github.com/navneet83/multimodal-mountain-peak-search">repositório no GitHub</a> e um <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/notebooks/multimodal_mountain_peak_search.ipynb">notebook no Colab</a>.</p><h2>Como tudo começou</h2><p>Este post do blog foi inspirado por uma criança de 10 anos que me pediu para mostrar todas as fotos do Monte Ama Dablam que tirei na minha trilha até o Acampamento Base do Everest. Enquanto examinávamos o álbum de fotos, também me pediram para identificar vários outros picos de montanhas, alguns dos quais eu não sabia o nome.</p><p>Isso me deu a ideia de que este pode ser um projeto divertido de visão computacional. O que queríamos alcançar:</p><ul><li><p>Encontre fotos de um pico de montanha pelo nome.</p></li><li><p>Adivinhe o nome do pico da montanha a partir de uma imagem e encontre picos semelhantes no álbum de fotos.</p></li><li><p>Fazer com que as consultas de conceito funcionem (<em>pessoa</em>, <em>rio</em>, <em>bandeiras de oração</em>, <em>etc.)</em></p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf82df9d7005fc3fe/6a17da78abe0f2e77bdfe8b9/e9d0d720a9b565d5b749bdc915068852d4f157ad-1200x1600.png" alt="Monte Ama Dablam " /><h2>Montando a equipe dos sonhos: SigLIP-2, Elasticsearch e Streamlit</h2><p>Rapidamente ficou claro que, para isso funcionar, precisaríamos transformar tanto o texto (“Ama Dablam”) quanto as imagens (fotos do meu álbum) em vetores que pudessem ser comparados de forma significativa, ou seja, no mesmo espaço vetorial. Uma vez feito isso, a busca se torna simplesmente "encontrar os vizinhos mais próximos".</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5f80b69a9d5bd28a/6a17da7a4b055ddd1243209e/20e6f8b7d4fa48414f407ec200adbe00ee28d517-1536x1024.png" alt="SigLIP-2, Elasticsearch e Streamlit - uma combinação dos sonhos." /><p>Para gerar representações vetoriais de imagens, usamos um<a href="https://huggingface.co/blog/vlms-2025"> codificador multilíngue de visão e linguagem</a>, de modo que uma foto de uma montanha e uma frase como "Ama Dablam" fiquem no mesmo espaço vetorial.</p><p><a href="https://huggingface.co/blog/siglip2"><strong>O SigLIP-2</strong></a>, lançado recentemente pelo Google, se encaixa bem aqui. Ele consegue gerar embeddings sem treinamento específico para a tarefa (uma configuração <strong>zero-shot</strong> ) e funciona bem para o nosso caso de uso: fotos não rotuladas e picos com nomes e idiomas diferentes. Como foi treinado para correspondência de texto ↔ imagem, uma foto da montanha tirada durante a trilha e um breve texto de exemplo resultam em representações vetoriais muito semelhantes, mesmo quando o idioma ou a ortografia da consulta variam.</p><p>O SigLIP-2 oferece um excelente equilíbrio entre qualidade e velocidade, suporta múltiplas resoluções de entrada e funciona tanto na CPU quanto na GPU. O SigLIP-2 foi projetado para ser mais resistente a fotos tiradas ao ar livre em comparação com modelos anteriores, como o CLIP original. Durante nossos testes, o SigLIP-2 gerou resultados confiáveis de forma consistente. Além disso, conta com amplo suporte, o que a torna a escolha óbvia para este projeto.</p><p>Em seguida, precisamos de um banco de dados vetorial para armazenar os embeddings e realizar buscas avançadas. Deveria suportar não apenas a busca kNN de cosseno em embeddings de imagem, mas também aplicar filtros de geolocalização e texto em uma única consulta. O Elasticsearch se encaixa bem aqui: ele lida muito bem com vetores (HNSW kNN em campos dense_vector), suporta busca híbrida que combina consultas de texto, vetores e geolocalização, e oferece filtragem e classificação prontas para uso. Ele também se adapta à escala horizontal, facilitando a expansão de um punhado de fotos para milhares. O <a href="https://www.elastic.co/docs/reference/elasticsearch/clients/python">cliente oficial do Elasticsearch para Python</a> mantém a infraestrutura simples e se integra perfeitamente ao projeto. Por fim, precisamos de uma interface leve onde possamos inserir consultas de pesquisa e visualizar os resultados. Para uma demonstração rápida baseada em Python, o Streamlit é uma ótima opção. Ele fornece os recursos básicos de que precisamos: upload de arquivos, uma grade de imagens responsiva e menus suspensos para classificação e geolocalização. É fácil clonar e executar localmente, e também funciona em um notebook do Colab.</p><h2>Implementação</h2><h3>Design e estratégia de indexação do Elasticsearch</h3><p>Usaremos dois índices para este projeto: <code>peaks_catalog</code> e <code>photos</code>.</p><h4>Índice do catálogo de picos</h4><p>Este índice serve como um catálogo compacto dos picos de montanhas mais proeminentes que podem ser vistos durante a trilha até o Acampamento Base do Everest. Cada documento neste índice corresponde a um único pico de montanha, como o Monte Everest. Para cada documento de pico de montanha, armazenamos nomes/apelidos, coordenadas opcionais de latitude e longitude e um único vetor protótipo construído pela combinação de prompts de texto SigLIP-2 (e imagens de referência opcionais).</p><p><strong>Mapeamento do índice:</strong></p><p>Campo</p><p>Tipo</p><p>Exemplo</p><p>Objetivo/Observações</p><p>Vetor/Indexação</p><p>eu ia</p><p>palavra-chave</p><p>ama-dablam</p><p>Slug/ID estável</p><p>—</p><p>nomes</p><p>texto + subcampo de palavra-chave</p><p>["Ama Dablam","Amadablam"]</p><p>Aliases / nomes multilíngues; names.raw para filtros exatos</p><p>—</p><p>latlon</p><p>ponto_geográfico</p><p>{"lat":27.8617,"lon":86.8614}</p><p>Coordenadas GPS do pico como uma combinação de latitude/longitude (opcional)</p><p>—</p><p>elev_m</p><p>inteiro</p><p>6812</p><p>Elevação (opcional)</p><p>—</p><p>texto incorporado</p><p>dense_vector</p><p>768</p><p>Protótipo misto (com instruções e, opcionalmente, 1 a 3 imagens de referência) para este pico.</p><p>índice:true, similaridade:"cosseno", opções_de_índice:{type:"hnsw", m:16, ef_construction:128}</p><p>Este índice é usado principalmente para buscas de imagem para imagem, como identificar picos de montanhas a partir de imagens. Também utilizamos esse índice para aprimorar os resultados de busca de texto para imagem.</p><p>Em resumo, o <code>peaks_catalog</code> transforma a pergunta "Que montanha é esta?" em um problema de vizinho mais próximo focado, separando efetivamente a compreensão conceitual das complexidades dos dados da imagem.</p><p><strong>Estratégia de indexação para o índice peaks_catalog: </strong>Começamos criando uma lista dos picos mais proeminentes visíveis durante a trilha do Campo Base do Everest. Para cada pico, armazenamos sua localização geográfica, nome, sinônimos e altitude em um <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/data/peaks.yaml">arquivo YAML</a>. O próximo passo é <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/embed_and_index_photos.py#L351">gerar o embedding</a> para cada pico e armazená-lo no campo <code>text_embed</code> . Para gerar embeddings robustos, utilizamos a seguinte técnica:</p><ul><li><p>Crie um protótipo de texto usando:</p><ul><li><p>nomes dos picos</p></li><li><p><a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/embed_and_index_photos.py#L301">Conjunto de prompts</a> (usando vários prompts diferentes para tentar responder à mesma pergunta), por exemplo:</p><ul><li><p>“uma foto natural do pico da montanha {name} no Himalaia, Nepal”</p></li><li><p>“{name} pico emblemático na região de Khumbu, paisagem alpina”</p></li><li><p>“{name} cume da montanha, neve, crista rochosa”</p></li></ul></li><li><p><a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/embed_and_index_photos.py#L333">Anti-conceito</a> opcional (indicando ao SigLIP-2 o que não deve ser correspondido): subtrair um pequeno vetor para "pintura, ilustração, pôster, mapa, logotipo" para que haja uma preferência por fotos reais.</p></li></ul></li><li><p>Opcionalmente, <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/embed_and_index_photos.py#L388C13-L388C29">crie um protótipo de imagem</a> se forem fornecidas imagens de referência do pico.</p></li></ul><p>Em seguida, <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/embed_and_index_photos.py#L392">combinamos o texto e o protótipo da imagem</a> para gerar a incorporação final. Finalmente, o documento é <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/embed_and_index_photos.py#L396">indexado</a> com todos os campos necessários:</p>def l2norm(v: np.ndarray) -&gt; np.ndarray:
    return v / (np.linalg.norm(v) + 1e-12)
def compute_blended_peak_vec(
        emb: Siglip2,
        names: List[str],
        peak_id: str,
        peaks_images_root: str,
        alpha_text: float = 0.5,
        max_images: int = 3,
) -&gt; Tuple[np.ndarray, int, int, List[str]]:
    """
    Build blended vector for a single peak.

    Returns:
      vec           : np.ndarray (L2-normalized)
      found_count   : number of reference images discovered
      used_count    : number of references used (&lt;= max_images)
      used_filenames: list of filenames used (for logging)
    """
    # 1) TEXT vector
    tv = embed_text_blend(emb, names)

    # 2) IMAGE refs: prefer folder by id; fallback to slug of the primary name
    root = Path(peaks_images_root)
    candidates = [root / peak_id]
    if names:
        candidates.append(root / slugify(names[0]))

    all_refs: List[Path] = []
    for c in candidates:
        if c.exists() and c.is_dir():
            all_refs = list_ref_images(c)
            if all_refs:
                break

    found = len(all_refs)
    used_list = all_refs[:max_images] if (max_images and found &gt; max_images) else all_refs
    used = len(used_list)

    img_v = embed_image_mean(emb, used_list) if used_list else None

    # 3) Blend TEXT and IMAGE vectors, clamp alpha to [0,1]
    a = max(0.0, min(1.0, float(alpha_text)))
    vec = l2norm(tv if img_v is None else (a * tv + (1.0 - a) * img_v)).astype("float32")
    return vec, found, used, [p.name for p in used_list]<p>Documento de exemplo do índice <code>peaks_catalog</code> :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1219f5d0e39b512c/6a17da7c57726263161bcace/bc05fbd0c4f8d721d5170c28a3884a9eda80bb7d-1210x1132.png" alt="Um documento de exemplo do índice peaks_catalog no Elasticsearch." /><h4>Índice de fotos</h4><p>Este índice principal armazena informações detalhadas sobre todas as fotos do álbum. Cada documento representa uma única fotografia, contendo as seguintes informações:</p><ul><li><p>Caminho relativo até a foto no álbum de fotos. Isso pode ser usado para visualizar a imagem correspondente ou carregar a imagem na interface de pesquisa.</p></li><li><p>Informações de GPS e horário da imagem.</p></li><li><p>Vetor denso para codificação de imagem gerado por SigLIP-2.</p></li><li><p><code>predicted_peaks</code> Isso nos permite filtrar pelo nome do pico.

<strong>Mapeamento de índice</strong></p></li></ul><p>Campo</p><p>Tipo</p><p>Exemplo</p><p>Objetivo/Observações</p><p>Vetor / Indexação</p><p>caminho</p><p>palavra-chave</p><p>dados/imagens/IMG_1234.HEIC</p><p>Como a interface do usuário abre a miniatura/imagem completa</p><p>—</p><p>imagem_recortada</p><p>dense_vector</p><p>768</p><p>Incorporação de imagem SigLIP-2</p><p>índice:true, similaridade:"cosseno", opções_de_índice:{type:"hnsw", m:16, ef_construction:128}</p><p>picos_previstos</p><p>palavra-chave</p><p>["ama-dablam","pumori"]</p><p>Top-K palpites no momento da indexação (filtro/faceta de UX barato)</p><p>—</p><p>GPS</p><p>ponto_geográfico</p><p>{"lat":27.96,"lon":86.83}</p><p>Ativa filtros geográficos</p><p>—</p><p>tempo_de_tiro</p><p>date</p><p>2023-10-18T09:41:00Z</p><p>Tempo de captura: classificar/filtrar</p><p>—</p><p><strong>Estratégia de indexação para o índice de fotos: </strong>Para cada foto no álbum, fazemos o seguinte:
 Extrair informações das imagens <code>shot_time</code> e <code>gps</code> <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/embed_and_index_photos.py#L526">dos metadados da imagem</a>.</p><ul><li><p><a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/embed_and_index_photos.py#L511">Incorporação de imagem SigLIP-2</a>: passe a imagem pelo modelo e normalize o vetor usando a notação L2. Armazene o embedding no campo <code>clip_image</code> .</p></li><li><p><a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/embed_and_index_photos.py#L519">Preveja os picos</a> e armazene-os no campo <code>predicted_peaks</code> . Para fazer isso, primeiro pegamos o vetor de imagem da foto gerado na etapa anterior e, em seguida, executamos uma busca kNN rápida no campo text_embed no índice <code>peaks_catalog</code> . Mantemos os 3 ou 4 picos mais altos e ignoramos o resto.</p></li><li><p>Calculamos o campo <code>_id</code> fazendo um <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/embed_and_index_photos.py#L509">hash</a> no nome e caminho da imagem. Isso garante que não teremos duplicatas após várias execuções.</p></li></ul><p>Após determinarmos todos os campos da foto, os documentos fotográficos são indexados em lotes usando indexação <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/embed_and_index_photos.py#L530">em massa</a> :</p>def bulk_index_photos(
        es: Elasticsearch,
        images_root: str,
        photos_index: str = "photos",
        peaks_index: str = "peaks_catalog",
        topk_predicted: int = 5,
        batch_size: int = 200,
        refresh: str = "false",
) -&gt; None:
    """Walk a folder of images, embed + enrich, and bulk index to Elasticsearch."""
    root = Path(images_root)
    if not root.exists():
        raise SystemExit(f"Images root not found: {images_root}")

    emb = Siglip2()
    batch: List[Dict[str, Any]] = []
    n_indexed = 0

    for p in iter_images(root):
        rel = relpath_within(root, p)
        _id = id_for_path(rel)

        # 1) Image embedding (and reuse it for predicted_peaks)
        try:
            with Image.open(p) as im:
                ivec = emb.image_vec(im.convert("RGB")).astype("float32")
        except (UnidentifiedImageError, OSError) as e:
            print(f"[skip] {rel} — cannot embed: {e}")
            continue

        # 2) Predict top-k peak names
        try:
            top_names = predict_peaks(es, ivec.tolist(), peaks_index=peaks_index, k=topk_predicted)
        except Exception as e:
            print(f"[warn] predict_peaks failed for {rel}: {e}")
            top_names = []

        # 3) EXIF enrichment (safe)
        gps = get_gps_decimal(str(p))
        shot = get_shot_time(str(p))

        # 4) Build doc and stage for bulk
        doc = {"path": rel, "clip_image": ivec.tolist(), "predicted_peaks": top_names}
        if gps:
            doc["gps"] = gps
        if shot:
            doc["shot_time"] = shot

        batch.append(
            {"_op_type": "index", "_index": photos_index, "_id": _id, "_source": doc}
        )

        # 5) Periodic flush
        if len(batch) &gt;= batch_size:
            helpers.bulk(es, batch, refresh=refresh)
            n_indexed += len(batch)
            print(f"[photos] indexed {n_indexed} (last: {rel})")
            batch.clear()

    # Final flush
    if batch:
        helpers.bulk(es, batch, refresh=refresh)
        n_indexed += len(batch)
        print(f"[photos] indexed {n_indexed} total.")

    print("[done] photos indexing")<p>Exemplo de documento do índice de fotos:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt744b7e6326937cfc/6a17da7e6df731d3040a0da8/1dc1406ac2a97440b6804838795b3c2205c4c6b2-1080x1234.png" alt="Um documento de exemplo do índice de fotos no Elasticsearch." /><p>Em resumo, o índice de fotos é um armazenamento rápido, filtrável e compatível com kNN de todas as fotos do álbum. Seu mapeamento é propositalmente minimalista — apenas a estrutura necessária para recuperar rapidamente, exibir de forma clara e segmentar os resultados por espaço e tempo. Este índice serve para ambos os casos de uso de pesquisa. O script em Python para criar ambos os índices pode ser encontrado <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/create_indices.py">aqui</a>.</p><p>A visualização do mapa Kibana abaixo exibe documentos do álbum de fotos como pontos verdes e picos de montanhas do índice <code>peaks_catalog</code> como triângulos vermelhos, com os pontos verdes alinhando-se bem com a trilha da caminhada até o Acampamento Base do Everest.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb5bf016e8d9c3e84/6a17da80be608681f10045e6/1c75d0ed0ce53d28a94bf2f47a354e25581d2baf-1600x1402.png" alt="Uma visualização do mapa Kibana exibindo documentos do álbum de fotos como pontos verdes e picos de montanhas do índice peaks_catalog como triângulos vermelhos, com os pontos verdes alinhando-se bem com a trilha da caminhada até o Acampamento Base do Everest." /><h2>Pesquisar casos de uso</h2><p><strong>Busca por nome (texto para imagem):</strong> Este recurso permite que os usuários localizem fotos de picos de montanhas (e até mesmo conceitos abstratos como "bandeiras de oração") usando consultas de texto. Para isso, o texto de entrada é <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/query_by_peak_name.py#L87C5-L87C20">convertido em um vetor de texto</a> usando o SigLIP-2. Para geração robusta de vetores de texto, empregamos a mesma estratégia usada para criar embeddings de texto no índice <code>peaks_catalog</code> : <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/query_by_peak_name.py#L104">combinando</a> a entrada de texto com um pequeno <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/query_by_peak_name.py#L100">conjunto de prompts</a>, subtraindo um<a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/query_by_peak_name.py#L103"> vetor de anti-conceito</a> menor e aplicando <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/query_by_peak_name.py#L104">a normalização L2</a> para produzir o vetor de consulta final. Uma <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/query_by_peak_name.py#L140">consulta</a> kNN é então executada no campo <code>photos.clip_image</code> para recuperar os picos correspondentes principais, com base na similaridade de cosseno para encontrar as imagens mais próximas. Opcionalmente, os resultados da pesquisa podem ser tornados mais relevantes aplicando <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/query_by_peak_name.py#L152">filtros</a> geográficos e de data e/ou um filtro de termo <code>photos.predicted_peaks</code> como parte da consulta (veja exemplos de consulta abaixo). Isso ajuda a excluir picos semelhantes que, na verdade, não estão visíveis durante a trilha.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9bb9abf5ce64fcbb/6a17da81e8fbce20db3a17da/b5fac28ffdbedb820505365ca07df125cd01b939-946x370.png" alt="Como funciona a busca multimodal por nome (texto para imagem) no Elasticsearch." /><p><strong>Consulta Elasticsearch com filtro geográfico:</strong></p>POST photos/_search
{
  "knn": {
    "field": "clip_image",
    "query_vector": [ ... ],
    "k": 60,
    "num_candidates": 2000
  },
  "query": {
    "bool": {
      "filter": [
        { "geo_bounding_box": { "gps": { "top_left": "...", "bottom_right": "..." } } }
      ]
    }
  },
  "_source": ["path","predicted_peaks","gps","shot_time"]
}

Response (first two documents):
{
 "hits": {
   "total": {
     "value": 56,
     "relation": "eq"
   },
   "max_score": 0.5779596,
   "hits": [
     {
       "_index": "photos",
       "_id": "d01da3a1141981486c3493f6053c79e92a788463",
       "_score": 0.5779596,
       "_source": {
         "path": "IMG_2738.HEIC",
         "predicted_peaks": [
           "Pumori",
           "Kyajo Ri",
           "Khumbila",
           "Nangkartshang",
           "Kongde Ri"
         ],
         "gps": {
           "lat": 27.97116388888889,
           "lon": 86.82331111111111
         },
         "shot_time": "2023-11-03T08:07:13"
       }
     },
     {
       "_index": "photos",
       "_id": "c79d251f07adc5efaedc53561110a7fd78e23914",
       "_score": 0.5766071,
       "_source": {
         "path": "IMG_2761.HEIC",
         "predicted_peaks": [
           "Kyajo Ri",
           "Makalu",
           "Baruntse",
           "Cho Oyu",
           "Khumbila"
         ],
         "gps": {
           "lat": 27.975558333333332,
           "lon": 86.82515
         },
         "shot_time": "2023-11-03T08:51:08"
       }
     }
}<p><strong>Busca por imagem (imagem para imagem):</strong> Este recurso permite identificar uma montanha em uma imagem e encontrar outras imagens dessa mesma montanha no álbum de fotos. Quando uma imagem é carregada, ela é processada pelo codificador de imagens SigLIP-2 para gerar um <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/identify_from_picture_find_similar_peaks.py#L228">vetor de imagem</a>. Uma <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/identify_from_picture_find_similar_peaks.py#L234">busca kNN</a> é então realizada no campo <code>peaks_catalog.text_embed</code> para identificar os nomes de picos que melhor correspondem. Em seguida, um <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/identify_from_picture_find_similar_peaks.py#L257">vetor de texto é gerado</a> a partir desses nomes de picos correspondentes, e outra <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/scripts/identify_from_picture_find_similar_peaks.py#L263">busca kNN</a> é realizada no índice de fotos para localizar as imagens correspondentes.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltab9d16333e2a9e69/6a17da827f6f155448c099cc/3a3d5635bee7a222b95529dd7f9fbee016381610-1226x550.png" alt="Como funciona a busca multimodal por imagem (imagem para imagem) no Elasticsearch." /><p><strong>Consulta do Elasticsearch:</strong></p><p>Passo 1: Encontre os nomes de pico correspondentes.</p>GET peaks_catalog/_search
{
 "knn": {
   "field": "text_embed",
   "query_vector": [...image-vector... ],
   "k": 3,
   "num_candidates": 500
 },
 "_source": [
   "id",
   "names",
   "latlon",
   "text_embed"
 ]
}


Response (first two documents):
{
 "took": 2,
 "timed_out": false,
 "_shards": {
   "total": 1,
   "successful": 1,
   "skipped": 0,
   "failed": 0
 },
 "hits": {
   "total": {
     "value": 3,
     "relation": "eq"
   },
   "max_score": 0.58039916,
   "hits": [
     {
       "_index": "peaks_catalog",
       "_id": "pumori",
       "_score": 0.58039916,
       "_source": {
         "id": "pumori",
         "names": [
           "Pumori",
           "Pumo Ri"
         ],
         "latlon": {
           "lat": 28.01472,
           "lon": 86.82806
         },
         "text_embed": [
                  ... embeddings...
         ]
       }
     },
     {
       "_index": "peaks_catalog",
       "_id": "kyajo-ri",
       "_score": 0.57942784,
       "_source": {
         "id": "kyajo-ri",
         "names": [
           "Kyajo Ri",
           "Kyazo Ri"
         ],
         "latlon": {
           "lat": 27.909167,
           "lon": 86.673611
         },
         "text_embed": [
           ... embeddings...
         ]
       }
     }
   ]
 }
}<p>Etapa 2: Realize uma busca no índice <code>photos</code> para encontrar as imagens correspondentes (mesma consulta mostrada no caso de uso de busca de texto para imagem):</p>POST photos/_search
{
 "knn": {
   "field": "clip_image",
   "query_vector": [ ...image-vector... ],
   "k": 30,
   "num_candidates": 2000
 },
 "_source": [
   "path",
   "gps",
   "shot_time",
   "predicted_peaks",
   "clip_image"
 ],
 "query": {
   "bool": {
     "filter": [
       {
         "term": {
           "predicted_peaks": "Pumori"
         }
       }
     ]
   }
 }
}


Response (first two documents):
{
 "hits": {
   "total": {
     "value": 56,
     "relation": "eq"
   },
   "max_score": 0.5779596,
   "hits": [
     {
       "_index": "photos",
       "_id": "d01da3a1141981486c3493f6053c79e92a788463",
       "_score": 0.5779596,
       "_source": {
         "path": "IMG_2738.HEIC",
         "predicted_peaks": [
           "Pumori",
           "Kyajo Ri",
           "Khumbila",
           "Nangkartshang",
           "Kongde Ri"
         ],
         "gps": {
           "lat": 27.97116388888889,
           "lon": 86.82331111111111
         },
         "shot_time": "2023-11-03T08:07:13"
       }
     },
     {
       "_index": "photos",
       "_id": "c79d251f07adc5efaedc53561110a7fd78e23914",
       "_score": 0.5766071,
       "_source": {
         "path": "IMG_2761.HEIC",
         "predicted_peaks": [
           "Kyajo Ri",
           "Makalu",
           "Baruntse",
           "Cho Oyu",
           "Khumbila"
         ],
         "gps": {
           "lat": 27.975558333333332,
           "lon": 86.82515
         },
         "shot_time": "2023-11-03T08:51:08"
       }
     }
}<h2>Interface de usuário Streamlit</h2><p>Para integrar tudo, criamos uma interface de usuário Streamlit simples que nos permite executar ambos os casos de uso de pesquisa. A barra lateral esquerda exibe uma lista rolável de picos (agregados de <code>photos.predicted_peaks</code>) com caixas de seleção e um minimapa/filtro geográfico. Na parte superior, há uma caixa <strong>de pesquisa por nome</strong> e um botão <strong>para identificar o usuário a partir de uma foto</strong> enviada. O painel central apresenta uma grade de miniaturas interativa que exibe as pontuações kNN, os indicadores de pico previsto e os horários de captura. Cada imagem inclui um botão <strong>"Ver imagem"</strong> para pré-visualizações em resolução total.</p><p><strong>Pesquisa por upload de imagem:</strong> Prevemos o pico e encontramos picos correspondentes no álbum de fotos.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd1fb2b0304a310d2/6a17da8425daab7cda08a0fa/dca540cbf5279e6d6102c5a0c0351ddd4ac91cda-1600x1112.png" alt="Uma interface de usuário simples e intuitiva que permite a busca multimodal por texto para imagem e por imagem para os picos do Monte Ama Dablam." /><p><strong>Pesquisa por texto</strong>: Encontre os picos correspondentes no álbum a partir do texto.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt496c1ae8f7886320/6a17da86abe0f2da48dfe8bd/b1e8618db746cd49ea4962d3dc73031387b975dd-1600x1166.png" alt="Como pesquisar um pico do Monte Everest usando a busca por texto na biblioteca de picos de montanhas." /><h2>Conclusão</h2><p>Tudo começou com <em>uma pergunta: "Podemos ver as </em><em> fotos</em><em><strong>do Ama Dablam ?"</strong></em> transformou-se em um pequeno sistema <strong>de busca multimodal</strong> funcional. Capturamos fotos brutas da trilha, transformamos em <strong>embeddings SigLIP-2</strong> e usamos <strong>o Elasticsearch</strong> para realizar uma rápida <strong>análise kNN</strong> sobre vetores, além de filtros geográficos/temporais simples para exibir as imagens <em>relevantes</em>. Ao longo do processo, separamos as preocupações com dois índices: um pequeno <code>peaks_catalog</code> de protótipos combinados (para identificação) e um índice escalável <code>photos</code> de vetores de imagem e EXIF (para recuperação). É prático, reproduzível e fácil de expandir.</p><p>Se você quiser ajustá-lo, existem algumas configurações que você pode modificar:</p><ul><li><p><strong>Configurações de tempo de consulta:</strong> <code>k</code> (quantos vizinhos você deseja retornar) e <code>num_candidates</code> (quão ampla a pesquisa antes da pontuação final). Essas configurações são discutidas no blog <a href="https://www.elastic.co/search-labs/blog/elasticsearch-knn-and-num-candidates-strategies">aqui</a>.</p></li><li><p><strong>Configurações de tempo de indexação:</strong> <code>m</code> (conectividade do grafo) e <code>ef_construction</code> (precisão do tempo de construção vs. memória). Para consultas, experimente também com <code>ef_search</code> — um valor maior geralmente significa melhor recuperação com alguma compensação de latência. Consulte <a href="https://www.elastic.co/search-labs/blog/hnsw-graph">este blog</a> para obter mais detalhes sobre essas configurações.</p></li></ul><p>Olhando para o futuro, modelos/reclassificadores nativos para busca <strong>multimodal</strong> e <strong>multilíngue</strong> chegarão em breve ao ecossistema Elastic, o que deverá tornar a recuperação de imagens/texto e a classificação híbrida ainda mais robustas e prontas para uso.<a href="https://ir.elastic.co/news/news-details/2025/Elastic-Completes-Acquisition-of-Jina-AI-a-Leader-in-Frontier-Models-for-Multimodal-and-Multilingual-Search/default.aspx?utm_source=chatgpt.com"> ir.elastic.co+1</a></p><p>Se você quiser experimentar você mesmo:</p><ul><li><p><strong>Repositório do GitHub:</strong> <a href="https://github.com/navneet83/multimodal-mountain-peak-search"><em>https://github.com/navneet83/multimodal-mountain-peak-search</em></a></p></li><li><p><strong>Guia rápido do Colab:</strong> <a href="https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/notebooks/multimodal_mountain_peak_search.ipynb">https://github.com/navneet83/multimodal-mountain-peak-search/blob/main/notebooks/multimodal_mountain_peak_search.ipynb</a></p></li></ul><p>Com isso, nossa jornada chegou ao fim e é hora de voltar para casa. Espero que isso tenha sido útil e, se você quebrar alguma coisa (ou melhorar alguma coisa), adoraria saber o que você mudou.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdce2fff1569d2a8b/6a17da894b055dd1f24320a2/d324d1e1472f1bfbd8f25747f57bdeeb9c7f16b2-1600x1200.png" alt="" />]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/multimodal-search-siglip-2-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/multimodal-search-siglip-2-elasticsearch</guid>
    <category><![CDATA[Banco de dados vetorial]]></category>
    <category><![CDATA[Busca híbrida]]></category>
    <category><![CDATA[AI]]></category>
    <category><![CDATA[Python]]></category>
    <dc:creator><![CDATA[Navneet Kumar]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltccb66279debb05f9/6a17da8b63baffe228741b15/ffcf93358a7c5dadcea82faf3de460bf060d003c-1600x1200.png" length="0" type="image/png"/>
    <pubDate>Tue, 04 Nov 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Experimentos para aprimorar ferramentas de IA Agética para Elasticsearch]]></title>
    <description><![CDATA[Saiba como aprimoramos os fluxos de trabalho de agentes de IA para Elasticsearch por meio de experimentos iterativos, combinando recuperadores lineares, busca híbrida e semantic_text para otimização RAG escalável.]]></description>
    <content:encoded><![CDATA[<p>Assim como todo mundo hoje em dia, aqui na Elastic, estamos investindo pesado em Chat, Agentes e RAG. Na área de Busca, temos trabalhado recentemente em um Construtor de Agentes e um Registro de Ferramentas, tudo com o intuito de tornar trivial a interação com seus dados no Elasticsearch.</p><p>Leia o <a href="https://www.elastic.co/search-labs/blog/ai-agentic-workflows-elastic-ai-agent-builder">artigo "Building AI Agentic Workflows with Elasticsearch"</a> para obter mais informações sobre o panorama geral desse projeto, ou <a href="https://www.elastic.co/search-labs/blog/ai-agent-builder-elasticsearch">"Your First Elastic Agent: From a Single Query to a AI-Powered Chat"</a> para uma introdução mais prática.</p><p>Neste blog, porém, vamos nos aprofundar um pouco em uma das primeiras coisas que acontecem quando você começa a conversar e apresentar algumas das melhorias recentes que implementamos.</p><h2>O que está acontecendo aqui?</h2><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1331b1043612efe3/6a17f115505ac3dc41ad8c3c/25a24055a166d7d6ba81d80aa35cb97163662e23-1600x443.png" alt="" /><p>Ao interagir com seus dados do Elasticsearch, nosso agente de IA padrão segue este fluxo padrão:</p><ol><li><p>Examine o prompt.</p></li><li><p>Identifique qual índice provavelmente contém as respostas para essa pergunta.</p></li><li><p>Gere uma consulta para esse índice, com base no prompt.</p></li><li><p>Pesquise esse índice com essa consulta.</p></li><li><p>Sintetize os resultados.</p></li><li><p>Os resultados respondem à pergunta? Em caso afirmativo, responda. Caso contrário, repita, mas tente algo diferente.</p></li></ol><p>Isso não deve parecer muito inovador - é apenas Geração Aumentada por Recuperação (RAG). E, como seria de esperar, a qualidade das suas respostas depende muito da relevância dos resultados da sua pesquisa inicial. Enquanto trabalhávamos para melhorar a qualidade de nossas respostas, prestamos muita atenção às consultas que gerávamos na etapa 3 e executávamos na etapa 4. E percebemos um padrão interessante.</p><p>Muitas vezes, quando nossas primeiras respostas eram "ruins", não era porque tínhamos executado uma consulta ruim. Isso aconteceu porque <em>tínhamos escolhido o índice errado</em> para consultar. Os passos 3 e 4 geralmente não eram o nosso problema - era o passo 2.</p><h2>O que estávamos fazendo?</h2><p>Nossa implementação inicial foi simples. Tínhamos criado uma ferramenta (chamada index_explorer) que efetivamente faria um <code>_cat/indices</code> para listar todos os índices disponíveis para nós e, em seguida, pediria ao LLM para identificar qual desses índices era a melhor correspondência para a mensagem/pergunta/solicitação do usuário. Você pode ver a <a href="https://github.com/elastic/kibana/blob/0cc78184957fcd12110dabae50353392ea937508/x-pack/platform/packages/shared/onechat/onechat-genai-utils/tools/index_explorer.ts#L98-L113">implementação original aqui</a>.</p>You are an AI assistant for the Elasticsearch company.
based on a natural language query from the user, your task is to select up to ${limit} most relevant indices from a list of indices.

*The natural language query is:* ${nlQuery}

*List of indices:*
${indices.map((index) =&gt; `- ${index.index}`).join('\n')}

Based on those information, please return most relevant indices with your reasoning.
Remember, you should select at maximum ${limit} indices.<p>Quão bem isso estava funcionando? Não tínhamos certeza! Tínhamos exemplos claros de situações em que <em>não estava</em> funcionando bem, mas nosso primeiro desafio real foi quantificar nossa situação atual.</p><h2>Estabelecer uma linha de base</h2><h3>Tudo começa com dados.</h3><p>O que precisávamos era de um Conjunto de Dados Ideal para medir a eficácia de uma ferramenta na seleção do índice correto, dada uma solicitação do usuário e um conjunto preexistente de índices. E nós não tínhamos um conjunto de dados desse tipo disponível. Então, nós geramos um.</p><p>Reconhecimento: Sabemos que isso não é a "melhor prática". Mas, às vezes, é melhor seguir em frente do que ficar discutindo detalhes irrelevantes. <a href="https://www.elastic.co/about/our-source-code#progress-perfection">Progresso, SIMPLES Perfeição</a>.</p><p>Geramos índices iniciais para vários domínios diferentes usando <a href="https://gist.github.com/seanstory/a08db2e149897da656db3a1ca72e17ac">este prompt</a>. Em seguida, para cada domínio gerado, geramos mais alguns índices usando<a href="https://gist.github.com/seanstory/a280a85d067e61bfeb5911bf2654e6e2"> esse prompt</a> (o objetivo aqui é semear confusão para o LLM com negativos difíceis e exemplos difíceis de classificar). Em seguida, editamos manualmente cada índice gerado e suas respectivas descrições. Por fim, geramos consultas de teste usando <a href="https://gist.github.com/seanstory/44291b666c05a383136f6e36bb9106fa">esse prompt</a>. Isso nos deixou com dados de exemplo como:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1bd9cd78154195e3/6a17f117dbb4fff7b5fb57d2/9d96d87e286eddbc012402b1ecccd57419a99253-1600x782.png" alt="" /><p>e casos de teste como:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltadf30a0aeafd56ef/6a17f1192f4a5c160ffa89eb/4c2e9ad941d98d7e66033bbc08c9b8060ec19097-1600x797.png" alt="" /><h3>Construindo um arnês de teste</h3><p>A partir daqui, o processo foi muito simples. Crie uma ferramenta que possa:</p><ol><li><p>Crie um ambiente totalmente novo com um cluster Elasticsearch de destino.</p></li><li><p>Crie todos os índices definidos no conjunto de dados de destino.</p></li><li><p>Para cada cenário de teste, execute a ferramenta i<code>ndex_explorer</code> (felizmente, temos uma <a href="https://www.elastic.co/docs/api/doc/kibana/operation/operation-post-agent-builder-tools-execute">API Execute Tool</a>).</p></li><li><p>Compare o índice resultante com o índice esperado e registre o resultado.</p></li><li><p>Após concluir todos os cenários de teste, tabule os resultados.</p></li></ol><h3>A pesquisa indica…</h3><p>Os resultados iniciais foram, previsivelmente, medíocres.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt73367741359e258d/6a17f11a505ac39749ad8c40/9c10679bcd6291edfa2a9ba42e7dd922aa483f0b-1216x806.png" alt="" /><p>No geral, a precisão na identificação do índice correto foi de 77,14%. E isso no cenário "ideal", onde todos os índices têm nomes bons e semanticamente significativos. Qualquer pessoa que já tenha executado um `PUT test2/_doc/foo {...}` sabe que seus índices nem sempre têm nomes significativos.</p><p>Portanto, temos uma base de referência, e ela mostra que há muito espaço para melhorias. Chegou a hora de fazer ciência! 🧪</p><h2>Experimentação</h2><h3>Hipótese 1: Os mapeamentos ajudarão</h3><p>O objetivo aqui é identificar um índice que contenha dados relevantes para a pergunta original. E a parte de um índice que melhor descreve os dados que ele contém são os <em>mapeamentos</em> do índice. Mesmo sem obter nenhuma amostra do conteúdo do índice, saber que o índice possui um campo de preço do tipo double implica que os dados representam algo que está à venda. Um campo de autor do tipo texto implica alguns dados linguísticos não estruturados. A combinação dos dois pode sugerir que os dados são livros/histórias/poemas. Podemos obter muitas pistas semânticas apenas conhecendo as propriedades de um índice. Então, em uma branch local, eu ajustei nosso arquivo `.index_explorer`. Ferramenta para enviar os mapeamentos completos de um índice (juntamente com seu nome) ao LLM para que este tome uma decisão. </p><p>O resultado (dos registros do Kibana):</p>[2025-09-05T11:01:21.552-05:00][ERROR][plugins.onechat] Error: Error calling connector: event: error
data: {"error":{"code":"request_entity_too_large","message":"Received a content too large status code for request from inference entity id [.rainbow-sprinkles-elastic] status [413]","type":"error"}}


    at createInferenceProviderError (errors.ts:90:10)
    at convertUpstreamError (convert_upstream_error.ts:39:38)
    at handle_connector_response.ts:26:33
    at Observable.init [as _subscribe] (/Users/seanstory/Desktop/Dev/kibana/node_modules/rxjs/src/internal/observable/throwError.ts:123:68)...<p>Os autores originais da ferramenta já haviam previsto isso. Embora o mapeamento de um índice seja uma mina de ouro de informações, ele também é um bloco JSON bastante extenso. E em um cenário realista onde você está comparando inúmeros índices (nosso conjunto de dados de avaliação define 20), esses blocos JSON se acumulam. Assim, queremos fornecer ao LLM mais contexto para sua decisão, não apenas os nomes dos índices de todas as opções, mas também os mapeamentos completos de cada uma.</p><h3>Hipótese 2: Mapeamentos “achatados” (listas de campos) como solução de compromisso.</h3><p>Partimos do pressuposto de que os criadores de índices usarão nomes de índice semanticamente significativos. E se estendermos essa suposição também aos nomes dos campos? Nosso experimento anterior falhou porque o mapeamento de JSON inclui MUITOS metadados e código repetitivo desnecessários.</p>     "description_text": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          },
          "copy_to": [
            "description_semantic"
          ]
        },<p>O bloco acima, por exemplo, tem 236 caracteres e define apenas um único campo em um mapeamento do Elasticsearch. Enquanto a string “description_text” possui apenas 16 caracteres. Isso representa um aumento de quase 15 vezes na contagem de caracteres, sem uma melhoria semântica significativa na descrição do que esse campo implica sobre os dados disponíveis. E se buscássemos os mapeamentos para todos os índices, mas antes de enviá-los para o LLM, os "aplanássemos" em uma lista contendo apenas os nomes de seus campos?</p><p>Nós experimentamos.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta5eda7a79493ee81/6a17f11c9da390327fe46590/112c2f447c11f154b5082725cd49b51d0a3c8a65-1214x804.png" alt="" /><p>Isso é ótimo! Melhorias em todos os aspectos. Mas será que poderíamos fazer melhor?</p><h3>Hipótese 3: Descrições no mapeamento _meta</h3><p>Se apenas os nomes dos campos, sem nenhum contexto adicional, causaram um salto tão grande, presumivelmente adicionar um contexto substancial seria ainda melhor! Não é necessariamente convencional que cada índice tenha uma descrição associada, mas é possível adicionar metadados de qualquer tipo ao objeto _meta do mapeamento. Retornamos aos índices gerados e adicionamos descrições para cada índice em nosso conjunto de dados. Contanto que as descrições não sejam excessivamente longas, elas devem usar menos tokens do que o mapeamento completo e fornecer informações significativamente melhores sobre quais dados estão incluídos no índice. Nosso experimento validou essa hipótese.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt61b85cf40e0e6357/6a17f11dfbc5f82809491bbe/32d2692ad4479d0e52d8ee723dcc5710a6ec90f3-1208x806.png" alt="" /><p>Uma pequena melhoria, e agora temos mais de 90% de precisão em todos os aspectos.</p><h3>Hipótese 4: O todo é maior que a soma das partes.</h3><p>Os nomes dos campos aumentaram nossos resultados. As descrições aumentaram nossos resultados. Portanto, utilizar <em>tanto </em>as descrições quanto os nomes dos campos deve apresentar resultados ainda melhores, certo?</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte6297c6aaf7db802/6a17f11e14d90c1bd779b6e6/114cbb408ff16b136251d2265416bd5270380fe5-1208x794.png" alt="" /><p>Os dados indicaram "não" (nenhuma mudança em relação ao experimento anterior). A principal teoria era que, como as descrições foram geradas a partir dos campos/mapeamentos do índice, não havia informações suficientes entre esses dois contextos para adicionar algo "novo" ao combiná-los. Além disso, a carga útil que estamos enviando para nossos 20 índices de teste está ficando bastante grande. A linha de raciocínio que seguimos até agora não é escalável. Na verdade, há bons motivos para acreditar que nenhum dos nossos experimentos até agora funcionaria em clusters Elasticsearch, onde existem centenas ou milhares de índices para escolher. Qualquer abordagem que aumente linearmente o tamanho da mensagem enviada ao LLM à medida que o número total de índices aumenta provavelmente não será uma estratégia generalizável.</p><p>O que realmente precisamos é de uma abordagem que nos ajude a reduzir um grande número de candidatos apenas às opções mais relevantes…</p><p>O que temos aqui é um problema de busca.</p><h3>Hipótese 5: Seleção via busca semântica</h3><p>Se o nome de um índice tiver significado semântico, ele poderá ser armazenado como um vetor e pesquisado semanticamente.</p><p>Se os nomes dos campos de um índice tiverem significado semântico, eles podem ser armazenados como vetores e pesquisados semanticamente.</p><p>Se um índice possui uma descrição com significado semântico, ele também pode ser armazenado como um vetor e pesquisado semanticamente.</p><p>Atualmente, os índices do Elasticsearch não tornam nenhuma dessas informações pesquisável (talvez devêssemos!), mas foi bastante trivial<a href="https://github.com/elastic/connectors/pull/3638"> improvisar algo</a> que pudesse contornar essa lacuna. Utilizando a estrutura de conectores da Elastic, criei um conector que gera um documento para cada índice em um cluster. Os documentos resultantes seriam algo como:</p> doc = {
                "_id": index_name,
                "index_name": index_name,
			"meta_description”: description,
"field_descriptions" = field_descriptions,
                "mapping": json.dumps(mapping),  
                "source_cluster": self.es_client.configured_host,
            }<p>Enviei esses documentos para um novo índice onde defini manualmente o mapeamento da seguinte forma:</p>{
   "mappings": {
       "properties": {
           "semantic_content": {
               "type": "semantic_text"
           },
           "index_name": {
               "type": "text",
               "copy_to": "semantic_content"
           },
           "mapping": {
               "type": "keyword",
               "copy_to": "semantic_content"
           },
           "source_cluster": {
               "type": "keyword"
           },
           "meta_description": {
               "type": "text",
               "copy_to": "semantic_content"
           },
           "field_descriptions": {
               "type": "text",
               "copy_to": "semantic_content"
           }
       }
   }
}<p>Isso cria um único campo semantic_content, onde todos os outros campos com significado semântico são divididos em blocos e indexados. A busca neste índice torna-se trivial, bastando:</p>GET indexed-indices/_search
{
 "query": {
   "semantic": {
     "field": "semantic_content",
     "query": "$query"
   }
 }
}<p>A ferramenta <code>index_explorer</code> modificada agora é <em>muito</em> mais rápida, pois não precisa fazer uma solicitação a um LLM, mas pode solicitar um único embedding para a consulta fornecida e executar uma operação de busca vetorial eficiente. Considerando o resultado mais relevante como nosso índice selecionado, obtivemos os seguintes resultados:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc27c302e6bef0b23/6a17f120577262d2f21bccdc/06ef5d78040d064d3444793f636d527d9e19a869-1214x800.png" alt="" /><p>Essa abordagem é escalável. Essa abordagem é eficiente. Mas essa abordagem é pouco melhor do que a nossa abordagem inicial. Isso não é surpreendente; a abordagem de busca aqui é incrivelmente ingênua. Não há nuances. Não há reconhecimento de que o nome e a descrição de um índice devam ter mais peso do que um nome de campo arbitrário que o índice contenha. Não há como priorizar correspondências lexicais exatas em detrimento de correspondências sinônimas. No entanto, construir uma consulta altamente detalhada exigiria muitas suposições sobre os dados disponíveis. Até agora, já fizemos algumas suposições importantes sobre o significado semântico dos nomes de índices e campos, mas precisaríamos ir um passo além e começar a supor <em>o quanto</em> de significado eles têm e como se relacionam entre si. Sem fazer isso, provavelmente não conseguiremos identificar com segurança a melhor correspondência como nosso resultado principal, mas podemos afirmar com mais certeza que a melhor correspondência está em algum lugar entre os N melhores resultados. Precisamos de algo que possa consumir informações semânticas no contexto em que existem, comparando-as com outra entidade que pode se representar de uma maneira semanticamente distinta, e fazendo um julgamento entre elas. Como um mestrado em Direito.</p><h3>Hipótese 6: Redução do conjunto de candidatos</h3><p>Houve vários outros experimentos que vou abordar superficialmente, mas o principal avanço foi abandonar a ideia de escolher a melhor correspondência puramente com base em uma busca semântica e, em vez disso, usar a busca semântica como um filtro para eliminar índices irrelevantes da análise do LLM. Combinamos os algoritmos Linear Retrievers, Hybrid Search com RRF e <code>semantic_text</code> em <a href="https://gist.github.com/seanstory/d704443120e20f6c844db10e30066860">nossa busca</a>, limitando os resultados aos 5 índices de correspondência principais.</p><p>Em seguida, para cada correspondência, adicionamos o nome do índice, a descrição e os nomes dos campos a uma mensagem para o LLM. Os resultados foram fantásticos:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7ac4cb8f7153fdf9/6a17f121af47b66d1dcde082/8fcabd78f591f90d6bc7c0e087d31317e4eef791-1206x804.png" alt="" /><p>A maior precisão obtida em qualquer experimento até hoje! E como essa abordagem não aumenta o tamanho da mensagem proporcionalmente ao número total de índices, ela é muito mais escalável.</p><h2>Resultados</h2><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8d66130d9fae6bea/6a17f123ddf97d7527910c19/04d630797213dbb8bf567da41d1cdd5c7b4586c9-1600x521.png" alt="" /><p>O primeiro resultado claro foi que nossa linha de base <em>pode</em> ser melhorada. Isso parece óbvio em retrospectiva, mas antes do início da experimentação, houve uma discussão séria sobre se deveríamos abandonar completamente nossa ferramenta <code>index_explorer</code> e confiar na configuração explícita do usuário para limitar o espaço de busca. Embora essa ainda seja uma opção viável e válida, esta pesquisa mostra que existem caminhos promissores para automatizar a seleção de índices quando essas informações fornecidas pelo usuário não estão disponíveis.</p><p>A próxima conclusão clara foi que simplesmente adicionar mais caracteres descritivos ao problema tem resultados cada vez menores. Antes desta pesquisa, estávamos debatendo se deveríamos investir na expansão da capacidade do Elasticsearch para armazenar <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/mapping-field-meta">metadados em nível de campo</a>. Atualmente, esses valores <code>meta</code> são limitados a 50 caracteres, e havia uma suposição de que precisaríamos aumentar esse valor para podermos obter uma compreensão semântica de nossos campos. Claramente, esse não é o caso, e o LLM parece funcionar muito bem apenas com os nomes das áreas de estudo. Poderemos investigar isso mais a fundo posteriormente, mas já não parece urgente.</p><p>Por outro lado, isso forneceu evidências claras da importância de se ter metadados de índice "pesquisáveis". Para esses experimentos, nós hackeamos um índice de índices. Mas isso é algo que poderíamos investigar, integrando diretamente ao Elasticsearch, criando APIs para gerenciar ou, pelo menos, estabelecendo uma convenção a respeito. Estaremos avaliando nossas opções e discutindo internamente, então fiquem atentos.</p><p>Finalmente, esse esforço confirmou o valor de dedicarmos tempo para experimentar e tomar decisões baseadas em dados. Na verdade, isso nos ajudou a reafirmar que nosso produto Agent Builder precisará de recursos robustos de avaliação integrados. Se precisarmos construir toda uma estrutura de testes apenas para uma ferramenta que seleciona índices, nossos clientes certamente precisarão de maneiras de avaliar qualitativamente suas ferramentas personalizadas à medida que fazem ajustes iterativos.</p><p>Estou ansioso para ver o que vamos construir, e espero que você também esteja!</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/ai-agent-builder-experiments-performance</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/ai-agent-builder-experiments-performance</guid>
    <category><![CDATA[IA agêntica]]></category>
    <category><![CDATA[Na Elastic]]></category>
    <category><![CDATA[Busca híbrida]]></category>
    <dc:creator><![CDATA[Sean Story]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt68d11a4c7fd11d4c/6a17f1257b54f9b6598b39d4/42903c869e034674b30bb36013345aaa97f6608b-1184x864.png" length="0" type="image/png"/>
    <pubDate>Mon, 06 Oct 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Busca híbrida revisitada: apresentando o recuperador linear no Elasticsearch!]]></title>
    <description><![CDATA[Descubra como o recuperador linear aprimora a busca híbrida, aproveitando pontuações ponderadas e normalização MinMax para classificações mais precisas e consistentes, e aprenda a usá-lo.]]></description>
    <content:encoded><![CDATA[<p>Em nossa postagem <a href="https://www.elastic.co/pt/search-labs/blog/elasticsearch-retrievers-ga-8.16.0">anterior,</a> apresentamos a estrutura de recuperadores redesenhada do zero, que permite a criação de pipelines de classificação complexos. Também exploramos como o recuperador Reciprocal Rank Fusion (RRF) permite a pesquisa híbrida ao mesclar resultados de diferentes consultas. Embora o RRF seja fácil de implementar, ele tem uma limitação notável: ele se concentra apenas em classificações relativas, ignorando pontuações reais. Isso torna o ajuste fino e a otimização um desafio.</p><h2>Conheça o retriever linear!</h2><p>Nesta postagem, apresentamos o <a href="https://www.elastic.co/pt/docs/solutions/search/retrievers-overview#retrievers-overview-types">recuperador</a> <a href="https://www.elastic.co/pt/docs/solutions/search/retrievers-overview#retrievers-overview-types"><code>linear</code></a> , nossa mais recente adição para oferecer suporte à pesquisa híbrida! Ao contrário de <code>rrf</code>, o recuperador <code>linear</code> calcula uma soma ponderada em todas as consultas que correspondem a um documento. Essa abordagem preserva a importância relativa de cada documento dentro de um conjunto de resultados, ao mesmo tempo que permite controle preciso sobre a influência de cada consulta na pontuação final. Como resultado, ele fornece uma maneira mais intuitiva e flexível de ajustar a pesquisa híbrida.</p><p>Definindo um recuperador linear onde a pontuação final será calculada como:</p><p>É tão simples quanto:</p>GET linear_retriever_blog/_search
{
   "retriever": {
       "linear": {
           "retrievers": [
               {
                   "retriever": {
                       "knn": {
                          ...
                        }
                    },
                   "weight": 5
               },
                  {
                   "retriever": {
                       "standard": {
                          ...
                        }
                    },
                   "weight": 1.5
               },


           ]
        }
     }
}<p>Percebeu como é simples e intuitivo? (e muito parecido com <code>rrf</code>!) Essa configuração permite que você controle precisamente quanto cada tipo de consulta contribui para a classificação final, ao contrário de <code>rrf</code>, que depende apenas de classificações relativas.</p><p>Uma ressalva permanece: as pontuações <code>knn</code> podem ser estritamente limitadas, dependendo da métrica de similaridade usada. Por exemplo, com similaridade de cosseno ou produto escalar de vetores normalizados por unidade, as pontuações sempre estarão dentro do intervalo <code>[0, 1]</code> . Em contraste, as pontuações <code>bm25</code> são menos previsíveis e não têm limites claramente definidos.</p><h2>Escalando as pontuações: kNN vs BM25</h2><p>Um desafio da busca híbrida é que diferentes recuperadores produzem pontuações em escalas diferentes. Considere, por exemplo, o seguinte cenário:</p><p>Pontuações da consulta A:</p><p></p><p>doc1</p><p>doc2</p><p>doc3</p><p>doc4</p><p>knn</p><p>0,347</p><p>0,35</p><p>0,348</p><p>0,346</p><p>bm25</p><p>100</p><p>1,5</p><p>1</p><p>0,5</p><p>Pontuações da consulta B:</p><p></p><p>doc1</p><p>doc2</p><p>doc3</p><p>doc4</p><p>knn</p><p>0,347</p><p>0,35</p><p>0,348</p><p>0,346</p><p>bm25</p><p>0,63</p><p>0,01</p><p>0,3</p><p>0,4</p><p>Você pode ver a disparidade acima: as pontuações <code>kNN</code> variam entre 0 e 1, enquanto as pontuações <code>bm25</code> podem variar muito. Essa diferença dificulta a definição de pesos estáticos ideais para combinar os resultados.</p><h2>Normalização para o resgate: o normalizador MinMax</h2><p>Para resolver isso, introduzimos um normalizador <code>minmax</code> opcional que dimensiona as pontuações, independentemente para cada consulta, para o intervalo <code>[0, 1]</code> usando a seguinte fórmula:</p><p>Isso preserva a importância relativa de cada documento dentro do conjunto de resultados de uma consulta, facilitando a combinação de pontuações de diferentes recuperadores. Com a normalização, as pontuações se tornam:</p><p>Pontuações da consulta A:</p><p></p><p>doc1</p><p>doc2</p><p>doc3</p><p>doc4</p><p>knn</p><p>0,347</p><p>0,35</p><p>0,348</p><p>0,346</p><p>bm25</p><p>1,00</p><p>0,01</p><p>0,005</p><p>0,000</p><p>Pontuações da consulta B:</p><p></p><p>doc1</p><p>doc2</p><p>doc3</p><p>doc4</p><p>knn</p><p>0,347</p><p>0,35</p><p>0,348</p><p>0,346</p><p>bm25</p><p>1,00</p><p>0,000</p><p>0,465</p><p>0,645</p><p>Todas as pontuações agora estão no intervalo <code>[0, 1]</code> e otimizar a soma ponderada é muito mais simples, pois agora capturamos a importância (em relação à consulta) de um resultado em vez de sua pontuação absoluta e mantemos a consistência entre as consultas.</p><h2>Exemplo de recuperador linear </h2><p>Vamos ver um exemplo agora para mostrar a aparência do exemplo acima e como o recuperador <code>linear</code> aborda algumas das deficiências do <code>rrf</code>. O RRF depende somente de classificações relativas e não considera diferenças reais de pontuação. Por exemplo, dadas estas pontuações:</p><p></p><p>doc1</p><p>doc2</p><p>doc3</p><p>doc4</p><p>knn</p><p>0,347</p><p>0,35</p><p>0,348</p><p>0,346</p><p>bm25</p><p>100</p><p>1,5</p><p>1</p><p>0,5</p><p>pontuação rrf</p><p>0,03226</p><p>0,03252</p><p>0,03200</p><p>0,03125</p><p>rrf classificaria os documentos como:</p><p>No entanto, doc1 tem uma pontuação <code>bm25</code> significativamente maior que as outras, o que <code>rrf</code> não consegue capturar porque só analisa classificações relativas. O recuperador <code>linear</code> , combinado com a normalização, contabiliza corretamente as pontuações e suas diferenças, produzindo uma classificação mais significativa:</p><p></p><p>doc1</p><p>doc2</p><p>doc3</p><p>doc4</p><p>knn</p><p>0,347</p><p>0,35</p><p>0,348</p><p>0,346</p><p>bm25</p><p>1</p><p>0,01</p><p>0,005</p><p>0</p><p>Como podemos ver acima, a ótima classificação do doc1 e <code>score</code> para <code>bm25</code> são devidamente contabilizadas e refletidas nas pontuações finais. Além disso, todas as pontuações agora estão no intervalo <code>[0, 1]</code> para que possamos compará-las e combiná-las de uma forma muito mais intuitiva (e até mesmo criar processos de otimização offline).</p><h2>Juntando tudo</h2><p>Para aproveitar ao máximo o recuperador <code>linear</code> com normalização, a solicitação de pesquisa ficaria assim:</p>GET linear_retriever_blog/_search
{
   "retriever": {
       "linear": {
           "retrievers": [
               {
                   "retriever": {
                       "knn": {
                          ...
                        }
                    },
                   "weight": 5
               },
                  {
                   "retriever": {
                       "standard": {
                          ...
                        }
                    },
                   "weight": 1.5,
                   "normalizer": "minmax"
               },


           ]
       }
   }
}<p>Essa abordagem combina o melhor dos dois mundos: ela mantém a flexibilidade e a pontuação intuitiva do recuperador <code>linear</code> , ao mesmo tempo em que garante uma escala de pontuação consistente com a normalização MinMax.</p><p>Assim como todos os nossos recuperadores, o recuperador <code>linear</code> pode ser integrado a qualquer nível de uma árvore hierárquica de recuperadores, com suporte para explicabilidade, destaque de correspondência, recolhimento de campo e muito mais.</p><h2>Quando escolher o retriever linear e por que isso faz a diferença</h2><p>O recuperador <code>linear</code> :</p><ul><li><p>Preserva a importância relativa aproveitando pontuações reais, não apenas classificações.</p></li><li><p>Permite ajustes finos com contribuições ponderadas de diferentes consultas.</p></li><li><p>Melhora a consistência usando a normalização, tornando a pesquisa híbrida mais robusta e previsível.</p></li></ul><h2>Conclusão</h2><p>O recuperador <code>linear</code> já está disponível no Elasticsearch Serverless e nas versões 8.18 e 9.0! Mais exemplos e parâmetros de configuração também podem ser encontrados em nossa documentação. Experimente e veja como ele pode melhorar sua experiência de pesquisa híbrida — aguardamos seu feedback. Boa busca!</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/linear-retriever-hybrid-search</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/linear-retriever-hybrid-search</guid>
    <category><![CDATA[Relevância]]></category>
    <category><![CDATA[Busca híbrida]]></category>
    <dc:creator><![CDATA[Panagiotis Bailis]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte58a751cbcc1153d/6a17e3c76317305c4f585a10/7a07e27e3095463ff93b4cb7f8a0cf3b8e44eab0-1777x1000.png" length="0" type="image/png"/>
    <pubDate>Wed, 28 May 2025 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>