在本教程中,我將引導您使用 Elasticsearch、OpenAI、LangChain 和 FastAPI 構建語義搜索服務。
LangChain 是這個領域的新酷孩子。 它是一個旨在幫助你與大型語言模型 (LLM) 交互的庫。 LangChain 簡化了與 LLMs 相關的許多日常任務,例如從文檔中提取文本或在向量數(shù)據(jù)庫中對它們建立索引。 如果你現(xiàn)在正在與 LLMs 一起工作,LangChain 可以節(jié)省你的工作時間。
然而,它的一個缺點是,盡管它的文檔很廣泛,但可能比較分散,對于新手來說很難理解。 此外,大多數(shù)在線內(nèi)容都集中在最新一代的向量數(shù)據(jù)庫上。 由于許多組織仍在使用 Elasticsearch?這樣經(jīng)過實戰(zhàn)考驗的技術,我決定使用它編寫一個教程。
我將 LangChain 和 Elasticsearch 結合到了最常見的 LLM 應用之一:語義搜索。 在本教程中,我將引導你使用 Elasticsearch、OpenAI、LangChain 和 FastAPI 構建語義搜索服務。 你將創(chuàng)建一個應用程序,讓用戶可以提出有關馬可·奧勒留《沉思錄》的問題,并通過從書中提取最相關的內(nèi)容為他們提供簡潔的答案。
讓我們深入了解吧!
前提條件
你應該熟悉這些主題才能充分利用本教程:
-
Elasticsearch:語義搜索、知識圖和向量數(shù)據(jù)庫概述
-
Elasticsearch:關于在 Python 中使用 Elasticsearch 你需要知道的一切 - 8.x
此外,你必須安裝 Docker 并在 OpenAI 上創(chuàng)建一個帳戶。
設計語義搜索服務
你將構建一個包含三個組件的服務:
- 索引器:這將創(chuàng)建索引,生成嵌入和元數(shù)據(jù)(在本例中為書籍的來源和標題),并將它們添加到向量數(shù)據(jù)庫中。
- 矢量數(shù)據(jù)庫:這是一個用于存儲和檢索生成的嵌入的數(shù)據(jù)庫。
- 搜索應用程序:這是一個后端服務,它使用用戶的搜索詞,從中生成嵌入,然后在矢量數(shù)據(jù)庫中查找最相似的嵌入。
這是該架構的示意圖:
接下來,你將設置本地環(huán)境。
設置你的本地環(huán)境
請按照以下步驟設置您的本地環(huán)境:
1)安裝 Python 3.10。
2)安裝 Poetry。 它是可選的,但強烈推薦。
sudo pip install poetry
3)? 克隆項目的存儲庫:
git clone https://github.com/liu-xiao-guo/semantic-search-elasticsearch-openai-langchain
4)從項目的根文件夾中,安裝依賴項:
- 使用 Poetry:在項目同目錄下創(chuàng)建虛擬環(huán)境并安裝依賴:
poetry config virtualenvs.in-project true
poetry install
- 使用 venv 和 pip:創(chuàng)建虛擬環(huán)境并安裝 requirements.txt 中列出的依賴項:
python3.10 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
5)打開 src/.env-example,添加你的 OpenAI 密鑰,并將文件另存為 .env。
(.venv) $ pwd
/Users/liuxg/python/semantic-search-elasticsearch-openai-langchain/src
(.venv) $ ls -al
total 32
drwxr-xr-x 7 liuxg staff 224 Sep 17 17:27 .
drwxr-xr-x 13 liuxg staff 416 Sep 17 21:23 ..
-rw-r--r-- 1 liuxg staff 41 Sep 17 17:27 .env-example
-rw-r--r-- 1 liuxg staff 870 Sep 17 17:27 app.py
-rw-r--r-- 1 liuxg staff 384 Sep 17 17:27 config.py
drwxr-xr-x 3 liuxg staff 96 Sep 17 17:27 data
-rw-r--r-- 1 liuxg staff 840 Sep 17 17:27 indexer.py
(.venv) $ mv .env-example .env
(.venv) $ vi .env
到目前為止,你將設置一個包含所需庫和存儲庫的本地副本的虛擬環(huán)境。 你的項目結構應該如下所示:
.
├── LICENSE
├── README.md
├── docker-compose.yml
├── .env
├── poetry.lock
├── pyproject.toml
├── requirements.txt
└── src
├── app.py
├── config.py
├── .env
├── .env-example
├── data
│?? └── Marcus_Aurelius_Antoninus_-_His_Meditations_concerning_himselfe
└── indexer.py
請注意:在上面的文件結構中,有兩個 .env 文件。根目錄下的 .env 文件是為 docker-compose.yml 文件所使用,而 src 目錄里的文件是為應用所示使用。我們可以在根目錄里的 .env 文件中定義想要的 Elastic Stack 版本號。
這些是項目中最相關的文件和目錄:
- poetry.lock 和 pyproject.toml:這些文件包含項目的規(guī)范和依賴項,被 Poetry 用來創(chuàng)建虛擬環(huán)境。
- requirements.txt:該文件包含項目所需的 Python 包列表。
- docker-compose.yml:此文件包含用于在本地運行 Elasticsearch 集群及 Kibana。
- src/app.py:該文件包含搜索應用程序的代碼。
- src/config.py:此文件包含項目配置規(guī)范,例如 OpenAI 的 API 密鑰(從 .env 文件讀?。?、數(shù)據(jù)路徑和索引名稱。
- src/data/:該目錄包含最初從維基文庫下載的?Meditations?。 你將使用它作為本教程的文本語料庫。
- src/indexer.py:此文件包含用于創(chuàng)建索引并將文檔插入 Elasticsearch 的代碼。
- .env-example:此文件通常用于環(huán)境變量。 在本例中,你可以使用它將 OpenAI 的 API 密鑰傳遞給您的應用程序。
- .venv/:該目錄包含項目的虛擬環(huán)境。
全做完了! 我們繼續(xù)向下進行吧。
啟動本地 Elasticsearch 集群
在我們進入代碼之前,你應該啟動一個本地 Elasticsearch 集群。 打開一個新終端,導航到項目的根文件夾,然后運行:
docker-compose up
在上面的部署中,出于方便,我們使用了沒有帶安全的 Elastic Stack 的安裝以方便進行開發(fā)。具體的安裝步驟,請參閱另外一篇文章 “Elasticsearch:如何在 Docker 上運行 Elasticsearch 8.x 進行本地開發(fā)”。如果一切順利,我們可以使用如下的命令來進行查看:
docker ps
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a2866c0356a2 kibana:8.9.2 "/bin/tini -- /usr/l…" 4 minutes ago Up 4 minutes 0.0.0.0:5601->5601/tcp kibana
b504079c59ea elasticsearch:8.9.2 "/bin/tini -- /usr/l…" 4 minutes ago Up 4 minutes 0.0.0.0:9200->9200/tcp, 9300/tcp elasticsearch
我們可以在瀏覽器中針對 Elasticsearch 進行訪問:
我們還可以在 localhost:5601 上訪問 Kibana:
拆分書籍并為其建立索引
在此步驟中,你將執(zhí)行兩件事:
- 通過將書中的文本拆分為 1,000 個 token 的塊來處理該文本。
- 對你在 Elasticsearch 集群中生成的文本塊(從現(xiàn)在開始稱為文檔)建立索引。
看一下 src/indexer.py:
from langchain.document_loaders import BSHTMLLoader
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import ElasticVectorSearch
from config import Paths, openai_api_key
def main():
loader = BSHTMLLoader(str(Paths.book))
data = loader.load()
text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
chunk_size=1000, chunk_overlap=0
)
documents = text_splitter.split_documents(data)
embeddings = OpenAIEmbeddings(openai_api_key=openai_api_key)
db = ElasticVectorSearch.from_documents(
documents,
embeddings,
elasticsearch_url="http://localhost:9200",
index_name="elastic-index",
)
print(db.client.info())
if __name__ == "__main__":
main()
此代碼采用 Meditations(書),將其拆分為 1,000 個 token 的文本塊,然后在 Elasticsearch 集群中為這些塊建立索引。 以下是詳細的細分:
- 第 1 行到第 4 行從 langchain 導入所需的組件:
- BSHTMLLoader:此 Loader 使用 BeautifulSoup4 來解析文檔。
- OpenAIembeddings:該組件是 OpenAI 嵌入的包裝器。 它可以幫助你生成文檔和查詢的嵌入。
- RecursiveCharacterTextSplitter:此實用程序函數(shù)通過嘗試按旨在保持語義相似內(nèi)容鄰近的順序嘗試各種字符來分割輸入文本。 用于分割的字符按以下順序排列為:“\n\n”、“\n”、“ ”、“”。
- ElasticSearchVector:這是 Elasticsearch 客戶端的包裝器,可簡化與集群的交互。
- 第 6 行從 config.py 導入相關配置
- 第 11 行和第 12 行使用 BSHTMLLoader 提取書籍的文本。
- 第 13 至 16 行初始化文本拆分器,并將文本拆分為不超過 1,000 個標記的塊。 在這種情況下,你可以使用 tiktoken 來計算 token,但你也可以使用不同長度的函數(shù),例如計算字符數(shù)而不是 token 或不同的 token 化函數(shù)。
- 第 18 至 25 行初始化嵌入函數(shù),創(chuàng)建新索引,并對文本拆分器生成的文檔建立索引。 在 elasticsearch_url 中,你指定應用程序在本地運行的端口,在index_name 中指定你將使用的索引的名稱。 最后,打印 Elasticsearch 客戶端信息。
要運行此腳本,請打開終端,激活虛擬環(huán)境,然后從項目的 src 文件夾中運行以下命令:
# ../src/
export export OPENAI_API_KEY=your_open_ai_token
python indexer.py
注意:你如果使用 OpenAI 來進行矢量化,那么你需要在你的賬號中有充分的錢來支付這種費用,否則你可能得到如下的錯誤信息:
Retrying langchain.embeddings.openai.embed_with_retry.<locals>._embed_with_retry in 4.0 seconds as it raised RateLimitError: You exceeded your current quota, please check your plan and billing details..
如果一切順利,你應該得到與此類似的輸出:
{'name': '0e1113eb2915', 'cluster_name': 'docker-cluster', 'cluster_uuid': 'og6mFMqwQtaJiv_3E_q2YQ', 'version': {'number': '8.9.2', 'build_flavor': 'default', 'build_type': 'docker', 'build_hash': '09520b59b6bc1057340b55750186466ea715e30e', 'build_date': '2023-03-27T16:31:09.816451435Z', 'build_snapshot': False, 'lucene_version': '9.5.0', 'minimum_wire_compatibility_version': '7.17.0', 'minimum_index_compatibility_version': '7.0.0'}, 'tagline': 'You Know, for Search'}
接下來,讓我們創(chuàng)建一個簡單的 FastAPI 應用程序,以與你的集群進行交互。
創(chuàng)建搜索應用程序
在此步驟中,你將創(chuàng)建一個簡單的應用程序來與 Meditations 交互。 你將連接到 Elasticsearch 集群,始化檢索提問/應答 Chain,并創(chuàng)建一個 /ask 端點以允許用戶與應用程序交互。
看一下 src/app.py 的代碼:
from fastapi import FastAPI
from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import ElasticVectorSearch
from config import openai_api_key
embedding = OpenAIEmbeddings(openai_api_key=openai_api_key)
db = ElasticVectorSearch(
elasticsearch_url="http://localhost:9200",
index_name="elastic-index",
embedding=embedding,
)
qa = RetrievalQA.from_chain_type(
llm=ChatOpenAI(temperature=0),
chain_type="stuff",
retriever=db.as_retriever(),
)
app = FastAPI()
@app.get("/")
def index():
return {
"message": "Make a post request to /ask to ask questions about Meditations by Marcus Aurelius"
}
@app.post("/ask")
def ask(query: str):
response = qa.run(query)
return {
"response": response,
}
此代碼允許用戶提出有關馬庫斯·奧勒留《沉思錄》的問題,并向用戶提供答案。 讓我向你展示它是如何工作的:
- 第 1 至 5 行導入所需的庫:
- FastAPI:此類初始化應用程序。
- RetrievalQA:這是一個允許你詢問有關向量數(shù)據(jù)庫中文檔的問題的 Chain。 它根據(jù)你的問題找到最相關的文檔并從中生成答案。
- ChatOpenAI:這是 OpenAI 聊天模型的包裝。
- OpenAIembeddings 和 ElasticVectorSearch:這些是上一節(jié)中討論的相同包裝器。
- 第 7 行導入 OpenAI 密鑰。
- 第 9 至 15 行使用 OpenAI 嵌入初始化 Elasticsearch 集群。
- 第 16 至 20 行使用以下參數(shù)初始化 RetrievalQA Chain:
- llm:指定用于運行鏈中定義的提示的 LLM。
- chain_type:定義如何從向量數(shù)據(jù)庫檢索和處理文檔。 通過指定內(nèi)容,將檢索文檔并將其傳遞到鏈以按原樣回答問題。 或者,你可以在回答問題之前使用 map_reduce 或 map_rerank 進行額外處理,但這些方法使用更多的 API 調用。 有關更多信息,請參閱 langchain 文檔。
- retrieve:指定鏈用于檢索文檔的向量數(shù)據(jù)庫。
- 第 22 至 36 行初始化 FastAPI 應用程序并定義兩個端點。 / 端點為用戶提供有關如何使用應用程序的信息。 /ask 端點接受用戶的問題(查詢參數(shù))并使用先前初始化的鏈返回答案。
最后,你可以從終端運行該應用程序(使用你的虛擬環(huán)境):
uvicorn app:app --reload
然后,訪問 http://127.0.0.1:8000/docs,并通過詢問有關這本書的問題來測試 /ask:
如果一切順利,你應該得到這樣的結果:
就是這樣! 您現(xiàn)在已經(jīng)啟動并運行了自己的基于 Elasticsearch、OpenAI、Langchain 和 FastAPI 的語義搜索服務。
結論
干得好! 在本教程中,你學習了如何使用 Elasticsearch、OpenAI 和 Langchain 構建語義搜索引擎。
特別是,你已經(jīng)了解到:文章來源:http://www.zghlxwxcb.cn/news/detail-715242.html
- 如何構建語義搜索服務。
- 如何使用 LangChain 對文檔進行拆分和索引。
- 如何使用 Elasticsearch 作為向量數(shù)據(jù)庫與 LangChain 一起使用。
- 如何使用檢索問答鏈通過向量數(shù)據(jù)庫回答問題。
- 產(chǎn)品化此類應用程序時應考慮什么。
希望您覺得本教程有用。 如果你有任何疑問,請參入討論!文章來源地址http://www.zghlxwxcb.cn/news/detail-715242.html
到了這里,關于使用 Elasticsearch、OpenAI 和 LangChain 進行語義搜索的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!