搜尋結果

×

用 LangChain 和 Ollama 實作如何控制向量資料庫:讓LLM只回答document相關問題,避免回答超出範圍之外

在語義檢索系統中,如何確保回答的內容只來自設定的資料範圍,以避免回答無關的問題。

在語義檢索系統中,如何確保回答的內容只來自設定的資料範圍,是開發者常見的需求。特別是當向量資料庫中有大量資料時,我們需要有效限制檢索結果的範圍,以避免回答無關的問題。

在本教學中,我們將以 LangChain 和 FAISS 為例,展示如何通過一系列技術手段,實現對檢索範圍的有效控制。

Github Repository : weitsung50110/Huggingface_Langchain_kit

本文是使用到裡面的

目標

  1. 構建一個基於 FAISS 的語義檢索系統。
  2. 設置檢索範圍控制,確保回答不超出指定內容。
  3. 處理無法回答的情況,避免模型「發揮」。

成果展示

回答相關問題:

root@4be643ba6a94:/app# python3 langchain_rag_doc_restrict.py
>>> 請告訴我崴寶的 ig
崴寶的 IG 是 https://instagram.com/weibert_coding。

>>> 崴寶的 youtube 是?
崴寶的 YouTube 是 https://youtube.com/@weibert。

>>> 崴寶的全名是?
崴寶的全名是 Weibert Weiberson。

>>> 崴寶有 threads 嗎?
是的,你可以在 https://threads.net/@weibert_coding 上找到崴寶的 Threads。

拒絕無關問題:

root@4be643ba6a94:/app# python3 langchain_rag_doc_restrict.py
>>> 崴寶是哪裡人
抱歉,我無法回答這個問題。

>>> 日本的首都是哪裡?
抱歉,我無法回答這個問題。

>>> 台灣有哪些離島?
抱歉,我無法回答這個問題。

實作

1:準備相關的文檔資料

from langchain_core.documents import Document

# 準備文檔資料
docs = [
    Document(page_content='崴寶Weibert Weiberson的網站:了解更多關於崴寶的資訊,請訪問 https://weitsung50110.github.io'),
    Document(page_content='崴寶Weibert Weiberson的YouTube:觀看崴寶的最新影片,請訪問 https://youtube.com/@weibert'),
    Document(page_content='崴寶Weibert Weiberson的Instagram(IG):跟隨崴寶的編程和創作,請訪問 https://instagram.com/weibert_coding'),
    Document(page_content='崴寶Weibert Weiberson的Threads:探索崴寶的更多動態,請訪問 https://threads.net/@weibert_coding')
]

2:進行文本分割

為了提高檢索精準度,我們使用文本分割工具,將長文檔分割成較小的段落或片段,方便向量化。

from langchain.text_splitter import CharacterTextSplitter

# 初始化文本分割器
text_splitter = CharacterTextSplitter(chunk_size=20, chunk_overlap=5)
documents = text_splitter.split_documents(docs)

分割規則:

  • 每段文字長度為 20 字符。
  • 片段之間有 5 字符重疊。

3:建立向量資料庫

利用 FAISS 建立向量資料庫,並設置檢索器。

from langchain_community.embeddings import OllamaEmbeddings
from langchain_community.vectorstores import FAISS

# 初始化嵌入模型
embeddings = OllamaEmbeddings(model="llama3")

# 建立向量資料庫
vectordb = FAISS.from_documents(docs, embeddings)

# 設置檢索器並添加相似度閾值
retriever = vectordb.as_retriever()
retriever.search_kwargs = {'distance_threshold': 0.8}  # 僅返回與查詢足夠相關的結果

相似度閾值(distance_threshold):

  • 此參數控制返回結果的相關性,範圍通常為 01
  • 設置為 0.8 意味著只返回高度相關的結果。

關於相似度閾值的數值詳細設定教學,請參考這篇
如何控制語義檢索的範圍:向量資料庫的相似度閾值(similarity threshold)

4:定義提示模板

提示模板負責告訴模型如何處理檢索到的結果。
以下範例要求模型僅根據上下文回答,無法找到答案時回應「無法回答」。

from langchain_core.prompts import ChatPromptTemplate

# 定義提示模板
prompt = ChatPromptTemplate.from_messages([
    ('system', '回答使用者的問題時,僅根據以下提供的上下文進行回答,若無法找到相關內容,請回答:「抱歉,我無法回答這個問題。」\n\n{context}'),
    ('user', '問題:{input}'),
])

5:整合檢索與回答鏈

結合 FAISS 檢索器和提示模板,構建檢索與回答的整合鏈。

from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain.chains import create_retrieval_chain
from langchain_community.llms import Ollama
from langchain.callbacks.manager import CallbackManager
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler

# 初始化大語言模型
llm = Ollama(
    model='kenneth85/llama-3-taiwan:8b-instruct',
    callback_manager=CallbackManager([StreamingStdOutCallbackHandler()])
)

# 創建文件鏈
document_chain = create_stuff_documents_chain(llm, prompt)

# 創建檢索鏈
retrieval_chain = create_retrieval_chain(retriever, document_chain)

6:運行檢索應用

context = []
input_text = input('>>> ')
while input_text.lower() != 'bye':
    response = retrieval_chain.invoke({
        'input': input_text,
        'context': context
    })

    # 如果找不到相關答案
    if not response['context']:
        print("抱歉,我無法回答這個問題。")
    else:
        print(response['answer'])

    input_text = input('>>> ')

如何有效控制檢索範圍?

1. 限制資料庫內容

僅添加目標主題相關的文檔資料,避免引入無關的內容。

2. 設置相似度閾值

使用 distance_threshold 嚴格過濾檢索結果,只返回高相關性答案。

關於相似度閾值的數值詳細設定教學,請參考這篇
如何控制語義檢索的範圍:向量資料庫的相似度閾值(similarity threshold)

3. 增加提示模板限制

在提示中明確要求模型只基於上下文回答,無法找到答案時回應「無法回答」。

4. 後處理檢索結果

檢查檢索返回的結果是否符合查詢條件,無關結果可直接過濾掉。

崴寶結語

通過本文的實作教學,可以成功構建一個能有效控制檢索範圍的語義檢索應用。

這樣的系統在知識庫問答、客製化搜尋等場景中有著廣泛應用,讓我們的 AI 回答更加準確且受控。🥰

    喜歡 好崴寶 Weibert Weiberson 的文章嗎?在這裡留下你的評論!本留言區支援 Markdown 語法