Com a popularização de ferramentas impulsionadas por modelos de linguagem amplo (Large Language Models) como o ChatGPT da OpenAI, LLama3 da Meta ou Omni do Claude, o termo embedding passou a ser mais conhecido por pessoas que não necessariamente vieram das raízes das pesquisas de processamento de linguagem natural.
Se você já foi na página de precificação da API da OpenAi, por exemplo, deve ter reparado que eles possuem os modelos text-embedding-3-small, text-embedding-3-large e o ada-v2, com preços mais baixos que as apis dos modelos de LLM como gpt-4.o ou até mesmo o mais recente e eficiente gpt-4.1.

Nesse post vamos explicar o que são os Embeddings, quais as funcionalidades desses modelos e apresentar sua relevância em aplicações como LLM, busca semântica e clusterização de textos.
Os tais Embeddings
A transformação de texto em embedding nada mais é que a obtenção de sua representação em um vetor V contido em um espaço vetorial R de n dimensões (Rˆn) .

Para cada frase (ou texto) haverá um vetor. E isso nos permite realizar comparaçõs entre vetores desse mesmo espaço, como por exemplo, calcular a distância e o ângulo entre todos os vetores.
Calma! se você nunca ouviu falar de espaço vetorial, similaridade de vetores ou até mesmo de álgebra linear, a próximas seção será voltada para trazer um resumo do resumo de forma bem desenhada para tentarmos deixar esses conceitos um pouco mais claros.
Em poucas palavras, a transformação em embeddings é a forma que transformarmos a linguagem humana em algo que computadores consigam entender. E o melhor, nos permite comparar as diferentes frases (agora em vetores) e obter as que são semelhantes entre si.
Isso por si só, aliado a um bom banco de dados vetorial, nos permite realizar busca semântica e prover contexto para empoderar (e muito!) a resposta da sua LLM favorita. Mas isso é assunto para outro post. Mas se ficou intrigado e não quer esperar, busque pelo termo RAG (Retrieval-Augmented Generation) e se deleite, no que é pra mim, em uma das melhores formas de utilizar uma LLM atualmente.
Para fechar essa seção, não pense que a transformação em embeddings se resume à transformação numérica de texos, é possível obter embeddings de outros tipos de dados, como por exemplo imagens e áudios!
Um pouco de background
Se você já conhece conceitos de álgebra linear nem perca tempo aqui, já pule para a próxima seção.
Para os que não estão familiarizados com a algebra linear, vamos começar nos limitando em um espaço vetorial de 2 dimensões chamado de R2 e explorar os conceitos básicos dos vetores. Esse espaço vetorial pode ser, por exemplo, representado pelo plano x-y, e um ponto nesse espaço é definido por 2 coordenadas do tipo (x, y). Na imagem abaixo temos o vetor V1 em roxo, com coordenadas (0.51379, 0.39747), definidos no espaço R2.

Portanto, de forma bem simplória, vamos definir que o espaço vetorial é o espaço onde podemos fazer soma entre dois vetores e/ou multiplica-los por qualquer número constante (um escalar). Ou seja, podemos por exemplo pegar os vetores V1 e V2 e multiplica-los por 2, fazendo com que os mesmos aumentem suas magnitudes dentro do espaço vetorial enquanto mantem a mesma direção. Essas duas propriedades (de soma e multiplicação) são válidas para todos os vetores no mesmo espaço vetorial.

No espaço R2, e até mesmo no espaço R3, conseguimos ter uma percepção espacial do vetor. Agora, imagine (ou melhor, apenas tente) um vetor em um espaço vetorial de 5, 8, 13, 21 ou 1232 dimensões! Foge completamente da nossa capacidade de renderização mental.
Com esses conceitos em mãos, podemos explorar o conceito de similaridade entre vetores, ou seja, verificar se dois ou mais vetores se encontram na mesma direção e/ou se possuem magnitudes similares.
É importante sabermos que existem várias formas de obtermos essa similaridade, sendo o cálculo da distância euclidiana entre as coordenadas e o cálculo da similaridade do cosseno entre os dois vetores, os métodos mais comuns.
Como eu faço bastante busca semântica e acabo utilizando mais o cálculo da similaridade do cosseno, vou utilizar esse método para continuarmos a nossa empreitada em tapar alguns buracos.
A similaridade entre os cossenos é dada pela fórmula abaixo:
$$ cos(\theta) = \frac{V_{1} \cdot V_{2}}{\left| V_1 \right | \left | V_{2} \right|} $$
O que nós estamos fazendo é calcular o produto interno entre os dois vetores e dividir o resultado pelo produto dos modulos dos vetores. Dessa forma podemos obter a similaridade do cosseno entre eles.
Mas se estudar algebra linear não é o caso no momento, basta sabermos que se a conta acima for igual a 1, então os vetores são exatamente iguais, e se caso dê -1, são exatamente os opostos.
Exemplificando, vamos calcular a similaridade entre os vetores V1 e V2.

Com isso podemos dizer que o vetores V1 e V2 são 76% similares.
Montando o quebra cabeça
Agora que possuímos um pequeno entendimento de espaço vetorial, vetores e similaridade entre vetores, fica um pouco mais fácil integrarmos tudo isso com o que foi dito no inicio sobre embeddings.
Embeddings como dito antes, são as representações de coisas em vetores, no caso desse post vou estar sempre utilizando textos. Portanto, vamos considerar as as frases abaixo e calcular qual a similaridade entre as sentenças F2 e F3 com F1 como exemplo.
Na proxima seção vou abordar com mais detalhes como se obtém os embeddings e as diferentes opções pra isso. Por hora vamos apenas utilizar o modelo all-MiniLM-L6-v2 e obter embeddings (vetores) para cada uma das frases acima.
sentences = [
"Quais as ações das empresas de tecnologia que mais lucraram esse ano",
"A Totvs (TOTS3) é uma das empresas de tecnologia que mais lucrou no ano, contabilizando tantos milhorreisn no último trimestre.",
"As ações da MERPO do setor de mármores chamuscados viraram pó na tarde de ontem! Uma merda em pó!"
]
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("all-MiniLM-L6-v2")
model.max_seq_length = 256
embeddings = model.encode(sentences, normalize_embeddings=True)
display(embeddings)
display(embeddings.shape)Como output temos 3 vetores.. porém com muito mais que 2 coordenadas pra cada vetor de embedding! Como dito anteriormente, um espaço vetorial pode ter mais dimensões do que nosso cérebro consegue visualizar geometricamente.
array([[-0.00815339, -0.01392658, -0.08726863, ..., 0.00932435,
0.08745421, -0.01407533],
[-0.02574616, -0.02340927, -0.09131505, ..., 0.01132488,
0.02972019, 0.06868411],
[-0.01270558, 0.12470785, -0.02973632, ..., -0.00460098,
-0.01225209, 0.01503461]], dtype=float32)
(3, 384)Agora podemos calcular qual a similaridade entre F2 e F3 em relação a F1 calculando o cosseno do angulo entre os vetores. Obviamente não vou fazer essa conta na mão.
from sklearn.metrics.pairwise import cosine_similarity
v1 = embeddings[0].reshape(1,-1)
for i in range(0,3):
cos_sim = cosine_similarity(v1, embeddings[i].reshape(1,-1))
print(f"Similaridade entre F1 com F{i+1}: {cos_sim[0][0]}")Similaridade entre F1 com F1: 1.0
Similaridade entre F1 com F2: 0.6518208384513855
Similaridade entre F1 com F3: 0.3244129419326782E como já suspeitavamos a frase 2 de fato tem uma similaridade maior com a frase 1, mas perceba bem, não é por conta das palavras semelhantes... mas sim pelo contexto!
Tanto a frase 2 como a frase 3 possuem palavras iguais ou semelhantes dentro da frase 1, como por exemplo ações, lucro, setor e tecnologia. Porém pelo contexto fica claro que a frase 2 é a mais próxima da frase 1.
A capacidade de transformar trechos com significados em vetores é onde reside o poder dos embeddings.
Obtenção dos embeddings
A representação matemática de textos não é nova e pode ser feita atravśe de modelos simples como o Bag of Words (BoW), onde as frequências de palavras dentro de uma sentença ou documento são contabilizadas. Esse tipo de modelo, embora simples, é muito eficiente em tarefas que lidam com classificação de texto.
E com a ascenção da aplicação de Redes Neurais Recorrentes (RNN) no campo de Processamento de Linguagem Natural (NLP), em particular com as contribuiçõs do google com o modelo Word2Vec em 2013, a forma de se obter embeddings de palavras passou a contabilizar uma janela de contexto com base nos arredores de cada palavra do texto.

