LangChain 和 Ollama 進行 SQL 查詢和自動化答案生成:LLM 實作與教學
日期:2024-11-05
使用 LangChain 框架來構建一個能夠自動生成 SQL 查詢並基於查詢結果返回自然語言答案的應用
本文是使用到裡面的:
- langchain_sqlite.py
- SQLite 資料庫 weibert.sqlite3
目標
我們的目標是實現一個系統,能夠:
- 接受用戶的自然語言問題。
- 根據資料庫的結構生成相應的 SQL 查詢。
- 執行 SQL 查詢並返回結果。
- 根據 SQL 查詢結果生成自然語言答案。
成果展示
告訴我全部共有幾個人
root@4be643ba6a94:/app# python3 langchain_sqlite.py >>> 告訴我全部共有幾個人 SQL> SELECT COUNT(*) FROM Users; 問題: 告訴我全部共有幾個人 執行: SELECT COUNT(*) FROM Users; 查詢結果: [(4,)] 回答: 有 4 人。
告訴我id2和id3的資訊
root@4be643ba6a94:/app# python3 langchain_sqlite.py >>> 告訴我id2和id3的資訊 SQL> SELECT * FROM Users WHERE id IN (2, 3); 問題: 告訴我id2和id3的資訊 執行: SELECT * FROM Users WHERE id IN (2, 3); 查詢結果: [(2, 'cccc', 'cccc@cccc.com.tw'), (3, 'zzcx', 'zzxc@zzxc.com.tw')] 回答: id2是'cccc',email是'cccc@cccc.com.tw'。id3是'zzcx',email是'zzxc@zzxc.com.tw'。>>>
設定環境
需要安裝一些必要的套件。這些套件來自 LangChain 和 SQLAlchemy,它們將幫助我們構建整個應用:
pip install langchain langchain-community sqlalchemy
崴寶創了一個DB名為 weibert.sqlite3
的SQLite 資料庫,我們將使用它來結合Langchain,裡面內容是我亂打的xD
id | username | |
---|---|---|
1 | aa | aa@aaa.cc |
2 | cccc | cccc@cccc.com.tw |
3 | zzcx | zzxc@zzxc.com.tw |
4 | apple | apple@qqqq.com.tw |
Docker
Docker Hub Repository: weitsung50110/ollama_flask >> 此為我安裝好的 Docker image 環境。
docker pull weitsung50110/ollama_flask:1.0
步驟 1:Ollama LLM
這次的大語言模型和之前的教學都不同,崴寶是選用kenneth85/llama-3-taiwan:8b-instruct
。
llm = ChatOllama(model='kenneth85/llama-3-taiwan:8b-instruct', callback_manager=CallbackManager([StreamingStdOutCallbackHandler()]))
步驟 2:初始化資料庫連接
首先,我們將建立一個 SQLite 資料庫的連接,並通過 SQLDatabase
類別來訪問資料庫。
from langchain_community.utilities import SQLDatabase
# 連接到 SQLite 資料庫
db = SQLDatabase.from_uri("sqlite:///./weibert.sqlite3")
步驟 3:創建 SQL 查詢生成的流程
創建一個模型提示模板來生成 SQL 查詢。這是通過 ChatPromptTemplate
完成的,該模板包含了用戶輸入的問題和資料庫的結構,模型將根據這些信息生成 SQL 查詢。
from langchain_core.prompts import ChatPromptTemplate
gen_sql_prompt = ChatPromptTemplate.from_messages([
('system', '根據下面的資料庫結構,編寫一個 SQL 查詢來回答使用者的問題:{db_schema}'),
('user', '請為以下問題生成一個 SQL 查詢:"{input}"。\
查詢應該格式化為以下方式,並且不附加任何額外的解釋:\
SQL> <sql_query>\
'),
])
這段程式碼中的 system
和 user
訊息將引導模型根據資料庫結構生成正確的 SQL 查詢。模型會根據用戶輸入的問題生成相應的 SQL 查詢,並以 SQL>
為標誌格式化返回的查詢。
步驟 4:創建 SQL 查詢解析器
為了處理模型生成的查詢,我們需要一個解析器來提取純粹的 SQL 查詢語句,並清除掉多餘的文字。
from langchain_core.output_parsers import StrOutputParser
class SqlQueryParser(StrOutputParser):
def parse(self, s):
r = s.split('SQL> ')
if len(r) > 1:
return r[1].strip() # 提取出 SQL 查詢部分
return s.strip()
這個 SqlQueryParser
類別將會提取從模型生成的文本中的 SQL 查詢部分。
步驟 5:執行 SQL 查詢
當我們得到 SQL 查詢後,需要執行它並獲取查詢結果。以下是執行 SQL 查詢並捕獲異常的代碼:
from sqlalchemy.exc import OperationalError
def run_query(query):
try:
return db.run(query)
except (OperationalError, Exception) as e:
return str(e)
這段代碼會執行 SQL 查詢並返回結果。如果有任何錯誤(例如 SQL 語法錯誤),則返回錯誤信息。
步驟 6:生成自然語言回答
當 SQL 查詢執行完畢後,我們需要生成一個自然語言的回答來解釋查詢結果。我們會使用另一個 ChatPromptTemplate
,讓模型根據問題、SQL 查詢和查詢結果生成一個簡潔的回答。
gen_answer_prompt = ChatPromptTemplate.from_template("""
根據提供的問題、SQL 查詢和查詢結果,撰寫一個自然語言的回答。
不應包含任何額外的解釋。
回答應該格式化為以下形式:
'''
問題: {input}
執行: {query}
查詢結果: {result}
回答: <answer>
'''
""")
這個模板將指導模型根據提供的資料庫查詢結果,生成最終的自然語言回應。
步驟 7:整合流程
最後,我們將所有部分組合在一起,形成一個完整的流程。這個流程包括了生成 SQL 查詢、執行查詢和生成最終答案。
from langchain_core.runnables import RunnablePassthrough
gen_query_chain = (
RunnablePassthrough.assign(db_schema=get_db_schema)
| gen_sql_prompt
| llm
| SqlQueryParser()
)
chain = (
RunnablePassthrough.assign(query=gen_query_chain).assign(
result=lambda x: run_query(x["query"]),
)
| gen_answer_prompt
| llm
)
在這裡,我們創建了一個 chain
,這個 chain
包含了所有步驟的組合,從生成 SQL 查詢到最終的自然語言回應。
步驟 8:交互式使用
現在我們已經建立了完整的系統,接下來是創建一個簡單的命令行界面,用戶可以在其中輸入問題並獲得答案:
input_text = input('>>> ')
while input_text.lower() != 'bye':
if input_text:
response = chain.invoke({
'input': input_text,
})
print(response) # 顯示回答
input_text = input('>>> ')
這段代碼讓用戶可以輸入問題,並根據模型生成的 SQL 查詢和資料庫結果來獲得回答。如果用戶輸入 “bye”,系統將終止。
print(gen_query_chain)
root@4be643ba6a94:/app# python3 langchain_sqlite.py
first=RunnableAssign(mapper={
db_schema: RunnableLambda(get_db_schema)
}) middle=[ChatPromptTemplate(input_variables=['db_schema', 'input'],
messages=[SystemMessagePromptTemplate(prompt=PromptTemplate(
input_variables=['db_schema'],
template='根據下面的資料庫結構,編寫一個 SQL 查詢來回答使用者的問題:{db_schema}')),
HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['input'],
template='請為以下問題生成一個 SQL 查詢:"{input}"。
查詢應該格式化為以下方式,並且不附加任何額外的解釋: SQL> <sql_query> '))]),
ChatOllama(callbacks=<
langchain_core.callbacks.manager.CallbackManager object at 0x7f409b773730>,
model='kenneth85/llama-3-taiwan:8b-instruct')] last=SqlQueryParser()
崴寶結語
在這篇教學中,我們展示了如何使用 LangChain 和 Ollama 架設一個基於自然語言的 SQL 查詢系統,並基於查詢結果生成清晰的自然語言答案。這種方式讓非技術用戶也能夠輕鬆地與資料庫進行互動。🌟
你可以根據需要擴展這個系統來處理更多的資料庫和問題場景。
喜歡 好崴寶 Weibert Weiberson 的文章嗎?在這裡留下你的評論!本留言區支援 Markdown 語法。