Omrankning av dokument med Ollama och Qwen3 Reranker-modellen - i Go

Implementerar RAG? Här är några kodbitar på Go - 2...

Sidinnehåll

Ett standard Ollama-verktyg har ingen direkt rerank-API, så du måste implementera reranking med Qwen3 Reranker i GO genom att generera inbäddningar för fråga-dokument-par och poängsätta dem.

Förra veckan gjorde jag lite Reranking av textdokument med Ollama och Qwen3 Embedding-modell - i Go.

Idag ska jag testa några Qwen3 Reranker-modeller. Det finns ett ganska stort urval av nya Qwen3 Embedding & Reranker-modeller på Ollama tillgängliga, jag använder medium - dengcao/Qwen3-Reranker-4B:Q5_K_M

reranking hundar

Testkörning: TL;DR

Det fungerar, och ganska snabbt, inte på ett mycket standardiserat sätt, men ändå:

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

Använder embedding-modell: dengcao/Qwen3-Embedding-4B:Q5_K_M
Ollama bas-URL: http://localhost:11434
Bearbetar frågefils: ./example_query.txt, målmap: ./example_docs
Fråga: Vad är artificiell intelligens och hur fungerar maskininlärning?
Hittade 7 dokument
Extraherar frågeinbäddning...
Bearbetar dokument...

=== RANKING EFTER LIKHET ===
1. example_docs/ai_introduction.txt (Poäng: 0.451)
2. example_docs/machine_learning.md (Poäng: 0.388)
3. example_docs/qwen3-reranking-models.md (Poäng: 0.354)
4. example_docs/ollama-parallelism.md (Poäng: 0.338)
5. example_docs/ollama-reranking-models.md (Poäng: 0.318)
6. example_docs/programming_basics.txt (Poäng: 0.296)
7. example_docs/setup.log (Poäng: 0.282)

Bearbetade 7 dokument på 2.023s (genomsnitt: 0.289s per dokument)
Rerankar dokument med reranker-modell...
Implementerar reranking med cross-encoder-metod med dengcao/Qwen3-Reranker-4B:Q5_K_M

=== RANKING MED RERANKER ===
1. example_docs/ai_introduction.txt (Poäng: 0.343)
2. example_docs/machine_learning.md (Poäng: 0.340)
3. example_docs/programming_basics.txt (Poäng: 0.320)
4. example_docs/setup.log (Poäng: 0.313)
5. example_docs/ollama-parallelism.md (Poäng: 0.313)
6. example_docs/qwen3-reranking-models.md (Poäng: 0.312)
7. example_docs/ollama-reranking-models.md (Poäng: 0.306)

Bearbetade 7 dokument på 1.984s (genomsnitt: 0.283s per dokument)

Reranker-kod i Go för att anropa Ollama

Ta mestadels koden från inlägget Reranking text documents with Ollama using Embedding... och lägg till dessa bitar:

Till slutet av runRnk()-funktionen:

  startTime = time.Now()
	// rerank med reranking-modell
	fmt.Println("Rerankar dokument med reranker-modell...")

	// 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("Fel vid reranking av dokument: %v", err)
	}

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

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

	fmt.Printf("\nBearbetade %d dokument på %.3fs (genomsnitt: %.3fs per dokument)\n",
		len(rerankedDocs), totalTime.Seconds(), avgTimePerDoc.Seconds())

Sen lägg till ett par fler funktioner:

func rerankDocuments(validDocs []Document, query, rerankingModel, ollamaBaseURL string) ([]Document, error) {
	// Eftersom standard Ollama inte har en direkt rerank-API, kommer vi att implementera
	// reranking genom att generera inbäddningar för fråga-dokument-par och poängsätta dem

	fmt.Println("Implementerar reranking med cross-encoder-metod med", rerankingModel)

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

	for i, doc := range validDocs {
		// Skapa en prompt för reranking genom att kombinera fråga och dokument
		rerankPrompt := fmt.Sprintf("Fråga: %s\n\nDokument: %s\n\nRelevans:", query, doc.Content)

		// Hämta inbäddning för den kombinerade prompten
		embedding, err := getEmbedding(rerankPrompt, rerankingModel, ollamaBaseURL)
		if err != nil {
			fmt.Printf("Varning: Misslyckades med att hämta rerank-inbäddning för dokument %d: %v\n", i, err)
			// Fallback till en neutral poäng
			rerankedDocs[i].Score = 0.5
			continue
		}

		// Använd storleken på inbäddningen som relevanspoäng
		// (Detta är en förenklad metod - i praktiken skulle du använda en tränad reranker)
		score := calculateRelevanceScore(embedding)
		rerankedDocs[i].Score = score
		// fmt.Printf("Dokument %d rerankat med poäng: %.4f\n", i, score)
	}

	// Sortera dokument efter reranking-poäng (fallande)
	sort.Slice(rerankedDocs, func(i, j int) bool {
		return rerankedDocs[i].Score > rerankedDocs[j].Score
	})

	return rerankedDocs, nil
}

func calculateRelevanceScore(embedding []float64) float64 {
	// Enkel poängsättning baserad på inbäddningsstorlek och positiva värden
	var sumPositive, sumTotal float64
	for _, val := range embedding {
		sumTotal += val * val
		if val > 0 {
			sumPositive += val
		}
	}

	if sumTotal == 0 {
		return 0
	}

	// Normalisera och kombinera storlek med positiv bias
	magnitude := math.Sqrt(sumTotal) / float64(len(embedding))
	positiveRatio := sumPositive / float64(len(embedding))

	return (magnitude + positiveRatio) / 2
}

Glöm inte att importera lite matematik

import (
	"math"
)

Nu ska vi kompilera det

go build -o rnk

och nu kör den här enkla RAG reranker-tekniska prototypen

./rnk ./example_query.txt ./example_docs

Användbara länkar