蹲式老虎,隐藏的龙
- 这一切始于对PrivateGPT的好奇心。
- 但是,在挖掘一点之后,真实的MVP是LangChain。
- 这是我的“创建本地AI聊天机器人的旅程”的快速摘要,希望能节省人们的痛苦。
(第1部分)设置
(1A)要求
- Python:3.9〜3.10似乎正常工作。
- Microsoft C++ Build Tools
(1B)虚拟环境与模块
- 创建一个项目文件夹。例如。
D:\CHATBOT
- 打开终端,然后导航到项目文件夹
cd D:\CHATBOT
- 创建虚拟环境
virtualenv venv
。 - 激活IT
venv\Scripts\activate
(Windows),venv/bin/activate
(Mac/Linux)。 pip install gpt4all chromadb langchain bs4
(1C)GPT4ALL模型
- 访问GPT4All Website,向下滚动到“模型Explorer”。
- 选择你的毒药。将您选择的模型保存到
D:\CHATBOT\models
中。
(第2部分)上下文和设置
(2a)虚拟文件
2a-dummy.txt
John is 12 years old, and wears a blue polo shirt.
His favorite color is blue, and likes to dance.
When he grows up, his dream is to be a farmer.
- 在进入“实际代码”之前,我们要处理“不是那么编程”的零件。
- 这只是一个虚拟文档,用作上下文。
(2B)提示模板
2b-prompt.txt
Use the following context section and only that context to answer the question at the end.
Do not use your internal knowledge. If you don't know the answer, just say that you don't know, don't try to make up an answer.
Context: {context}
Question: {query}
Answer:
- 简单地说,我们使用它来修改用户的原始问题。
- 用户的问题将插入
{query}
。 - 上述虚拟文档的相关部分将插入为
{context}
,因此AI知道发生了什么。
(2C)设置
2c-settings.json
{
"model_file" : "ggml-model-gpt4all-falcon-q4_0.bin",
"model_tokens" : 1000,
"doc_file" : "2a-dummy.txt",
"doc_chunks" : 512,
"doc_overlap" : 20,
"ws_host" : "localhost",
"ws_port" : 5678
}
将model_file
更改为自己。
(第3部分)命令行聊天机器人
3-cli.py
# (A) LOAD MODULES
import os, json
from langchain.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import Chroma
from langchain.embeddings import GPT4AllEmbeddings
from langchain.llms import GPT4All
from langchain import PromptTemplate, LLMChain
# (B) SETTINGS
# (B1) SYSTEM PATH
set = { "path" : os.path.dirname(os.path.realpath(__file__)) }
# (B2) LOAD SETTINGS
with open(os.path.join(set["path"], "2c-settings.json"), "r") as fs:
set.update(json.load(fs))
fs.close()
set["model_file"] = os.path.join(set["path"], "models", set["model_file"])
set["doc_file"] = os.path.join(set["path"], set["doc_file"])
# (B3) LOAD PROMPT TEMPLATE
with open(os.path.join(set["path"], "2b-prompt.txt"), "r") as fs:
set["prompt"] = fs.read()
fs.close()
# (C) INIT
# (C1) CREATE VECTOR STORE FROM DOCUMENT
vstore = Chroma.from_documents(
documents = RecursiveCharacterTextSplitter(
chunk_size = set["doc_chunks"], chunk_overlap = set["doc_overlap"]
).split_documents(TextLoader(set["doc_file"]).load()),
embedding = GPT4AllEmbeddings()
)
# (C2) LLM
llm = GPT4All(model = set["model_file"], max_tokens = set["model_tokens"])
# (D) Q&A SESSION
while True:
# (D1) LISTEN TO QUERIES
query = input("\nEnter a query: ")
if query == "exit":
break
if query.strip() == "":
continue
# (D2) BUILD CONTEXT FROM QUERY & VECTOR STORE
context = ""
for doc in vstore.similarity_search(query):
context = context + doc.page_content + " \n\n "
# (D3) LLM CHAIN
llm_chain = LLMChain(
llm = llm,
prompt = PromptTemplate(
template = set["prompt"], input_variables = ["context", "query"]
).partial(context = context)
)
# (D4) OUTPUT RESULT
print(llm_chain.run(query))
- (a)加载所需的模块。
- (b)加载设置和提示模板。
- (C1)基于
2-dummy.txt
创建一个矢量存储(数据库)。 - (C2)“使用GPT4All”作为LLM(大语言模型)。
- (d)无尽回答问题的循环。
- (d1)听
query
输入。 - (d2)基于
query
,从vector Store中提取数据的恢复部分为context
。 - (d3)将查询,上下文,提示模板馈入模型。
- (D4)输出结果。
- (d1)听
(第4部分)基于Web的聊天机器人
(4A)Websocket模块
- 聊天机器人已经有效。
- 但是,如果您想“实施到网页”,最简单的方法是使用WebSockets。
pip install websockets
(4B)修改的聊天机器人脚本
4b-web.py
# A TO C ARE PRETTY MUCH THE SAME
# ONLY AN ADDITIONAL "IMPORT WEBSOCKETS"
# (D) Q&A SESSION
# (D1) ANSWER QUERY
async def qna (websocket):
async for query in websocket:
# (D1-1) BUILD CONTEXT FROM QUERY & VECTOR STORE
context = ""
for doc in vstore.similarity_search(query):
context = context + doc.page_content + " \n\n "
# (D1-2) LLM CHAIN
llm_chain = LLMChain(
llm = llm,
prompt = PromptTemplate(
template = set["prompt"], input_variables = ["context", "query"]
).partial(context = context)
)
# (D1-3) RESPOND
await websocket.send(llm_chain.run(query))
# (D2) GO!
async def main ():
async with websockets.serve(qna, set["ws_host"], set["ws_port"]):
print("Server deployed at " + set["ws_host"] + ":" + str(set["ws_port"]))
await asyncio.Future()
if __name__ == "__main__":
asyncio.run(main())
几乎相同 - 除了我们现在将聊天机器人放在ws://localhost:5678
的websocket后面。
(4C)聊天机器人HTML页面
4c-web.html
<!-- (A) CHAT HISTORY -->
<div id="messages"></div>
<!-- (B) QUESTION -->
<form id="question" onsubmit="return chat.send()">
<input type="text" id="qTxt" placeholder="Question" required disabled>
<input type="submit" id="qGo" value="Go" disabled>
</form>
-
<div id="messages">
聊天历史。 -
<form id="question">
输入您的问题。
(4D)聊天机器人JavaScript
4d-web.js
var chat = {
// (A) SETTINGS & FLAGS
host : "ws://localhost:5678/", socket : null,
hMsg : null, hTxt : null, hGo : null,
// (B) INIT
init : () => {
// (B1) GET HTML ELEMENTS
chat.hMsg = document.getElementById("messages");
chat.hTxt = document.getElementById("qTxt");
chat.hGo = document.getElementById("qGo");
// (B2) CONNECT TO WEBSOCKET
chat.socket = new WebSocket(chat.host);
// (B3) ON CONNECT - ENABLE QUERY FORM
chat.socket.addEventListener("open", () => {
chat.controls(1);
chat.draw("Ready!", "sys");
});
// (B4) ON RECEIVE MESSAGE - DRAW IN HTML
chat.socket.addEventListener("message", e => chat.draw(e.data, "bot"));
// (B5) ON ERROR & CONNECTION LOST
chat.socket.addEventListener("close", () => {
chat.controls();
chat.draw("Websocket connection lost!", "sys");
});
chat.socket.addEventListener("error", err => {
chat.controls();
console.log(err);
chat.draw("Websocket connection error!", "sys");
});
},
// (C) TOGGLE HTML CONTROLS
controls : enable => {
if (enable) {
chat.hTxt.disabled = false;
chat.hGo.disabled = false;
} else {
chat.hTxt.disabled = true;
chat.hGo.disabled = true;
}
},
// (D) SEND MESSAGE TO CHAT SERVER
send : () => {
chat.controls(); // disable question form until bot replies
chat.draw(chat.hTxt.value, "human");
chat.socket.send(chat.hTxt.value);
chat.hTxt.value = "";
return false;
},
// (E) DRAW MESSAGE IN HTML
draw : (msg, css) => {
let row = document.createElement("div");
row.className = css;
row.innerHTML = `<div class="chatName">${css}</div> <div class="chatMsg">${msg}</div>`;
chat.hMsg.appendChild(row);
if (css=="bot") { chat.controls(1); } // enable form on bot reply
// window.scrollTo(0, 0);
}
};
window.addEventListener("load", chat.init);
不要逐行解释...几乎是“连接到ws://localhost:5678
”,发送问题并从AI ChatBot接收答案。
结束
这是要点上的代码的链接,还有其他一些内容: