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.
💡 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.
Você também pode gostar
Como Implementar um Sistema de Recomendação Semântica no Laravel com Embeddings (Sem Tags, Sem Categorias)
Aprenda como construir um sistema de recomendação semântica real no Laravel, usando embeddings e PostgreSQL (pgvector) — sem depender de categorias, tags ou heurísticas frágeis.
Guia de RAG para devs backend: do zero ao pgvector em Laravel
Tutorial completo de RAG em Laravel com PostgreSQL e pgvector: ingestion assíncrono, busca híbrida BM25 + embeddings com RRF, tool use no Claude API e as três métricas que separam protótipo de produto (recall@5, faithfulness e latência p95).
Glossário do AI Engineer 2026: 30 termos que todo engenheiro precisa saber (sem hype)
Dicionário de campo com 30 termos que aparecem em todo projeto sério de IA em 2026: núcleo, capacidades, padrões agênticos, recuperação, engenharia e operação. Cada termo em uma linha clara, com um exemplo concreto e zero hype. Mais mini-FAQ com 10 perguntas que economizam reunião.
Laravel AI SDK chegou: vale migrar do Prism (ou do seu wrapper)?
Laravel AI SDK saiu em fevereiro/2026 e ficou estável em março, junto com o Laravel 13. Portei um projeto real de Prism pra SDK oficial: 47 linhas a menos, switch de provider em uma atribuição, embeddings e vector store first-party. O diff aberto, o que continua valendo no Prism e quando não migrar.