Data Science | Generative AI | Agentic AI | IA | ML | Linkedin
👉 Introdução
Este artigo apresenta alguns métodos de comparação de textos a nível semântico, ou seja, o quão semelhantes são os textos comparados com relação ao seu significado.
O artigo começa com a apresentação de conceitos básicos e tópicos relevantes sobre o tema, tais como a motivação para uso desta técnica, aplicabilidade, semântica superficial e profunda, entre outros. Depois são apresentados sete métodos de implementação para comparação semântica, com crescente grau de eficiência semântica.
Os métodos de comparação de similaridade semântica utilizarão, neste artigo, cáculo de distância por cosseno. Eles retornarão um valor entre 0 e 1, onde 1 significa que o texto é idêntico e 0.7 ou acima já se considera que os textos comparados possuem o mesmo valor semântico. A interpretação do valor pode variar um pouco de acordo com o método e modelo utilizado, mas esse é um bom parâmetro inicial.
👉 Motivação
Este tipo de medição, feito por meio de comparação semântica, é útil, por exemplo, para criar métricas que permitam comparar o desempenho de modelos de LLM e Agentes de IA. Em geral, podemos aplicar este método comparando a resposta produzida por um modelo de ML com a resposta que esperávamos receber ou que consideramos ideal.
Como modelos LLM produzem resultados não determinísticos, nossa estratégia de medição pode ser a de avaliar as respostas a nível semântico e estabelecer faixas aceitáveis para os resultados. Isso permite, inclusive, criar mecanismos de observalidade, de monitoramento da saúde/eficiência da solução e de aprimoramento automatizados.
👉 Aplicação prática
Para os efeitos deste artigo, os métodos e técnicas nele apresentados foram (em maioria) aplicados a um produto Multi Agente, baseado em modelos LLM, com objetivo de permitir que seus usuários realizem trabalhos de cunho analítico (Data Analytics).
A solução Multi Agente é integrada a uma base de dados analítica com arqutetura Data Mesh, em ambiente de Cloud AWS. O produto é capaz de receber uma solicitação do usuário em linguagem natural, interpretar a solicitação, criar instruções SQL, executar o SQL na base Data Mesh e produzir resultados sofisticados, que incluem tabelas e gráficos analíticos com os resultados.
A comparação por similaridade semântica foi utilizada para medir a aderência dos modelos de LLM usados em cada agente ao System Prompt fornecido a eles. Além disso, foi usado para medir a coerência das resposta perante o que foi solicitado. Para esse fim, 40 cenários diferentes foram preparados, todos baseados em casos de uso reais dos usuários da ferramenta Multi Agente. Os cenários foram submetidos à ferramenta através de uma execução automatizada que simula a interação do usuário. A resposta final é comparada com respostas prováveis e consideradas aderentes às expectativas do usuário final.
👉 Esta é a melhor técnica?
Este não é o único método de avaliação de desempenho para Agentes de IA e modelos LLM. Também pode não ser o melhor método para a sua necessidade. Porém, o objetivo do artigo é apresentar as opções disponíveis para explorar esta técnica em particular.
👉 Métodos disponíveis
Há vários métodos disponíveis, com maior ou menor grau de eficiência semântica, velocidade de resposta e tamanho (dos pacotes e do modelo utilizados).
Os métodos com melhor eficiência semântica utilizam modelos pré-treinados e tendem a ser mais pesados, contudo, há soluções intermediárias com ótimos resultados comparativos. Tudo vai depender da necesidade a ser atendida e das restrições ambientais.
Ao longo desse artigo serão apresentados sete métodos de implementação, para cenários e aplicação diferentes, incluindo indicação de uso ideal para cada um. Além disso, será apresentado ao menos um exemplo de implementação e a classificação quanto: a) Eficiência semântica; b) Tamanho da solução; c) Velocidade da solução.
O artigo não pretende esgotar todos os métodos disponíveis, mas sim apresentar uma quantidade e variedade suficiente para cobrir vários cenários de uso comuns e dar uma boa base para trabalhos futuros.
👉 Quesitos de comparação
Serão comparados tês quesitos entre as soluções que serão apresentadas:
- A classificação quanto a eficiência semântica será apontada como baixa, média ou alta.
- O tamanho de cada solução será expresso em MB (aproximado, pois os pacotes variam de tamanho, conforme a versão).
- A velocidade de processamento será classificado entre baixa, média e alta.
Vale ressaltar que as classificações que usam rótulos têm a intenção de estabelecer um critério de comparação especificamente entre as soluções apresentadas neste artigo.
👉 Semântica superficial e profunda
Para seguirmos, é preciso antes entender a diferência básica entre a semântica superficial (ou contexto superficial) e a semântica profunda (ou ontexto profundo).
É um conceito bem simples, mas importante. A semântica superficial não difere palavras que podem ter o mesmo sentido, dependendo do contexto de uma frase, como, por exemplo, as palavras “gato” e “felino” nas frases abaixo:
- O gato está no telhado.
- Um felino está em cima da casa.
Isso significa que, mesmo com pré-processamento, técnicas mais simples como Jaccard, Levenshtein e TF-IDF, que apresentaremos adiante, não entendem que essas palavras possuem, em determinadas frases, o mesmo significado. Logo, são tratadas como palavras diferentes.
Para compreensão e análise de textos com semântica profunda, é necessário utilizar modelos de ML. Técnicas simples de medição de similaridade por conjuntos vetoriais não possuem inteligência para análises de alto valor semântico.
🛠️ Pré-processamento para melhoria de desempenho
O pré-processamento é o tratamento dos dados de entrada de maneira a tornar esses dados mais adequados para sua utilização, seja com modelos de ML ou, no nosso caso, para comparação semântica.
Essa prática é largamente utilizada e, em geral, aumenta o desempenho das soluções e a acurácia. Contudo, utilizar ou não depende do tipo de aplicação e do modelo de ML utilizado.
Ao longo do artigo cada método será apresentado e, adicionalmente, haverá uma análise sobre a utilidade de usar ou não as técnicas de processamento explicadas a seguir.
⚙️ Tratamentos comuns em textos
A seguir algumas técnicas de tratamento de texto que são bastante utilizadas:
- Remoção de Stop Words: Técnica que consiste na exclusão de palavras comuns que não agregam significado (sentido semântico), tais como artigos e preposições, entre outros. Exemplos: “o”, “de”, “em”, “lhe”, etc.. Esta técnica reduz ruído e melhora a qualidade dos vetores;
- Stemming ou Lemmatização: Reduz as palavras à sua raiz para agrupar variações morfológicas e, desta forma, melhorar a comparação semântica. Exemplo: as palavras “correndo” e “correu” transforman-se, ambas, em “correr”, pois possuem o mesmo valor semântico.
- Lowercasing, remoção de pontuação e remoção de caracteres especiais: Realiza a uniformização dos textos e evita que diferenças superficiais afetem a análise de similaridade.
⚙️ Refinamento do pré-processamento
É possível melhorar ainda mais o resultado realizando customização do vocabulário para tratamento de Stop Words. Isso é viável, caso a solução seja para atender um contexto especializado. Dessa forma, muito mais palavras podem ser categorizadas como Stop Words e eliminadas, a fim de produzir resultados mais assertivos.
💻 Exemplo de implementação
def compact_text(text, lowercasing = True):
"""
Limpeza da string para diminuir a quantidade de
caracteres. Retira excesso de espaços, identação
e quebras de linhas. Útil para reduzir o volume
de dados trafegado em rede e para usar com
modelos de ML.
"""
if text is None:
return None
text = textwrap.dedent(text).strip()
text = re.sub(r"\n", " ", text)
text = re.sub(r"\s+", " ", text)
if lowercasing:
text.lower()
return text
def clean_text(text: str):
"""
Limpeza do texto, removendo pontuações,
stop words e aplicando stemming.
"""
if text is None:
return None
# Download dos dados do NLTK:
nltk.data.path.append(NLTK_PATH)
nltk.download('stopwords', download_dir=NLTK_PATH, quiet=True)
# Limpeza básica do texto:
text = compact_text(text)
text = re.sub(r'[^\w\s]', '', text)
# Stop Words e Stemming:
stop_words = set(nltk.corpus.stopwords.words('portuguese'))
stemmer = nltk.stem.SnowballStemmer('portuguese')
tokens = text.split()
tokens = [stemmer.stem(word) for word in tokens if word not in stop_words]
return ' '.join(tokens)
🧩 Método 1 — Jaccard
Método bastante simples, baseado em recursos Core do Python (não usa modelos), de baixa eficiência semântica, usado para textos curtos e médios, especialmente se os conjuntos de palavras a serem comparados forem pequenos. Jaccard compara conjuntos de palavras ou n-gramas.
Seu uso ideal é para comparação de textos onde a ordem das palavras não importa, como análise de tópicos ou identificação de similaridade em documentos bastante curtos.
Retorna um valor entre 0 e 1, onde 1 significa que o texto é idêntico e 0.7 ou acima já se considera que os textos comparados possuem o mesmo valor semântico.
🛠️ Pré-processamento
O pré-processamento ajuda, a remoção de Stop Words e o Stemming/Lemmatização melhora a qualidade da comparação, pois reduz ruído e aumenta a chance de encontrar interseções significativas, aumentando a precisão superficial. Também aumentaa a velocidade, pois há menos tokens para comparar.
🧪 Testes em laboratório (Produto Multi Agente)
A baixa eficiência semânica do método Jaccard limita muito sua aplicabilidade. Portanto, ele não é viável para avaliação de modelos de ML, que é o objetivo deste trabalho. Nos testes, apresentou sempre valores abaixo de 0.4, mesmo comparando textos com alta similaridade. O método foi descartado logo no início da pesquisa, pois já apresentava resultados ruins desde os testes unitários.
📥 Instalação
Não é necessária instalação de bibliotecas e nem qualquer import em especial, usa recursos Core do Python. Logo, é extremamente leve.
💻 Exemplo de implementação
def compare_texts_jaccard(real_text: str, candidate: str, clean_string = True):
"""
Método de comparação semântica chamado Jaccard. Indicado para
textos curtos e médios, especialmente se os conjuntos de palavras
forem pequenos e quando a ordem das palavras não importa, como
análise de tópicos. Retorna um valor entre 0 e 1, onde 1 significa
que o texto é idêntico e 0.7 ou acima já se considera que os textos
comparados possuem o mesmo valor semântico.
"""
if real_text is None or candidate is None:
return None
if clean_string:
real_text = clean_text(real_text)
candidate = clean_text(candidate)
set1, set2 = set(real_text.split()), set(candidate.split())
intersection = len(set1 & set2)
union = len(set1 | set2)
return round(intersection / union, 2)
print(compare_texts_jaccard(
"O gato está no telhado.",
"Um felino está em cima da casa."
))
OBS: Esses métodos de pré-processamento serão referenciados nos exemplos de implementação dos métodos de comparação por similaridade semântica mais adiante.
🧩 Método 2 — Distância de Levenshtein
Método bastante simples, baseado na lib python-levenshtein (não usa modelos), de baixa eficiência semântica, um pouco melhor que o Jaccard. Usado para textos curtos ou médios, mais lento para textos muito longos devido ao custo quadrático. Uso ideal para comparação de strings curtas, como nomes, palavras ou pequenas frases.
Retorna um valor entre 0 e 1, onde 1 significa que o texto é idêntico e 0.8 ou acima já se considera que os textos comparados possuem o mesmo valor semântico.
O pacote python-Levenshtein é escrito em C para alta performance, ele realiza cálculo de distância, similaridade de strings e operações de edição.
🛠️ Pré-processamento
O pré-processamento pode ajudar, mas precisa ser implementado com cuidado. O Levenshtein mede a diferença caractere a caractere, logo, remover pontuação e normalizar (ex: lowercasing) é útil. Stemming ou remoção de stop words não são recomendados, pois alteram a estrutura da frase e podem distorcer a distância real.
🧪 Testes em laboratório (Produto Multi Agente)
Embora apresente resultados melhores que o método Jaccard, ainda possui baixa eficiência semânica e, desta forma, não é viável para avaliação de modelos de ML. Nos testes, apresentou sempre valores abaixo de 0.57, mesmo comparando textos com alta similaridade.
Após submetido a 40 cenários distintos, com a maioria das respostas contendo similaridade semântica alta, o resumo estatístico foi o seguinte:
- Média: 0.43;
- Desvio Padrão: 0,092;
- Mínimo e Máximo: 0,1 e 0,57;
- Quartis: 25%=0.41, 50%=0,45, 75%=0,48.
📦 Pacotes e tamanhos aproximados
PacoteTamanhopython-Levenshtein~1.2 MB
📥 Instalação
Via comando PIP:
pip install python-levenshtein
ou arquivo “requirements.txt”:
python-Levenshtein==0.27.1
💻 Exemplo de implementação
from levenshtein import ratio
def compare_texts_levenshtein(real_text: str, candidate: str, clean_string = True):
"""
Método de comparação semântica chamado Distância de Levenshtein.
Indicado para textos curtos ou médios, pois pode ser lento para
textos longos, devido ao custo quadrático. Uso ideal para
comparação de strings curtas, como nomes, palavras ou pequenas frases.
Retorna um valor entre 0 e 1, onde 1 significa que o texto é idêntico
e 0.8 ou acima já se considera que os textos comparados possuem o
mesmo valor semântico.
"""
if real_text is None or candidate is None:
return None
if clean_string:
real_text = compact_text(real_text)
candidate = compact_text(candidate)
return round(ratio(real_text, candidate), 2)
print(compare_texts_levenshtein(
"O gato está no telhado.",
"Um felino está em cima da casa."
))
🧩 Método 3 — TF-IDF + Similaridade de Cosseno
Método simples e fácil de usar, baseado na lib scikit-learn (não usa modelos), extremamente leve, sem dependência de modelos pré-treinados e com baixa eficiência semântica. Útil para textos curtos e simples.
📦 Pacotes e tamanhos aproximados
scikit-learn, para vetorização TF-IDF e cálculo de similaridade: ~25 MB
nltk, para Stemmer e outras funções de NLP: ~10 MB
nltk stopwords, tratamento de Stop words: ~5 MB
numpy, operações matemáticas (opcional, mas útil para vetores e normalização): ~20 MB
Total estimado: ~60 MB
🛠️ Pré-processamento
Neste método o pré-processamento é essencial, embora permaneça uma análise semântica superficial. A eficiência semântica é incrementada devido aos seguintes fatores:
- Melhora a qualidade dos vetores ao remover ruído.
- Aumenta a eficiência computacional (menos termos, vetores menores).
🧪 Testes em laboratório (Produto Multi Agente)
Apresentou resultados ligeiramente melhores que o método Distância de Levenshtein. A faixa dinâmica maior da variável alvo, evidenciadas por seus valores mínimo e máximo, demonstram melhor capacidade de capturar diferenças entre os textos. Porém, ainda é considerado insuficiente para avaliação de modelos de ML, mostrando resultados muito inferioes ao métodos que utilizam modelos pré-treinados e oferecem análise semântica profunda (obviamente).
Apesar disso, pode ser considerado para aplicações mais simples que tolerem análise semântica superficial, tendo apresentado o melhor desempenho dos 3 métodos deste tipo que foram analisados (Jaccard, Levenshtein e TF-IDF). Vale ressaltar que o TF-IDF pode ser melhor trabalhado com um dicionário customizado e remoção de Stop Words que consideram o contexto da problemática/necessidade de negócio em tratativa. Após submetido a 40 cenários distintos, com a maioria das respostas contendo similaridade semântica alta, o resumo estatístico foi o seguinte:
- Média: 0,38;
- Desvio Padrão: 0,18;
- Mínimo e Máximo: 0 e 0,72;
- Quartis 25%=0,20, 50%=0,44, 75%=0,51.
📥 Instalação
Via PIP:
pip install scikit-learn
ou “requirements.txt”:
scikit-learn==1.7.2
💻 Exemplo de implementação
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
def compare_texts_tf_idf(real_text: str, candidate: str, clean_string = True):
if clean_string:
real_text = clean_text(real_text)
candidate = clean_text(candidate)
vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform([real_text, candidate])
similarity = cosine_similarity(tfidf_matrix[0:1], tfidf_matrix[1:2])
return round(similarity[0][0], 2)
print(compare_texts_tf_idf(
"O gato está no telhado.",
"Um felino está em cima da casa."
))
🧩 Método 4 — Sentence Transformers com modelos compactos
Método fácil de utilizar, baseado em modelos pré-treinados, disponibiliza modelos compactos e com alta eficiência semântica. Oferece modelos pequenos e leves, se comparado a soluções mais robustas (como BERT, por exemplo). Modelos como all-MiniLM-L6-v2 são bem menores e rápidos, mantendo alta eficiência semântica.
A vantagem desse método é oferecer um desempenho semântico melhor que as outras soluções apresentadas, porém, ainda leve, se comparado a modelos maiores. O tamanho do modelo all-MiniLM-L6-v2, por exemplo, é de ~90 MB. Após o primeiro download, o modelo fica armazenado em cache local (~/.cache/huggingface/). Há vários modelos disponíveis e que podem ser testados com a necessidade específica ser tratada.
🛠️ Pré-processamento
Neste método o pré-processamento pode atrapalhar, pois esses modelos são contextuais e foram treinados com frases completas e naturais. Neste caso, remover stop words ou aplicar stemming pode reduzir a qualidade semântica. Contudo, é útil usar texto limpo, ou seja, apenas lowercasing e remoção de pontuação leve.
🧪 Testes em laboratório (Produto Multi Agente)
Coforme esperado, os resultados com o Sentence Transformers, usando modelo “all-MiniLM-L6-v2”, são muito melhores que os das ténicas mais simples, apresentadas até aqui. Após submetido a 40 cenários distintos, com a maioria das respostas contendo similaridade semântica alta, o resumo estatístico foi o seguinte:
- Média: 0,65;
- Desvio Padrão: 0,19;
- Mínimo e Máximo: 0,01 e 0,85;
- Quartis 25%=0,6, 50%=0,68, 75%=0,77.
O resultado é bastante coerente com as respostas observadas, geradas pela solução multi agente e colhidas do log da aplicação. Apesar da maioria das respostas ter boa similaridade semântica, desvios ainda ocorrem, o que justifica um mínimo e um máximo ainda tão distantes (ampla faixa dinâmica da variável alvo). O motivo da amplitude da variável alvo (similaridade semântica) é justamente o problema que motivou esse estudo: o modelo atualmente utilizado nos agentes da ferramenta oferece baixa aderência ao system prompt e, por isso, é preciso medir essa aderência para comparar com outros modelos mais promissores.
📦 Pacotes e tamanhos aproximados
sentence-transformers: ~15 MB
transformers (carrega modelos da Hugging Face): ~100 MB
torch (PyTorch CPU — executa os modelos): ~150 MB
scikit-learn, numpy, scipy, tqdm, huggingface-hub: ~30 MB
Modelo all-MiniLM-L6-v2: ~90 MB
Modelo paraphrase-MiniLM-L3-v2: ~45 MB
Total estimado: ~240–385 MB
⚠️ Observações
- Se incluir a instalação da versão GPU do PyTorch, o tamanho pode ultrapassar 1 GB. Mas o uso de CPU é suficiente para a função de similaridade de textos.
- Para reduzir ainda mais o tamanho, pode ser usado quantização ou ONNX (mais adiante).
📥 Instalação
Instalação do PyTorch versão CPU, ou seja, sem bibliotecas relacionadas à GPU, como CUDA ou cuDNN:
pip install torch --index-url https://download.pytorch.org/whl/cpu
Para verificar se o PyTorch está usando apenas CPU utilize o seguinte código:
import torch
print("Usando GPU" if torch.cuda.is_available() else "Usando apenas CPU")
Para remover a versão com GPU, caso já esteja instalada, utilize o código abaixo:
pip uninstall torch torchvision torchaudio
Instalação do Sentence Transformers:
pip install sentence-transformers
Instalação via “requirements.txt”:
# PyTorch versão CPU
torch==2.8.0+cpu --index-url https://download.pytorch.org/whl/cpu
# Sentence Transformers e suas dependências
sentence-transformers==5.1.0
scikit-learn==1.7.2
scipy==1.13.1
numpy==1.26.4
💻 Exemplo de implementação
from sentence_transformers import SentenceTransformer, util
def compare_texts_transformer(real_text: str, candidate: str, clean_text = True):
if real_text is None or candidate is None:
return None
if clean_text: # preprocessing
real_text = compact_text(real_text)
candidate = compact_text(candidate)
print("Usando GPU" if torch.cuda.is_available() else "Usando CPU")
model = SentenceTransformer('all-MiniLM-L6-v2')
embeddings = model.encode(
[real_text.lower(), candidate.lower()],
convert_to_tensor=True,
show_progress_bar=False
)
return round(util.pytorch_cos_sim(
embeddings[0], embeddings[1]
).item(), 2)
print(compare_texts_transformer(
"O gato está no telhado.",
"Um felino está em cima da casa."
))
🧩 Método 5 — ONNX + Transformers
Método simples de implementar e fácil de usar, baseado em modelos pré-treinados, que se apresenta como uma boa opção ao PyTorch e, portante, mais leve. A instalação da biblioteca PyTorch varia de ~150 MB, na versão CPU, até ~1.5 GB, na versão GPU. Além disso, há ambientes que restrigem o uso dessa lib, por motivos diversos.
Esta solução utiliza modelos convertidos para ONNX, sendo mais indicada para cenários de restrição de espaço. Além disso, o ONNX é ideal para ambientes sem GPU, offline, ou embarcados. Ele pode ser baixado pronto ou convertido com optimum-cli. O ONNX pode trabalhar com modelos hospedados no Hugging Face e é compatível com optimum.onnxruntime.
✅ Vantagens do ONNX + Transformers
- Não usa o PyTorch, executando com onnxruntime, que é uma opção mais leve e multiplataforma.
- É uma solução rápida, ideal para ambientes com restrição de recursos.
- Possui vários modelos compatíveis, sendo também possível converter modelos Hugging Face para ONNX ou usar os que já estiverem convertidos.
🛠️ Pré-processamento
Esses modelos são contextuais e foram treinados com frases naturais. Portanto, a remoção de Stop Words e o Stemming podem reduzir a qualidade semântica. Algumas técnicas, no entanto, ainda podem ser usadas, tais como Lowercasing, remoção leve de pontuação e normalização de espaços.
🧪 Testes em laboratório (Produto Multi Agente)
Os testes apresentaram ótimos resultados. Devido usar o modelo “all-MiniLM-L6-v2”, mesmo usado no Sentence Transformer com PyTorch, os resultados foram, obviamente, muito semelhantes. Por ser mais leve e dispensar o uso do PyTorch, além de oferecer grande variedade de modelos, esse foi o método escolhido para usar na ferramenta multi agente e seguir com as comparações de desempenho entre diferentes modelos LLM para cada agente da ferramenta. Após submetido a 40 cenários distintos, com a maioria das respostas contendo similaridade semântica alta, o resumo estatístico foi o seguinte:
- Média: 0,65;
- Desvio Padrão: 0,19;
- Mínimo e Máximo: 0,014 e 0,85;
- Quartis 25%=0,6, 50%=0,68, 75%=0,77.
⚠️ Mais adiante serão apresentados os modelos testados e comparados junto com o método Sentence Transformers + ONNX.
📦 Pacotes e tamanhos aproximados
transformers: ~100 MB
onnxruntime: ~50 MB
optimum (núcleo): ~20 MB
numpy, scipy, etc.: ~30 MB
Modelo (vários): ~50–1500 MB*
Total estimado: ~250–1500 MB
*O tamanho do modelo depende da arquitetura (MiniLM, DistilBERT, etc.).
📥 Instalação
Via comando PIP:
pip install transformers[onnxruntime]
pip install onnxruntime --only-binary=:all:
pip install optimum[onnxruntime]
pip install light_embed
ou arquivo “requirements.txt”:
transformers[onnxruntime]==4.56.1
onnxruntime==1.22.1 --only-binary=:all:
optimum[onnxruntime]==1.17.1
light_embed==1.0.8
OBS: Também é possível usar o TensorFlow ao invés do ONX (pip install transformers[tf-cpu]).
💻 Exemplo de implementação
import numpy as np
from numpy.linalg import norm
from light_embed import TextEmbedding
class MLModel(Enum):
BERT = 'onnx-models/msmarco-bert-base-dot-v5-onnx'
PARAPHRASE_MINILM_L6V2 = 'onnx-models/paraphrase-MiniLM-L6-v2-onnx'
ALL_MINILM_L6V2 = 'onnx-models/all-MiniLM-L6-v2-onnx'
DISTILBERT = 'onnx-models/msmarco-distilbert-dot-v5-onnx'
MPNET_V2 = 'onnx-models/all-mpnet-base-v2-onnx'
def compare_texts_onnx(
real_text: str,
candidate: str,
model_name: MLModel = MLModel.PARAPHRASE_MINILM_L6V2,
clean_string = True
):
if real_text is None or candidate is None:
return None
if clean_string:
real_text = compact_text(real_text)
candidate = compact_text(candidate)
model_config = {
"onnx_file": "onnx/model.onnx",
"model_type": "onnx",
"normalize": False
}
# Carregamento do modelo e extração de embeddings:
get_logger().debug("Usando ONNX Runtime para inferência")
model = TextEmbedding(model_name.value, model_config=model_config, cache_folder=ONNX_PATH, show_progress_bar=False, )
embeddings = model.encode([real_text, candidate])
# Similaridade de cosseno
similarity = np.dot(embeddings[0], embeddings[1]) / (np.linalg.norm(embeddings[0]) * np.linalg.norm(embeddings[1]))
return round(similarity.item(), 2)
print(compare_texts_onnx(
"O gato está no telhado.",
"Um felino está em cima da casa."
))
🧩 Método 6 — SpaCy com modelos leves
Método fácil de usar, muito rápido, baseado em modelos pré-treinados, cuja principal vantagem é ser uma solução leve, ou seja, que oferece pacotes e modelos pequenos, como o modelo “en_core_web_sm”, por exemplo.
Devido oferecer modelos pequenos, é ideal para aplicações embarcadas. Mas seu desempenho semântico o faz ser mais indicado para tarefas básicas, tais como similaridade de frases curtas, análise de entidades e POS tagging.
🛠️ Pré-processamento
É útil realizar a remoção de Stop Words, mas stemming pode atrapalhar se os vetores forem baseados em palavras completas. Além disso, o SpaCy já realiza a tokenização e lematização internamente, logo, essas técnicas não são necessárias e apenas aumentariam o custo de processamento.
🧪 Testes em laboratório (Produto Multi Agente)
Devido a versatilidade da solução ONNX e a variedade de modelos disponíveis, além do ótimo desempenho semântico, a solução com Spacy foi descartada. O fato do Spacy ser relatado por outras fontes como uma solução de menor eficiência semântica também contribuiu para essa decisão. Porém, o estudo feito foi registrado para enriquecer este artigo, deixando mais uma opção para trabalhos futuros e, eventualmente, necessidades diferentes.
📦 Pacotes e tamanhos aproximados
A seguir, o tamanho da biblioteca SpaCy e alguns modelos que podem ser utilizados:
Código base do SpaCy: ~50 MB
Modelos en_core_web_sm (pequeno ⚠️): ~12 MB
Modelo en_core_web_md (médio): ~50–120 MB
Modelo en_core_web_lg (grande): ~800 MB
Tamanho total: ~862–932 MB
⚠️ O modelo pequeno (sm) não usa vetores de palavras, por esse motivo, a função similarity() pode não funcionar bem.
Você pode instalar apenas o modelo pequeno, por exemplo:
python -m spacy download en_core_web_sm
📥 Instalação do Spacy
pip install spacy
💻 Exemplo de implementação
import spacy
def compare_texts_spacy(real_text: str, candidate: str):
# Carrega o modelo:
nlp = spacy.load("en_core_web_sm")
# Faz a comparação e retorna o resultado:
doc1 = nlp(real_text)
doc2 = nlp(candidate)
return doc1.similarity(doc2)
print(compare_texts_spacy(
"O gato está no telhado.",
"Um felino está em cima da casa."
))
Método 7 — Gensim com Word2Vec ou FastText
Método fácil de usar, com alta eficiência semântica, porém um pouco pesado devido o tamanho dos modelos utilizados — apesar de haver modelos de tamanhos variados. Ainda assim, é bem mais leve que soluções com bibliotecas pesadas como PyTorch ou TensorFlow.
Gensim é uma biblioteca Python especializada em modelagem de tópicos e vetores semânticos que permite treinar seu próprio modelo, carregar modelos pré-treinados e comparar textos por similaridade de cosseno entre vetores.
✅ Vantagens
- Não usa bibliotecas pesadas;
- Permite treinar e usar seu próprio modelo customizado;
- Leve, se usar ou treinar modelos pequenos;
- Boa semântica para palavras e frases curtas;
- Permite baixar e usar modelos offline.
❌ Limitações
- Não entende semântica profunda, como em frases longas ou ambíguas.
- Modelos grandes podem ocupar muito espaço.
🛠️ Pré-processamento
Remover stop words pode ajudar, em particular se estiver realizando média de vetores para frases. Stemming pode ser útil, dependendo do modelo (FastText lida melhor com variações morfológicas). Em geral, o pré-processamento pode melhorar a velocidade ao reduzir o número de palavras processadas.
🧪 Testes em laboratório (Produto Multi Agente)
Este método também não foi testado devido o método ONNX atender plenamente e também (principalmente) por este método oferecer modelos bem mais pesados que os disponíveis para ONNX.
📝 O que é Word2Vec?
Trata-se de um modelo de ML não supervisionado que transforma palavras em vetores numéricos (embeddings). As palavras com significados semelhantes possuem vetores próximos no espaço vetorial. Dessa forma, possibilita relacionar palavras através de cáculos de distância entre elas no espaço vetorial. Exemplo: os vetores das palavras “gato” e “felino” estarão próximos no espaço vetorial.
📝 O que é FastText?
Trata-se de uma biblioteca criada pelo Facebook AI Research que, assim como Word2Vec, transforma palavras em vetores. Contudo, existem algumas vantagens oferecidas pelo FastText:
- Trabalha com subpalavras (n-gramas), isso ajuda a lidar melhor com palavras raras ou desconhecidas.
- Pode gerar embeddings para palavras não vistas durante o treinamento.
📦 Pacotes e tamanhos aproximados
Pacotes Gensim e suas dependências:
gensim: ~25 MB
numpy, scipy: ~30 MB
Total estimado: ~55 MB
Modelos pré-treinados
Existem alguns modelos pré-treinados e disponíveis para uso neste link:
ModeloFrameworkOrigem DadosIdiomaTamanhocc.pt.300.vecFastTextGooglePortuguês~1.5 GBcc.en.300.vecFastTextGoogleInglês~1.5 GBwiki.pt.vecFastTextWikipediaPortuguês~1.5 MBwiki.en.vecFastTextWikipediaInglês~1.5 MBwiki.pt.align.vecFastTextWikipediaPortuguês~1.2 GBGoogleNews-vectors-negative300Word2VecGoogle NewsPortuguês~1.5 GBTotal estimado~0.5–1.5 GB
⚠️ Os modelos pré-treinados são grandes. Contudo, é possível treinar modelos menores com dados próprios. Mais adiante será apresentado em exemplo de implementação para criar um modelo customizado.
📥 Instalação
Via PIP:
pip install gensim scipy numpy
ou requirements.txt:
gensim
scipy
numpy
💻 Exemplo de implementação com modelos pré-treinados
Exemplo com Word2Vec
import gensim
def compare_texts_gensim(real_text: str, candidate: str, clean_string = True):
if real_text is None or candidate is None:
return None
if clean_string:
real_text = clean_text(real_text)
candidate = clean_text(candidate)
model = gensim.models.KeyedVectors.load_word2vec_format('wiki.pt.vec', binary=False)
similarity = model.similarity(real_text, candidate)
return round(similarity, 2)
print(compate_texts_gensim(
"O gato está no telhado.",
"Um felino está em cima da casa."
))
Exemplo com FastText
from gensim.models import KeyedVectors
def compate_texts_gensim(real_text: str, candidate: str):
# Carrega modelo FastText pré-treinado:
model = KeyedVectors.load_word2vec_format('wiki.pt.vec', binary=False)
# Calcula e retorna a similaridade:
similarity = model.similarity(real_text, candidate)
return round(similarity, 2)
print(compate_texts_gensim(
"O gato está no telhado.",
"Um felino está em cima da casa."
))
💻 Modelo customizado Word2Vec com Gensim
Para treinar um modelo com dados próprios, usando Word2Vec com Gensim, utilize o exemplo de implementação abaixo:
from gensim.models import Word2Vec
sentences = [
["gato", "no", "telhado"],
["felino", "em", "cima", "da", "casa"]
]
model = Word2Vec(
sentences,
vector_size=100,
window=5,
min_count=1,
workers=4
)
similarity = model.wv.similarity("gato", "felino")
print(f"Similaridade: {similarity:.4f}")
👉 Resumo e Conclusão
O método de implementação e o modelo ideais vão depender da necessidade específica. Há métodos que oferecem alta eficiência semântica, porém são mais pesados. Por outro lado, temos métodos extremamente leves e rápidos, porém, com baixa eficiência semântica e análise semântica superficial.
Para necessidades muito simples e textos curtos, métodos como Levenshtein e TF-IDF poderiam ser usados. Em especial, o TF-IDF pode ter seu potencial maximizado utilizando pré-processamento e customização de stop words, para se adequar melhor ao contexto aplicado.
Para casos em que a análise semântica profunda é necessária, uma implementação com Transformers e ONNX se mostrou a mais adequada. Com ONNX pode-se utilizar uma grande diversidade de modelos, dentre os quais, para efeitos desse trabalho, pôde-se encontrar um modelo de ~90 MB que apresentou excelentes resultados.
O ONNX é uma ótima opção ao Sentence Transformer, o qual exige PyTorch e se torna uma opção mais pesada. Além disso, o ONNX oferece grande variedade de modelos e é multiplataforma, com implementação bastante facilitada pela biblioteca light_embed. Esta foi a escolha óbvia ao final deste trabalho e solução adotada para avaliação do produto multi agente, objetivo final desta pesquisa.
🔍 Comparação entre métodos de implementação
A seguir, duas tabelas comparativas entre os métodos avaliados para a implementação da técnica de comparação por similaridade semântica.
⚡Comparativo de eficiência semântica, velocidade e tamanho
⚡Impacto do pré-processamento na eficiência e velocidade
#DataScience #GenerativeAI #AgenticAI #AI #ML







Leave a Reply