Texte mit Ollama und Qwen3 Embedding LLM neu rangieren – in Go
RAG umsetzen? Hier sind einige Codeausschnitte in Golang.
Dieses kleine Reranking Go-Codebeispiel ruft Ollama auf, um Embeddings zu generieren für die Abfrage und für jede Kandidatendokumente, dann Sortieren nach absteigender Kosinusähnlichkeit.
Wir haben bereits eine ähnliche Aktivität durchgeführt - Reranking mit Embedding-Modellen aber das war in Python, mit einem anderen LLM und fast ein Jahr alt.
Ein weiteres ähnliches Codebeispiel, aber mit Qwen3 Reranker:
TL;DR
Das Ergebnis sieht sehr gut aus, die Geschwindigkeit beträgt 0,128 Sekunden pro Dokument. Die Frage wird als Dokument gezählt. Und das Sortieren und Drucken sind auch in diese Statistik einbezogen.
LLM-Speicherbedarf:
Obwohl die Modellgröße auf der SSD (ollama ls
) kleiner als 3 GB ist
dengcao/Qwen3-Embedding-4B:Q5_K_M 7e8c9ad6885b 2,9 GB
Benötigt es in der GPU VRAM (nicht ein bisschen) mehr: 5,5 GB. (ollama ps
)
NAME ID SIZE
dengcao/Qwen3-Embedding-4B:Q5_K_M 7e8c9ad6885b 5,5 GB
Wenn Sie eine GPU mit 8 GB haben - sollte das in Ordnung sein.
Reranking mit Embeddings auf Ollama - Beispieloutput
In allen drei Testfällen war das Reranking mit Embedding mithilfe des Ollama-Modells dengcao/Qwen3-Embedding-4B:Q5_K_M großartig! Sehen Sie es selbst.
Wir haben 7 Dateien mit Texten, die beschreiben, was ihr Dateiname sagt:
- ai_introduction.txt
- machine_learning.md
- qwen3-reranking-models.md
- ollama-parallelism.md
- ollama-reranking-models.md
- programming_basics.txt
- setup.log
Testläufe:
Reranking-Test: Was ist künstliche Intelligenz und wie funktioniert maschinelles Lernen?
./rnk example_query.txt example_docs/
Verwendetes Embedding-Modell: dengcao/Qwen3-Embedding-4B:Q5_K_M
Ollama-Grund-URL: http://localhost:11434
Verarbeite Abfrage-Datei: example_query.txt, Zielverzeichnis: example_docs/
Abfrage: Was ist künstliche Intelligenz und wie funktioniert maschinelles Lernen?
7 Dokumente gefunden
Extrahiere Abfrage-Embedding...
Verarbeite Dokumente...
=== RANGLISTE NACH ÄHNLICHKEIT ===
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 Dokumente verarbeitet in 0,899s (Durchschnitt: 0,128s pro Dokument)
Reranking-Test: Wie verarbeitet Ollama parallele Anfragen?
./rnk example_query2.txt example_docs/
Verwendetes Embedding-Modell: dengcao/Qwen3-Embedding-4B:Q5_K_M
Ollama-Grund-URL: http://localhost:11434
Verarbeite Abfrage-Datei: example_query2.txt, Zielverzeichnis: example_docs/
Abfrage: Wie verarbeitet Ollama parallele Anfragen?
7 Dokumente gefunden
Extrahiere Abfrage-Embedding...
Verarbeite Dokumente...
=== RANGLISTE NACH ÄHNLICHKEIT ===
1. example_docs/ollama-parallelism.md (Score: 0,557)
2. example_docs/qwen3-reranking-models.md (Score: 0,532)
3. example_docs/ollama-reranking-models.md (Score: 0,498)
4. example_docs/ai_introduction.txt (Score: 0,366)
5. example_docs/machine_learning.md (Score: 0,332)
6. example_docs/programming_basics.txt (Score: 0,307)
7. example_docs/setup.log (Score: 0,257)
7 Dokumente verarbeitet in 0,858s (Durchschnitt: 0,123s pro Dokument)
Reranking-Test: Wie können wir das Reranking eines Dokuments mit Ollama durchführen?
./rnk example_query3.txt example_docs/
Verwendetes Embedding-Modell: dengcao/Qwen3-Embedding-4B:Q5_K_M
Ollama-Grund-URL: http://localhost:11434
Verarbeite Abfrage-Datei: example_query3.txt, Zielverzeichnis: example_docs/
Abfrage: Wie können wir das Reranking eines Dokuments mit Ollama durchführen?
7 Dokumente gefunden
Extrahiere Abfrage-Embedding...
Verarbeite Dokumente...
=== RANGLISTE NACH ÄHNLICHKEIT ===
1. example_docs/ollama-reranking-models.md (Score: 0,552)
2. example_docs/ollama-parallelism.md (Score: 0,525)
3. example_docs/qwen3-reranking-models.md (Score: 0,524)
4. example_docs/ai_introduction.txt (Score: 0,369)
5. example_docs/machine_learning.md (Score: 0,346)
6. example_docs/programming_basics.txt (Score: 0,316)
7. example_docs/setup.log (Score: 0,279)
7 Dokumente verarbeitet in 0,882s (Durchschnitt: 0,126s pro Dokument)
Go-Quellcode
Legen Sie alles in einen Ordner und kompilieren Sie es wie folgt
go build -o rnk
Sie können es frei in jedem unterhaltsamen oder kommerziellen Zweck verwenden oder es bei Bedarf auf GitHub hochladen. MIT-Lizenz.
main.go
package main
import (
"fmt"
"log"
"os"
"sort"
"time"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
Use: "rnk [query-file] [target-directory]",
Short: "RAG-System mit Ollama-Embeddings",
Long: "Ein einfaches RAG-System, das Embeddings extrahiert und Dokumente mithilfe von Ollama rangiert",
Args: cobra.ExactArgs(2),
Run: runRnk,
}
var (
embeddingModel string
ollamaBaseURL string
)
func init() {
rootCmd.Flags().StringVarP(&embeddingModel, "model", "m", "dengcao/Qwen3-Embedding-4B:Q5_K_M", "Embedding-Modell, das verwendet werden soll")
rootCmd.Flags().StringVarP(&ollamaBaseURL, "url", "u", "http://localhost:11434", "Ollama-Grund-URL")
}
func main() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func runRnk(cmd *cobra.Command, args []string) {
queryFile := args[0]
targetDir := args[1]
startTime := time.Now()
fmt.Printf("Verwendetes Embedding-Modell: %s\n", embeddingModel)
fmt.Printf("Ollama-Grund-URL: %s\n", ollamaBaseURL)
fmt.Printf("Verarbeite Abfrage-Datei: %s, Zielverzeichnis: %s\n", queryFile, targetDir)
// Lesen Sie die Abfrage aus der Datei
query, err := readQueryFromFile(queryFile)
if err != nil {
log.Fatalf("Fehler beim Lesen der Abfragedatei: %v", err)
}
fmt.Printf("Abfrage: %s\n", query)
// Finden Sie alle Textdateien im Zielverzeichnis
documents, err := findTextFiles(targetDir)
if err != nil {
log.Fatalf("Fehler beim Finden der Textdateien: %v", err)
}
fmt.Printf("Gefunden: %d Dokumente\n", len(documents))
// Extrahieren Sie Embeddings für die Abfrage
fmt.Println("Extrahiere Abfrage-Embedding...")
queryEmbedding, err := getEmbedding(query, embeddingModel, ollamaBaseURL)
if err != nil {
log.Fatalf("Fehler beim Extrahieren des Abfrage-Embeddings: %v", err)
}
// Verarbeiten Sie die Dokumente
fmt.Println("Verarbeite Dokumente...")
validDocs := make([]Document, 0)
for _, doc := range documents {
embedding, err := getEmbedding(doc.Content, embeddingModel, ollamaBaseURL)
if err != nil {
fmt.Printf("Warnung: Fehlgeschlagen, Embedding für %s zu erhalten: %v\n", doc.Path, err)
continue
}
similarity := cosineSimilarity(queryEmbedding, embedding)
doc.Score = similarity
validDocs = append(validDocs, doc)
}
if len(validDocs) == 0 {
log.Fatalf("Keine Dokumente konnten erfolgreich verarbeitet werden")
}
// Sortieren Sie nach Ähnlichkeitspunktzahl (absteigend)
sort.Slice(validDocs, func(i, j int) bool {
return validDocs[i].Score > validDocs[j].Score
})
// Zeigen Sie die Ergebnisse an
fmt.Println("\n=== RANGLISTE NACH ÄHNLICHKEIT ===")
for i, doc := range validDocs {
fmt.Printf("%d. %s (Score: %.3f)\n", i+1, doc.Path, doc.Score)
}
totalTime := time.Since(startTime)
avgTimePerDoc := totalTime / time.Duration(len(validDocs))
fmt.Printf("\nVerarbeitet %d Dokumente in %.3fs (Durchschnitt: %.3fs pro Dokument)\n",
len(validDocs), totalTime.Seconds(), avgTimePerDoc.Seconds())
}
documents.go
package main
import (
"fmt"
"os"
"path/filepath"
"strings"
)
func readQueryFromFile(filename string) (string, error) {
content, err := os.ReadFile(filename)
if err != nil {
return "", err
}
return strings.TrimSpace(string(content)), nil
}
func findTextFiles(dir string) ([]Document, error) {
var documents []Document
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() && isTextFile(path) {
content, err := os.ReadFile(path)
if err != nil {
fmt.Printf("Warnung: Datei %s konnte nicht gelesen werden: %v\n", path, err)
return nil
}
documents = append(documents, Document{
Path: path,
Content: string(content),
})
}
return nil
})
return documents, err
}
func isTextFile(filename string) bool {
ext := strings.ToLower(filepath.Ext(filename))
textExts := []string{".txt", ".md", ".rst", ".csv", ".json", ".xml", ".html", ".htm", ".log"}
for _, textExt := range textExts {
if ext == textExt {
return true
}
}
return false
}
embeddings.go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func getEmbedding(text string, model string, ollamaBaseURL string) ([]float64, error) {
req := OllamaEmbeddingRequest{
Model: model,
Prompt: text,
}
jsonData, err := json.Marshal(req)
if err != nil {
return nil, err
}
resp, err := http.Post(ollamaBaseURL+"/api/embeddings", "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("Ollama API-Fehler: %s", string(body))
}
var embeddingResp OllamaEmbeddingResponse
if err := json.NewDecoder(resp.Body).Decode(&embeddingResp); err != nil {
return nil, err
}
return embeddingResp.Embedding, nil
}
similarity.go
package main
func cosineSimilarity(a, b []float64) float64 {
if len(a) != len(b) {
return 0
}
var dotProduct, normA, normB float64
for i := range a {
dotProduct += a[i] * b[i]
normA += a[i] * a[i]
normB += b[i] * b[i]
}
if normA == 0 || normB == 0 {
return 0
}
return dotProduct / (sqrt(normA) * sqrt(normB))
}
func sqrt(x float64) float64 {
if x == 0 {
return 0
}
z := x
for i := 0; i < 10; i++ {
z = (z + x/z) / 2
}
return z
}
types.go
package main
// OllamaEmbeddingRequest stellt die Anforderungslast für die Ollama-Embedding-API dar
type OllamaEmbeddingRequest struct {
Model string `json:"model"`
Prompt string `json:"prompt"`
}
// OllamaEmbeddingResponse stellt die Antwort von der Ollama-Embedding-API dar
type OllamaEmbeddingResponse struct {
Embedding []float64 `json:"embedding"`
}
// Document stellt ein Dokument mit seinen Metadaten dar
type Document struct {
Path string
Content string
Score float64
}
Nützliche Links
- Ollama Cheatsheet
- Reranking von Textdokumenten mit Ollama und Qwen3 Reranker-Modell - in Go
- Qwen3 Embedding & Reranker-Modelle auf Ollama: State-of-the-Art-Leistung
- https://de.wikipedia.org/wiki/Retrieval-augmented_generation
- Installieren und Konfigurieren der Ollama-Modell-Position
- Wie Ollama parallele Anfragen verarbeitet
- Schreiben effektiver Prompts für LLMs
- Testen von LLMs: gemma2, qwen2 und Mistral Nemo auf Ollama
- LLMs-Vergleich: Mistral Small, Gemma 2, Qwen 2.5, Mistral Nemo, LLama3 und Phi - Auf Ollama
- Test: Wie Ollama Intel-CPU-Performance und effiziente Kerne verwendet
- Reranking mit Embedding-Modellen auf Ollama in Python
- Vergleich der Zusammenfassungsfähigkeiten von LLMs
- Cloud-LLM-Anbieter