Практычныя прытамулкі: 5 тэхнікаў перраЭангавання ў RAG: ад шырокага выкарыстоўвання да точнасці
Практычныя прыказкі: 5 тэхнікаў перраЭйтання рангаў у RAG: ад шырокага выкарыстоўвання да точнасці; контракты, перакрычанні і слоты для коду для команд, якія викорыстоўваюць гэты патэрн.
У гэтым карыце парадоксальным чынам перакладзеныя ад сыр'ёчных матэрыялаў да рабочай системы для: 5 тэхнік пераранжавання ў RAG: ад быстрага выкарыстоўвання да точнага контэксту. Акцэнт ставіцца на практычныя крокі, чыстае перакананне і код, які можна проста дадаць у репазітарый без неабясненых спадчыных намераў. У стадіі агляду неабходна з'явіць вхідныя даны, адпаведальнага за крок і критэрыя завершэння прычым перад зменай коду. Аперацыйныя працавнікі должны магчымае перадзвануць крок з вядомай точкі контролю без неабясненняя скрытага стану. Запісваюцца часы выконання і косты токенаў або запытак па боку функцыйнаых рэзультатаў. Відразлівае паказанне костаў запобегае неспадзянанным рахункам, калі процес пераходзіць з дэмаверсіі ў спяльныя среды.
Бутлнэк у выкарыстоўванні дадзеных, пра які ніхто не гаворыць
Калі працуеце над стадзіяй «The Retrieval Bottleneck Nobody», спачатку запісайце умовы: неабяжлівыя даны, сігнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі список контроля дапамагае заліцьварыць пазнейшыя змены ў кодзе. Зберагаюце настройкі паза кодам прыемліка. Файлы сераўнавання, хранальнікі секрэтных данных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куды аператары можаюць адбавіць аудыт без неабяжлівага чытання всей структуры. Перад налаштаваннем запитоў пераканайцеся ў рэкалі на фіксаваным наборе запитанняў. Частае змена запітоў рэдка калі вярнуе слабую эфектыўнасць адзысквання данных.
Што такое Reranking?
Калі працюеце над стадзіяй «Што такое Reranking», спачатку запісайце умовы кантракту: неабяжлівыя даны, сігнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі список контроля дапамагае заліцьварыць пазнейшыя змены ў кодзе. Дакументавайце як шлях успеху, так і шлях вярнення да стану нормы. Перапрыбуткі, людзкія перакрыцця і обробка некоректных паведамленняў ёсць часткай продукту, а не пазнейшым дапрацоўкам. Змяржывайце рэкалі на фіксаваным наборы запытанняў прычымо да налаштавання прапты. Частае змена прапты рэдка калі вярнайць слабкую эфектыўнасць адзысквання інформаціі.
Адзыскванне інформаціі проты Reranking
Калі працуеце над стадзіяй «Адзысканне vs Пераранкінг», спачатку запісайце умовы: неабяжлівыя данні, сигнал успеху і тое, што выканаецца у разе частковага нявыполнення. Такі список контроля дапамагае заліцьваты змяны ў кодзе.
Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выйшае, прычына нявыполнення павінна вказываць на адзіную адпаведальнасць, а не на заплутаны ланцюг задач.
Перад налаштаваннем запитоў пераканайцеся ў рэкалі на фіксаваным наборе запитанняў. Частыя змены запитоў рэдка калі вядуць да павышэння якасці адзыскання інфармацыі.
Калі працуеце над стадзіяй «Адзысканне vs Пераранкінг», спачатку запісайце умовы: неабяжлівыя данні, сигнал успеху і тое, што выканаецца у разе частковага нявыполнення. Такі список контроля дапамагае заліцьваты змяны ў кодзе.
Запісвайце час выканання і вартасьць токеноў або запитаў разам з функцыональнымі рэзултатамі. Відкрытая інформацыя пра вартасьці запобегае неспакойным рахункам, калі праця пераходзіць з дэмовай среды ў спакульную.
| Aspect | Initial Retrieval | Reranking |
| ------------------- | ------------------------ | ----------------------------- |
| Goal | Find candidates fast | Judge true relevance |
| Speed | Milliseconds | Tens to hundreds of milliseconds |
| Input | Query + index | Query + top-k candidates |
| Scoring depth | Shallow (embedding dot product) | Deep (cross-attention, token interaction) |
| Cost | Low (local compute) | Higher (model inference) |
| When to use | Every query | On top-k candidates only |
Пяць тэхнік переранжавання
Этап пяці тэхнік переранжавання працюе найэфектывней, калі яго розглядаць як меркаваную плошчу. Зберагучы адна «золатая» копія даных, адзін прыклад неудачы і запіс пра зворотную дзеянь перш чым расширваць масштабы, можна падбаць пра якосць. Канфігурацыю трэба залічыць пазначкай занята ўнутрь коду прыемліка. Файлы сяродавішняе сераўісу, хранілішчы секрэтных дадзеных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куды аператары можаць адбавіць аудыт без неабходнасці чытання всей структуры. Палітыку разбівання на часткі трэба аддзеліць ад палітыки выкарыстоўвання дадзеных. Змена адной з іх не должна вымагаць перапісвання другой, калі зменяюцца паказнікі якосці.
1. Переранжаванне за дапамою Cross-Encoder
Этап переранкінгу з викорыстоўванням Cross-Encoder працюе наякша, калі яго розглядаць як меркаваную плошчу. Перад расшырэнням масштаба зафіксавайце адна ідеальная транскрыпцыя, адзін прыклад неудачы і запіс пра вярнэнне да поперадньага стану. Запісвайце адночасна шлях успеху і шлях вярнэння. Перапрыбуткі, людзкі контроль і обработка некоректных паведамленняў є частью продукту, а не етапамі пазнейшай доработкі. Раздзеліце правілы частковай обработкі даных ад правіл абрання даных. Змена аднаго з іх не должна вымагаць перапісвання другога, калі зменяюцыся показнікі якосці.
from sentence_transformers import CrossEncoder
# Load a cross-encoder reranker
# ms-marco-MiniLM-L-6-v2 is fast and accurate for general use
cross_encoder = CrossEncoder("cross-encoder/ms-marco-MiniLM-L-6-v2")
def rerank_with_cross_encoder(query: str, retrieved_docs: list[str], top_k: int = 5):
"""
Rerank retrieved documents using a cross-encoder.
Args:
query: The user question
retrieved_docs: List of document chunks from initial retrieval
top_k: Number of documents to return after reranking
Returns:
List of (document, score) tuples, sorted by relevance
"""
# Create query-document pairs
pairs = [[query, doc] for doc in retrieved_docs]
# Get relevance scores
scores = cross_encoder.predict(pairs)
# Combine docs with scores and sort
scored_docs = list(zip(retrieved_docs, scores))
scored_docs.sort(key=lambda x: x[1], reverse=True)
return scored_docs[:top_k]
# Example usage
query = "What are the side effects of amoxicillin?"
retrieved = [
"Amoxicillin is a penicillin antibiotic used to treat bacterial infections.",
"Common side effects include nausea, vomiting, and diarrhea.",
"The drug was first discovered in 1958 by researchers at Beecham.",
"Patients with penicillin allergies should avoid amoxicillin.",
"Side effects may include rash, itching, and in rare cases, anaphylaxis.",
]
top_docs = rerank_with_cross_encoder(query, retrieved, top_k=3)
for doc, score in top_docs:
print(f"Score: {score:.4f} | {doc}")
2. Вялікавырахоўванне рангу (RRF)
Этап саюзу двух взаімных рангоў працюе найэфектывней, калі яго спрыяваць як мерыемую паверхню. Зберагучы адна ідеальная версія, адзин случай неудачы і прыметку па вярнэнню да пачатковага стану, перш чым расширваць сферу дзеяння. Валіць краща маленькія, тэставаныя елементы, чым велікія скрыпты. Калі якісь крок не выходзіць, прычына неудачы павінна вказываць на адную адпаведальнасць, а не на заплутаны ланцюг задач. Раздзеляйце правілы часткавання інфармацыі ад правіл яе выявлення. Змена ў одных не павінна прымусваць перапісванне іншых, калі змянююцца паказнікі якосці. Этап саюзу двух взаімных рангоў працюе найэфектывней, калі яго спрыяваць як мерыемую паверхню. Зберагучы адна ідеальная версія, адзин случай неудачы і прыметку па вярнэнню да пачатковага стану, перш чым расширваць сферу дзеяння. Запісвайце часы выконання і косты токеноў або запитаў разам з функцыональнымі рэзультатамі. Відразлівасць костаў з самага пачатку запобегае неспакойным рахункам, калі процес пераходзіць з дэмовай среды ў спяльныя сераўеры.
def reciprocal_rank_fusion(rankings: list[list[str]], k: int = 60) -> list[tuple[str, float]]:
"""
Merge multiple document rankings using Reciprocal Rank Fusion.
Args:
rankings: List of rankings, where each ranking is a list of document IDs
ordered from most to least relevant
k: RRF constant (default 60, as recommended in the original paper)
Returns:
List of (document_id, rrf_score) tuples, sorted by fused score
"""
scores = {}
for ranking in rankings:
for rank, doc_id in enumerate(ranking, start=1):
if doc_id not in scores:
scores[doc_id] = 0.0
# RRF formula: 1 / (k + rank)
scores[doc_id] += 1.0 / (k + rank)
# Sort by score descending
return sorted(scores.items(), key=lambda x: x[1], reverse=True)
# Example: merging BM25 and vector search results
bm25_results = ["doc_5", "doc_2", "doc_8", "doc_1", "doc_9"]
vector_results = ["doc_1", "doc_5", "doc_3", "doc_8", "doc_7"]
fused = reciprocal_rank_fusion([bm25_results, vector_results])
print("Fused ranking:")
for doc_id, score in fused:
print(f" {doc_id}: {score:.4f}")
# Notice: doc_5 and doc_1 appear in both retrievers and get boosted to the top
3. Cohere Rerank API
Для трэцьяго этапа API Cohere Rerank неабходна прадзеўжыць вводныя даны, выклікача кроку і крэтарыя выходу пры перадзеўжанні коду. Аператары должны магчымае перзапускнуць крок з вядомага пункту контролю, не спрабоўваючы з’ясаваць захаваны стан. Канфігурацыю трэба залічыць праза код аплікацыі. Файлы сяродавішча, хранільнікі секрэтных дадзеных і флагі функцияў должны знаходзіцца ў аднам месцы, якое аператары можаць пераглядаць, не чытаяўшы весь граф. Паказваць трэба тыя часткі тексту, якія фактычна ляглі в основу адпаведзення. Без цых цитатаў аператары не можаць разлічыць галюцинацію ад працягу індексавання.
import cohere
from dotenv import load_dotenv
import os
load_dotenv()
# Initialize Cohere client
co = cohere.Client(os.getenv("COHERE_API_KEY"))
def rerank_with_cohere(query: str, documents: list[str], top_k: int = 5):
"""
Rerank documents using Cohere's managed Rerank API.
Args:
query: The user question
documents: List of document chunks from initial retrieval
top_k: Number of documents to return
Returns:
List of (document, relevance_score) tuples
"""
response = co.rerank(
model="rerank-v3.5",
query=query,
documents=documents,
top_n=top_k,
return_documents=True
)
results = []
for result in response.results:
results.append((
result.document.text,
result.relevance_score
))
return results
# Example usage
query = "How do I handle authentication in a FastAPI app?"
docs = [
"FastAPI is a modern web framework for building APIs with Python.",
"To add authentication, use OAuth2PasswordBearer and JWT tokens.",
"Pydantic models in FastAPI provide automatic request validation.",
"The OAuth2PasswordBearer class expects a token URL endpoint.",
"FastAPI was created by Sebastián Ramírez and released in 2018.",
]
ranked = rerank_with_cohere(query, docs, top_k=3)
for doc, score in ranked:
print(f"Score: {score:.4f} | {doc}")
4. ColBERT
Для 4-го этапу ColBERT неабяжна прадзецаваць вхідныя даны, адпраўніка крока і критэрыя завершэння перад змінайом коду. Аперацыяныя працавнікі павінны магчыма было перзапусціць крок з вядомага пункту контролю, не спрабоўваючы здагадвацца пра схованы стан. Неабяжна задокументаваць як шлях успеху, так і шлях вяснавання проблем. Перапрыбуткі, людзкія пераказчыкі і обробка некоректных паведамленняў є частью продукту, а не чымсь, што дадзецца пазней.
from colbert import Searcher
from colbert.infra import Run, RunConfig
def setup_colbert_searcher(index_path: str, checkpoint: str):
"""
Initialize a ColBERT searcher for late-interaction reranking.
Args:
index_path: Path to the pre-built ColBERT index
checkpoint: Path to the ColBERT model checkpoint
Returns:
Configured Searcher instance
"""
with Run().context(RunConfig(nranks=1, experiment="reranking")):
searcher = Searcher(
index=index_path,
checkpoint=checkpoint
)
return searcher
def rerank_with_colbert(searcher, query: str, doc_ids: list[str], top_k: int = 5):
"""
Rerank documents using ColBERT's late interaction.
Args:
searcher: Initialized ColBERT Searcher
query: The user question
doc_ids: List of document IDs from initial retrieval
top_k: Number of documents to return
Returns:
List of (doc_id, score) tuples
"""
# Search within the candidate set
results = searcher.search(
query,
k=top_k,
filter_fn=lambda pid: pid in doc_ids # Only rerank candidates
)
return list(zip(results[0], results[2])) # doc_ids, scores
# Note: ColBERT requires a pre-built index and model checkpoint.
# For production use, build the index once and load it at startup.
5. LLM-як суддзі
Для стадіі 5 «LLM-как суддзя» неабходна прадварыяе апранэнне вхідных дадзеных, адпаведнага адпаведальніка за шаг і крэтарыяў завершэння працы перад зменым коду. Аперацыйныя працавнікі должны магчымае перадзеўжваць шаг з вядомай точкі контролю, не падозрываючы прыхованы стан. Лепш выбіраць маленькія, тэставаныя елементы замест большых скрыптов. Калі шаг не выйшаў, прычына неудачы павінна вказываць на адзін конкрэтны аспект, а не на заплутаны ланцоўкі задач. Калі наступны шаг — гэта код або вызов інструмента, лепш выкарыстоўваць структураваныя выходныя данні з перакананнем ў ўсасце шымату, замест вольнага формата тэксту. Для стадіі 5 «LLM-как суддзя» неабходна прадварыяе апранэнне вхідных дадзеных, адпаведнага адпаведальніка за шаг і крэтарыяў завершэння працы перад зменым коду. Аперацыйныя працавнікі должны магчымае перадзеўжваць шаг з вядомай точкі контролю, не падозрываючы прыхованы стан. Запісваць час выконання і кост токенав або запытаў разам з функцыйнальнымі рэзультатамі. Відразувыя данні пра косты запобегаюць неспакойным рахункам, калі працэс пераходзіць з дэмавай версіі ў спяльныя среды.
You are evaluating documents for a retrieval system.
Query: {query}
Document: {document}
Rate how relevant this document is for answering the query.
Respond with a single integer from 1 to 10, where 10 means perfectly relevant.
Relevance score:
from openai import OpenAI
import os
from dotenv import load_dotenv
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
def score_document_with_llm(query: str, document: str) -> int:
"""
Ask an LLM to score a document's relevance to a query.
Args:
query: The user question
document: A candidate document chunk
Returns:
Integer relevance score from 1-10
"""
prompt = f"""You are evaluating documents for a retrieval system.
Query: {query}
Document: {document}
Rate how relevant this document is for answering the query.
Respond with a single integer from 1 to 10, where 10 means perfectly relevant.
Be strict: only give high scores to documents that directly help answer the query.
Relevance score:"""
response = client.chat.completions.create(
model="gpt-4.1-mini",
messages=[{"role": "user", "content": prompt}],
temperature=0,
max_tokens=5
)
try:
score = int(response.choices[0].message.content.strip())
return max(1, min(10, score)) # Clamp to 1-10
except ValueError:
return 5 # Default on parse failure
def rerank_with_llm_judge(query: str, documents: list[str], top_k: int = 3):
"""
Rerank documents using an LLM as a relevance judge.
Args:
query: The user question
documents: List of candidate document chunks
top_k: Number of documents to return
Returns:
List of (document, score) tuples, sorted by relevance
"""
scored = []
for doc in documents:
score = score_document_with_llm(query, doc)
scored.append((doc, score))
scored.sort(key=lambda x: x[1], reverse=True)
return scored[:top_k]
# Example usage
query = "What are the tax implications of RSU vesting for employees in California?"
docs = [
"RSUs are restricted stock units granted to employees as part of compensation.",
"In California, RSU income is taxed as ordinary income at vesting, not at grant.",
"Employers typically withhold federal and state taxes at vesting time.",
"Stock options and RSUs have different tax treatments under IRS rules.",
"California has one of the highest state income tax rates in the US.",
]
ranked = rerank_with_llm_judge(query, docs, top_k=3)
for doc, score in ranked:
print(f"Score: {score}/10 | {doc}")
Кой з іх трэба выкарыстоўваць?
Калі працуеце над этапам «Кой з іх трэба выкарыстоўваць?», спачатку запісайце умовы дагавору: неабходныя даны, сігнал успеху і тое, што выканаецца у разы частковага нявыпалення. Такі список контроля дапамагае заліцьваты змяны ў кодзе пазнейша. Зберагайце настройкі за межамі коду прыемліка. Файлы сераўнавання, хранільнікі секрэтных дадзеных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куды аператары можаюць адбавіць аудыт без неабяжнага чытання всіх элементаў. Перад налагоджэньем запрошэнняяў пераканайцеся, як працуе алгорытм на фіксаванай сэтке запытаў. Частае зміненне запрошэнняяў рэдка калі вядомае да павышэння якосці выкарыстоўвання дадзеных.
| Technique | Best For | Latency | Cost |
| --------------------- | ------------------------------------------------- | ------------ | -------------- |
| Cross-Encoder | Maximum quality on top-k candidates | 50-200ms | Local GPU/CPU |
| RRF | Hybrid retrieval without adding model inference | ~0ms | Free |
| Cohere Rerank API | Speed without operational overhead | 100-300ms | Per API call |
| ColBERT | Large-scale, low-latency use cases | 20-100ms | Index + GPU |
| LLM-as-a-Judge | Complex, high-value queries (medical, legal) | 1-5 seconds | Per API call |
Заключныя меркі
Калі працюеце над стадзіяй «Заключныя заўважэнні», спачатку запісайце контракт: неабходныя даны, сігнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі список пераконтролюе чыстасць пазнейшых змян у кодзе. Документавайце як шлях успеху, так і шлях вярнення да нормы. Перапрыбуткі, людзкія контрольныя пункты і обработка некоректных поведамленняў ёсць часткай продукту, а не пазнейшым дапрацоўкам. Змяржывайце рэткасць адпаведзенняў на фіксаваны набор запытанняў прычымо да налаштавання запытаў. Частае змяненне запытаў рэдка калі-небудзь выправляе слабую систему адналёгчэння інформацыі.
Чек-ліст для эксплуатацыі
Стадзія чек-ліста для эксплуатацыі працюе найэфектывней, калі яе спрыяваць як мерыемую велічыну. Запісайце адна ідеальная транскрыпцыя, адзін прыклад нявыпання і прыметку па вярненню да пачатковага стану пры расшырэнні масштабаў. Спрыявайце гэтую стадзію як контракт межа данымі і перакананымі выходамі. Дайце назвы артыфактам, задаць критэрыя успеху і адмовіцеся ад мовчанкавага частковага завершэння.
Раздзеліце політыку фрагментавання і політыку адгэтування дадзеных. Змена адной з іх не павінна вымагаць перапісвання другой, калі зменяюцыся паказнікі якосці.
Оцэнюйце адказы пасля аднае і многаэтапныя траекторыі окрема. Агрегаванне балавань чату маскіруе неудачы ў роботе з інструментамі.
Напісціце кароткі посібнік: як зменяць кантрольныя клучы, як спрачысваць чергу запитоў, як вярнуць стан да пярэдніх настройкаў.
Документавацьце як правільны, так і альтернатыўны падходы. Практыкі перапрыбутку, людзкі контроль і обработка некоректных запытоў є частью продукту, а не пасляднім дапрацоўкам.
Перш чым пераводзіць систему на новы рэвізію, заморозьце існуючыя версіі, зафіксавайце важлівыя транскрыпты для критычных сцэнарыёў і паказваце крокі для вярнення да пярэдніх настройкаў. У спадзеленых средах неабходны ліміты частоты запытоў, перакананні ў належнасці ресурсаў і чысткі власнік для змены кантрольных клучоў. Валіце простую надзейнасць працы над крэатывнымі, але разовымі дэманстрацыямі.
Запіскі для пакета 16f80a919c4e: не класты ключі прадаўцоў у репазітарыю, задаць максымальны ліміт токена на сесію, а таксама зберагчы транскрыпціі празаўсюды з фікстурамі для ацэнкі, каб пазнейшыя замены моделяў заставаліся пораўнанымі.