iT邦幫忙

2024 iThome 鐵人賽

DAY 20
1
生成式 AI

懶人救星:生成式AI 系列 第 20

Day20-RAG大秘密揭露!資料檢索其實可以這麼高效

  • 分享至 

  • xImage
  •  

前言✨

LlamaIndex Querying 功能為用戶提供了一個強大的數據檢索工具。這項功能使用戶能夠以簡單而直觀的方式查詢資料,無論是尋求具體答案還是進行更複雜的指令。Querying 的過程包括檢索、後處理和生成回覆三個主要階段,這使得用戶能夠靈活地獲取所需的資訊,並從中生成有意義的回覆。

透過 LlamaIndex🦙 ,開發者可以輕鬆構建查詢引擎,並定制檢索策略以滿足不同的需求。無論是從結構化數據還是非結構化數據中提取資訊, LlamaIndex 都能提供高效的解決方案。接下來,我們將深入探討這一功能的具體實現和應用案例,幫助讀者掌握如何利用LlamaIndex提升數據查詢的效率與準確性。
https://ithelp.ithome.com.tw/upload/images/20240918/20168117aAY7MEtv6w.png

(圖片來源:作者自製)

【Querying🔍】

LlamaIndex 的 Querying 是查詢外部數據的核心功能。該功能允許將 LLM 的自然語言處理能力與外部數據結合,進行智能的查詢回覆。以下是 Querying 功能的主要特性:

  1. 自然語言查詢(NLP):使用自然語言來查詢已連接的外部數據資源, LlamaIndex 會根據用戶的查詢,從相關數據中提取並生成答案。
  2. 支援多種數據:連接多種外部數據資源,包括結構化數據SQL 資料庫)、半結構化數據如 JSON 文件)、非結構化數據如WORD、PDF、PPT)等。
  3. 查詢優化與排序:自動優化機制,根據查詢的上下文和數據的相關性,對結果進行自動排序和篩選
  4. 查詢結果生成:不僅可以提取數據,透過結合 Prompt + LLM 將輸出轉換成可讀性更高、更精確的回覆。

Querying 中重要的幾個 Low-Level 模組:

首先要介紹的就是 RAG (Retrieval-Augmented Generation) 中的三元素,檢索(Retrieval)、強化(Augmented)、生成(Generation),分別對應 LlamaIndex 中的 Retrieval、Node Postprocessors、Response Synthesis 三大功能,接著讓我們一探究竟。

【Retrieval📜】

檢索器主要負責根據使用者查詢(或聊天資訊)取得最相關的上下文

常用 Retrieval:

  • Vector Index Retriever:透過 Embedding Vector 搜尋最相似的 Top_k 個 Nodes。(similarity_top_k: 想要提取多少個相關 Nodes。)

    # 建立完 Index 後增加以下 code
    retriever = index.as_retriever(similarity_top_k=3)
    response = retriever.retrieve("Your Query")
    
  • Keyword Table Index Retriever:首先透過 LLM 取得關鍵字,再利用 Keyword Filter 提取相似 Nodes。

    # 建立完 Index 後增加以下 code
    retriever = retriever = index.as_retriever(retriever_mode='default')
    response = retriever.retrieve("Your Query")
    
  • BM25 Retriever:透過 BM25 演算法計算相似的 Nodes。(可惜預設沒有支援中文,但有興趣的人可以改寫原始程式。)

    from llama_index.retrievers.bm25 import BM25Retriever
    import Stemmer
    
    # We can pass in the index, docstore, or list of nodes to create the retriever
    bm25_retriever = BM25Retriever.from_defaults(
        nodes=nodes,
        similarity_top_k=2,
        # Optional: We can pass in the stemmer and set the language for stopwords
        # This is important for removing stopwords and stemming the query + text
        # The default is english for both
        stemmer=Stemmer.Stemmer("english"),
        language="english",
    )
    
    retrieved_nodes = bm25_retriever.retrieve(
        "Your Query"
    )
    
  • Other Retriever:如對其它檢索器有興趣,LlamaIndex 提供了許多 High-Level Function 使用上非常方便。


【Node Postprocessors🔄】

Node Postprocessors 的主要功能是針對檢索後的 Node 進行過濾排序,以此提升搜索精準度。

常用 Postprocessors:

