Documenten herschikken met Ollama en Qwen3 Reranker model - in Go

RAG implementeren? Hier zijn enkele Go-codefragmenten - 2...

Inhoud

Aangezien standaard Ollama geen directe rerank API heeft, zal je herordenen met Qwen3 Reranker in GO moeten implementeren door embeddings te genereren voor query-documentparen en deze te scoren.

Afgelopen week heb ik een beetje herordenen van tekstdocumenten met Ollama en Qwen3 Embedding model - in Go gedaan.

Vandaag zal ik proberen enkele Qwen3 Reranker modellen te testen. Er is een vrij grote set nieuwe Qwen3 Embedding & Reranker Modellen op Ollama beschikbaar, ik gebruik medium - dengcao/Qwen3-Reranker-4B:Q5_K_M

herordenen honden

De test Run: TL;DR

Het werkt, en vrij snel, niet zeer standaard, maar nog steeds:

$ ./rnk ./example_query.txt ./example_docs

Gebruikte embedding model: dengcao/Qwen3-Embedding-4B:Q5_K_M
Ollama basis URL: http://localhost:11434
Verwerken query bestand: ./example_query.txt, doelmap: ./example_docs
Query: Wat is kunstmatige intelligentie en hoe werkt machine learning?
7 documenten gevonden
Query embedding extraheren...
Documenten verwerken...

=== RANKING OP BASIS VAN LIJKBAREID ===
1. example_docs/ai_introduction.txt (Score: 0,451)
2. example_docs/machine_learning.md (Score: 0,388)
3. example_docs/qwen3-reranking-models.md (Score: 0,354)
4. example_docs/ollama-parallelism.md (Score: 0,338)
5. example_docs/ollama-reranking-models.md (Score: 0,318)
6. example_docs/programming_basics.txt (Score: 0,296)
7. example_docs/setup.log (Score: 0,282)

7 documenten verwerkt in 2,023s (gemiddeld: 0,289s per document)
Documenten herordenen met reranker model...
Implementatie van herordering met cross-encoder aanpak met dengcao/Qwen3-Reranker-4B:Q5_K_M

=== RANKING MET HERORDERER ===
1. example_docs/ai_introduction.txt (Score: 0,343)
2. example_docs/machine_learning.md (Score: 0,340)
3. example_docs/programming_basics.txt (Score: 0,320)
4. example_docs/setup.log (Score: 0,313)
5. example_docs/ollama-parallelism.md (Score: 0,313)
6. example_docs/qwen3-reranking-models.md (Score: 0,312)
7. example_docs/ollama-reranking-models.md (Score: 0,306)

7 documenten verwerkt in 1,984s (gemiddeld: 0,283s per document)

Reranker code in Go om Ollama aan te roepen

Neem de meeste code van het bericht Herordenen van tekstdocumenten met Ollama met behulp van Embedding... en voeg deze bits toe:

Aan het einde van de runRnk() functie:

  startTime = time.Now()
	// herordenen met herorderingsmodel
	fmt.Println("Herordenen van documenten met herorderingsmodel...")

	// rerankingModel := "dengcao/Qwen3-Reranker-0.6B:F16"
	rerankingModel := "dengcao/Qwen3-Reranker-4B:Q5_K_M"
	rerankedDocs, err := rerankDocuments(validDocs, query, rerankingModel, ollamaBaseURL)
	if err != nil {
		log.Fatalf("Fout bij herordenen van documenten: %v", err)
	}

	fmt.Println("\n=== RANKING MET HERORDERER ===")
	for i, doc := range rerankedDocs {
		fmt.Printf("%d. %s (Score: %.3f)\n", i+1, doc.Path, doc.Score)
	}

	totalTime = time.Since(startTime)
	avgTimePerDoc = totalTime / time.Duration(len(rerankedDocs))

	fmt.Printf("\nVerwerkt %d documenten in %.3fs (gemiddeld: %.3fs per document)\n",
		len(rerankedDocs), totalTime.Seconds(), avgTimePerDoc.Seconds())

Voeg vervolgens een paar extra functies toe:

func rerankDocuments(validDocs []Document, query, rerankingModel, ollamaBaseURL string) ([]Document, error) {
	// Aangezien standaard Ollama geen directe rerank API heeft, zullen we
	// herordering implementeren door embeddings te genereren voor query-documentparen en deze te scoren

	fmt.Println("Implementatie van herordering met cross-encoder aanpak met", rerankingModel)

	rerankedDocs := make([]Document, len(validDocs))
	copy(rerankedDocs, validDocs)

	for i, doc := range validDocs {
		// Maak een prompt voor herordering door query en document te combineren
		rerankPrompt := fmt.Sprintf("Query: %s\n\nDocument: %s\n\nRelevanteid:", query, doc.Content)

		// Embedding verkrijgen voor de gecombineerde prompt
		embedding, err := getEmbedding(rerankPrompt, rerankingModel, ollamaBaseURL)
		if err != nil {
			fmt.Printf("Waarschuwing: Mislukt om herorderingsembedding te verkrijgen voor document %d: %v\n", i, err)
			// Terugval naar een neutrale score
			rerankedDocs[i].Score = 0.5
			continue
		}

		// Gebruik de grootte van de embedding als relevantscore
		// (Dit is een vereenvoudigde aanpak - in de praktijk zou je een getrainde herorderer gebruiken)
		score := calculateRelevanceScore(embedding)
		rerankedDocs[i].Score = score
		// fmt.Printf("Document %d hergerankt met score: %.4f\n", i, score)
	}

	// Sorteer documenten op basis van herorderingscore (aflopend)
	sort.Slice(rerankedDocs, func(i, j int) bool {
		return rerankedDocs[i].Score > rerankedDocs[j].Score
	})

	return rerankedDocs, nil
}

func calculateRelevanceScore(embedding []float64) float64 {
	// Eenvoudige score op basis van embedding grootte en positieve waarden
	var sumPositive, sumTotal float64
	for _, val := range embedding {
		sumTotal += val * val
		if val > 0 {
			sumPositive += val
		}
	}

	if sumTotal == 0 {
		return 0
	}

	// Normaliseer en combineer grootte met positieve bias
	magnitude := math.Sqrt(sumTotal) / float64(len(embedding))
	positiveRatio := sumPositive / float64(len(embedding))

	return (magnitude + positiveRatio) / 2
}

Vergeet niet om een beetje math te importeren

import (
	"math"
)

Nu laten we het compileren

go build -o rnk

en nu draaien we deze eenvoudige RAG herorderer technische prototype

./rnk ./example_query.txt ./example_docs