Mas o que de fato possibilitou mudanças drásticas no campo de NLP e pavimentou o caminho para o uso de modelos de linguagem amplo (chat-gpt, gemini, e etc) da forma que utilizamos hoje, foi a introdução de uma nova arquitetura de rede neural que foi denominada como Transformer. (Vaswani et al., 2017)
Adentrar na explicação da arquitetura do transformer demandaria um post exclusivo pra ele, portanto entenda que o mecanismo que integra o sistema do transformer permite que longas sentenças sejam transformadas com muito mais eficiência e menor custo computacional quando comparado com o Word2Vec, por exemplo.
Os embeddigns que geramos no exemplo da seção anterior foram obtidos pelo módulo em python SentenceTransformer também conhecido como SBERT.
Além dele, utilizo bastante o gerador de embeddings text-embedding-3-small da API da OpenAI, com uma dimensão de 1536. Em um dos projetos de semantic search que trabalhei obtive resultados melhores com ele do que com o SBERT.
Em contra partida, o modelo da OpenAI é pago, onde é cobrado pela quantidade de tokens do texto a ser transformado. Mas o custo é realmente bem baixo o que justifica tranquilamente optar por ele na maioria dos casos.
Aplicações
Ao longo do artigo citei algumas aplicações dos embeddings, em especial a busca semântica, onde se busca termos similares em um texto ou documentos.
No campo da utilização das LLMs (chatgpt e afins), a busca semântica desempenha um papel fundamental na aplicação da técnica conhecida como RAG.
Essa técnica nada mais é que prover contexto no corpo do seu prompt antes de submetê-lo para LLM. Dessa forma, a LLM passa a considerar o escopo de busca e resposta dentro desse contexto fornecido, possibilitando, por exemplo que a IA passe a considerar dados atualizados antes de te fornecer a resposta.

Se quiser apenas brincar com a tecnologia da busca semântica, o script que utilizei para demonstrar a similaridade entre vetores é um bom ponto de partida. A própria bilioteca SentenceTransformer possui o método para calcular a similaridade.
Mas se quiser fazer as coisas um pouco mais sérias, passamos a adentrar no mundo dos bancos de dados vetoriais, como o qdrant por exemplo, projeto para armazenar e buscar embeddings.
Em breve estarei postando aqui um artigo onde passo por todo o processo, desde a obtenção dos embeddings, seu armazenamento no banco de dados de vetorial rodando dentro de um container, até sua integração com alguma LLM.
Clusterização de textos
A clusterização de textos é um outro tipo de aplicação onde os embeddings são a chave.
Para realizar clusterização de textos, isso é, agrupar textos semelhantes, podemos utilizar vários algoritimos não supervisionados de clusterização, sendo o mais famoso deles o agrupamento por K-means.
Sem adentrar na formulação matemática, entenda que e o K-means utiliza o cálculo de distância entre dois pontos para determinar se esses pontos são semelhantes ou não. E como nossos embeddings nada mais são que pontos em um espaço vetorial, fica claro que podemos aplicar esse tipo de algoritimo pra determinar se textos (em formato de embeddings) são próximos uns dos outros o suficiente para formar grupos.
Mas calma lá! Simplesmente pegar todos os vetores, de 1534 dimensões cada, e aplicar o k-means não irá produzir bons resultados. Infelizmente existe um fenômeno dentro da análise de dados conhecido como "curse of dimensionality", nesse caso, quanto maior o número de dimensões, menor será o significado entre dois pontos de dados uma vez que todas as distâncias se tornam muito similares.
Para contornar esse problema aplicamos técnicas de redução dimensional, onde podemos reduzir nossos 1534 dimensões para 3, caindo no nosso confortável espaço tri dimensional onde conseguimos renderizar na nossa cabeça.
Dentre as técnicas de redução de dimensionalidade temos o t-SNE e UMAP, mas o post já ficou grande demais e vou deixar todo esse tópico de clusterização para ser explorado em outro post. Mas vou deixar o resultado de uma clusterização de 12 mil descrições de ferramentas de IA que eu fiz buscando descobrir categorias em comuns dentre elas, tive um resultado bem satisfatŕio, com cerca de 66 categorias.

Conclusão
Espero que eu tenha atingido meu objetivo de ter contribuído pelo menos um pouquinho com essa explicação do que são os embeddings e sua relevância.
Se gostou do texto e foi útil pra você, compartilhe com quem tem interesse. Quaisquer dúvidas nos mande um e-mail e podemos discutir alguns pontos em mais detalhes.
Referências
Embeddings in Natural Language Processing - Theory and Advances in Vector Representation of Meaning -Colocar nome do autor[[Gilbert Strang - Linear Algebra and Its Applications (4ed)-Brooks Cole (2005).pdf|Linear Algebra and its Application - Gilbert Strange]]

