文檔概要索引,簡(jiǎn)單提升檢索性能的新選擇 原創(chuàng)
今天介紹了一種全新的 LlamaIndex 數(shù)據(jù)結(jié)構(gòu):文檔摘要索引。將描述它如何比傳統(tǒng)語(yǔ)義搜索提供更好的檢索性能,并通過(guò)一個(gè)示例進(jìn)行了演示。
背景
大型語(yǔ)言模型 (LLM) 的核心用例之一是針對(duì)自己的數(shù)據(jù)進(jìn)行問(wèn)答。為此,我們將 LLM 與“檢索”模型配對(duì),該模型可以對(duì)知識(shí)語(yǔ)料庫(kù)執(zhí)行信息檢索,并使用 LLM 對(duì)檢索到的文本執(zhí)行響應(yīng)合成。這個(gè)整體框架稱(chēng)為檢索增強(qiáng)生成(RAG)。
目前,大多數(shù)構(gòu)建 LLM 驅(qū)動(dòng)的 QA 系統(tǒng)的用戶(hù)傾向于執(zhí)行以下操作:
- 獲取源文檔,將每個(gè)文檔拆分為文本塊
- 將文本塊存儲(chǔ)在向量數(shù)據(jù)庫(kù)中
- 在查詢(xún)時(shí),通過(guò)嵌入相似性和/或關(guān)鍵字過(guò)濾器來(lái)檢索文本塊。
- 執(zhí)行響應(yīng)合成?
由于各種原因,這種方法的檢索性能有限。
現(xiàn)有方法的局限性
使用文本塊進(jìn)行嵌入檢索存在一些限制。
- 文本塊缺乏全局上下文。問(wèn)題通常需要超出特定塊索引內(nèi)容的上下文。
- 仔細(xì)調(diào)整 top-k/相似度得分閾值。如果值太小,將錯(cuò)過(guò)上下文。如果值太大,成本/延遲可能會(huì)隨著不相關(guān)上下文的增加而增加。
- 嵌入并不總是會(huì)選擇與問(wèn)題最相關(guān)的上下文。嵌入本質(zhì)上是在文本和上下文之間分別確定的。
添加關(guān)鍵字過(guò)濾器是增強(qiáng)檢索結(jié)果的一種方法。但這也帶來(lái)了一系列挑戰(zhàn)。我們需要充分確定每個(gè)文檔的正確關(guān)鍵字,無(wú)論是手動(dòng)還是通過(guò) NLP 關(guān)鍵字提取/主題標(biāo)記模型。此外,我們還需要從查詢(xún)中充分推斷出正確的關(guān)鍵字。
文檔概要索引
文檔概要索引,它將提取/索引每個(gè)文檔的非結(jié)構(gòu)化文本摘要。此索引可以幫助增強(qiáng)現(xiàn)有檢索方法之外的檢索性能。它有助于索引比單個(gè)文本塊更多的信息,并且比關(guān)鍵字標(biāo)簽具有更多的語(yǔ)義含義。它還允許更靈活的檢索形式:我們可以進(jìn)行 LLM 檢索和基于嵌入的檢索。
工作原理
在構(gòu)建期間,我們會(huì)提取每個(gè)文檔,并使用 LLM 從每個(gè)文檔中提取摘要,還將文檔拆分為文本塊(節(jié)點(diǎn))。摘要和節(jié)點(diǎn)都存儲(chǔ)在我們的文檔存儲(chǔ)抽象中。我們維護(hù)從摘要到源文檔/節(jié)點(diǎn)的映射。
在查詢(xún)期間,我們根據(jù)摘要檢索與查詢(xún)相關(guān)的文檔,使用以下方法:
- 基于 LLM 的檢索:我們向 LLM 提供一系列文檔摘要,并要求 LLM 確定哪些文檔是相關(guān)的 + 它們的相關(guān)性分?jǐn)?shù)。
- 基于嵌入的檢索:我們根據(jù)摘要嵌入相似度(具有前 k 個(gè)截止值)檢索相關(guān)文檔。
注意,這種文檔摘要檢索方法(即使采用基于嵌入的方法)與基于嵌入的文本塊檢索不同。文檔摘要索引的檢索類(lèi)會(huì)檢索任何選定文檔的所有節(jié)點(diǎn),而不是返回節(jié)點(diǎn)級(jí)別的相關(guān)塊。
存儲(chǔ)文檔摘要還可以實(shí)現(xiàn)基于 LLM 的檢索。我們不必一開(kāi)始就將整個(gè)文檔提供給 LLM,而是先讓 LLM 檢查簡(jiǎn)明的文檔摘要,看看它是否與查詢(xún)相關(guān)。這利用了 LLM 的推理能力,這些能力比基于嵌入的查找更先進(jìn),但避免了將整個(gè)文檔提供給 LLM 的成本/延遲。
更多
帶摘要的文檔檢索可以看作是所有文檔中的語(yǔ)義搜索和強(qiáng)力摘要之間的“中間地帶”。我們根據(jù)給定查詢(xún)的摘要相關(guān)性查找文檔,然后返回與檢索到的文檔相對(duì)應(yīng)的所有“節(jié)點(diǎn)”。
我們?yōu)槭裁匆@樣做?這種檢索方法通過(guò)在文檔級(jí)別檢索上下文,為用戶(hù)提供了比文本塊上的 top-k 更多的上下文。但是,它也是一種比主題建模更靈活/自動(dòng)化的方法;無(wú)需再擔(dān)心您的文本是否具有正確的關(guān)鍵字標(biāo)簽!
代碼示例
下面展示部分構(gòu)建代碼,完整代碼地址:
https://docs.llamaindex.ai/en/stable/examples/index_structs/doc_summary/DocSummary/
from llama_index import (
SimpleDirectoryReader,
LLMPredictor,
ServiceContext,
ResponseSynthesizer
)
from llama_index.indices.document_summary import GPTDocumentSummaryIndex
from langchain.chat_models import ChatOpenAI
# load docs, define service context
...
# build the index
response_synthesizer = ResponseSynthesizer.from_args(response_mode="tree_summarize", use_async=True)
doc_summary_index = GPTDocumentSummaryIndex.from_documents(
city_docs,
service_cnotallow=service_context,
response_synthesizer=response_synthesizer
)
一旦索引建立,我們就可以獲得任何給定文檔的摘要:
summary = doc_summary_index.get_document_summary("Boston")
接下來(lái),讓我們看一個(gè)基于 LLM 的索引檢索示例。
from llama_index.indices.document_summary import DocumentSummaryIndexRetriever
retriever = DocumentSummaryIndexRetriever(
doc_summary_index,
# choice_select_prompt=choice_select_prompt,
# choice_batch_size=choice_batch_size,
# format_node_batch_fn=format_node_batch_fn,
# parse_choice_select_answer_fn=parse_choice_select_answer_fn,
# service_cnotallow=service_context
)
retrieved_nodes = retriever.retrieve("What are the sports teams in Toronto?")
print(retrieved_nodes[0].score)
print(retrieved_nodes[0].node.get_text())The retriever will retrieve a set of relevant nodes for a given index.
請(qǐng)注意,LLM 除了返回文檔文本之外,還返回相關(guān)性分?jǐn)?shù):
8.0
Toronto ( (listen) t?-RON-toh; locally [t???????] or [?t?????]) is the capital city of the Canadian province of Ontario. With a recorded population of 2,794,356 in 2021, it is the most populous city in Canada...
我們還可以將索引用作整體查詢(xún)引擎的一部分,不僅可以檢索相關(guān)上下文,還可以合成給定問(wèn)題的答案。我們可以通過(guò)高級(jí) API 和低級(jí) API 來(lái)實(shí)現(xiàn)這一點(diǎn)。
高級(jí) API
query_engine = doc_summary_index.as_query_engine(
response_mode="tree_summarize", use_async=True
)
response = query_engine.query("What are the sports teams in Toronto?")
print(response)
低級(jí) API
# use retriever as part of a query engine
from llama_index.query_engine import RetrieverQueryEngine
# configure response synthesizer
response_synthesizer = ResponseSynthesizer.from_args()
# assemble query engine
query_engine = RetrieverQueryEngine(
retriever=retriever,
response_synthesizer=response_synthesizer,
)
# query
response = query_engine.query("What are the sports teams in Toronto?")
print(response)
本文轉(zhuǎn)載自公眾號(hào)哎呀AIYA
原文鏈接:??https://mp.weixin.qq.com/s/USkhLo_qDhvZKoMTQAXquQ??
