每天的專案會同步到 GitLab 上,可以前往 GitLab 查看,有興趣的朋友歡迎留言或來信討論,我的信箱是 nickchen1998@gmail.com。
MultiQueryRetriever 是一個強大的檢索器,它可以自動生成多個不同版本的查詢來幫助你從向量資料庫中檢索出更相關的文件。這項技術特別適合應對基於距離的檢索系統,當查詢措辭稍有不同時,可能會導致檢索結果不一致的情況。MultiQueryRetriever 能夠透過不同的視角處理使用者的查詢問題,並生成多個查詢,最終將這些查詢的結果合併成一個獨立的結果集。
當我們在進行檢索時,向量檢索模型有時可能無法完全捕捉語義上的細微差別,導致檢索結果不夠準確。而 MultiQueryRetriever 能夠從多個角度生成查詢,減少單一查詢可能產生的模糊性,這對於增強檢索的準確性和覆蓋範圍非常有幫助。
DEFAULT_QUERY_PROMPT
的作用MultiQueryRetriever 背後運行時使用了名為 DEFAULT_QUERY_PROMPT
的預設提示來生成多重查詢。這個提示會告訴語言模型生成不同版本的查詢,以提供多視角的檢索。具體的提示內容如下:
DEFAULT_QUERY_PROMPT = PromptTemplate(
input_variables=["question"],
template="""You are an AI language model assistant. Your task is
to generate 3 different versions of the given user
question to retrieve relevant documents from a vector database.
By generating multiple perspectives on the user question,
your goal is to help the user overcome some of the limitations
of distance-based similarity search. Provide these alternative
questions separated by newlines. Original question: {question}""",
)
這段提示讓語言模型針對使用者的問題生成三個不同版本的查詢,並將這些查詢用於向量檢索。這樣做的目的是幫助使用者克服基於距離的相似性檢索的限制,讓模型從不同的角度理解和檢索文件。
在這次的範例中,我們使用這個預設提示來處理「工作一年有幾天休假?」的問題,系統生成了以下三個查詢:
INFO:langchain.retrievers.multi_query:Generated queries: ['一年中通常有多少天休假?', '全职员工每年可以休几天假?', '一年内工作者能享受的休假天数是多少?']
透過這些多重查詢,檢索系統能夠更全面地捕捉到與「休假天數」相關的文件。
在本例中,我們將展示如何將 MultiQueryRetriever 與 Pinecone 整合,來實現更好的查詢檢索。
import logging
from env_settings import EnvSettings
from pinecone import Pinecone
from langchain_pinecone import PineconeVectorStore
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.retrievers.multi_query import MultiQueryRetriever
from langchain.chat_models import ChatOpenAI
# 設置日誌級別,顯示生成的查詢
logging.basicConfig()
logging.getLogger("langchain.retrievers.multi_query").setLevel(logging.INFO)
# 準備 Pinecone 連線
env_settings = EnvSettings()
vector_store = PineconeVectorStore(
index=Pinecone(api_key=env_settings.PINECONE_API_KEY).Index("chunks"),
embedding=OpenAIEmbeddings(openai_api_key=env_settings.OPENAI_API_KEY)
)
# 使用 ChatOpenAI 作為 LLM 來生成查詢
llm = ChatOpenAI(
api_key=env_settings.OPENAI_API_KEY,
model_name="gpt-4o"
)
# 建立 MultiQueryRetriever,並將 Pinecone 索引作為檢索器
retriever_from_llm = MultiQueryRetriever.from_llm(
retriever=vector_store.as_retriever(), llm=llm
)
# 設定問題並檢索
question = "工作一年有幾天休假?"
unique_docs = retriever_from_llm.invoke(question)
# 查看文件數量
print(f"檢索到的文件數量: {len(unique_docs)}")
在這段程式碼中,我們首先準備了 Pinecone 的連線,並通過 PineconeVectorStore
將向量資料儲存在 Pinecone 索引中。接著,我們使用了 ChatOpenAI
來作為生成查詢的語言模型。然後,我們透過 MultiQueryRetriever
來生成多個查詢,並將這些查詢結果進行檢索。
此外,透過設置 logging
,我們可以在運行時看到系統為我們生成了哪些查詢。這對於了解檢索的過程和進一步優化查詢非常有幫助。
MultiQueryRetriever 的強大之處在於它能夠自動生成多個查詢版本,而不需要人工編寫多個查詢。這能夠更全面地檢索相關內容,減少單一查詢的語義偏差。例如,當我們輸入「工作一年有幾天休假?」時,系統生成了以下三個不同的查詢:
這樣的查詢多樣性有助於檢索系統找到更全面的結果,避免因單一查詢措辭不同導致的檢索偏差,下圖展示了使用 MultiQueryRetriever 檢索出的結果:
我們可以通過自定義 Prompt 和解析器,來控制語言模型以繁體中文生成查詢。首先,我們定義一個 LineListOutputParser
類別來解析多行查詢:
# 定義 LineListOutputParser 來解析多行文本
class LineListOutputParser(BaseOutputParser[List[str]]):
"""Output parser for a list of lines."""
def parse(self, text: str) -> List[str]:
lines = text.strip().split("\n")
return list(filter(None, lines)) # 移除空行
接著,我們定義自定義的 Prompt,並結合這個解析器使用:
CUSTOM_QUERY_PROMPT = PromptTemplate(
input_variables=["question"],
template="""你是一個 AI 語言模型助手。你的任務是根據用戶輸入的問題生成三個不同版本的查詢,以繁體中文進行檢索。請將這些查詢分行顯示。
原始問題: {question}"""
)
# 使用自定義 Prompt 和解析器
llm_chain = CUSTOM_QUERY_PROMPT | llm | LineListOutputParser()
retriever_from_llm = MultiQueryRetriever(
retriever=vector_store.as_retriever(),
llm_chain=llm_chain
)
當我們輸入「工作一年有幾天休假?」時,系統生成了以下三個查詢:
INFO:langchain.retrievers.multi_query:Generated queries: ['一年中通常有多少天休假?', '全職員工每年可以休幾天假?', '一年內工作者能享受的休假天數是多少?']
下圖為完整的查詢 log:
今天我們介紹了 MultiQueryRetriever 的基本使用方法,並展示了如何結合 Pinecone 來進行檢索。明天,我們將進一步探討如何自定義生成查詢的提示,讓我們可以更靈活地控制查詢生成的過程,並深入了解向量檢索的更多細節。