使用 Elasticsearch 和 OpenAI 构建生成式 AI 应用程序

本笔记本演示了如何:

  • 将 OpenAI Wikipedia 向量数据集索引到 Elasticsearch 中
  • 使用 Streamlit 构建一个简单的 Gen AI 应用程序,该应用程序使用 Elasticsearch 检索上下文并使用 OpenAI 制定答案

安装

安装 Elasticsearch 及 Kibana

如果你还没有安装好自己的 Elasticsearch 及 Kibana,那么请参考一下的文章来进行安装:

  • 如何在 Linux,MacOS 及 Windows 上进行安装 Elasticsearch

  • Kibana:如何在 Linux,MacOS 及 Windows 上安装 Elastic 栈中的 Kibana

在安装的时候,请选择 Elastic Stack 8.x 进行安装。在安装的时候,我们可以看到如下的安装信息:

环境变量

在启动 Jupyter 之前,我们设置如下的环境变量:

export ES_USER="elastic"
export ES_PASSWORD="xnLj56lTrH98Lf_6n76y"
export ES_ENDPOINT="localhost"
export OPENAI_API_KEY="YourOpenAiKey"

请在上面修改相应的变量的值。这个需要在启动 jupyter 之前运行。

拷贝 Elasticsearch 证书

我们把 Elasticsearch 的证书拷贝到当前的目录下:

$ pwd
/Users/liuxg/python/elser
$ cp ~/elastic/elasticsearch-8.12.0/config/certs/http_ca.crt .
$ ls http_ca.crt 
http_ca.crt

安装 Python 依赖包

python3 -m pip install -qU openai pandas==1.5.3 wget elasticsearch streamlit tqdm load_dotenv

准备数据

我们可以使用如下的命令来下载数据:

wget https://cdn.openai.com/API/examples/data/vector_database_wikipedia_articles_embedded.zip
$ pwd
/Users/liuxg/python/elser
$ wget https://cdn.openai.com/API/examples/data/vector_database_wikipedia_articles_embedded.zip
--2024-02-09 12:06:36--  https://cdn.openai.com/API/examples/data/vector_database_wikipedia_articles_embedded.zip
Resolving cdn.openai.com (cdn.openai.com)... 13.107.213.69
Connecting to cdn.openai.com (cdn.openai.com)|13.107.213.69|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 698933052 (667M) [application/zip]
Saving to: ‘vector_database_wikipedia_articles_embedded.zip’vector_database_wikipedi 100%[==================================>] 666.55M  1.73MB/s    in 3m 2s   2024-02-09 12:09:40 (3.66 MB/s) - ‘vector_database_wikipedia_articles_embedded.zip’ saved [698933052/698933052]

创建应用并展示

我们在当前的目录下打入如下的命令来创建 notebook:

$ pwd
/Users/liuxg/python/elser
$ jupyter notebook

导入包及连接到 Elasticsearch

import os
from getpass import getpass
from elasticsearch import Elasticsearch, helpers
import wget, zipfile, pandas as pd, json, openai
import streamlit as st
from tqdm.notebook import tqdm
from dotenv import load_dotenvload_dotenv()openai_api_key=os.getenv('OPENAI_API_KEY')
elastic_user=os.getenv('ES_USER')
elastic_password=os.getenv('ES_PASSWORD')
elastic_endpoint=os.getenv("ES_ENDPOINT")url = f"https://{elastic_user}:{elastic_password}@{elastic_endpoint}:9200"
client = Elasticsearch(url, ca_certs = "./http_ca.crt", verify_certs = True)print(client.info())

配置 OpenAI 连接

我们的示例将使用 OpenAI 来制定答案,因此请在此处提供有效的 OpenAI Api 密钥。

你可以按照本指南检索你的 API 密钥。然后测试与OpenAI的连接,检查该笔记本使用的型号是否可用。

from openai import OpenAIopenai = OpenAI()
openai.models.retrieve("text-embedding-ada-002")
$ pip3 list | grep openai
langchain-openai                         0.0.5
openai                                   1.12.0

下载数据集

with zipfile.ZipFile("vector_database_wikipedia_articles_embedded.zip",
"r") as zip_ref:zip_ref.extractall("data")

运行上面的代码后,我们可以在如下地址找到解压缩的文件 vector_database_wikipedia_articles_embedded.csv:

$ pwd
/Users/liuxg/python/elser
$ ls ./data
__MACOSX                                        vector_database_wikipedia_articles_embedded.csv
paul_graham

将 CSV 文件读入 Pandas DataFrame

接下来,我们使用 Pandas 库将解压的 CSV 文件读入 DataFrame。 此步骤可以更轻松地将数据批量索引到 Elasticsearch 中。

wikipedia_dataframe = pd.read_csv("data/vector_database_wikipedia_articles_embedded.csv")

