https://blog.streamlit.io/build-a-real-time-llm-app-without-vector-databases-using-pathway/#step-1-data-collection-custom-data-ingestion
先备着,回头调试学习一下.
曾经尝试过向 ChatGPT 询问有关实时折扣、交易或优惠券的问题吗?
例如,“你能给我阿迪达斯男鞋的折扣吗?” 如果您这样做了,我确信您会对它给您的通用响应感到沮丧,“对不起,但我没有实时成长的能力或无法获得当前的促销。”
为什么?因为GPT缺乏具体信息。
现有解决方案的挑战
您可以尝试输入Amazon products deal中的单个 JSON 项目,但您将面临两个问题:
文本长度。文本长度受到限制——在处理数千个销售商品时这是一个大问题。
无法使用的数据。数据可能需要清理和格式化。
0:20
/ 0:20
1×
您还可以尝试使用 OpenAI聊天完成端点或构建自定义插件,但您将面临其他问题:
成本。提供更详细的信息和示例来提高模型的性能可能会增加成本。例如,对于 GPT-4,对于 10k 个代币的输入和 200 个代币的输出,每次预测的成本为 0.624 美元。除非您使用本地缓存系统,否则重复发送相同的请求可能会增加成本。
潜伏。使用 ChatGPT API 进行生产(如 OpenAI 的 API),延迟方面可能是不可预测的。无法保证提供一致的服务。
安全。集成自定义插件需要在OpenAPI 规范中指定每个 API 端点的功能。这意味着将您的内部 API 设置暴露给 ChatGPT,这可能是许多企业都怀疑的风险。
线下评价。当您对代码和数据输出进行离线测试或在本地复制数据流时,每个系统请求可能会产生不同的响应。
为了解决这些挑战(当然,还要以折扣价购买很酷的阿迪达斯鞋子!👟),我构建了一个自定义语言学习模型 (LLM) 折扣查找应用程序,而不使用矢量数据库、额外的框架和复杂的堆栈。
相同的解决方案可用于开发可用于生产的 AI 应用程序,这些应用程序使用数据源中可用的实时数据。
在这篇文章中,我将分 10 个步骤介绍如何使用Pathway和LLM App开发和公开 AI 支持的 HTTP REST API ,并使用 Streamlit 设计 UI 以通过 REST 使用 API 数据。
Pathway和LLM App的作用
Pathway是 Python 中的一个功能强大的数据处理框架,它使用其内置的结构化、非结构化和实时数据连接器来处理来自各种数据源的实时数据更新。对于折扣查找器应用程序,我使用 Pathway 将销售数据作为流摄取到应用程序,并确保应用程序检测到经常更改的数据输入中的每个更改。
LLM App是一个用于构建和服务 AI 应用程序的生产 Python 框架。LLM App 在底层使用 Pathway 库来实现实时数据索引和向量相似性搜索。结合使用这两个工具,应用程序不仅可以了解文档中的更改,还可以实时更新向量索引,并使用这些新知识来回答接下来的问题,而无需在文档中存储和检索向量索引。矢量数据库。
整体应用架构
让我们看一下该应用程序的整体架构。我受到这篇文章的启发,希望我的应用程序能够公开 HTTP REST API 端点,以便您可以通过使用 CSV、JSON Lines、API、消息代理或数据库获得最佳优惠。
该应用程序支持两种类型的数据源(如果需要,您可以添加自定义输入连接器):
JSON 行:数据源期望每一行包含一个doc对象。确保将输入数据转换为 Jsonlines 格式。您可以在discounts.jsonl找到示例数据文件。
Rainforest 产品 API :该 API 为您提供亚马逊产品的每日折扣数据。
转到应用程序并尝试输入“显示折扣”:
0:00
/ 0:23
1×
该应用程序将实时索引Rainforest API 和示例 文件文档,并在处理查询时使用数据。discounts.csv
如何构建实时折扣跟踪应用程序
步骤 1. 数据收集(自定义数据摄取)
要为 ChatGPT 添加自定义数据,您需要构建一个数据管道来实时提取、处理和公开数据。
为简单起见,请使用任何JSON Lines文件作为数据源。该应用程序接受discounts.jsonl等文件,并在处理用户查询时使用此数据。数据源中的每一行都应包含一个doc对象。确保将输入数据转换为 JSON Lines 格式。
以下是包含单个条目的 JSON Lines 文件的示例:
{“doc”: “{‘position’: 1, ‘link’: ‘https://www.amazon.com/deal/6123cc9f’, ‘asin’: ‘B00QVKOT0U’, ‘is_lightning_deal’: False, ‘deal_type’: ‘DEAL_OF_THE_DAY’, ‘is_prime_exclusive’: False, ‘starts_at’: ‘2023-08-15T00:00:01.665Z’, ‘ends_at’: ‘2023-08-17T14:55:01.665Z’, ‘type’: ‘multi_item’, ‘title’: ‘Deal on Crocs, DUNLOP REFINED(\u30c0\u30f3\u30ed\u30c3\u30d7\u30ea\u30d5\u30a1\u30a4\u30f3\u30c9)’, ‘image’: ‘https://m.media-amazon.com/images/I/41yFkNSlMcL.jpg’, ‘deal_price_lower’: {‘value’: 35.48, ‘currency’: ‘USD’, ‘symbol’: ‘KaTeX parse error: Expected 'EOF', got '}' at position 18: … 'raw': '35.48'}̲, 'deal_price_u…’, ‘raw’: ‘52.14’}, ‘deal_price’: 35.48, ‘list_price_lower’: {‘value’: 49.99, ‘currency’: ‘USD’, ‘symbol’: ‘KaTeX parse error: Expected 'EOF', got '}' at position 18: … 'raw': '49.99'}̲, 'list_price_u…’, ‘raw’: ‘59.99’}, ‘list_price’: {‘value’: 49.99, ‘currency’: ‘USD’, ‘symbol’: ‘KaTeX parse error: Expected 'EOF', got '}' at position 48: …': 'List Price'}̲, 'current_pric…’, ‘raw’: ‘35.48’}, ‘current_price_upper’: {‘value’: 52.14, ‘currency’: ‘USD’, ‘symbol’: ‘KaTeX parse error: Expected 'EOF', got '}' at position 18: … 'raw': '52.14'}̲, 'current_pric…’, ‘raw’: ‘35.48 - 52.14’, ‘name’: ‘Current Price’}, ‘merchant_name’: ‘Amazon Japan’, ‘free_shipping’: False, ‘is_prime’: False, ‘is_map’: False, ‘deal_id’: ‘6123cc9f’, ‘seller_id’: ‘A3GZEOQINOCL0Y’, ‘description’: ‘Deal on Crocs, DUNLOP REFINED(\u30c0\u30f3\u30ed\u30c3\u30d7\u30ea\u30d5\u30a1\u30a4\u30f3\u30c9)’, ‘rating’: 4.72, ‘ratings_total’: 6766, ‘page’: 1, ‘old_price’: 49.99, ‘currency’: ‘USD’}”}
该应用程序始终了解数据文件夹中的更改。如果您添加另一个 JSON Lines 文件,它将自动更新 AI 模型的响应。
步骤 2. 数据加载和映射
使用 Pathway 的JSON Lines 输入连接器,读取本地 JSON Lines 文件,将数据条目映射到schema中,并创建 Pathway表(请参阅app.py中的完整源代码):
…
sales_data = pw.io.jsonlines.read(
“./examples/data”,
schema=DataInputSchema,
mode=“streaming”
)
将每个数据行映射到结构化文档模式(请参阅app.py中的完整源代码 ):
class DataInputSchema(pw.Schema):
doc: str
步骤 3. 数据嵌入
每个文档都 嵌入了 OpenAI API 并检索嵌入结果(请参阅 embedder.py中的完整源代码):
…
embedded_data = embeddings(context=sales_data, data_to_embed=sales_data.doc)
步骤 4. 数据索引
在生成的嵌入上构建即时索引:
index = index_embeddings(embedded_data)
步骤 5. 用户查询处理和索引
创建 REST 端点,从 API 请求负载中获取用户查询,并将用户查询嵌入 OpenAI API。
…
query, response_writer = pw.io.http.rest_connector(
host=host,
port=port,
schema=QueryInputSchema,
autocommit_duration_ms=50,
)
embedded_query = embeddings(context=query, data_to_embed=pw.this.query)
步骤6.相似性搜索和提示工程
要执行相似性搜索,请利用索引来识别与查询嵌入最相关的匹配项。然后创建一个提示,将用户的查询与检索到的相关数据结果结合起来。然后,此提示会发送到 ChatGPT 完成端点,以生成全面且详细的响应。
responses = prompt(index, embedded_query, pw.this.query)
您在创建提示时使用了相同的上下文学习方法,并将内部知识合并到了prompt.py文件中的 ChatGPT 中。
prompt = f"Given the following discounts data: \\n {docs_str} \\nanswer this query: {query}"
步骤 7. 返回响应
最后一步是将 API 响应返回给用户。
Build prompt using indexed data
responses = prompt(index, embedded_query, pw.this.query)
第 8 步:将所有内容放在一起
结合所有步骤,获取支持 LLM 的 Python API,以获取自定义折扣数据。您可以参考app.py Python脚本中的实现来使用。
import pathway as pw
from common.embedder import embeddings, index_embeddings
from common.prompt import prompt
def run(host, port):
# Given a user question as a query from your API
query, response_writer = pw.io.http.rest_connector(
host=host,
port=port,
schema=QueryInputSchema,
autocommit_duration_ms=50,
)
# Real-time data coming from external data sources such as jsonlines file
sales_data = pw.io.jsonlines.read(
"./examples/data",
schema=DataInputSchema,
mode="streaming"
)
# Compute embeddings for each document using the OpenAI Embeddings API
embedded_data = embeddings(context=sales_data, data_to_embed=sales_data.doc)
# Construct an index on the generated embeddings in real-time
index = index_embeddings(embedded_data)
# Generate embeddings for the query from the OpenAI Embeddings API
embedded_query = embeddings(context=query, data_to_embed=pw.this.query)
# Build prompt using indexed data
responses = prompt(index, embedded_query, pw.this.query)
# Feed the prompt to ChatGPT and obtain the generated answer.
response_writer(responses)
# Run the pipeline
pw.run()
class DataInputSchema(pw.Schema):
doc: str
class QueryInputSchema(pw.Schema):
query: str
步骤 9. 使用 Streamlit 设计 UI
使用 Streamlit 使您的应用程序更具交互性(请参阅app.py文件中的实现)。您无需了解前端工具即可为后端服务构建 UI。Streamlit 的使用st.sidebar允许组织次要信息,使主要区域集中在主要交互上。您创建一个侧边栏来向用户解释如何使用该应用程序:
with st.sidebar:
st.markdown(
“## How to use\n”
“1. Choose data sources.\n”
“2. If CSV is chosen as a data source, upload a CSV file.\n”
“3. Ask a question about the discounts.\n”
)
用户会看到一个多选下拉列表来选择数据源,如果选择 CSV,他们可以通过小部件上传 CSV 文件st.file_uploader。Streamlit 的声明性本质在代码中很突出,界面根据变量的状态进行更新。例如,文件上传者的disabled状态链接到所选数据源。
uploaded_file = st.file_uploader(
“Upload a CSV file”,
type=(“csv”),
disabled=(DataSource.CSV.value not in data_sources)
)
上传 CSV 文件后,其内容将被处理并写入jsonlines文件格式,并显示进度条以告知用户正在进行的操作。进度条在处理上传的 CSV 时提供实时反馈。
if uploaded_file and DataSource.CSV.value in data_sources:
df = pd.read_csv(uploaded_file)
# Start progress bar
progress_bar = st.progress(0, "Processing your file. Please wait.")
根据所选的数据源和提供的问题,应用程序与 Discounts API 交互以获取相关答案。
question = st.text_input(
“Search for something”,
placeholder=“What discounts are looking for?”,
disabled=not data_sources
)
以下是当用户选择数据源并提出问题时处理 Discounts API 请求的代码。st.error来自 API 的错误消息和响应得到顺利处理,通过和方法向用户提供直接反馈st.write。
if data_sources and question:
if not os.path.exists(csv_path) and not os.path.exists(rainforest_path):
st.error(“Failed to process discounts file”)
url = f'http://{api_host}:{api_port}/'
data = {"query": question}
response = requests.post(url, json=data)
if response.status_code == 200:
st.write("### Answer")
st.write(response.json())
else:
st.error(f"Failed to send data to Discounts API. Status code: {response.status_code}")
步骤 10. 运行应用程序
按照README.md文件的如何运行项目部分中的说明来运行应用程序。请注意,您需要将 API 和 UI 作为单独的进程运行。Streamlit 将自动连接到 Discounts 后端 API,您将看到 UI 前端在浏览器中运行。
在本教程中,Pathway 的 LLM 应用程序和 Streamlit 通过 HTTP REST API 进行通信。您可以通过单个docker compose up命令使用 Docker 运行应用程序(请参阅README.md文件中的使用 Docker 运行部分)。无法将 LLM 应用程序作为单个进程嵌入到 Streamlit 中是因为 Streamlit 有自己的程序生命周期循环,每当发生更改时都会触发完整的应用程序重新运行。此行为可能会中断数据流,特别是因为 Pathway 在流模式下运行。考虑到上述情况,还有两种方法可以将 Pathway 的 LLM 应用程序与 Streamlit 集成:
将 Pathway 的 LLM 应用程序作为子进程运行,并通过进程间通信(例如套接字或 TCP/IP)与其进行通信。这可能涉及使用随机端口或信号来触发诸如可以拾取或腌制的状态转储之类的操作。例如,您可以利用 Python 的Subprocess模块来实现这一点。
Pathway 的 LLM App 和 Streamlit 共享相同的文件存储来进行通信。例如,您将带有用户查询的文档上传到本地磁盘上的文件夹。LLM App 可以侦听该文件夹中的每个更改并访问文件来处理它们、回答用户查询并将响应写回文件。
包起来
我仅触及了LLM 应用程序的皮毛,即通过将折扣等特定领域的知识纳入 ChatGPT 中。你也可以:
合并来自外部 API 的附加数据、JSON Lines、PDF、Doc、HTML 或文本等格式以及 PostgreSQL 或 MySQL 等数据库。
来自 Kafka、Redpanda 或 Debedizum 等平台的流数据。
增强 Streamlit UI 以接受任何交易 API,而不仅仅是 Rainforest API。
维护数据快照以观察销售价格随时间的变化。Pathway提供了一个内置功能来计算两个改变之间的差异。
将处理后的数据发送到其他下游连接器,例如 BI 和分析工具。例如,您可以将其配置为在检测到价格变化时接收警报。
如果您有任何疑问,请在下面的评论部分留言或通过LinkedIn和Twitter与我联系。加入Discord 频道,了解AI ChatBot 助手的工作原理。
快乐流媒体!🎈