作者:來自 Elastic?Jeffrey Rengifo
了解如何從 LlamaIndex RankGPT reranker 遷移到 Elastic 內置的 semantic reranker。
Elasticsearch 擁有與行業領先的 Gen AI 工具和服務商的原生集成。查看我們的網絡研討會,了解如何突破 RAG 基礎,或使用 Elastic Vector Database 構建可投入生產的應用。
為了為你的使用場景構建最佳搜索方案,可以立即開始免費云試用,或在本地機器上嘗試 Elastic。
在本文中,我們將探討如何使用 Llamaindex RankGPT Reranker 和 Elasticsearch 內置的 semantic reranker。Elastic 提供開箱即用的體驗,在 retrievers pipeline 中部署和使用 reranker,無需額外操作,且具備可擴展性。
最初,在 Elasticsearch 中進行 rerank 需要多個步驟,但現在它已經直接集成進 retrievers pipeline:第一階段運行搜索查詢,第二階段對結果進行 rerank,如下圖所示:
什么是 rerank?
Rerank 是一種在檢索出一組與用戶查詢相關的文檔后,使用較昂貴的機制將最相關的文檔推到結果頂部的過程。
有許多策略可以使用專門的 cross-encoder 模型對文檔進行 rerank,比如 Elastic Rerank 模型,或 MS Marco 的 Cross encoder( cross-encoder/ms-marco-MiniLM-L6-v2)。另一種方法是使用 LLM 進行 rerank。Elastic Rerank 模型的一個優點是,它既可以作為 semantic search pipeline 的一部分使用,也可以作為獨立工具改進現有的 BM25 打分系統。
一個 reranker 需要一組候選文檔和用戶查詢,根據用戶查詢重新排序這些候選文檔,從最相關到最不相關。
在本文中,我們將探索 Llamaindex RankGPT Reranker(即 RankGPT reranker 實現)和 Elastic Semantic Reranker,后者使用 Elastic Rerank 模型。
完整示例可在此 notebook 中查看。
步驟
- Products 索引
- 用戶問題
- LlamaIndex rerank
- Elasticsearch semantic rerank
Products 索引
讓我們基于用戶的問題為筆記本電腦創建一個 reranker。如果用戶是重度玩家,他們應該獲得性能最強的機器。如果他們是學生,輕便的機器可能就可以了。
讓我們從在 Notebook 中創建一些文檔開始:
products = [{"name": "ASUS ROG Strix G16","description": "Powerful gaming laptop with Intel Core i9 and RTX 4070.","price": 1899.99,"reviews": 4.7,"sales": 320,"features": ["Intel Core i9","RTX 4070","16GB RAM","512GB SSD","165Hz Display",],},{"name": "Razer Blade 15","description": "Premium gaming laptop with an ultra-slim design and high refresh rate." ,"price": 2499.99,"reviews": 4.6,"sales": 290,"features": ["Intel Core i7","RTX 4060","16GB RAM","1TB SSD","240Hz Display",],},{"name": "Acer Predator Helios 300","description": "Affordable yet powerful gaming laptop with RTX graphics.","price": 1399.99,"reviews": 4.5,"sales": 500,"features": ["Intel Core i7","RTX 3060","16GB RAM","512GB SSD","144Hz Display",],},{"name": "MSI Stealth 17","description": "High-performance gaming laptop with a 17-inch display.","price": 2799.99,"reviews": 4.8,"sales": 200,"features": ["Intel Core i9", "RTX 4080", "32GB RAM", "1TB SSD", "4K Display"],},{"name": "Dell XPS 15","description": "Sleek and powerful ultrabook with a high-resolution display.","price": 2199.99,"reviews": 4.7,"sales": 350,"features": ["Intel Core i7","RTX 3050 Ti","16GB RAM","1TB SSD","OLED Display",],},{"name": "HP Omen 16","description": "Gaming laptop with a balanced price-to-performance ratio.","price": 1599.99,"reviews": 4.4,"sales": 280,"features": ["AMD Ryzen 7","RTX 3060","16GB RAM","512GB SSD","165Hz Display",],},{"name": "Lenovo Legion 5 Pro","description": "Powerful Ryzen-powered gaming laptop with high refresh rate.","price": 1799.99,"reviews": 4.6,"sales": 400,"features": ["AMD Ryzen 9","RTX 3070 Ti","16GB RAM","1TB SSD","165Hz Display",],},{"name": "MacBook Pro 16","description": "Apple's most powerful laptop with M3 Max chip.","price": 3499.99,"reviews": 4.9,"sales": 500,"features": ["Apple M3 Max","32GB RAM","1TB SSD","Liquid Retina XDR Display",],},{"name": "Alienware m18","description": "High-end gaming laptop with extreme performance.","price": 2999.99,"reviews": 4.8,"sales": 150,"features": ["Intel Core i9","RTX 4090","32GB RAM","2TB SSD","480Hz Display",],},{"name": "Samsung Galaxy Book3 Ultra","description": "Ultra-lightweight yet powerful laptop with AMOLED display.","price": 2099.99,"reviews": 4.5,"sales": 180,"features": ["Intel Core i7","RTX 4070","16GB RAM","512GB SSD","AMOLED Display",],},{"name": "Microsoft Surface Laptop 5","description": "Sleek productivity laptop with great battery life.","price": 1699.99,"reviews": 4.3,"sales": 220,"features": ["Intel Core i7", "16GB RAM", "512GB SSD", "Touchscreen"],},{"name": "Gigabyte AORUS 17","description": "Performance-focused gaming laptop with powerful cooling.","price": 1999.99,"reviews": 4.6,"sales": 250,"features": ["Intel Core i9","RTX 4070","16GB RAM","1TB SSD","360Hz Display",],},
]
用戶問題
讓我們定義一個將用于 rerank 結果的問題。
user_query = "Best laptops for gaming"
LlamaIndex rerank
安裝依賴并導入包
我們安裝執行 LlamaIndex 的 RankGPT reranker 和 Elasticsearch 文檔檢索所需的所有依賴。然后,我們將筆記本電腦數據加載到 ElasticsearchStore 中,ElasticsearchStore 是 LlamaIndex 對 Elasticsearch 向量數據庫的抽象,并使用 VectorStoreIndex 類進行檢索。
pip install llama-index-core llama-index-llms-openai rank-llm llama-index-postprocessor-rankgpt-rerank llama-index-vector-stores-elasticsearch elasticsearch -qimport os
import nest_asyncio
from getpass import getpassfrom llama_index.vector_stores.elasticsearch import ElasticsearchStore
from llama_index.core import (Document,VectorStoreIndex,QueryBundle,Settings,StorageContext,
)
from llama_index.core.retrievers import VectorIndexRetriever
from llama_index.postprocessor.rankgpt_rerank import RankGPTRerank
from llama_index.llms.openai import OpenAIfrom elasticsearch import Elasticsearchnest_asyncio.apply()
設置密鑰:
os.environ["OPENAI_API_KEY"] = "OPENAI_API_KEY"
os.environ["ELASTICSEARCH_ENDPOINT"] = "ELASTIC_ENDPOINT"
os.environ["ELASTICSEARCH_API_KEY"] = "ELASTIC_API_KEY"INDEX_NAME = "products-laptops"
Elasticsearch 客戶端
我們實例化 Elasticsearch 客戶端,用于索引文檔并針對我們的集群運行查詢。
_client = Elasticsearch(os.environ["ELASTICSEARCH_ENDPOINT"],api_key=os.environ["ELASTICSEARCH_API_KEY"],
)
Mappings
我們將使用普通文本字段進行全文搜索,并創建一個 semantic_field,復制所有內容,以便運行 semantic 和 hybrid 查詢。在 Elasticsearch 8.18+ 中,推理端點將自動部署。
# Creating mapping for the index
try:_client.indices.create(index=INDEX_NAME,body={"mappings": {"properties": {"metadata": {"properties": {"name": {"type": "text", "copy_to": "semantic_field"},"description": {"type": "text","copy_to": "semantic_field",},"price": {"type": "float",},"reviews": {"type": "float",},"sales": {"type": "integer"},"features": {"type": "keyword","copy_to": "semantic_field",},}},"semantic_field": {"type": "semantic_text"},"text": {"type": "text"}, # Field to store the text content for LlamaIndex"embeddings": {"type": "dense_vector", "dims": 512},}}},)print("index created successfully")
except Exception as e:print(f"Error creating inference endpoint: {e.info['error']['root_cause'][0]['reason'] }")
向 LlamaIndex 索引數據
從我們定義的產品數組創建 ElasticsearchStore。這將創建一個 Elasticsearch 向量存儲,后續可以使用 VectorStoreIndex 進行訪問。
document_objects = []es_store = ElasticsearchStore(es_url=os.environ["ELASTICSEARCH_ENDPOINT"],es_api_key=os.environ["ELASTICSEARCH_API_KEY"],index_name=INDEX_NAME,embedding_field="embeddings",text_field="text",
)storage_context = StorageContext.from_defaults(vector_store=es_store)for doc in products:text_content = f"""Product Name: {doc["name"]}Description: {doc["description"]}Price: ${doc["price"]}Reviews: {doc["reviews"]} starsSales: {doc["sales"]} units soldFeatures: {', '.join(doc["features"])}"""metadata = {"name": doc["name"],"description": doc["description"],"price": doc["price"],"reviews": doc["reviews"],"sales": doc["sales"],"features": doc["features"],}document_objects.append(Document(text=text_content, metadata=metadata))index = VectorStoreIndex([], storage_context=storage_context)for doc in document_objects:index.insert(doc)
LLM 設置
定義將作為 reranker 的 LLM:
Settings.llm = OpenAI(temperature=0, model="gpt-4.1-mini")
Settings.chunk_size = 512
Rerank 功能
我們現在創建一個函數,該函數先執行 retriever 從向量索引中獲取與用戶問題最相似的文檔,然后在此基礎上應用 RankGPTRerank 進行 rerank,最后返回重新排序后的文檔。
def get_retrieved_nodes(query_str, vector_top_k=10, reranker_top_n=5, with_reranker=False
):query_bundle = QueryBundle(query_str)# configure retrieverretriever = VectorIndexRetriever(index=index,similarity_top_k=vector_top_k,)retrieved_nodes = retriever.retrieve(query_bundle)if with_reranker:# configure rerankerreranker = RankGPTRerank(llm=OpenAI(model="gpt-4.1-mini",temperature=0.0,api_key=os.environ["OPENAI_API_KEY"],),top_n=reranker_top_n,verbose=True,)retrieved_nodes = reranker.postprocess_nodes(retrieved_nodes, query_bundle)return retrieved_nodes
我們還創建了一個函數來格式化結果文檔。
def visualize_retrieved_nodes(nodes):formatted_results = []for node in nodes:text = node.node.get_text()product_name = text.split("Product Name:")[1].split("\n")[0].strip()price = text.split("Price:")[1].split("\n")[0].strip()reviews = text.split("Reviews:")[1].split("\n")[0].strip()features = text.split("Features:")[1].strip()formatted_result = f"{price} - {product_name} ({reviews}) {features}"formatted_results.append(formatted_result)return formatted_results
不使用 rerank
我們先運行不帶 rerank 的請求。
new_nodes = get_retrieved_nodes(query_str=user_query,vector_top_k=5,with_reranker=False,
)results = visualize_retrieved_nodes(new_nodes)print("\nTop 5 results without rerank:")
for idx, result in enumerate(results, start=1):print(f"{idx}. {result}")
答案:
Top 5 results without rerank:
1. $2499.99 - Razer Blade 15 (4.6 stars) Intel Core i7, RTX 4060, 16GB RAM, 1TB SSD, 240Hz Display
2. $1899.99 - ASUS ROG Strix G16 (4.7 stars) Intel Core i9, RTX 4070, 16GB RAM, 512GB SSD, 165Hz Display
3. $1999.99 - Gigabyte AORUS 17 (4.6 stars) Intel Core i9, RTX 4070, 16GB RAM, 1TB SSD, 360Hz Display
4. $2799.99 - MSI Stealth 17 (4.8 stars) Intel Core i9, RTX 4080, 32GB RAM, 1TB SSD, 4K Display
5. $2999.99 - Alienware m18 (4.8 stars) Intel Core i9, RTX 4090, 32GB RAM, 2TB SSD, 480Hz Display
使用 rerank
現在我們啟用 rerank,它將執行相同的向量搜索,然后使用 LLM 對結果進行 rerank,應用 “Best laptops for gaming” 標準對前 5 個結果進行排序。我們可以看到細微差別,比如 Intel Core i7 處理器被排到最后,而 Alienware m18 升到了第 2 位。
new_nodes = get_retrieved_nodes(user_query,vector_top_k=5,reranker_top_n=5,with_reranker=True,
)results = visualize_retrieved_nodes(new_nodes)print("\nTop 5 results with reranking:")
for idx, result in enumerate(results, start=1):print(f"{idx}. {result}")
答案:
Top 5 results with reranking:
1. $1899.99 - ASUS ROG Strix G16 (4.7 stars) Intel Core i9, RTX 4070, 16GB RAM, 512GB SSD, 165Hz Display
2. $2999.99 - Alienware m18 (4.8 stars) Intel Core i9, RTX 4090, 32GB RAM, 2TB SSD, 480Hz Display
3. $2799.99 - MSI Stealth 17 (4.8 stars) Intel Core i9, RTX 4080, 32GB RAM, 1TB SSD, 4K Display
4. $1999.99 - Gigabyte AORUS 17 (4.6 stars) Intel Core i9, RTX 4070, 16GB RAM, 1TB SSD, 360Hz Display
5. $2499.99 - Razer Blade 15 (4.6 stars) Intel Core i7, RTX 4060, 16GB RAM, 1TB SSD, 240Hz Display
Elasticsearch 語義 rerank
推理 rerank 端點
創建一個推理端點,可以獨立調用它來根據查詢對候選列表進行 rerank,或作為 retriever 的一部分使用:
INFERENCE_RERANK_NAME = "my-elastic-rerank"try:_client.options(request_timeout=60, max_retries=3, retry_on_timeout=True).inference.put(task_type="rerank",inference_id=INFERENCE_RERANK_NAME,body={"service": "elasticsearch","service_settings": {"model_id": ".rerank-v1","num_threads": 1,"adaptive_allocations": {"enabled": True,"min_number_of_allocations": 1,"max_number_of_allocations": 4,},},},)print("Inference endpoint created successfully.")except Exception as e:print(f"Error creating inference endpoint: {e.info['error']['root_cause'][0]['reason'] }")
我們定義一個函數來執行搜索查詢,然后解析返回的命中結果。
async def es_search(query):response = _client.search(index=INDEX_NAME, body=query)hits = response["hits"]["hits"]if not hits:return ""return hits
與 LlamaIndex 一樣,我們創建一個函數來格式化結果文檔。
def format_es_results(hits):formatted_results = []for hit in hits:metadata = hit["_source"]["metadata"]name = metadata.get("name")price = metadata.get("price")reviews = metadata.get("reviews")features = metadata.get("features")formatted_result = f"{price} - {name} ({reviews}) {features}"formatted_results.append(formatted_result)return formatted_results
語義查詢
我們將從語義查詢開始,返回與用戶問題最相似的結果。
semantic_results = await es_search({"size": 5,"query": {"semantic": {"field": "semantic_field","query": user_query,}},"_source": {"includes": ["metadata",]},}
)semantic_formatted_results = format_es_results(semantic_results)print("Query results:")
for idx, result in enumerate(semantic_formatted_results, start=1):print(f"{idx}. {result}")
查詢結果:
1. 2999.99 - Alienware m18 (4.8) ['Intel Core i9', 'RTX 4090', '32GB RAM', '2TB SSD', '480Hz Display']
2. 2799.99 - MSI Stealth 17 (4.8) ['Intel Core i9', 'RTX 4080', '32GB RAM', '1TB SSD', '4K Display']
3. 1599.99 - HP Omen 16 (4.4) ['AMD Ryzen 7', 'RTX 3060', '16GB RAM', '512GB SSD', '165Hz Display']
4. 1399.99 - Acer Predator Helios 300 (4.5) ['Intel Core i7', 'RTX 3060', '16GB RAM', '512GB SSD', '144Hz Display']
5. 1999.99 - Gigabyte AORUS 17 (4.6) ['Intel Core i9', 'RTX 4070', '16GB RAM', '1TB SSD', '360Hz Display']
rerank_results = await es_search({"size": 5,"_source": {"includes": ["metadata",]},"retriever": {"text_similarity_reranker": {"retriever": {"standard": {"query": {"semantic": {"field": "semantic_field","query": user_query,}}}},"field": "semantic_field","inference_id": INFERENCE_RERANK_NAME,"inference_text": "reorder by quality-price ratio","rank_window_size": 5,}},}
)rerank_formatted_results = format_es_results(rerank_results)print("Query results:")
for idx, result in enumerate(rerank_formatted_results, start=1):print(f"{idx}. {result}")
查詢結果:
1. 1399.99 - Acer Predator Helios 300 (4.5) ['Intel Core i7', 'RTX 3060', '16GB RAM', '512GB SSD', '144Hz Display']2. 2999.99 - Alienware m18 (4.8) ['Intel Core i9', 'RTX 4090', '32GB RAM', '2TB SSD', '480Hz Display']3. 2799.99 - MSI Stealth 17 (4.8) ['Intel Core i9', 'RTX 4080', '32GB RAM', '1TB SSD', '4K Display']4. 1999.99 - Gigabyte AORUS 17 (4.6) ['Intel Core i9', 'RTX 4070', '16GB RAM', '1TB SSD', '360Hz Display']5. 1599.99 - HP Omen 16 (4.4) ['AMD Ryzen 7', 'RTX 3060', '16GB RAM', '512GB SSD', '165Hz Display']
在下表中,我們可以看到不同測試中的排名對比:
Laptop model | Llama (no rerank) | Llama (with rerank) | Elastic (no rerank) | Elastic (with rerank) |
---|---|---|---|---|
Razer Blade 15 | 1 | 5 | - | - |
ASUS ROG Strix G16 | 2 | 1 | - | - |
Gigabyte AORUS 17 | 3 | 4 | 5 | 4 |
MSI Stealth 17 | 4 | 3 | 2 | 3 |
Alienware m18 | 5 | 2 | 1 | 2 |
HP Omen 16 | - | - | 3 | 5 |
Acer Predator Helios 300 | - | - | 4 | 1 |
圖例:破折號(-)表示該方法的前五名中未出現該項。
它保持了一致性,將高端筆記本如 Alienware m18 和 MSI Stealth 17 保持在前列 —— 就像 LlamaIndex rerank 一樣 —— 同時實現了更好的性價比。
結論
Reranker 是提升搜索系統質量的強大工具,確保我們總能檢索到每個用戶問題中最重要的信息。
LlamaIndex 提供多種 reranker 策略,使用專門模型或 LLM。在最簡單的實現中,你可以創建內存中的向量存儲并本地保存文檔,然后進行檢索和 rerank,或者使用 Elasticsearch 作為持久化的向量存儲。
另一方面,Elasticsearch 提供開箱即用的推理端點框架,可以將 reranker 作為檢索管道的一部分或獨立端點使用。你還可以選擇 Elastic 自身、Cohere、Jina 或阿里巴巴等多種服務商,或部署任何兼容的第三方模型。在 Elasticsearch 的最簡單實現中,你的文檔和 rerank 模型都存儲在 Elasticsearch 集群中,便于擴展。
原文:LlamaIndex and Elasticsearch Rerankers: Unbeatable simplicity - Elasticsearch Labs