Reranking con modelli di embedding

Un codice Python per il reranking di RAG

Indice

Reranking è un secondo passo nella Generazione Aumentata dal Recupero (RAG) sistemi, posizionato esattamente tra il Recupero e la Generazione.

Cubi elettrici nello spazio digitale

Questo è come Flux-1 dev immagina Cubi elettrici nello spazio digitale.

Per una guida completa sulla costruzione di sistemi RAG, consulta il Tutorial Generazione Aumentata dal Recupero (RAG): Architettura, Implementazione e Guida alla Produzione.

Questo articolo si concentra sul ridordinamento con modelli di embedding. Per approcci alternativi, puoi anche consultare Ridordinamento di testi con Ollama e Qwen3 Embedding LLM - in Go e Ridordinamento di documenti con Ollama e modello Reranker Qwen3 - in Go.

Recupero con ridordinamento

Se immagazziniamo i documenti sotto forma di embedding nel database vettoriale fin dall’inizio, il recupero ci fornirà immediatamente l’elenco dei documenti simili.

Ridordinamento autonomo

Tuttavia, se scarichiamo prima i documenti da Internet, la risposta del sistema di ricerca potrebbe essere influenzata dalle preferenze/algoritmi del provider di ricerca, contenuti sponsorizzati, ottimizzazione SEO, ecc., quindi abbiamo bisogno di un ridordinamento post-ricerca.

Cosa stavo facendo:

  • ottenere gli embedding per la query di ricerca
  • ottenere gli embedding per ciascun documento. Il documento non doveva comunque superare i 8k token
  • calcolare la similarità tra la query e gli embedding di ciascun documento
  • ordinare i documenti in base a questa similarità.

Nessun database vettoriale qui, andiamo.

Codice di esempio

Utilizzo di Langchain per connettersi a Ollama e della funzione cosine_similarity di Langchain. Puoi filtrare in base alla misura di similarità, ma tieni presente che per diversi domini e LLM di embedding la soglia sarà diversa.

Sarò felice se questo frammento di codice ti sarà utile in qualche modo. Licenza Copia/Incolla/UsaComeVuoi. Saluti.

from langchain_core.documents import Document
from langchain_community.embeddings import OllamaEmbeddings
from langchain_community.utils.math import cosine_similarity
import numpy as np


def cosine_distance(a: np.ndarray, b: np.ndarray) -> np.ndarray:
    return 1.0 - cosine_similarity(a, b)

def compute_score(vectors: np.ndarray) -> float:
    score = cosine_distance(vectors[0].reshape(1, -1), vectors[1].reshape(1, -1)).item()
    return score

def list_to_array(lst):
    return np.array(lst, dtype=float)   

def compute_scorel(lists) -> float:
    v1 = list_to_array(lists[0])
    v2 = list_to_array(lists[1])
    return compute_score([v1, v2])

def filter_docs(emb_model_name, docs, query, num_docs):
    content_arr = [doc.page_content for doc in docs]

    ollama_emb = OllamaEmbeddings(
        model=emb_model_name
    )

    docs_embs = ollama_emb.embed_documents(content_arr)
    query_embs = ollama_emb.embed_query(query)
    sims = []
    for i, emb in enumerate(docs_embs):
        idx = docs[i].id
        s = compute_scorel([query_embs, docs_embs[i]])
        simstr = str(round(s, 4))
        docs[i].metadata["sim"] = simstr
        sim = {
            "idx": idx,
            "i": i,
            "sim": s,
        }
        sims.append(sim)

    sims.sort(key=sortFn)

    sorted_docs = [docs[x["i"]] for x in sims]
    filtered_docs = sorted_docs[:num_docs]
    return filtered_docs

Migliori Modelli di Embedding

Per i miei compiti, il miglior modello di embedding attualmente è bge-large:335m-en-v1.5-fp16.

Il secondo posto è stato preso da nomic-embed-text:137m-v1.5-fp16 e jina/jina-embeddings-v2-base-en:latest.

Ma effettua i tuoi test per il tuo dominio e le tue query.