iT邦幫忙

2025 iThome 鐵人賽

DAY 14
0
生成式 AI

一塊一塊拼湊的 AI 樂高世界之旅系列 第 14

[Day 14] RAG 前前處理 - 介紹 RAG & Embedding

  • 分享至 

  • xImage
  •  

想像你在考試。

LLM 就像是一個「很會考試的學生」,他腦袋裡記了很多書本知識,但這些知識只到他讀書的那一天。如果考題問到新出的資訊(例如最新的新聞、產品或研究),他可能就答不出來,或乾脆「亂掰」一個聽起來合理的答案。

但如果使用 RAG(Retrieval Augmented Generation 檢索增強生成)就像這個學生在考試時,允許他「打開課本或上網查資料」。他還是會用自己的理解能力(生成文字的能力)來回答問題,但同時可以把最新的、正確的資料拿進來輔助。

以下是 RAG 的優點:

  • LLM 訓練後的知識不會自動更新,但 RAG 可以隨時從資料庫或網路抓最新內容。
  • 比起讓模型「胡編」,RAG 能引用文件中的原始內容,答案更可追溯。
  • 你可以自己決定模型要讀哪些文件(公司內部文件、專案報告、FAQ),確保答案符合需求。
  • 與其花大錢重新訓練模型,不如直接用 RAG 加外部知識。

先來一張流程圖吧

https://ithelp.ithome.com.tw/upload/images/20250928/20161224E3Z0AHldcJ.png

在講解 RAG 時候,還有一個特別的東西要單獨講,「向量資料庫」,當你有成千上萬筆向量要儲存與比對時,單純放在一般資料庫裡效率就會變得很差。這時候就需要 向量資料庫,其重點有兩個 1. 專門針對高維度向量做優化 2. 能在龐大資料裡,秒級找到最相似的結果。

常見的向量資料庫有 FAISS、Qdrant、Pinecone 等。這些工具讓我們可以把 embedding 向量丟進去,然後透過「相似度搜尋」快速找到相關內容。

那這邊介紹兩個方便的向量搜尋的工具 QdrantFaiss 的用法吧

  • Faiss

    import faiss
    import numpy as np
    import ollama
    
    def get_embedding(text):
        result = ollama.embeddings(
            model="bge-m3:567m", 
            prompt=text,
            keep_alive="1s"
        )["embedding"]
        return result
    
    sentences = [
        "貓喜歡吃魚",
        "狗喜歡玩球",
        "我今天去超市買牛奶",
        "昨天晚上看了一部電影"
    ]
    embeddings = []
    
    for text in sentences:
        embeddings.append(get_embedding(text))
    
    # 建立 index
    dim = len(embeddings[0])  # 向量維度
    index = faiss.IndexFlatL2(dim)  # L2 距離
    index.add(np.array(embeddings).astype("float32"))
    
    # 查詢
    query = "超市買東西"
    query_vec = np.array([get_embedding(query)]).astype("float32")
    D, I = index.search(query_vec, k=1)  # 找最相似的兩個
    
    print("Faiss 結果:", sentences[I[0][0]])
    

    結果:

    https://ithelp.ithome.com.tw/upload/images/20250928/20161224yw4HIhnKSl.png

  • Qdrant

    import numpy as np
    import ollama
    from qdrant_client import QdrantClient
    from qdrant_client.models import VectorParams, Distance, PointStruct
    
    def get_embedding(text):
        result = ollama.embeddings(
            model="bge-m3:567m", 
            prompt=text,
            keep_alive="1s"
        )["embedding"]
        return result
    
    # 文件資料
    sentences = [
        "貓喜歡吃魚",
        "狗喜歡玩球",
        "我今天去超市買牛奶",
        "昨天晚上看了一部電影"
    ]
    
    # 建立 embedding
    embeddings = [get_embedding(s) for s in sentences]
    dim = len(embeddings[0])  # 向量維度
    
    # 啟動 Qdrant (用記憶體模式,方便測試;正式環境可連線到伺服器)
    qdrant = QdrantClient(":memory:")
    
    # 建立 collection
    qdrant.recreate_collection(
        collection_name="docs",
        vectors_config=VectorParams(size=dim, distance=Distance.COSINE),
    )
    
    # 插入資料 (帶 payload 以便查回原始句子)
    qdrant.upsert(
        collection_name="docs",
        points=[
            PointStruct(
                id=i,
                vector=embeddings[i],
                payload={"text": sentences[i]}
            )
            for i in range(len(sentences))
        ]
    )
    
    # 查詢
    query = "超市買東西"
    query_vec = get_embedding(query)
    
    search_result = qdrant.search(
        collection_name="docs",
        query_vector=query_vec,
        limit=1
    )
    
    print("Qdrant 結果:", search_result[0].payload["text"])
    

參考資料


上一篇
[Day 13] 對!就是在說你 Ollama!
下一篇
[Day 15] Rag 前處理 - 文件處理
系列文
一塊一塊拼湊的 AI 樂高世界之旅17
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言