用 LangChain 和 Ollama 實作如何控制向量資料庫:讓LLM只回答document相關問題,避免回答超出範圍之外
日期:2024-11-21
在語義檢索系統中,如何確保回答的內容只來自設定的資料範圍,以避免回答無關的問題。
在本教學中,我們將以 LangChain 和 FAISS 為例,展示如何通過一系列技術手段,實現對檢索範圍的有效控制。
Github Repository : weitsung50110/Huggingface_Langchain_kit
本文是使用到裡面的
目標
- 構建一個基於 FAISS 的語義檢索系統。
- 設置檢索範圍控制,確保回答不超出指定內容。
- 處理無法回答的情況,避免模型「發揮」。
成果展示
回答相關問題:
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):
- 此參數控制返回結果的相關性,範圍通常為
0
到1
。 - 設置為
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 語法。