使用 LangChain 和 Ollama 結合向量Vector database打造 NBA 球員數據問答系統:讓數字不要出現幻覺
日期:2024-12-06
使用 LangChain 和 Chroma 打造一個簡單的問答系統,能夠回答 NBA 球員相關數據的問題。你會學會整合大型語言模型(LLM)、嵌入向量檢索與結構化數據存儲,打造一個實用的問答應用。
需要文件下載
Github Repository — weitsung50110/Huggingface_Langchain_kit
本文是使用到裡面的 langchain_rag_chroma_preload.py
檔案。
一、崴寶專案目標
本專案的目標是:
- 準備 NBA 球員數據,包含球員的得分、助攻等資訊。
- 使用 LangChain 提供的 Ollama 與 OllamaEmbeddings 生成嵌入向量。
- 利用 Chroma 實現數據的存儲與檢索。
- 建立一個互動式問答系統,結合檢索到的數據與 LLM 回答用戶問題。
二、準備工作
Docker
weitsung50110/ollama_flask >> 此為我安裝好的 Docker image 環境。
docker pull weitsung50110/ollama_flask:1.0
docker run等使用說明請進入Docker Hub裡面的說明欄查看。
1. 初始化專案環境
在開始構建系統之前,初始化 LLM、嵌入模型與向量數據庫:
import hashlib
import os
from langchain_community.llms import Ollama
from langchain_community.embeddings import OllamaEmbeddings
from langchain_chroma import Chroma
from langchain.chains import RetrievalQA
from langchain.callbacks.manager import CallbackManager
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
from langchain.schema import Document
2. 初始化 LLM 與嵌入模型
我們選用 Ollama 的模型作為語言生成的基礎模型,同時使用 OllamaEmbeddings 生成嵌入向量:
model 是可以調整更動的 ~
model = ‘更換成你載入的模型’
llm = Ollama(model=’llama3’)
# 初始化 Callback Manager
callback_manager = CallbackManager([StreamingStdOutCallbackHandler()])
# 初始化 Ollama LLM
llm = Ollama(
model="kenneth85/llama-3-taiwan:8b-instruct",
callback_manager=callback_manager
)
# 初始化 Ollama Embeddings
embeddings = OllamaEmbeddings(model="kenneth85/llama-3-taiwan:8b-instruct")
3. 準備數據
假設我們有一組模擬的 NBA 球員數據,包含姓名、場均得分、助攻次數與所屬球隊:
# 範例 NBA 數據
nba_data = [
{"player": "好崴寶Weibert", "points_per_game": 30.1, "assists_per_game": 5.7, "team": "Weibert"},
{"player": "孟孟", "points_per_game": 29.7, "assists_per_game": 8.7, "team": "Mengbert"},
{"player": "崴崴Weiberson", "points_per_game": 25.1, "assists_per_game": 10.5, "team": "Weiberson"}
]
4. 建立數據哈希與檢查
使用數據哈希檢查數據是否更新,避免每次都重新生成數據庫:
def calculate_data_hash(data):
hasher = hashlib.md5()
hasher.update(str(data).encode('utf-8'))
return hasher.hexdigest()
hash_file_path = os.path.join("chroma_vectorstore_nba", "data_hash.txt")
def needs_update(data, hash_file_path):
new_hash = calculate_data_hash(data)
if not os.path.exists(hash_file_path):
return True, new_hash
with open(hash_file_path, "r") as f:
existing_hash = f.read().strip()
return new_hash != existing_hash, new_hash
5. 建立向量數據庫
如果數據更新或首次執行,重新生成向量數據庫,並使用 Chroma 存儲:
update_required, new_hash = needs_update(nba_data, hash_file_path)
if os.path.exists("chroma_vectorstore_nba") and not update_required:
print("---正在加載現有的向量數據庫...")
vectorstore = Chroma(persist_directory="chroma_vectorstore_nba", embedding_function=embeddings)
else:
print("---數據已更新,正在重新生成數據庫...")
if os.path.exists("chroma_vectorstore_nba"):
import shutil
shutil.rmtree("chroma_vectorstore_nba")
documents = [
Document(page_content=data["player"], metadata=data) for data in nba_data
]
vectorstore = Chroma.from_documents(
documents=documents,
embedding=embeddings,
persist_directory="chroma_vectorstore_nba"
)
with open(hash_file_path, "w") as f:
f.write(new_hash)
6. 啟動問答系統
使用 LangChain 的 RetrievalQA
,將檢索器與 LLM 整合為問答系統:
retriever = vectorstore.as_retriever()
qa_chain = RetrievalQA.from_chain_type(llm=llm, chain_type="stuff", retriever=retriever)
7. 用戶交互功能
實現用戶輸入查詢,檢索相關數據,並結合 LLM 生成回答:
def query_system():
while True:
query = input("請輸入查詢內容(輸入 'bye' 退出):")
if query.lower() == "bye":
print("已退出查詢系統。")
break
results = retriever.get_relevant_documents(query)
if results:
context = "\n".join(
[f"球員: {res.metadata['player']}, 場均得分: {res.metadata['points_per_game']}, 助攻: {res.metadata['assists_per_game']}, 球隊: {res.metadata['team']}" for res in results]
)
prompt = f"以下是相關數據:\n{context}\n\n根據以上數據,回答以下問題:{query}"
response = qa_chain.invoke(prompt)
print(f"回答:{response}")
else:
print("未找到相關數據,請嘗試其他查詢。")
query_system()
三、成果展示
生成Chroma向量資料庫
root@4be643ba6a94:/app# python3 langchain_rag_chroma_preload.py
/app/langchain_rag_chroma_preload.py:15: LangChainDeprecationWarning: The class `Ollama` was deprecated in LangChain 0.3.1 and will be removed in 1.0.0. An updated version of the class exists in the :class:`~langchain-ollama package and should be used instead. To use it run `pip install -U :class:`~langchain-ollama` and import as `from :class:`~langchain_ollama import OllamaLLM``.
llm = Ollama(
/app/langchain_rag_chroma_preload.py:15: DeprecationWarning: callback_manager is deprecated. Please use callbacks instead.
llm = Ollama(
/app/langchain_rag_chroma_preload.py:21: LangChainDeprecationWarning: The class `OllamaEmbeddings` was deprecated in LangChain 0.3.1 and will be removed in 1.0.0. An updated version of the class exists in the :class:`~langchain-ollama package and should be used instead. To use it run `pip install -U :class:`~langchain-ollama` and import as `from :class:`~langchain_ollama import OllamaEmbeddings``.
embeddings = OllamaEmbeddings(model="kenneth85/llama-3-taiwan:8b-instruct")
---數據已更新,正在重新生成數據庫...
---正在刪除舊的向量數據庫...
---正在生成向量數據庫...
---向量數據庫已保存!
Q: 好崴寶Weibert得幾分?
請輸入查詢內容(輸入 'bye' 退出):好崴寶Weibert得幾分?
---檢索到的相關數據:
球員: 崴崴Weiberson, 場均得分: 25.1, 助攻: 10.5, 球隊: Weiberson
球員: 好崴寶Weibert, 場均得分: 30.1, 助攻: 5.7, 球隊: Weibert
球員: 孟孟, 場均得分: 29.7, 助攻: 8.7, 球隊: Mengbert
Number of requested results 4 is greater than number of elements in index 3, updating n_results = 3
回答:好崴寶Weibert場均得分為30.1。
#以下是產生的prompt,這樣可以讓LLM說出的數字更準確。
{'query': '以下是相關數據:\n球員: 崴崴Weiberson, 場均得分: 25.1, 助攻: 10.5,
球隊: Weiberson\n球員: 好崴寶Weibert, 場均得分: 30.1, 助攻: 5.7, 球隊: Weibert\n
球員: 孟孟, 場均得分: 29.7, 助攻: 8.7, 球隊: Mengbert\n\n根據以上數據,
回答以下問題:好崴寶得幾分?', 'result': '好崴寶Weibert場均得分為30.1。'}
Q: 崴崴weiberson的助攻是多少?
請輸入查詢內容(輸入 'bye' 退出):崴崴weiberson的助攻是多少?
---檢索到的相關數據:
球員: 崴崴Weiberson, 場均得分: 25.1, 助攻: 10.5, 球隊: Weiberson
球員: 好崴寶Weibert, 場均得分: 30.1, 助攻: 5.7, 球隊: Weibert
球員: 孟孟, 場均得分: 29.7, 助攻: 8.7, 球隊: Mengbert
Number of requested results 4 is greater than number of elements in index 3, updating n_results = 3
回答:崴崴Weiberson的助攻是10.5。。
#以下是產生的prompt,這樣可以讓LLM說出的數字更準確。
{'query': '以下是相關數據:\n球員: 崴崴Weiberson, 場均得分: 25.1, 助攻: 10.5,
球隊: Weiberson\n球員: 好崴寶Weibert, 場均得分: 30.1, 助攻: 5.7,
球隊: Weibert\n球員: 孟孟, 場均得分: 29.7, 助攻: 8.7, 球隊: Mengbert\n\n
根據以上數據,回答以下問題:崴崴weiberson的助攻是多少?',
'result': '崴崴Weiberson的助攻是10.5。'}
Q: 孟孟是哪個球隊的?他得分是多少?
請輸入查詢內容(輸入 'bye' 退出):孟孟是哪個球隊的?他得分是多少?
---檢索到的相關數據:
球員: 崴崴Weiberson, 場均得分: 25.1, 助攻: 10.5, 球隊: Weiberson
球員: 好崴寶Weibert, 場均得分: 30.1, 助攻: 5.7, 球隊: Weibert
球員: 孟孟, 場均得分: 29.7, 助攻: 8.7, 球隊: Mengbert
Number of requested results 4 is greater than number of elements in index 3, updating n_results = 3
回答:孟孟所屬的球隊是Mengbert。他場均得分為29.7分。
#以下是產生的prompt,這樣可以讓LLM說出的數字更準確。
{'query': '以下是相關數據:\n球員: 崴崴Weiberson, 場均得分: 25.1, 助攻: 10.5,
球隊: Weiberson\n球員: 好崴寶Weibert, 場均得分: 30.1, 助攻: 5.7,
球隊: Weibert\n球員: 孟孟, 場均得分: 29.7, 助攻: 8.7,
球隊: Mengbert\n\n根據以上數據,回答以下問題:孟孟是哪個球隊的?他得分是多少?',
'result': '孟孟所屬的球隊是Mengbert。他場均得分為29.7分。'}
崴寶總結
看到這裡,恭喜你學會了以下內容!
- 如何準備數據並生成嵌入向量。
- 使用 Chroma 建立向量數據庫並進行檢索。
- 使用 LangChain 整合 LLM 與檢索結果回答問題。
喜歡 好崴寶 Weibert Weiberson 的文章嗎?在這裡留下你的評論!本留言區支援 Markdown 語法。