使用映射创建索引

现在我们需要使用必要的映射创建一个 Elasticsearch 索引。 这将使我们能够将数据索引到 Elasticsearch 中。

我们对 title_vector 和 content_vector 字段使用密集向量字段类型。 这是一种特殊的字段类型,允许我们在 Elasticsearch 中存储密集向量。

稍后,我们需要以密集向量字段为目标进行 kNN 搜索。

index_mapping= {"properties": {"title_vector": {"type": "dense_vector","dims": 1536,"index": "true","similarity": "cosine"},"content_vector": {"type": "dense_vector","dims": 1536,"index": "true","similarity": "cosine"},"text": {"type": "text"},"title": {"type": "text"},"url": { "type": "keyword"},"vector_id": {"type": "long"}}
}
client.indices.create(index="wikipedia_vector_index", mappings=index_mapping)

请注意 title_vector 及 content_vector 两个字段已经是以向量的形式来存储的。我们不需要额外的工作来对字段进行向量化。

将数据索引到 Elasticsearch

以下函数生成所需的批量操作,这些操作可以传递到 Elasticsearch 的 bulk API,因此我们可以在单个请求中有效地索引多个文档。

对于 DataFrame 中的每一行,该函数都会生成一个字典,表示要索引的单个文档。

def dataframe_to_bulk_actions(df):for index, row in df.iterrows():yield {"_index": 'wikipedia_vector_index',"_id": row['id'],"_source": {'url' : row["url"],'title' : row["title"],'text' : row["text"],'title_vector' : json.loads(row["title_vector"]),'content_vector' : json.loads(row["content_vector"]),'vector_id' : row["vector_id"]}}

由于数据帧很大,我们将以 100 个为一组对数据进行索引。我们使用 Python 客户端的 bulk API 帮助程序将数据索引到 Elasticsearch 中。

total_documents = len(wikipedia_dataframe)progress_bar = tqdm(total=total_documents, unit="documents")
success_count = 0for ok, info in helpers.streaming_bulk(client, actions=dataframe_to_bulk_actions(wikipedia_dataframe), raise_on_error=False, chunk_size=100):if ok:success_count += 1else:print(f"Unable to index {info['index']['_id']}: {info['index']['error']}")progress_bar.update(1)progress_bar.set_postfix(success=success_count)

等上面的代码运行完毕后,我们可以在 Kibana 中进行查看:

使用 Streamlit 构建应用程序

在下一节中, 你将使用 Streamlit 构建一个简单的界面。

该应用程序将显示一个简单的搜索栏,用户可以在其中提出问题。 Elasticsearch 用于检索与问题匹配的相关文档(上下文),然后 OpenAI 使用上下文制定答案。

安装依赖项以在运行后访问应用程序。

!npm install localtunnel
%%writefile app.pyimport os
import streamlit as st
import openai
from elasticsearch import Elasticsearch
from dotenv import load_dotenvfrom openai import OpenAIopenai = OpenAI()load_dotenv()openai_api_key=os.getenv('OPENAI_API_KEY')
elastic_user=os.getenv('ES_USER')
elastic_password=os.getenv('ES_PASSWORD')
elastic_endpoint=os.getenv("ES_ENDPOINT")url = f"https://{elastic_user}:{elastic_password}@{elastic_endpoint}:9200"
client = Elasticsearch(url, ca_certs = "./http_ca.crt", verify_certs = True)# Define model
EMBEDDING_MODEL = "text-embedding-ada-002"def openai_summarize(query, response):context = response['hits']['hits'][0]['_source']['text']summary = openai.chat.completions.create(model="gpt-3.5-turbo",messages=[{"role": "system", "content": "You are a helpful assistant."},{"role": "user", "content": "Answer the following question:" + query + "by using the following text: " + context},])print(summary)return summary.choices[0].message.contentdef search_es(query):# Create embeddingquestion_embedding = openai.embeddings.create(input=query, model=EMBEDDING_MODEL)# Define Elasticsearch queryresponse = client.search(index = "wikipedia_vector_index",knn={"field": "content_vector","query_vector":  question_embedding.data[0].embedding,"k": 10,"num_candidates": 100})return responsedef main():st.title("Gen AI Application")# Input for user search queryuser_query = st.text_input("Enter your question:")if st.button("Search"):if user_query:st.write(f"Searching for: {user_query}")result = search_es(user_query)# print(result)openai_summary = openai_summarize(user_query, result)st.write(f"OpenAI Summary: {openai_summary}")# Display search resultsif result['hits']['total']['value'] > 0:st.write("Search Results:")for hit in result['hits']['hits']:st.write(hit['_source']['title'])st.write(hit['_source']['text'])else:st.write("No results found.")if __name__ == "__main__":main()

运行应用

