← Back to home

Busca Semântica

By Pscodium · 8/4/2026 · 3 views

Busca Semântica na Prática com Embeddings

No artigo anterior vimos que a busca semântica tenta encontrar resultados com base no significado de uma consulta, e não apenas nas palavras exatas utilizadas.

Por exemplo, imagine que temos estes documentos:

1. "Como melhorar o desempenho do seu computador"
2. "Como preparar um bolo de chocolate"
3. "Como configurar um servidor Linux"

O usuário pesquisa:

"Meu PC está muito lento"

Uma busca lexical pode ter dificuldade porque o documento fala:

computador

enquanto o usuário escreveu:

PC

Já uma busca semântica consegue perceber que:

"Meu PC está muito lento"

e:

"Como melhorar o desempenho do seu computador"

possuem significados relacionados.

Para fazer isso, podemos utilizar Embeddings.


1. O que são Embeddings?

Um embedding transforma um texto em uma representação numérica.

Por exemplo:

"Meu PC está muito lento"

pode ser convertido conceitualmente em:

[0.12, -0.34, 0.87, 0.22, ...]

Outro texto:

"Como melhorar o desempenho do seu computador"

também recebe um vetor:

[0.10, -0.31, 0.84, 0.25, ...]

Como os vetores são parecidos, podemos considerar que os textos possuem uma relação semântica.

O fluxo é:

Texto
  ↓
Embedding Model
  ↓
Vetor
  ↓
Comparação
  ↓
Documentos mais semelhantes

2. Instalando o SDK

Vamos utilizar o SDK da OpenAI:

npm install openai

Também precisamos configurar nossa API Key:

OPENAI_API_KEY=sua_api_key

3. Gerando Embeddings

Vamos criar uma função para transformar um texto em embedding.

import OpenAI from "openai";

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

async function createEmbedding(text: string) {
  const response = await openai.embeddings.create({
    model: "text-embedding-3-small",
    input: text,
  });

  return response.data[0].embedding;
}

Agora podemos fazer:

const embedding = await createEmbedding(
  "Meu PC está muito lento"
);

console.log(embedding);

O resultado será um vetor numérico.


4. Criando nossos documentos

Vamos imaginar que temos uma pequena base de conhecimento:

const documents = [
  {
    id: 1,
    text: "Como melhorar o desempenho do seu computador",
  },
  {
    id: 2,
    text: "Como preparar um bolo de chocolate",
  },
  {
    id: 3,
    text: "Como configurar um servidor Linux",
  },
];

Precisamos gerar um embedding para cada documento.

for (const document of documents) {
  document.embedding = await createEmbedding(
    document.text
  );
}

Agora cada documento possui:

Document
├── id
├── text
└── embedding

Por exemplo:

{
  id: 1,
  text: "Como melhorar o desempenho do seu computador",
  embedding: [0.12, -0.31, 0.84, ...]
}

5. Comparando Embeddings

Uma maneira comum de comparar embeddings é utilizando Cosine Similarity.

A fórmula é:

similarity(A, B) =
    A · B
    ───────
    ||A|| ||B||

Em TypeScript:

function cosineSimilarity(
  a: number[],
  b: number[]
): number {
  let dotProduct = 0;
  let magnitudeA = 0;
  let magnitudeB = 0;

  for (let i = 0; i < a.length; i++) {
    dotProduct += a[i] * b[i];

    magnitudeA += a[i] ** 2;

    magnitudeB += b[i] ** 2;
  }

  return (
    dotProduct /
    (Math.sqrt(magnitudeA) *
      Math.sqrt(magnitudeB))
  );
}

Quanto maior o resultado, maior a similaridade entre os textos.


6. Realizando uma busca

Agora podemos criar nossa função de busca:

async function semanticSearch(
  query: string
) {
  const queryEmbedding =
    await createEmbedding(query);

  const results = documents.map((document) => ({
    ...document,
    score: cosineSimilarity(
      queryEmbedding,
      document.embedding
    ),
  }));

  return results.sort(
    (a, b) => b.score - a.score
  );
}

Podemos pesquisar:

const results = await semanticSearch(
  "Meu PC está muito lento"
);

console.log(results);

O resultado poderia ser:

[
  {
    id: 1,
    text: "Como melhorar o desempenho do seu computador",
    score: 0.89
  },
  {
    id: 3,
    text: "Como configurar um servidor Linux",
    score: 0.42
  },
  {
    id: 2,
    text: "Como preparar um bolo de chocolate",
    score: 0.08
  }
]

Observe que o usuário pesquisou:

"Meu PC está muito lento"

Mas o resultado mais relevante foi:

"Como melhorar o desempenho do seu computador"

Mesmo que as palavras não sejam exatamente iguais.

Isso é o conceito fundamental da busca semântica.


7. O problema dessa implementação

Nosso exemplo funciona para demonstrar o conceito, mas não seria uma boa solução para produção.

Imagine:

10 documentos

Podemos comparar a query com todos eles.

Mas imagine:

10 milhões de documentos

Não queremos fazer:

Query
 ↓
Comparar com 10 milhões de vetores
 ↓
Ordenar tudo

Isso seria muito lento.

Em sistemas reais, normalmente utilizamos um:

Vector Database

ou um mecanismo de busca que suporte pesquisa vetorial.

Algumas opções são:

PostgreSQL + pgvector
Qdrant
Pinecone
Weaviate
Milvus
Elasticsearch
OpenSearch

O fluxo passa a ser:

                 DOCUMENTOS
                      ↓
                Embeddings
                      ↓
                Vector Database
                      ↑
                      │
Usuário → Query → Embedding
                      │
                      ↓
               Vector Search
                      ↓
             Top K resultados

8. Usando PostgreSQL + pgvector

Se já utilizamos PostgreSQL, podemos armazenar embeddings utilizando a extensão:

pgvector

A tabela poderia ser:

CREATE TABLE documents (
  id SERIAL PRIMARY KEY,
  content TEXT NOT NULL,
  embedding VECTOR(1536)
);

O tamanho do vetor depende do modelo utilizado.

Podemos armazenar:

Documento
    ↓
Embedding
    ↓
PostgreSQL

E depois procurar os vetores mais próximos.

Conceitualmente:

SELECT
  id,
  content
FROM documents
ORDER BY embedding <=> $1
LIMIT 10;

O operador:

<=>

pode ser utilizado para calcular distância de cosseno no pgvector.

O banco retorna os documentos mais próximos semanticamente da consulta.


9. Arquitetura completa

Uma aplicação real poderia funcionar assim:

Usuário
   │
   │ "Meu computador está lento"
   ▼
Backend
   │
   ▼
OpenAI Embeddings
   │
   ▼
Query Vector
   │
   ▼
PostgreSQL + pgvector
   │
   ▼
Top 10 documentos
   │
   ▼
Backend
   │
   ▼
Frontend

Se estivermos construindo um chatbot com RAG, podemos adicionar um LLM:

Usuário
   │
   ▼
Pergunta
   │
   ▼
Embedding
   │
   ▼
Busca Semântica
   │
   ▼
Documentos relevantes
   │
   ▼
LLM
   │
   ▼
Resposta

Nesse caso, a busca semântica funciona como a etapa responsável por encontrar o contexto correto para que o modelo de IA possa gerar uma resposta.


Conclusão

Uma implementação básica de busca semântica pode ser resumida em:

1. Transformar documentos em embeddings
2. Armazenar os embeddings
3. Transformar a query em embedding
4. Comparar os vetores
5. Ordenar pela similaridade
6. Retornar os documentos mais relevantes

O exemplo mais simples seria:

Documentos
    ↓
Embeddings
    ↓
Vector Database
    ↓
         Query
           ↓
       Embedding
           ↓
    Busca por similaridade
           ↓
     Resultados relevantes

A grande vantagem é que podemos encontrar documentos pelo significado, mesmo quando as palavras utilizadas na consulta são diferentes das palavras presentes no conteúdo.

Em aplicações reais, entretanto, a busca semântica geralmente é combinada com busca lexical, filtros e técnicas de reranking, formando uma busca híbrida mais precisa.


Comments

No comments yet.