Ollama 와 Qwen3 Reranker 모델을 사용한 Go 언어 기반 문서 리랭킹
RAG 구현 중이신가요? 여기 Go 코드 조각이 있습니다 - 2...
Page content
표준 Ollama 에는 직접적인 rerank API 가 없으므로, 쿼리 - 문서 쌍에 대한 임베딩을 생성하고 점수를 매기는 방식으로 GO 에서 Qwen3 Reranker 를 사용한 재순위 지정 을 구현해야 합니다.
지난 주에는 Ollama 와 Qwen3 임베딩 모델을 사용한 텍스트 문서 재순위 지정 - Go 로 에 대해 다루었습니다.
오늘은 Qwen3 Reranker 모델을 사용해 보겠습니다. 이는 아키텍처와 구현 패턴을 다루는 더 넓은 검색 증강 생성 (RAG) 튜토리얼 의 일부입니다. Ollama 에서 사용할 수 있는 새로운 Qwen3 임베딩 및 Reranker 모델 이 꽤 많이 출시되었는데, 저는 중간 규모의 dengcao/Qwen3-Reranker-4B:Q5_K_M 모델을 사용했습니다.

테스트 실행: TL;DR
작동하며 꽤 빠릅니다. 표준적인 방식은 아니지만 여전히 다음과 같습니다:
$ ./rnk ./example_query.txt ./example_docs
Using embedding model: dengcao/Qwen3-Embedding-4B:Q5_K_M
Ollama base URL: http://localhost:11434
Processing query file: ./example_query.txt, target directory: ./example_docs
Query: What is artificial intelligence and how does machine learning work?
Found 7 documents
Extracting query embedding...
Processing documents...
=== RANKING BY SIMILARITY ===
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)
Processed 7 documents in 2.023s (avg: 0.289s per document)
Reranking documents with reranker model...
Implementing reranking using cross-encoder approach with dengcao/Qwen3-Reranker-4B:Q5_K_M
=== RANKING WITH RERANKER ===
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)
Processed 7 documents in 1.984s (avg: 0.283s per document)
Ollama 를 호출하기 위한 Go 의 Reranker 코드
Reranking text documents with Ollama using Embedding... 게시물에서 대부분의 코드를 가져와서 다음 부분을 추가합니다:
runRnk() 함수의 끝에 추가합니다:
startTime = time.Now()
// rerank using reranking model
fmt.Println("Reranking documents with reranker model...")
// 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("Error reranking documents: %v", err)
}
fmt.Println("\n=== RANKING WITH RERANKER ===")
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("\nProcessed %d documents in %.3fs (avg: %.3fs per document)\n",
len(rerankedDocs), totalTime.Seconds(), avgTimePerDoc.Seconds())
그리고 몇 가지 함수를 더 추가합니다:
func rerankDocuments(validDocs []Document, query, rerankingModel, ollamaBaseURL string) ([]Document, error) {
// Since standard Ollama doesn't have a direct rerank API, we'll implement
// reranking by generating embeddings for query-document pairs and scoring them
fmt.Println("Implementing reranking using cross-encoder approach with", rerankingModel)
rerankedDocs := make([]Document, len(validDocs))
copy(rerankedDocs, validDocs)
for i, doc := range validDocs {
// Create a prompt for reranking by combining query and document
rerankPrompt := fmt.Sprintf("Query: %s\n\nDocument: %s\n\nRelevance:", query, doc.Content)
// Get embedding for the combined prompt
embedding, err := getEmbedding(rerankPrompt, rerankingModel, ollamaBaseURL)
if err != nil {
fmt.Printf("Warning: Failed to get rerank embedding for document %d: %v\n", i, err)
// Fallback to a neutral score
rerankedDocs[i].Score = 0.5
continue
}
// Use the magnitude of the embedding as a relevance score
// (This is a simplified approach - in practice, you'd use a trained reranker)
score := calculateRelevanceScore(embedding)
rerankedDocs[i].Score = score
// fmt.Printf("Document %d reranked with score: %.4f\n", i, score)
}
// Sort documents by reranking score (descending)
sort.Slice(rerankedDocs, func(i, j int) bool {
return rerankedDocs[i].Score > rerankedDocs[j].Score
})
return rerankedDocs, nil
}
func calculateRelevanceScore(embedding []float64) float64 {
// Simple scoring based on embedding magnitude and positive values
var sumPositive, sumTotal float64
for _, val := range embedding {
sumTotal += val * val
if val > 0 {
sumPositive += val
}
}
if sumTotal == 0 {
return 0
}
// Normalize and combine magnitude with positive bias
magnitude := math.Sqrt(sumTotal) / float64(len(embedding))
positiveRatio := sumPositive / float64(len(embedding))
return (magnitude + positiveRatio) / 2
}
수학 라이브러리 (math) 를 import 하는 것을 잊지 마세요.
import (
"math"
)
이제 컴파일해 보겠습니다.
go build -o rnk
그리고 이제 이 간단한 RAG reranker 기술 프로토타입을 실행합니다.
./rnk ./example_query.txt ./example_docs
유용한 링크
- 임베딩 모델을 사용한 텍스트 재순위 지정
- Ollama 와 Qwen3 임베딩 모델을 사용한 텍스트 문서 재순위 지정 - Go 로
- Ollama 상의 Qwen3 임베딩 및 Reranker 모델: 최첨단 성능
- Ollama 치트시트
- Ollama 모델 위치 설치 및 구성
- Ollama 가 병렬 요청을 처리하는 방식
- 테스트: Ollama 가 Intel CPU 성능과 효율 코어를 사용하는 방식