iT邦幫忙

2025 iThome 鐵人賽

DAY 28
0
AI & Data

ㄧ個八卦的時間也能了解AI最新趨勢系列 第 28

Day 28 我的GPT 怎麼笨笨的?-- 用RAG 幫幫你吧!(中)

  • 分享至 

  • xImage
  •  

嗨嚕~我們今天終於要來打造自己的專屬聊天機器人啦!🤖
這次我會使用自己整理的「烏龜頸」資料作為示範,讓 GPT 能回答與烏龜頸相關的問題。
當然,你也可以換成任何你想要的主題資料,看你想打造什麼樣的聊天機器人都行!(例如健康助理、旅遊小幫手等~都行!)

在螢幕前面的你,請抬頭挺胸 別再烏龜頸🫵🏻
事不宜遲我們改快開始吧!

前置作業

這次用 Google Colab 示範,你也可以用任何喜歡的編輯器呦~

首先免不了的就是要安裝需要的套件

!pip install -q --upgrade openai langchain langchain-community langchain-openai chromadb

引入必要的套件

import os
from google.colab import userdata
from openai import OpenAI
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings

驗證OpenAI API

大家還記得前天文章中有教大家如何申請OpenAI 帳好以及創建API 嗎~
我們要先驗證我們的API,之後我們使用模型都會是透過這個API來呼叫模型喔!

os.environ["OPENAI_API_KEY"] = userdata.get("OPENAI_API_KEY")
client = OpenAI()

這樣就驗證完成嚕

💡 這邊的 API Key 是儲存在 Colab 裡的 Secrets,不會顯示在程式碼中,這樣可以避免金鑰外洩喔!

簡易RAG

還記得我們昨天有提到RAG 的概念嗎?
因為模型本身有一些限制,所以我們需要給他額外的資料讓他可以根據這些資料去回應,昨天也有提到,基本的RAG 會有三個步驟:

  • 把長文件切成有chunks

  • 把 chunks 轉成 embeddings,存到向量資料庫

  • 依照使用者問題檢索最相關片段,連同問題一起丟給模型

那我們就來一步ㄧ步來看吧!

  1. 切分成chuncks
    切分區塊的方式有許多種,我們選用最常見的方式,稱作RecursiveCharacterTextSplitter
    這種方式主要是我們切塊的方式會有重疊,而重疊的好處就是能保留上下文,避免把關鍵句拆開而降低檢索品質
text_splitter = RecursiveCharacterTextSplitter(
    separators=["\n\n", "\n", " ", ""],#按照什麼做切分
    chunk_size=300,#一個chunck 的大小為何
    chunk_overlap=80, #每個chunck之間有多少overlap
)
docs = text_splitter.create_documents([text])

#這邊我們設定要以"相似度"抓回資料,並抓回前4筆最相關的資訊
retriever = db.as_retriever(search_type="similarity", search_kwargs={"k": 4})
  1. 再來我們將切分好的區塊轉換成embeddings 並存入向量資料庫中!
persist_dir = "chroma_store_turtleneck"
embeddings = OpenAIEmbeddings() 

db = Chroma.from_documents(
    documents=docs,
    embedding=embeddings,
    persist_directory=persist_dir
)
db.persist()

我們這邊是把切分後的文字區塊轉換成向量(embedding),再把這些向量儲存在 Chroma 向量資料庫中,Chroma 是一個專門用來儲存文字向量及其原始內容的資料庫,方便之後根據相似度進行檢索。LangChain還有支援許多不同的向量資料庫(像 FAISS、Pinecone、Weaviate 等),有興趣的朋友可以自己去試試看!

測試看看吧

我們前置作業已經完成惹!再來我們寫一個簡易 RAG function,讓他可以先檢索最相關的文字片段,再把片段與使用者問題一併送進模型產生回覆!

def rag_answer(question: str, model_name: str = "gpt-5"):
    # 檢索
    top_docs = retriever.get_relevant_documents(question)
    if not top_docs:
        return "目前在知識庫中找不到相關內容,請換個說法或提供更多線索。"
    context_text = "\n---\n".join([d.page_content for d in top_docs]) #將檢索到的內容全部合併
    #告訴模型需要拿檢索到的資訊生成回應
    system_prompt = (
        f"你是一位謹慎的助理。請只用檢索到的{context_text}與你的常識,"
        "回答使用者的問題。若片段沒有提到,請誠實告知。避免捏造。"
        "必要時可用條列給出要點。"
    )
    user_content = (
        f"使用者問題:{question}\n\n"
        "請根據以上資訊與你的常識回答問題"
    )

    resp = client.chat.completions.create(
        model=model_name,
        messages=[
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_content},
        ],
    )
    return resp.choices[0].message.content

在我們的文字檔裡,有提到「王美珠是烏龜頸的代表人物」,所以如果要問烏龜頸代表人物有誰,模型必須從我們提供的文件中去找到這則訊息才能回覆,那我們就來測試看看它能不能順利回答吧!

query = "烏龜頸代表人物是誰?"
print(rag_answer(query))

輸出答案

王美珠。

小小總結

將將~~~範例中我們可以看到模型成功結合外部資訊(烏龜頸的內容)和它自己的知識,完美回答了使用者的問題!是不是超讚~
今天的範例只是拿一個簡單的文字檔來示範,讓大家先感受一下 RAG的概念以及它的強大,而在實際案例中,許多公司都希望擁有自己的聊天機器人,能回答員工或客戶的問題,這時候,資料來源就會是公司內部的資訊,而資訊可能不是存成txt檔,可能是pdf、excel 等,我們今天雖然只有示範如何除理文字檔,但其實任何檔案都可以處理喔!只是方式會稍稍不同~

而至於要怎麼做出一個完美的RAG系統,你可以從範例程式碼當中看到,從切chunk的方式、要選用哪個向量資料庫、應該用什麼方式取回相關訊息,這些都可以依照自己的資料型態與需求去客製化調整,所以,只要你理解了 RAG 的基本流程,你就能打造出屬於自己(或公司專用)的智慧助理啦~

好啦!那就讓各位自己玩玩看嚕!掰噗


上一篇
Day 27 我的GPT 怎麼笨笨的?-- 用RAG 幫幫你吧!(上)
下一篇
Day 29 我的GPT 怎麼笨笨的?-- 用RAG 幫幫你吧!(下)
系列文
ㄧ個八卦的時間也能了解AI最新趨勢30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言