- 評估使用哪種顆粒度(Granularity)的資料來作為背景知識。
- 在這裡指的是 sentence-level、paragraph-level 和 document-level。
- 如何使用 semantic search 和 re-ranking。
- 了解使用 RAG 和沒有使用 RAG 的差異。
- 閱讀或學習過 Natural Language Processing (NLP) 相關知識。
- Python 程式開發經驗,有 matplotlib 套件使用基礎尤佳。
- 以 Transformer 神經網路為基礎的模型使用經驗。
- Visual Studio Code (vscode) 連結
- vscode 擴充功能:
SQLite3 Editor
- vscode 擴充功能:
安裝 Conda (二者擇一即可)
建立 Conda 虛擬環境
# 安裝 conda 環境
conda create -n rag python=3.10 ipykernel
# 切換到剛安裝好的 conda 環境
conda activate rag
# (Optional) 刪除 conda 環境
conda remove -n rag --allconda install pytorch torchvision torchaudio pytorch-cuda=12.1 -c pytorch -c nvidiaconda install pytorch::pytorch torchvision torchaudio -c pytorch- Windows 11 Pro (23H2)
- NVIDIA GeForce RTX 4090 * 1 (GPU memory: 24 GB)
- Driver Version: 561.09
- Cuda compilation tools, release 12.1, V12.1.66
- Ubuntu 22.04.4 LTS
- nVIDIA GeForce RTX 3090 * 1 (GPU memory: 24 GB)
- Driver Version: 535.183.01
- Cuda compilation tools, release 12.1, V12.1.66
- MacOS Sonoma 14.6.1
- Apple M2 Max (CPU/GPU memory: 32 GB)
- Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks 論文
圖:雙向編碼器與交叉編碼器
Embedding model:
- BAAI/bge-m3 連結 論文
- 雙向編碼器。
- 提供語義搜尋 (semantic search) 的功能:依「相似度」對文字(句子、段落、文件等)所代表的 embeddings 進行比對與排序。
- 支援最高 8192 tokens,會產生 embeddings。
- 幫助我們理解從資料庫檢索/查詢出來的知識(法規、條文)。
- 使用搜尋與查詢字串相似的文字,例如用 Question 找出相似的 Question。
- BAAI/bge-reranker-large 連結
- 交叉編碼器。
- 提供重新排序 (re-rank) 的功能:依「相關性」對文字(句子、段落、文件等)進行重新排序。
- 僅重新排序 semantic search 的結果,不會另外產生 embeddings。
- 找出可以回答問題的文字,例如找出與 Question 相關性高,可以用來回答 Question 的 Answer。
- 以臺北市立圖書館的常見問答為例:連結
語言模型
- MediaTek-Research/Breeze-7B-Instruct-v1_0 連結
- 全國法規資料庫 連結
- 嘗試整理出與財政、金融相關的法規
- financial_laws.db
- 將法規進行 chunking,分成:
- 以單部法規為主
- 以法規的條文為主
- 以條文的項、款、目為主
- 資料表名稱:
laws_full-> 法律/法規的所有條文laws_part-> 法律/法規的某個條文laws_sent-> 法律/法規的特定條文的某一句話
- 將法規進行 chunking,分成:
chart.ipynb: 透過簡單的視覺化,來評估應該使用哪種顆粒度來建立 embeddings。conv.py: 將知識庫當中的文字資料,連同 embeddings 一起儲存在 Pickle 檔案中。financial_laws.db: 知識庫,以 sqlite3 的資料庫作為儲存資料的工具。requirements.txt: 套件列表。run.py: 對 Web API 發出請求,取得 LLM 回應的答案。test_dense_vector_search.py: 檢視 semantic search + re-ranking 的結果。web_api.py: 將 LLM 整合在 Web API 當中,接收請求,並生成回應。
pip install -r requirements.txt- 先使用
chart.ipynb來評估要以整部法規、各別條文,還是條文的項、款、目來作為 chunks。 - 建立與儲存 embeddgins (包含對應的 passages,也就是 chunks)
# 建立 emb.pkl 檔 (會在 test_dense_vector_search.py 和 web_api.py 使用) time python conv.py # 測試 RAG 的 dense vector search 功能 (要先建立 emb.pkl 檔) time python test_dense_vector_search.py
- 在終端機啟動跟語言模型對話的 Web API 服務 (tmux 教學網頁)
# 安裝 tmux sudo apt-get install tmux # 建立終端機(terminal)的 session tmux new -s f_api # 切換至先前新增的 conda 虛擬環境 conda activate rag # 建立跟語言模型對話的服務 (使用 Flask 作為 Web Service) python web_api.py # 離開 tmux session (不會關閉 session) 先按下 ctrl + b 後,放掉,再按 d # 要再進入先前建立的終端機 session tmux a -t f_api
- 在 RAG 架構下,跟語言模型對話 (使用
requests模擬互動)python run.py
- 關閉 Web API 服務
# 進入先前建立的終端機 session tmux a -t f_api # 關閉 Flask 服務 按下 Ctrl + C,確認服務停止後即可
- 關閉 tmux session
# 確認目前在 tmux session 當中,在可以輸入指令的狀態下 輸入 exit 後,按下 enter,回到 Terminal
- 語言生成(language generation)以自我回歸(autoregression)為基礎:
- 單字序列的機率分佈,是透過條件機率來計算下一個單字分佈的乘積。舉例而言,當手機輸入文字的時候,系統會推薦或提供可能選擇的下一個字。
- 建議閱讀:How to generate text: using different decoding methods for language generation with Transformers
- Sampling
generation_kwargs = dict( ... do_sample=True, temperature=0.7, top_k=50, top_p=0.9, ... )
- Greedy Search or Beam Search
generation_kwargs = dict( ... do_sample=False, num_beams=5, no_repeat_ngram_size=2, early_stopping=True, ... )
- Sampling
-
為什麼使用 RAG 當作問答系統的架構?
當沒有資源去預訓練或微調一個大型語言模型(LLM)來用於回答特定的問題時,可以透過資訊檢索的技術,將檢索結果當作 LLM 回答問題的參考資訊或背景知識,讓 LLM 可以依據資訊或知識來回答使用者的提問。
-
Chunking Size 設定多少比較合適?
個人認為 chunking size 只是一個概念,常見如每 128/256/512/1024 tokens 截斷一次,有時反而會失去原有的語義。人類寫作的時候,無論是單詞的使用、句子的成形、段落的舖陳,甚至是整篇文章所傳達的訊息,都有他的意義,例如迴文「上海自來水來自海上」,如果 chunking size 為 4,可能會被分成「上海自來」、「水來自海」、「上」這三個部分,如此一來,便失去原先要表達的意涵。
可能較好的方式,就是針對不同文件的內容,客製化建立它們的 chunks。例如一篇文章是常見作文,可以將每一個段落視為 chunk,若是文章當中有段落也有表格,可以將段落與表格分別建立 chunk,有時候段落和表格的前面加上原始文件的標題或是表格內容的摘要,檢索效果較好;若文章中的每個句子或短文都有各別的意義,例如成語、國語辭典(有時候包括解釋說明),那就以句子或短文形式來建立 chunk。
倘若 embedding model 的 max_seq_length 很大(可以理解更長的文字資料),或是所有知識庫當中的文字資料,都可以被當前使用的 embedding model 的 max_seq_length 所含括,有時候不進行 chunking 也是一種選擇。
-
文件內容結構太複雜,怎麼辦?
可以使用一些軟體或套件,將原始文件內容(如文字段落、表格等)轉變成結構化或半結構化的格式,例如 Dataframe、JSON、XML、CSV 等,再進行剖析;圖片的內容可以透過 OCR 技術進行擷取。
-
有其它檢索方案可以使用嗎?
如果指的是案例中的向量檢索,可以考慮使用 Huggingface: intfloat 的 E5 模型,它是直接以 Question-Answer 成對關係的資料進行訓練,或許不需要進行 semantic search + re-ranking,直接以 QA 格式進行相似度比對。bge-m3 可以支援到 8192 tokens,如果使用其它 embedding model,要連同資料可能佔用的 tokens (例如可支援的 max_seq_length,決定模型可以一次看完多少 tokens) 一起考慮進去。
如果指的是以統計量為基礎的檢索方法,可以考慮使用 BM25 進行檢索。它結合了 TF-IDF 和詞袋模型的特性,加入了文件平均長度等元素,增強了檢索的效果。
在實務中,BM25 通常可以達到很好的效果,若是沒有辦法使用向量檢索(例如沒有 GPU、主機效能不佳等因素),推薦使用 BM25,惟 BM25 需要針對特定領域的任務建立關鍵字詞庫(例如 jieba 的
jieba.load_userdict()功能),如果沒有預先整理出合適的關鍵字詞庫,檢索效果可能會不如預期。 -
一定要使用 Re-ranking 嗎?
視任務需求而定。如果你只是希望找到跟查詢字串相似度高的文字資料(例如用 Question 搜尋很相似的 Question),語義搜尋就足夠了;倘若文字資料混雜了很多資訊,例如 Questions 和 Answers 都放在一起,沒有區分,使用 Re-ranking 的話,用來回答查詢字串的 Answers 有可能因為排名提升而被看見。
-
Pickle 檔案太大,怎麼辦?
有一種作法,就是將不同用途或種類的 Pickle 檔案區分開來,需要用到的時候才讀取,不需要則釋放,彈性地使用 Pickle 檔。
如果你是進階使用者,可以考慮使用 FAISS、ElasticSearch、Milvus、Weaviate 等向量索引/資料庫儲存工具,可以更便利地使用/儲存向量。
-
一定要先使用 semantic search,才能使用 re-ranker 嗎?
不一定。semantic search 通常是用來產生 embeddings,供其它可儲存 embeddings 如 FAISS 或 elasticsearch 等支援 Dense Vector Search 的工具,或是 model 本身,進行大規模的搜尋/檢索機制使用(找出與查詢文字相似的所有資訊)。
Re-ranker 如 bge-reranker-*,架構是採用
XLMRobertaForSequenceClassification,對 sequence 進行分類,所以能夠獨立運作,主要是使用query找出relevant passages/chunks。可視任務情境來評估是否要將兩者整合成 pipeline,或是依需求獨立運作。



