譯者 | 布加迪
審校 | 重樓
如果你正在構建一個檢索增強生成(RAG)應用程序,就知道其功能有多強大,前提是當它順暢運行時。但是語義嵌入模型并不是什么魔法。大多數RAG實現依賴語義相似性作為唯一的檢索機制,將每個文檔放入到向量數據庫中,并對每個查詢運用相同的檢索邏輯。這種方法適用于簡單直觀的問題,但常常檢索上下文無關(但語義相似)的文檔。當精準的查詢需要精確的答案時,僅語義相似性就會導致混淆或不正確的響應。
問題不在于你的模型,而在于你的檢索過程。
我們在這里將介紹一種更好的方法:代理混合搜索。通過使用結構化元數據并讓大語言模型(LLM)為每個查詢選擇最佳檢索操作,你就可以將RAG應用程序變成真正智能化的助手。我們將從介紹核心概念入手,然后通過一個示例將簡單的“信用卡策略QA機器人”變成動態(tài)適應用戶需求的代理系統(tǒng)。
告別千篇一律的檢索,迎接更智能化的RAG體驗。
為什么你的RAG應用程序不盡如人意?
究其核心,RAG將LLM與外部知識聯(lián)系起來。你可以為文檔編制索引,使用向量搜索檢索語義相似的文檔,并讓LLM根據這些結果生成響應。是不是覺得聽起來很簡單?
但簡單性是一把雙刃劍。雖然許多開發(fā)人員致力于改進知識庫——用更多的文檔或更好的嵌入來豐富知識庫,或者針對LLM對提示進行微調,但真正的瓶頸常常在于檢索過程本身。大多數RAG實現依賴語義相似性作為一種通用策略。這種方法常常檢索錯誤的文檔:要么提取上下文無關的結果,因為語義相似性不是查詢的正確方法,要么檢索太多重疊或冗余的文檔,從而降低了響應的有用性。如果沒有一種更智能的方法來過濾和優(yōu)先處理結果,依賴細微差別的精準查詢會繼續(xù)失敗。
想象一下QA機器人負責回答特定的問題,比如“如果我晚10天支付Premium Card賬單會發(fā)生什么?”或“A銀行的基礎卡提供購買保障嗎?”這些問題需要精確的答案,這些答案取決于策略之間的細微差別。同樣,考慮一下像三星這樣的公司的支持機器人,支持從智能手機到冰箱的眾多產品。比如,“如何重置我的Galaxy S23?”就需要檢索該款手機所特有的操作說明,而查詢冰箱的保修需要完全不同的文檔。借助簡單的向量搜索,機器人可能會獲取語義相關但上下文無關的文檔,因混入用于全然不同的產品或用例的信息而混淆響應或引起幻覺。
無論你的LLM或嵌入有多先進,這個問題始終存在。開發(fā)人員常通過微調模型或調整提示作為對策,但真正的解決方案在于改進文檔在生成之前的檢索方式。簡單的檢索系統(tǒng)要么檢索太多的內容,迫使LLM篩選不相關的信息——這有時可以借助巧妙的提示加以緩解;要么檢索太少的內容,使LLM“盲目行動”,沒有必要的上下文來生成有意義的響應。通過使檢索更智能化、上下文感知,混合搜索解決了這兩個問題:它通過針對相關主題進行搜索來減少不相關的干擾信息,并確保檢索的文檔含有LLM所需的更多精確信息。這大大提高了RAG應用程序的準確性和可靠性。
解決方案:代理混合搜索
解決方案異常簡單,卻具有變革性:將結構化元數據支持的混合搜索與LLM的代理決策功能相結合,以實現代理混合搜索。這種方法不需要全面改變你的架構或丟棄現有的投入,它立足于已有的系統(tǒng)上,卻可以帶來全新的智能和靈活性。
從簡單到代理:更智能化的流程
一個典型的RAG應用程序遵循簡單直觀的過程:提問→搜索→生成。用戶的問題被傳遞給檢索引擎(常常是向量搜索),檢索語義上最相似的文檔。然后將這些文檔傳遞給LLM以生成響應。這對于簡單的查詢很有效,但是面對需要精細的檢索策略時卻束手無策。
代理混合搜索使用一種更智能化、適應性更強的流程:提問→分析→搜索→生成,取代了這種死板僵硬的流程。LLM不是直接跳轉到檢索,而是分析問題以確定最佳檢索策略。這種靈活性使系統(tǒng)能夠更準確地處理更廣泛的用例。
功能解鎖
有了代理型混合搜索,你的RAG應用程序將變得功能異常強大:
- 多個知識庫——LLM可以根據問題動態(tài)決定查詢哪個知識庫。比如說,QA機器人可能從一個數據庫提取一般的策略信息,從另一個數據庫提取某家銀行特有的常見問答(FAQ)。
- 定制的搜索查詢——LLM 可以定制自定義搜索查詢,而不是僅僅依賴語義相似性。比如說,“A銀行的哪些卡提供購買保障?”之類的問題可能會觸發(fā)對帶有“購買保障”標簽的卡執(zhí)行元數據過濾的搜索。
- 元數據過濾器——通過使用結構化的元數據(比如信用卡名、銀行名稱、部門、日期)豐富文檔,可以實現精確的、針對性的搜索,避免了不相關的結果。
- 多個搜索操作——有些問題需要將查詢分解成多個子部分。比如說,“Premium Card的資格要求和好處是什么?”可能需要對資格標準執(zhí)行一次搜索,對好處執(zhí)行另一次搜索。
這些功能擴展了應用程序可以處理的查詢類型。你的RAG應用程序現在可以處理探索性研究、多步驟推理和特定領域的任務,同時保持準確性,而不是局限于簡單的事實發(fā)現。
工作機理:徹底轉變信用卡策略QA機器人
不妨看一個例子。假設你正在構建一個機器人來回答有關多家銀行信用卡策略的問題。這是一個簡單的實現:
簡單的方法
文檔在向量數據庫中建立索引,機器人執(zhí)行簡單的語義搜索來檢索最相似的文檔。無論用戶查詢資格要求、費用或取消策略,檢索邏輯都是相同的。
from langchain_core.runnables import (
RunnablePassthrough,
ConfigurableField,
)
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_astradb.graph_vectorstores import AstraDBVectorStore
llm = ChatOpenAI()
embeddings = OpenAIEmbeddings()
vectorstore = AstraDBVectorStore(
collection_name="knowledge_store",
embedding=embeddings,
)
ANSWER_PROMPT = (
"Use the information in the results to provide a concise answer the original question.\n\n"
"Original Question: {question}\n\n"
"Vector Store Results:\n{'\n\n'.join(c.page_content for c in context)}\n\n"
)
retriever = vectorstore.as_retriever()
# Construct the LLM execution chain
chain = (
{"context": retriever, "question": RunnablePassthrough()}
| ChatPromptTemplate.from_messages([ANSWER_PROMPT])
| llm
)
結果怎樣?對于像“我的會員年費是多少?”這樣的問題,系統(tǒng)可能從不相關的卡檢索策略,因為嵌入優(yōu)先注重廣泛的相似性而不是特殊性。
chain.invoke("How much is my annual membership fee?",)
# > Response: Your annual membership fee could be $250, $95, $695, or $325, depending on the specific plan or card you have chosen. Please refer to your specific card member agreement or plan details to confirm the exact amount of your annual membership fee.
代理方法
在代理混合搜索方法中,我們通過以下手段對系統(tǒng)進行改進:
用元數據豐富文檔——在索引策略時,我們添加了結構化元數據,比如:
- 卡名(“Premium Card”)
- 銀行名稱(“A銀行”)
- 策略部分(“費用”、“獎勵”、“資格”)
使用LLM來選擇檢索操作——機器人使用查詢上下文來決定以下問題,而不是盲目地執(zhí)行向量搜索:
- 是否應該搜索語義上相似的策略?
- 是否應該根據信用卡或銀行元數據進行過濾?
- 是否應該針對特定的策略部分發(fā)出多個查詢?
從多個搜索組合響應——機器人智能地組合結果,以生成精確、可信賴的答案。
下面是它實際上的樣子:
示例代碼:
from typing import List, Literal
from pydantic import BaseModel, Field
from langchain_core.documents.base import Document
from langchain_core.tools import StructuredTool
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages([
("system", "Concisely answer the following question, using information retrieved from tools and the provided information about the user."),
("system", "The following card types are associated with the user: {cards}"),
("system", "Always use the provided tools to retrieve information needed to answer policy-related questions."),
("human", "{question}"),
MessagesPlaceholder("agent_scratchpad"),
])
# First we define the parameters to our search operation
class RetrieveInput(BaseModel):
question: str = Field(description="Question to retrieve content for. Should be a simple question describing the starting point for retrieval likely to have content.")
card_type: str = Field(description=f"Search for documents related to this card type. Value must be one of {pages.keys()}")
# Next, create a "tool" that implements the search logic
def retrieve_policy(question: str, card_type: str) -> List[Document]:
print(f"retrieve_policy(card_type: {card_type}, question: {question})")
retriever = graph_vectorstore.as_retriever(
search_type = "similarity",
search_kwargs = {"metadata_filter": {"card-type": card_type}},
)
return list(retriever.invoke(question))
policy_tool = StructuredTool.from_function(
func=retrieve_policy,
name="RetrievePolicy",
description="Retrieve information about a specific card policy.",
args_schema=RetrieveInput,
return_direct=False,
)
# Finally, construct an agent to use the tool we created
agent = create_tool_calling_agent(llm, [policy_tool], prompt)
agent_executor = AgentExecutor(agent=agent, tools=[policy_tool], verbose=True)
在這個示例中,機器人認識到查詢具有高度針對性,使用元數據過濾器根據所提供的用戶配置文件來檢索準確的策略。此外,LLM重寫用戶的問題,以便完全專注于檢索相關文檔所需的信息。
agent_executor.invoke({
"question": "How much is my annual membership fee?",
"cards": ["gold"],
})
# > Agent: Invoking: `RetrievePolicy` with `{'question': 'annual membership fee', 'card_type': 'gold'}`
# > Response: Your annual membership fee could be $250, $95, $695, or $325, depending on the specific plan or card you have chosen. Please refer to your specific card member agreement or plan details to confirm the exact amount of your annual membership fee.
由于LLM選擇如何使用搜索工具,我們并不僅限于為每個問題使用相同的過濾器。比如說,LLM可以動態(tài)地認識到用戶針對與自己的策略不同的策略詢問問題,并創(chuàng)建相應的過濾器。
agent_executor.invoke({
"question": "What's the annual membership fee for platinum cards?",
"cards": ["gold"],
})
# > Agent: Invoking: `RetrievePolicy` with `{'question': 'annual membership fee for platinum cards', 'card_type': 'platinum'}`
# > Response: The annual membership fee for Platinum cards is $695. Additionally, each Additional Platinum Card has an annual fee of $195, but there is no annual fee for Companion Platinum Cards.
LLM甚至決定多次使用某個工具。比如說,下列問題需要LLM不僅了解問題中提及的策略,還需要了解用戶的當前策略。
agent_executor.invoke({
"question": "How much would my membership fee change if I upgraded to a platinum card?",
"cards": ["gold"],
})
# > Agent: Invoking: `RetrievePolicy` with `{'question': 'membership fee for gold card', 'card_type': 'gold'}`
# > Agent: Invoking: `RetrievePolicy` with `{'question': 'membership fee for platinum card', 'card_type': 'platinum'}`
# > Response: The annual membership fee for your current American Express? Gold Card is $325. If you were to upgrade to a Platinum Card, the annual fee would be $695. Therefore, upgrading from a Gold Card to a Platinum Card would increase your annual membership fee by $370.
不妨在這個筆記本:Agentic_Retrieval.ipynb中親自試一試代碼。
為什么這管用?
神奇之處在于利用LLM作為決策者。你不需要硬編碼檢索邏輯,而是允許LLM分析查詢并動態(tài)選擇最佳方法。這種靈活性使你的系統(tǒng)更智能化、適應性更強,而不需要對基礎結構進行重大改變。
回報:更智能化的檢索,更精準的響應
采用代理混合搜索可以將你的RAG應用程序變成能夠處理復雜細微查詢的系統(tǒng)。通過引入更智能化的檢索,你可以獲得幾大好處:
- 提高準確性——更智能化的檢索確保為每個查詢顯示正確的文檔,減少幻覺和不相關的結果。這直接提高了LLM響應的質量。
- 增強信任——通過只提取上下文適當的信息,你可以避免混淆關鍵細節(jié)等令人尷尬的錯誤,確保用戶對系統(tǒng)有信心。
- 支持更廣泛的用例——動態(tài)搜索策略允許你的應用程序處理更復雜的查詢、整合多個知識來源,并為更廣泛的用戶和場景提供服務。
- 簡化維護——你可以讓LLM動態(tài)調整檢索策略,減少對持續(xù)手動干預的需要,而不是硬編碼檢索規(guī)則或手動管理過濾器。
- 面向未來的可擴展性——隨著數據集日益龐大或知識庫日益多樣化,代理方法可以擴展以應對新的挑戰(zhàn),無需對系統(tǒng)進行根本性改變。
通過使檢索更智能化、更具適應性,你可以提高系統(tǒng)的整體性能,無需進行重大改動。
兼顧靈活性和成本
為檢索過程添加代理層確實帶來了幾個不足:
- 增加延遲——每個查詢分析都需要額外的LLM調用,執(zhí)行多個定制的搜索可能比單個操作花費更長的時間。這可能會稍微延長響應時間,尤其對于對延遲敏感的應用程序而言。
- 提高了推理成本——查詢分析和編排多個搜索增加了計算開銷,對于查詢量大的系統(tǒng)而言這可能會增加成本。
- 編排的復雜性——雖然實現很簡單,但維護一個動態(tài)選擇檢索策略的系統(tǒng)可能會帶來額外的調試或測試問題。
盡管存在這些不足,但代理混合搜索的好處通常壓倒成本。對于大多數應用而言,增加的靈活性和精度大大提高了用戶滿意度和系統(tǒng)可靠性,使投入物有所值。此外,延遲和成本問題通常可以通過緩存、預計算過濾器或僅針對復雜查詢進行分析等優(yōu)化手段來予以緩解。
如何理解和管理這些不足,你可以充分發(fā)揮代理混合搜索的潛力,以構建更智能化、更強大的RAG應用程序。
結語
代理混合搜索是充分發(fā)揮RAG應用程序的潛力的關鍵。通過使用結構化元數據豐富文檔,并讓LLM智能化決定檢索策略,你可以不僅限于簡單的語義相似性,構建用戶可以真正依賴的助手。
這是一個很容易接受的改變,會帶來驚人的巨大回報。何不在你的下一個項目中試一下?用戶和未來的你會感謝你的。
原文標題:Supercharge Your RAG App With Agentic Hybrid Search,作者:Ryan Michael