Como Implementar Busca Semântica no Laravel com Embeddings e PostgreSQL (PGVector)
🧠 O Que É Busca Semântica
Antes de mais nada, vale entender o conceito: ao invés de comparar apenas palavras, busca semântica converte textos e consultas em vetores numéricos (embeddings) que capturam o significado do conteúdo. Com isso, sua aplicação consegue encontrar resultados relevantes mesmo que os termos pesquisados não apareçam literalmente no texto — porque eles ocupam posições próximas no espaço vetorial.
🔧 Tecnologias Usadas
✔️ Laravel – framework PHP
✔️ PostgreSQL com pgvector – extensão para armazenar e buscar vetores
✔️ OpenAI (ou outro serviço de embeddings) – gerar representações vetoriais dos textos
✔️ SQL direto – consultas de similaridade sem camadas de abstração como Laravel Scout
🛠️ Passo a Passo
1) Preparar o Banco de Dados com pgvector
No PostgreSQL você precisa habilitar a extensão que permite armazenar vetores:
CREATE EXTENSION IF NOT EXISTS vector;
Essa extensão adiciona um tipo de dado vector ao PostgreSQL, possibilitando operações de similaridade diretamente no banco.
Na sua migration do Laravel, inclua uma coluna para guardar o vetor resultante do embedding:
Schema::table('articles', function (Blueprint $table) {
$table->vector('embedding', 1536)->nullable();
});
O número 1536 representa a dimensão escolhida para os embeddings — ajuste conforme o modelo de linguagem que você usar.
2) Gerar Embeddings para os Documentos
Para cada item que você quer buscar (por exemplo, um artigo, produto ou FAQ), gere um embedding usando uma API de linguagem, como a de OpenAI:
$client = new \OpenAI\Client(env('OPENAI_API_KEY'));
$response = $client->embeddings()->create([
'model' => 'text-embedding-3-small',
'input' => $article->content,
]);
$embedding = $response->data[0]->embedding;
$article->embedding = $embedding;
$article->save();
Esse vetor agora representa semanticamente o conteúdo do artigo. Você pode fazer isso em Jobs em background para não travar a experiência do usuário.
3) Implementar a Busca por Similaridade
Quando o usuário faz uma consulta, você também converte essa pesquisa em um embedding:
$queryEmbedding = $client->embeddings()->create([
'model' => 'text-embedding-3-small',
'input' => $request->query('search')
])->data[0]->embedding;
Em seguida você faz uma consulta SQL para encontrar os registros mais próximos no espaço vetorial — ou seja, semanticamente mais similares:
$results = DB::select(
"SELECT *, embedding <=> :query AS distance
FROM articles
ORDER BY embedding <=> :query
LIMIT 10",
['query' => $queryEmbedding]
);
Aqui, o operador <=> calcula a distância cosseno entre vetores no PostgreSQL habilitado com a extensão pgvector — ou seja, ele mede o quão semanticamente próximos dois vetores estão. Quanto menor a distância cosseno, mais semanticamente similares os textos são, e mais relevante será o resultado para a consulta do usuário.
Quando você usa similaridade vetorial (como com embeddings e o operador <=> no PostgreSQL com pgvector), o valor retornado representa a distância cosseno entre dois vetores que codificam significado (por exemplo: a consulta do usuário e o texto de um documento).
👉 Distância cosseno é uma maneira de medir o ângulo entre dois vetores no espaço multidimensional — quanto menor a distância, mais parecidos semanticamente eles são.
- Valor 0 → os vetores apontam na mesma direção (significados muito parecidos).
- Valores próximos a 0,1–0,3 → texto e consulta são bastante relacionados semanticamente.
- Valores em torno de ~0,45 → indica um nível intermediário de similaridade: existe alguma relação de significado, mas não é uma correspondência forte.
- Valores maiores (por exemplo ~0,7–1,0) → implicam pouca ou nenhuma similaridade semântica.
Vamos pegar um exemplo, distance = 0,4523423
🔍 Interpretando o valor "0,4523423"
💡 Um valor de 0,4523423 significa que os vetores — ou seja, o texto do documento e a consulta — têm um ângulo considerável entre eles:
✔️ Não são semanticamente idênticos
✔️ Têm alguma relação de significado, mas não tão próxima quanto um valor menor (por exemplo ~0,1–0,2)
Isso pode acontecer quando:
- O documento menciona conceitos relacionados à consulta, mas não responde exatamente ao que foi perguntado;
- O texto trata de tópicos semelhantes mas com foco diferente;
- Há sinônimos ou temas transversais, mas não uma correspondência direta.
📌 Em buscas semânticas, geralmente ordenamos os resultados do menor para o maior valor de distância — ou seja, quanto menor a distância cosseno, mais relevante o resultado tende a ser.
🧠 Uma analogia simples 🧠
Pense nos vetores como setas apontando em direções no espaço:
✅ Distância = 0 → as setas apontam quase exatamente para a mesma direção.
📍 Distância ≈ 0,45 → as setas ainda estão relativamente alinhadas, mas com um ângulo perceptível entre elas — ou seja, existe alguma conexão, mas não uma correspondência perfeita.
Tutorial te mostra o caminho — no Clã você constrói junto. Aula ao vivo toda semana, projetos reais de Engenharia de IA, ao lado de quem já está em produção.
Entrar no Clã💡 Dicas e Boas Práticas
✅ Pré-indexe os embeddings ao criar/atualizar documentos
✅ Realize a geração de embeddings em background com Jobs
✅ Use caches de resultados populares para reduzir chamadas à API
✅ Combine com busca full-text tradicional para um sistema híbrido ainda mais eficaz (semântica + palavras-chave)
🎯 O Que Você Ganha com Essa Abordagem
✔️ Resultados relevantes mesmo sem termos exatos
✔️ Busca por intenção e significado em vez de apenas correspondência textual
✔️ Funciona com qualquer texto estruturado — artigos, produtos, FAQs, etc.
✔️ Escalável, porque a maior parte da lógica fica no banco de dados
🧠 Conclusão
Implementar busca semântica no Laravel sem usar frameworks como Scout é totalmente possível e valioso. Com PostgreSQL + pgvector + embeddings, você cria um sistema de busca que realmente entende o conteúdo, entregando resultados mais inteligentes e relevantes aos seus usuários — e tudo sem depender de ferramentas externas para indexação.
{AI Engineer} — apaixonado por Laravel, arquitetura de software e construir produtos com impacto. Compartilho aqui tutoriais, descobertas e reflexões sobre o dia a dia de engenharia.
Conteúdo é o que não falta. Falta quem desembaralhe: o que importa agora é como implementar do jeito certo. No Clã você tem isso ao vivo, toda semana, com quem já filtrou o ruído.
Entrar no Clã