Herordenen met embeddingmodellen

Een Python-code voor het herordenen van RAG

Inhoud

Reranking is een tweede stap in Retrieval Augmented Generation (RAG) systemen, recht tussen het Ophalen en het Genereren.

Elektrische kubussen in digitale ruimte

Het hierboven is hoe Flux-1 dev Elektrische kubussen in digitale ruimte voorstelt.

Ophalen met reranking

Als we de documenten vanaf het begin opslaan in de vorm van embeddings in de vector DB - dan geeft het ophalen direct een lijst met vergelijkbare documenten.

Afhankelijk reranking

Maar als we de documenten eerst van het internet downloaden, kan het antwoord van het zoeksysteem beïnvloed worden door voorkeuren/algoritmen van zoekproviders, gesponsorde inhoud, SEO-optimalisatie, enzovoort, dus we hebben postzoek reranking nodig.

Wat ik deed:

  • embeddings ophalen voor de zoekquery
  • embeddings ophalen voor elk document. het document werd sowieso niet verwacht te zijn langer dan 8k tokens
  • de gelijkenis tussen query en elk van de documentembeddings berekenen
  • documenten sorteren op basis van deze gelijkenis.

Geen vector DB hier, laten we gaan.

Voorbeeldcode

Met behulp van Langchain om verbinding te maken met Ollama en de cosine_similarity functie van langchain. Je kunt filteren op gelijkenismaat, maar houd er rekening mee dat de drempel anders is voor verschillende domeinen en embedding LLMs.

Ik ben blij als deze code op welke manier dan ook voor jou nuttig is. Copy/Paste/UseAnyWayYouWant licentie. Cheers.

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

Beste Embeddingmodellen

Voor mijn taken is momenteel het beste embeddingmodel bge-large:335m-en-v1.5-fp16

Op tweede plaats kwam nomic-embed-text:137m-v1.5-fp16 en jina/jina-embeddings-v2-base-en:latest.

Maar voer je eigen tests uit voor je eigen domein en queries.