Hai un archivio di documenti tecnici, un catalogo prodotti o una knowledge base. La ricerca con parole esatte non basta: un utente cerca “riparazione rapida del forno” e tu hai scritto “manutenzione veloce del forno”. Zero risultati. Frustrazione. Abbandono.
Il problema è che la macchina non capisce il significato, confronta solo stringhe. Le parole sono le stesse? No. Per questo serve un approccio diverso: gli embeddings. Trasformano il testo in numeri che rappresentano il senso, non i caratteri. Così “riparazione rapida” e “manutenzione veloce” diventano vicini in uno spazio vettoriale. La ricerca diventa semantica.
Noi, di Meteora Web, abbiamo integrato questa tecnica in progetti reali: da motori di ricerca interni a chatbot per assistenza clienti. In questa guida vediamo come funzionano gli embeddings, quali modelli usare e come costruire un sistema di search semantica in Python. Niente teoria astratta: codice che funziona, esempi concreti, scelte ragionate.
Cosa sono gli embeddings e perché sono fondamentali per la search semantica?
Un embedding è una rappresentazione vettoriale densa di un testo: una lista di numeri (tipicamente da 384 a 4096 dimensioni) che cattura il significato. Parole o frasi simili hanno vettori vicini nello spazio multidimensionale. La distanza si misura con similarità del coseno o prodotto scalare.
Perché funziona? Perché i modelli di embedding (come Sentence-BERT, OpenAI ada-002, Cohere embed) sono addestrati su enormi quantità di testi per imparare relazioni semantiche. Non conta se le parole sono diverse: conta il contesto e il senso.
Esempio pratico: immagina di dover cercare in un database di manuali. La query “spegnimento di emergenza stampante” deve trovare documenti che parlano di “arresto immediato della periferica” anche se le parole non combaciano. Con un embedding, i due testi avranno un coseno > 0.8, mentre con una ricerca lessicale classica sarebbero a zero.
Sponsored Protocol
Vantaggio per la tua azienda: riduzione del tempo di ricerca, aumento della soddisfazione utente, possibilità di domande in linguaggio naturale. Se il tuo sito o la tua intranet hanno centinaia o migliaia di documenti, la search semantica è un salto di qualità.
Come funziona la conversione da testo a vettore?
Prendi una frase. La passi a un modello pre-addestrato che restituisce un array di float. Sembra magia, ma è matematica: il modello trasforma ogni parola in un vettore di base, poi li combina (media, pooling, transformer) per ottenere un vettore fisso per l’intera frase.
Vediamo un esempio concreto usando sentence-transformers (libreria open-source, basata su modelli BERT/GPT). Il codice seguente carica un modello italiano, genera embedding per due frasi e calcola la similarità.
from sentence_transformers import SentenceTransformer, util
# Modello italiano: distiluse-base-multilingual-cased-v2
model = SentenceTransformer('distiluse-base-multilingual-cased-v2')
frase1 = "riparazione rapida del forno"
frase2 = "manutenzione veloce del forno"
emb1 = model.encode(frase1)
emb2 = model.encode(frase2)
similarity = util.cos_sim(emb1, emb2)
print(f"Similarità: {similarity.item():.4f}") # Output tipico: 0.85-0.95
Con poche righe abbiamo una misura di somiglianza semantica. Questo è il cuore della search: ogni documento della tua base viene indicizzato come vettore, la query dell’utente viene convertita allo stesso modo, e si cercano i vettori più vicini.
Sponsored Protocol
Importante: gli embedding non sono magici. Se il modello non è stato addestrato sul tuo dominio (es. linguaggio medico o legale), i risultati possono essere meno precisi. Esistono modelli specializzati (BioBERT, Legal-BERT) che puoi usare. Per la maggior parte dei casi d’uso business, un modello multilingua o italiano (come distiluse-base-multilingual-cased-v2 o paraphrase-multilingual-MiniLM-L12-v2) funziona bene.
Quali modelli di embeddings scegliere per l’italiano?
Non tutti i modelli sono uguali. Ecco una panoramica delle opzioni per search semantica in italiano:
- Sentence-Transformers (open source): modelli pre-addestrati su centinaia di lingue. Il nostro preferito:
distiluse-base-multilingual-cased-v2(512 dimensioni, buon rapporto qualità/velocità). Alternativa:paraphrase-multilingual-MiniLM-L12-v2(384 dimensioni, più veloce). - OpenAI Embeddings (API a pagamento): modello
text-embedding-ada-002(1536 dimensioni). Molto potente, ma richiede chiamata API (costo per token) e i dati escono dal tuo server. Utile per prototipi rapidi, meno per produzione se hai volumi elevati. - Cohere Embed (API a pagamento): supporto multilingua, buono per classificazione e search. Prezzo per chiamata.
- Google Vertex AI Embeddings (API Google Cloud): supporto italiano, integrato con infrastruttura Google.
Noi partiamo sempre dai modelli open-source: zero costi di API, privacy dei dati, possibilità di fine-tuning se necessario. Per la maggior parte dei progetti di PMI, il modello distiluse-base-multilingual-cased-v2 è più che sufficiente. Costa solo tempo di CPU, e una volta indicizzati i vettori, la latenza è bassa (pochi millisecondi per query).
Sponsored Protocol
Criteri di scelta:
- Volume di documenti: se hai milioni di docs, considera un modello più piccolo (384 dim) e indici vettoriali approssimati (faiss, Annoy).
- Precisione necessaria: se le query sono molto tecniche, testa modelli più grandi (768-1024 dim).
- Latenza: in tempo reale (chatbot), preferisci modelli con encoding veloce.
- Privacy: non inviare dati sensibili a API esterne; usa modelli locali.
Come costruire un sistema di ricerca semantica con embeddings e Python?
Ecco i passi operativi per una soluzione end-to-end. Supponiamo di avere una lista di documenti (testi di articoli, descrizioni prodotti, FAQ). Creeremo un indice vettoriale e una funzione di query.
1. Indicizzare i documenti
from sentence_transformers import SentenceTransformer
import numpy as np
model = SentenceTransformer('distiluse-base-multilingual-cased-v2')
documents = [
"Come effettuare la manutenzione ordinaria del forno",
"Procedura di spegnimento di emergenza stampante laser",
"Riparazione rapida del forno a gas",
"Configurazione stampante in rete Wi-Fi"
]
embeddings = model.encode(documents, show_progress_bar=True)
# Salva su file o in memoria
np.save('document_embeddings.npy', embeddings)
# Salva anche i documenti originali
with open('documents.txt', 'w') as f:
for doc in documents:
f.write(doc + '\n')
2. Eseguire una query
import numpy as np
from sentence_transformers import SentenceTransformer, util
model = SentenceTransformer('distiluse-base-multilingual-cased-v2')
# Carica indice
embeddings = np.load('document_embeddings.npy')
with open('documents.txt', 'r') as f:
documents = [line.strip() for line in f]
query = "arresto stampante in emergenza"
query_embedding = model.encode(query)
# Calcola similarità con tutti i documenti
scores = util.cos_sim(query_embedding, embeddings)[0]
top_indices = np.argsort(scores)[::-1][:3] # top 3
for i, idx in enumerate(top_indices):
print(f"{i+1}. {documents[idx]} (score: {scores[idx]:.4f})")
Output tipico:
Sponsored Protocol
1. Procedura di spegnimento di emergenza stampante laser (score: 0.9123)
2. Configurazione stampante in rete Wi-Fi (score: 0.4210)
3. Come effettuare la manutenzione ordinaria del forno (score: 0.3872)
La prima risposta è semanticamente pertinente, nonostante “arresto” non compaia nel testo.
3. Scalare con indici vettoriali
Per insiemi >10.000 documenti, fare coseno su tutto l’array diventa lento. Usiamo FAISS (Facebook AI Similarity Search) per ricerca approssimata:
import faiss
import numpy as np
# Costruisce indice Flat (esatto, per benchmark)
dimension = embeddings.shape[1]
index = faiss.IndexFlatIP(dimension) # Inner Product ≈ coseno con vettori normalizzati
faiss.normalize_L2(embeddings)
index.add(embeddings)
# Query
query_vec_norm = query_embedding / np.linalg.norm(query_embedding)
scores, indices = index.search(np.array([query_vec_norm]), k=3)
Con FAISS possiamo gestire milioni di vettori in millisecondi. Documentazione ufficiale FAISS.
Come valutare la qualità degli embeddings nella search semantica?
Non basta lanciare il codice. Devi validare che il sistema restituisca risultati utili. Due metriche pratiche:
- Recall@k: quante volte il risultato corretto è nei primi k risultati.
- Precision@k: quanti dei primi k risultati sono realmente pertinenti.
Puoi creare un piccolo dataset di test con query e documenti rilevanti etichettati manualmente. Poi calcoli le metriche e confronti modelli diversi.
Sponsored Protocol
Errore comune: usare il modello pre-addestrato senza adattarlo al tuo dominio. Se i documenti sono in gergo specialistico, considera il fine-tuning con coppie di frasi simili/dissimili del tuo settore. Sentence-Transformers permette di farlo con poche righe.
Noi, di Meteora Web, abbiamo visto un cliente aumentare la precisione dal 40% al 78% semplicemente passando da un modello generico a uno fine-tuned su manuali tecnici di macchinari industriali. Il costo di addestramento è stato irrisorio rispetto al ritorno in efficienza.
Cosa fare adesso
- Identifica il tuo caso d’uso: search su sito, assistente virtuale interno, raccomandazione prodotti?
- Scegli il modello: parti con
distiluse-base-multilingual-cased-v2oparaphrase-multilingual-MiniLM-L12-v2– open source, gratis, nessun dato esce dal perimetro. - Indicizza i tuoi contenuti: estrai testi puliti (senza HTML, senza boilerplate), genera embeddings, salva su disco o database vettoriale (Chroma, Pinecone, Qdrant – ma per iniziare basta numpy).
- Testa con query reali: prendi 10-20 domande che ricevi spesso dagli utenti e verifica che i risultati siano pertinenti.
- Integra nel tuo frontend: una semplice API Flask/Express che riceve una query e restituisce i top N documenti.
Se hai dubbi su quali modelli adottare o vuoi che valutiamo il tuo dataset, contattaci. La search semantica non è un lusso: è ciò che separa un’esperienza utente frustrante da una che converte.
Approfondisci il contesto con la Pillar Guide su LangChain e LLM, dove gli embeddings sono uno dei mattoni fondamentali.