Reranking teks dengan Ollama dan Qwen3 Embedding LLM - dalam Go
Menerapkan RAG? Berikut adalah beberapa contoh kode dalam Golang...
Ini sedikit Contoh kode Go untuk reranking memanggil Ollama untuk menghasilkan embedding untuk query dan setiap dokumen kandidat, kemudian mengurutkan menurun berdasarkan kesamaan kosinus.
Kami sudah melakukan aktivitas serupa - Reranking dengan model embedding tetapi itu dalam python, dengan LLM yang berbeda dan hampir setahun yang lalu.
Kode serupa lainnya, tetapi menggunakan Qwen3 Reranker:
TL;DR
Hasilnya terlihat sangat baik, kecepatannya adalah 0,128 detik per dokumen. Pertanyaan dihitung sebagai dokumen. Dan pengurutan dan pencetakan juga termasuk dalam statistik ini.
Konsumsi memori LLM:
Meskipun ukuran model di sdd (ollama ls
) kurang dari 3 GB
dengcao/Qwen3-Embedding-4B:Q5_K_M 7e8c9ad6885b 2,9 GB
Di GPU VRAM membutuhkan (tidak sedikit) lebih: 5,5 GB. (ollama ps
)
NAMA ID UKURAN
dengcao/Qwen3-Embedding-4B:Q5_K_M 7e8c9ad6885b 5,5 GB
Jika Anda memiliki GPU 8 GB - seharusnya baik-baik saja.
Uji Coba Reranking dengan Embedding di Ollama - Output Contoh
Dalam semua tiga kasus uji reranking dengan embedding menggunakan model ollama dengcao/Qwen3-Embedding-4B:Q5_K_M sangat luar biasa! Lihat sendiri.
Kami memiliki 7 file yang berisi beberapa teks yang menggambarkan apa yang disebutkan oleh nama filenya:
- ai_introduction.txt
- machine_learning.md
- qwen3-reranking-models.md
- ollama-parallelism.md
- ollama-reranking-models.md
- programming_basics.txt
- setup.log
jalannya uji:
Uji reranking: Apa itu kecerdasan buatan dan bagaimana mesin belajar bekerja?
./rnk example_query.txt example_docs/
Menggunakan model embedding: dengcao/Qwen3-Embedding-4B:Q5_K_M
URL dasar Ollama: http://localhost:11434
Memproses file query: example_query.txt, direktori target: example_docs/
Query: Apa itu kecerdasan buatan dan bagaimana mesin belajar bekerja?
Ditemukan 7 dokumen
Mengekstrak embedding query...
Memproses dokumen...
=== PEMBAGIAN BERDASARKAN KESAMAAN ===
1. example_docs/ai_introduction.txt (Skor: 0,451)
2. example_docs/machine_learning.md (Skor: 0,388)
3. example_docs/qwen3-reranking-models.md (Skor: 0,354)
4. example_docs/ollama-parallelism.md (Skor: 0,338)
5. example_docs/ollama-reranking-models.md (Skor: 0,318)
6. example_docs/programming_basics.txt (Skor: 0,296)
7. example_docs/setup.log (Skor: 0,282)
Memproses 7 dokumen dalam 0,899s (rata-rata: 0,128s per dokumen)
Uji reranking: Bagaimana ollama menangani permintaan paralel?
./rnk example_query2.txt example_docs/
Menggunakan model embedding: dengcao/Qwen3-Embedding-4B:Q5_K_M
URL dasar Ollama: http://localhost:11434
Memproses file query: example_query2.txt, direktori target: example_docs/
Query: Bagaimana ollama menangani permintaan paralel?
Ditemukan 7 dokumen
Mengekstrak embedding query...
Memproses dokumen...
=== PEMBAGIAN BERDASARKAN KESAMAAN ===
1. example_docs/ollama-parallelism.md (Skor: 0,557)
2. example_docs/qwen3-reranking-models.md (Skor: 0,532)
3. example_docs/ollama-reranking-models.md (Skor: 0,498)
4. example_docs/ai_introduction.txt (Skor: 0,366)
5. example_docs/machine_learning.md (Skor: 0,332)
6. example_docs/programming_basics.txt (Skor: 0,307)
7. example_docs/setup.log (Skor: 0,257)
Memproses 7 dokumen dalam 0,858s (rata-rata: 0,123s per dokumen)
Uji reranking: Bagaimana kita dapat melakukan reranking dokumen dengan ollama?
./rnk example_query3.txt example_docs/
Menggunakan model embedding: dengcao/Qwen3-Embedding-4B:Q5_K_M
URL dasar Ollama: http://localhost:11434
Memproses file query: example_query3.txt, direktori target: example_docs/
Query: Bagaimana kita dapat melakukan reranking dokumen dengan ollama?
Ditemukan 7 dokumen
Mengekstrak embedding query...
Memproses dokumen...
=== PEMBAGIAN BERDASARKAN KESAMAAN ===
1. example_docs/ollama-reranking-models.md (Skor: 0,552)
2. example_docs/ollama-parallelism.md (Skor: 0,525)
3. example_docs/qwen3-reranking-models.md (Skor: 0,524)
4. example_docs/ai_introduction.txt (Skor: 0,369)
5. example_docs/machine_learning.md (Skor: 0,346)
6. example_docs/programming_basics.txt (Skor: 0,316)
7. example_docs/setup.log (Skor: 0,279)
Memproses 7 dokumen dalam 0,882s (rata-rata: 0,126s per dokumen)
Kode Sumber Go
Masukkan semua ke dalam sebuah folder dan kompilasi seperti
go build -o rnk
Silakan gunakan dalam tujuan hiburan atau komersial atau unggah ke github jika Anda suka. Lisensi MIT.
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: "Sistem RAG menggunakan embedding Ollama",
Long: "Sistem RAG sederhana yang mengekstrak embedding dan mengurutkan dokumen menggunakan Ollama",
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", "Model embedding yang akan digunakan")
rootCmd.Flags().StringVarP(&ollamaBaseURL, "url", "u", "http://localhost:11434", "URL dasar Ollama")
}
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("Menggunakan model embedding: %s\n", embeddingModel)
fmt.Printf("URL dasar Ollama: %s\n", ollamaBaseURL)
fmt.Printf("Memproses file query: %s, direktori target: %s\n", queryFile, targetDir)
// Membaca query dari file
query, err := readQueryFromFile(queryFile)
if err != nil {
log.Fatalf("Kesalahan membaca file query: %v", err)
}
fmt.Printf("Query: %s\n", query)
// Mencari semua file teks dalam direktori target
documents, err := findTextFiles(targetDir)
if err != nil {
log.Fatalf("Kesalahan mencari file teks: %v", err)
}
fmt.Printf("Ditemukan %d dokumen\n", len(documents))
// Mengekstrak embedding untuk query
fmt.Println("Mengekstrak embedding query...")
queryEmbedding, err := getEmbedding(query, embeddingModel, ollamaBaseURL)
if err != nil {
log.Fatalf("Kesalahan mendapatkan embedding query: %v", err)
}
// Memproses dokumen
fmt.Println("Memproses dokumen...")
validDocs := make([]Document, 0)
for _, doc := range documents {
embedding, err := getEmbedding(doc.Content, embeddingModel, ollamaBaseURL)
if err != nil {
fmt.Printf("Peringatan: Gagal mendapatkan embedding untuk %s: %v\n", doc.Path, err)
continue
}
similarity := cosineSimilarity(queryEmbedding, embedding)
doc.Score = similarity
validDocs = append(validDocs, doc)
}
if len(validDocs) == 0 {
log.Fatalf("Tidak ada dokumen yang dapat diproses dengan sukses")
}
// Mengurutkan berdasarkan skor kesamaan (menurun)
sort.Slice(validDocs, func(i, j int) bool {
return validDocs[i].Score > validDocs[j].Score
})
// Menampilkan hasil
fmt.Println("\n=== PEMBAGIAN BERDASARKAN KESAMAAN ===")
for i, doc := range validDocs {
fmt.Printf("%d. %s (Skor: %.3f)\n", i+1, doc.Path, doc.Score)
}
totalTime := time.Since(startTime)
avgTimePerDoc := totalTime / time.Duration(len(validDocs))
fmt.Printf("\nMemproses %d dokumen dalam %.3fs (rata-rata: %.3fs per dokumen)\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("Peringatan: Tidak dapat membaca file %s: %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("kesalahan API Ollama: %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 merepresentasikan payload permintaan untuk API embedding Ollama
type OllamaEmbeddingRequest struct {
Model string `json:"model"`
Prompt string `json:"prompt"`
}
// OllamaEmbeddingResponse merepresentasikan respons dari API embedding Ollama
type OllamaEmbeddingResponse struct {
Embedding []float64 `json:"embedding"`
}
// Document merepresentasikan dokumen dengan metadatanya
type Document struct {
Path string
Content string
Score float64
}
Tautan yang Berguna
- Kartu cepat Ollama
- Reranking dokumen teks dengan Ollama dan model Qwen3 Reranker - dalam Go
- Model Qwen3 Embedding & Reranker di Ollama: Kinerja Terbaik
- https://en.wikipedia.org/wiki/Retrieval-augmented_generation
- Pasang dan Konfigurasi Lokasi Model Ollama
- Bagaimana Ollama Menangani Permintaan Paralel
- Menulis Prompt yang Efektif untuk LLM
- Uji Coba LLM: gemma2, qwen2 dan Mistral Nemo di Ollama
- Perbandingan LLM: Mistral Small, Gemma 2, Qwen 2.5, Mistral Nemo, LLama3 dan Phi - Di Ollama
- Uji Coba: Bagaimana Ollama Menggunakan Kinerja Intel CPU dan Core Efisien
- Reranking dengan model embedding di Ollama dalam Python
- Perbandingan Kemampuan Penyusunan Ringkasan LLM
- Pemasok LLM di Cloud