1. FILTER🗑️

  • SimilarityPostprocessor:用於刪除低於相似度分數閾值的 Node。

    from llama_index.core.postprocessor import SimilarityPostprocessor
    # Create Documents
    ...
    
    # Create Index
    index = VectorStoreIndex.from_documents(documents)
    
    # Query Engine(Filter Similarity Score)
    query_engine = index.as_query_engine(
        node_postprocessors=[
            SimilarityPostprocessor(
               similarity_cutoff=0.75
           )
        ]
    )
    
  • KeywordNodePostprocessor:用於排除或包含某些關鍵字的 Node,可以單獨使用或像上述程式碼結合 as_query_engine 一起使用。

    from llama_index.core.postprocessor import KeywordNodePostprocessor
    
    postprocessor = KeywordNodePostprocessor(
        required_keywords=["word1", "word2"], exclude_keywords=["word3", "word4"]
    )
    postprocessor.postprocess_nodes(nodes)
    
  • MetadataReplacementPostProcessor:用於以 Node Metadata 中的欄位取代 Node 內容,簡單來說就是只檢索指定的 Metadata 內容。

    from llama_index.core.postprocessor import MetadataReplacementPostProcessor
    
    postprocessor = MetadataReplacementPostProcessor(
        target_metadata_key="city",
    )
    
    postprocessor.postprocess_nodes(nodes)
    

2. RERANK🏆

  • CohereRerank:主要用於改善搜索引擎或問答系統的結果排序, API KEY 需透過以下連結註冊。(試用 API 免費,大量使用才需要收費。)
    透過以下程式可以看出,Rerank 能有效地在檢索階段將和查詢更相關的 Node 排序到更靠前的位置,能補足 Embedding 的缺點,但相對的如果使用 Local Model 就會需要較高的運算資源。

    #!pip install llama-index-postprocessor-cohere-rerank
    
    import os
    os.environ["OPENAI_API_KEY"] = "YOUR-API-KEY"
    import llama_index.core
    llama_index.core.set_global_handler("simple")
    from llama_index.core import Document, VectorStoreIndex
    
    # Create Documents and Index
    ...
    
    # Create Query Engine
    query_engine = index.as_query_engine()
    res = query_engine.query("林家花園在哪個縣市?")
    
    # Out [1]: ...
    ---------------------
    city: 新竹
    
    新竹被譽為「風城」,因為當地的強風而得名。它位於台灣的西北部,距離台北約一小時車程。新竹是台灣高科技產業的重要基地,特別是以竹科(新竹科學園區)而聞名,是台灣的“矽谷”。新竹擁有良好的教育環境,著名的清華大學與交通大學皆位於此地。雖然新竹給人現代化的高科技城市印象,但它同時保留了豐富的歷史文化資產,如新竹城隍廟、新竹市東門城等。當地的風味小吃,如米粉和貢丸湯,也深受遊客喜愛,是品嚐道地台灣味的好去處。
    
    city: 台中
    
    台中位於台灣中部,氣候溫暖,擁有台灣第三大城市的規模。它以文化氣息濃厚著稱,擁有豐富的藝術與文化活動,如國立台灣美術館、霧峰林家花園等。台中還是熱門的觀光景點之一,尤其以彩虹眷村和高美濕地最為著名。此外,台中市還以舒適的生活環境和悠閒的生活步調著稱,常被視為居住和發展的理想城市。台中的夜市文化也相當發達,逢甲夜市是其中最具代表性的夜市之一,吸引了無數美食愛好者前來品嚐台灣各地的美食
    ---------------------
    ...
    
    # Add Reranker
    from llama_index.postprocessor.cohere_rerank import CohereRerank
    
    query_engine = index.as_query_engine(
        node_postprocessors=[
            CohereRerank(
                top_n=2, model="rerank-multilingual-v3.0", api_key="YOUR-Cohere-KEY"
            )
        ]
    )
    res = query_engine.query("林家花園在哪個縣市?")
    
    # Out [2]:...
    ---------------------
    city: 台中
    
    台中位於台灣中部,氣候溫暖,擁有台灣第三大城市的規模。它以文化氣息濃厚著稱,擁有豐富的藝術與文化活動,如國立台灣美術館、霧峰林家花園等。台中還是熱門的觀光景點之一,尤其以彩虹眷村和高美濕地最為著名。此外,台中市還以舒適的生活環境和悠閒的生活步調著稱,常被視為居住和發展的理想城市。台中的夜市文化也相當發達,逢甲夜市是其中最具代表性的夜市之一,吸引了無數美食愛好者前來品嚐台灣各地的美食
    
    city: 新竹
    
    新竹被譽為「風城」,因為當地的強風而得名。它位於台灣的西北部,距離台北約一小時車程。新竹是台灣高科技產業的重要基地,特別是以竹科(新竹科學園區)而聞名,是台灣的“矽谷”。新竹擁有良好的教育環境,著名的清華大學與交通大學皆位於此地。雖然新竹給人現代化的高科技城市印象,但它同時保留了豐富的歷史文化資產,如新竹城隍廟、新竹市東門城等。當地的風味小吃,如米粉和貢丸湯,也深受遊客喜愛,是品嚐道地台灣味的好去處。
    ---------------------
    
  • SentenceTransformerRerank:可串接支援 sentence-transformer 的 Rerank 模型,快速實現用戶自行持有開源模型,不需要額外付費給 API 公司。如需結合query_engine、chat_engine可以參考上方程式碼。(如果要使用中文 Rerank 筆者建議可以使用 BGE 模型,效果很不錯。)

    # pip install llama-index-embeddings-huggingface
    # pip install llama-index-llms-openai
    
    from llama_index.core.postprocessor import SentenceTransformerRerank
    
    # We choose a model with relatively high speed and decent accuracy.
    postprocessor = SentenceTransformerRerank(
        model="cross-encoder/ms-marco-MiniLM-L-2-v2", top_n=3
    )
    
    postprocessor.postprocess_nodes(nodes)
    
  • Other Method: LlamaIndex 還提供了其它 AI 公司的 API 接口,如有興趣可以至官方網站查看整合方式。


【Response Synthesis🧠】

Response Synthesis 提供用戶自訂 Prompt 並支持透過查詢和 Node 生成回覆,不僅增加了自定義的彈性,也簡化了自行串接 LLM 的繁瑣過程。(response_mode 在明天將會結合 query_engine 進一步詳細介紹)

from llama_index.core.data_structs import Node
from llama_index.core.response_synthesizers import ResponseMode
from llama_index.core import get_response_synthesizer

response_synthesizer = get_response_synthesizer(
    response_mode=ResponseMode.COMPACT
)

response = response_synthesizer.synthesize(
    "query text", nodes=[Node(text="text"), ...]
)

結合前幾天+今天的所有內容就可以完成一個簡單的 RAG 系統:

透過一層一層的串接可以簡單實現 RAG 架構,Documents → Embedding → Indexing → Retrievel → Node Postprocessors(Filter、Rerank) → Response Synthesis。透過以下範例能看到每一層都能幫助我們系統過濾掉不精確的 Node ,並在 Rerank 後精準找到了最相關的 Node,再透過 Response Synthesis 生成回覆。

import os
os.environ["OPENAI_API_KEY"] = " YOUR-API-KEY "
import llama_index.core
llama_index.core.set_global_handler("simple")

from llama_index.core import Document, VectorStoreIndex

# Create document
text_chunks = [
    "台北是台灣的首都,也是台灣政治、經濟、文化和交通的中心。這座城市充滿了活力與多元文化,結合了現代與傳統的魅力。台北擁有世界知名的地標——台北101,它曾是全球最高的摩天大樓,並且是購物和觀光的熱門地點。此外,台北還有許多文化和歷史景點,如故宮博物院、龍山寺和中正紀念堂,吸引了大量國內外遊客。台北市內交通便捷,捷運系統發達,是探索這座都市的絕佳方式。這裡也是台灣美食的集中地,夜市文化如士林夜市、饒河街夜市更是不可錯過的體驗之一。", 
    "新竹被譽為「風城」,因為當地的強風而得名。它位於台灣的西北部,距離台北約一小時車程。新竹是台灣高科技產業的重要基地,特別是以竹科(新竹科學園區)而聞名,是台灣的“矽谷”。新竹擁有良好的教育環境,著名的清華大學與交通大學皆位於此地。雖然新竹給人現代化的高科技城市印象,但它同時保留了豐富的歷史文化資產,如新竹城隍廟、新竹市東門城等。當地的風味小吃,如米粉和貢丸湯,也深受遊客喜愛,是品嚐道地台灣味的好去處。", 
    "台中位於台灣中部,氣候溫暖,擁有台灣第三大城市的規模。它以文化氣息濃厚著稱,擁有豐富的藝術與文化活動,如國立台灣美術館、霧峰林家花園等。台中還是熱門的觀光景點之一,尤其以彩虹眷村和高美濕地最為著名。此外,台中市還以舒適的生活環境和悠閒的生活步調著稱,常被視為居住和發展的理想城市。台中的夜市文化也相當發達,逢甲夜市是其中最具代表性的夜市之一,吸引了無數美食愛好者前來品嚐台灣各地的美食",
    "台南是台灣最古老的城市,也是台灣的文化和歷史重鎮,擁有豐富的歷史遺跡和古蹟。作為台灣的發源地,台南保存了大量具有歷史價值的建築物,如赤崁樓、安平古堡和延平郡王祠。這座城市還以其宗教文化著名,每年都有多場盛大的廟會活動,如媽祖遶境、五廟祭典等,吸引大量信徒參與。台南同時也是美食天堂,台南小吃如擔仔麵、碗粿和牛肉湯聞名全台。台南擁有獨特的歷史氛圍與人文風情,讓每個造訪者都能感受到濃厚的古早味。",
    "高雄是台灣的南部最重要的港口城市。高雄港是世界最繁忙的貨運港之一,帶動了當地的經濟發展。高雄市內的交通便捷,擁有輕軌和捷運系統,讓市民和遊客都能方便地遊覽這座城市。高雄的著名景點包括蓮池潭、打狗英國領事館、六合夜市等,是旅遊和購物的好地方。此外,旗津半島也是高雄知名的觀光勝地,以海灘、美食和古蹟著稱。高雄擁有豐富的自然景觀和現代化的都市建設,結合了傳統與現代的多元風貌。"
]
metadata_chunks = ['台北', '新竹', '台中', '台南', '高雄']
documents = []
for i, text in enumerate(text_chunks):
    doc = Document(
    text=text, 
    id_=f"doc_id_{i}",
    metadata={"city": metadata_chunks[i]})
    documents.append(doc)