运行应用程序并检查您的隧道 IP:

!streamlit run app.py

如果你想把网站供全网其它的电脑访问,你可以使用如下的命令:

npx localtunnel --port 8501

整个 notebook 的源码可以在地址下载:https://github.com/liu-xiao-guo/semantic_search_es/blob/main/openai_rag_streamlit.ipynb

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/469398.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软考27-上午题-查找

一、基本概念 1-1、查找表: 同一类型的数据元素构成的集合。 对查找表常用的操作: 从查找表中查询某个特定的元素;检索某个特定的元素的各种属性。 通常只进行这两种操作的查找表:静态查找表 1-1-2、静态查找表: 顺…

面试前的准备

面试前的准备 Java程序员校招与社招的区别 校招和社招都是企业招聘形式的一种,只是面向的对象不同。校招 只允许在校生参加,社招理论上是任何人都能参加的(包括在校生)。 但是,无论是社招还是校招,它的难度都取决于你的水平高低。…

关于Windows Media Player的一些知识,看这篇文章就差不多了

你知道如何在电脑上打开Windows Media Player吗?如果它不是你电脑上默认的媒体播放器,你知道如何将其设为默认吗?此外,如果你找不到它,你知道怎么把它找回来吗?这篇文章将向你展示你想要了解的所有信息。 在这篇文章中,我们将向你展示以下信息: 如何打开Windows Medi…

python从入门到精通(十):python常见标准库的使用

python数据分析和可视化基础 (一)Python 中处理日期和时间的模块time导入time模块time获取当前时间戳localtime获取当前时间struct_timeasctime获取格式化的时间ctime获取格式化的时间gmtime获取格式化的时间计时器功能strftime格式化日期strptime格式化…

Spring 用法学习总结(一)之基于 XML 注入属性

百度网盘: 👉 Spring学习书籍链接 Spring学习 1 Spring框架概述2 Spring容器3 基于XML方式创建对象4 基于XML方式注入属性4.1 通过set方法注入属性4.2 通过构造器注入属性4.3 使用p命名空间注入属性4.4 注入bean与自动装配4.5 注入集合4.6 注入外部属性…

【前端web入门第六天】02 flex布局

文章目录 Flex布局1.Flex组成2.主轴与侧轴对齐方式2.1 主轴对齐方式(横轴)2.2 侧轴对齐方式 (纵轴)2.3 修改主轴方向 3.弹性伸缩比4.弹性换行与行对齐方式4.1 弹性换行4.2 行对齐方式 Flex布局 1.Flex组成 设置方式:给父元素设置display: flex,子元素可以自动挤压…

Zabbix图形中文乱码问题(显示口口)解决办法

一 切换到zabbix安装目录assets/fonts下,下载字体 这里使用是nginxphp作为zabbix-web展示,使用find 命令查找 进入目录下,将原有字体备份,下载msyh字体 wget https://www.xxshell.com/download/sh/zabbix/ttf/msyh.ttf 二 修改配…

Android adb使用超级大全

Android adb使用超级大全 ADB,即Android Debug Bridge,是一款强大的工具,对于Android开发/测试人员来说是不可或缺的,同时也是Android设备玩家的好玩具。本文将详细介绍ADB的使用方法。 ADB的基本用法如下: 命令语法…

Web基础01-HTML+CSS

目录 一、HTML 1.概述 2.html结构解析 3.HTML标签分类 4.HTML标签关系 5.HTML空元素 6.HTML属性 7.常用标签 (1)HTML标签 (2)标题标签 (3)换/折行标签 (4)段落标签 &am…

【数据分享】2020~2050年青藏高原未来LAI变化情景数据集

各位同学们好,今天和大伙儿分享的是2020~2050年青藏高原未来LAI变化情景数据集。如果大家有下载处理数据等方面的问题,可以添加我的微信交流~ 贾坤, 赵琳琳, 夏沐. (2023). 青藏高原未来LAI变化情景数据集(2020-2050). 国家青藏高…

Hive的相关概念——分区表、分桶表

目录 一、Hive分区表 1.1 分区表的概念 1.2 分区表的创建 1.3 分区表数据加载及查询 1.3.1 静态分区 1.3.2 动态分区 1.4 分区表的本质及使用 1.5 分区表的注意事项 1.6 多重分区表 二、Hive分桶表 2.1 分桶表的概念 2.2 分桶表的创建 2.3 分桶表的数据加载 2.4 …

【python之美】减少人工成本之创建文件并写入数据_1

创建txt文件,干巴巴的特产 path "C:\\Users\\Administrator\\Desktop\\text\\" numb int(input("需要创建几个文件:")) a 1 for i in range(numb):f open(path text _ str(a) .txt, w)f.write(这是第 str(a) 文件)a 1print(创建 s…