# Indexing
index = VectorStoreIndex.from_documents(documents)

# Query
query = "國立台灣美術館在哪裡?"

# Retriever
retriever = index.as_retriever(similarity_top_k=4)
nodes = retriever.retrieve(query)
print(f"Number of Nodes:{len(nodes)}")
print(f"Node Similarity Order:{[x.metadata['city'] for x in nodes]}")

# Out [1]:
    Number of Nodes:4
    Node Similarity Order:['台北', '台中', '新竹', '台南']

# Node Postprocessor
# Filter
from llama_index.core.postprocessor import SimilarityPostprocessor
processor = SimilarityPostprocessor(similarity_cutoff=0.78)
nodes = processor.postprocess_nodes(nodes)
print(f"Num of Nodes:{len(nodes)}")
print(f"Node Similarity Order:{[x.metadata['city'] for x in nodes]}")
# Out [2]:
    Num of Nodes:3
    Node Similarity Order:['台北', '台中', '新竹']


# Rerank
from llama_index.postprocessor.cohere_rerank import CohereRerank
reranker = CohereRerank(
    model="rerank-multilingual-v3.0",
    top_n=2,
    api_key=" YOUR-API-KEY ",
)
nodes = reranker.postprocess_nodes(nodes, query_str=query)
print(f"Num of Nodes:{len(nodes)}")
print(f"Node Similarity Order:{[x.metadata['city'] for x in nodes]}")
# Out [3]:
    Num of Nodes:2
    Node Similarity Order:['台中', '台北']

# Response Synthesizer
from llama_index.core import get_response_synthesizer
response_synthesizer = get_response_synthesizer(response_mode="compact")
response = response_synthesizer.synthesize(
    query, nodes=nodes
)
print(response.response)
# Out [4]: 台中

結論🎯

LlamaIndex 提供了一套靈活且高效的 RAG 方法,結合了檢索、後處理與生成回覆的能力,使其成為開發者實現智慧查詢系統的強大工具。無論是結構化數據還是非結構化數據,透過 LlamaIndex 使用者能夠輕鬆地構建與優化查詢策略,確保能迅速且準確地取得所需資訊。接著我們將介紹 query_engine、chat_engine 敬請期待。


上一篇
Day19-從零開始:如何透過LlamaIndex儲存Index、Documents、Vector?
下一篇
Day21-揭秘 LlamaIndex:用圖解帶你搞懂複雜查詢與對話引擎!
系列文
懶人救星:生成式AI 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
cklgy88
iT邦新手 5 級 ‧ 2024-10-07 12:31:37

請問如果是金融pdf要llm去計算財務指標
會需要用到哪個Retrieval呢

如果是很多份相似的PDF的話,我的經驗是Vector + (BM25 or Keyword)就可以在搜索部分有一定水準了,BM25、Keyword要很準確需要在斷詞、停用詞等前處理下功夫,才能提升搜索精準度。

我要留言

立即登入留言