譯者 | 李睿
審校 | 重樓
AI target=_blank class=infotextkey>OpenAI公司推出的GPT如今已經(jīng)成為全球最重要的人工智能工具,并精通基于其訓(xùn)練數(shù)據(jù)處理查詢。但是,它不能回答未知話題的問題,例如:
- 2021年9月之后的近期事件
- 非公開文件
- 來自過去談話的信息
當(dāng)用戶處理頻繁變化的實時數(shù)據(jù)時,這項任務(wù)變得更加復(fù)雜。此外,用戶不能向GPT提供大量內(nèi)容,它也不能長時間保留他們的數(shù)據(jù)。在這種情況下,需要有效地構(gòu)建一個自定義的大型語言模型(LLM)應(yīng)用程序來為回答過程提供場景。
本文將引導(dǎo)人們完成使用Python/ target=_blank class=infotextkey>Python中的開源LLM App庫開發(fā)此類應(yīng)用程序的步驟。源代碼在Github上(鏈接在下面的“為銷售構(gòu)建ChatGPT Python API”一節(jié)中)。
學(xué)習(xí)目標
通過本文了解以下內(nèi)容:
- 需要添加自定義數(shù)據(jù)到ChatGPT的原因。
- 如何使用嵌入、提示工程和ChatGPT來更好地回答問題。
- 用戶使用LLM應(yīng)用程序與自定義數(shù)據(jù)構(gòu)建自己的ChatGPT。
- 創(chuàng)建一個ChatGPT Python API查找實時折扣或銷售價格。
為什么為ChatGPT提供自定義知識庫?
在討論增強ChatGPT功能的方法之前,首先探索人工方法并確定它們面臨的挑戰(zhàn)。通常情況下,ChatGPT通過提示工程進行擴展。假設(shè)用戶想在各種在線市場上找到實時折扣/交易/優(yōu)惠券。
例如,當(dāng)詢問ChatGPT,“你能幫我找到阿迪達斯男鞋在本周的折扣嗎?”,在沒有自定義知識的情況下,可能從ChatGPT UI界面得到的標準回答是:
顯然,ChatGPT提供了關(guān)于尋找折扣的通常建議,但缺乏關(guān)于在哪里或什么類型的折扣以及其他細節(jié)的具體信息。現(xiàn)在為了幫助這個模型,使用來自可靠數(shù)據(jù)源的折扣信息對其進行補充。在發(fā)布實際問題之前,必須通過添加初始文檔內(nèi)容來參與ChatGPT。將從Amazon產(chǎn)品交易數(shù)據(jù)集中收集這一示例數(shù)據(jù),并在提示中僅插入一個JSON項:
如上圖所示,用戶得到了預(yù)期的輸出,這很容易實現(xiàn),因為ChatGPT現(xiàn)在是場景感知的。然而,這種方法的問題是模型的場景受到限制(GPT-4的最大文本長度為8,192個令牌)。當(dāng)輸入數(shù)據(jù)規(guī)模非常大時,這種策略很快就會出現(xiàn)問題,用戶可能希望在銷售中發(fā)現(xiàn)數(shù)千種商品,而無法將如此大量的數(shù)據(jù)作為輸入消息提供。此外,一旦收集了數(shù)據(jù),可能需要對數(shù)據(jù)進行清理、格式化和預(yù)處理,以確保數(shù)據(jù)質(zhì)量和相關(guān)性。
如果用戶使用OpenAI聊天完成度端點或為ChatGPT構(gòu)建自定義插件,它會引入以下其他問題:
- 成本—通過提供更詳細的信息和示例,大型語言模型的性能可能會得到改善,盡管成本更高(對于輸入10000個令牌和輸出200個令牌的GPT-4,每次預(yù)測的成本為0.624美元)。重復(fù)發(fā)送相同的請求會增加成本,除非使用本地緩存系統(tǒng)。
- 延遲—在生產(chǎn)中使用ChatGPT API的一個挑戰(zhàn)是它們的不可預(yù)測性,不能保證提供一致的服務(wù)。
- 安全性—當(dāng)集成自定義插件時,每個API端點必須在OpenAPI規(guī)范中指定功能。這意味著用戶正在向ChatGPT泄露其內(nèi)部API設(shè)置,這是令許多企業(yè)擔(dān)心的風(fēng)險。
- 離線評估—對代碼和數(shù)據(jù)輸出進行離線測試或在本地復(fù)制數(shù)據(jù)流對開發(fā)人員來說是具有挑戰(zhàn)性的。這是因為對系統(tǒng)的每個請求可能產(chǎn)生不同的響應(yīng)。
使用嵌入、提示工程和ChatGPT進行問答
人們在互聯(lián)網(wǎng)上發(fā)現(xiàn)的一種很有前途的方法是利用大型語言模型(LLM)創(chuàng)建嵌入,然后使用這些嵌入構(gòu)建應(yīng)用程序,例如用于搜索和詢問系統(tǒng)。換句話說,不是使用聊天完成端點查詢ChatGPT,而是執(zhí)行以下查詢:
給定以下折扣數(shù)據(jù):{input_data},回答這個查詢:{user_query}。
這個概念很簡單。這種方法不是直接發(fā)布問題,而是首先通過OpenAI API為每個輸入文檔(文本、圖像、CSV、PDF或其他類型的數(shù)據(jù))創(chuàng)建向量嵌入,然后對生成的嵌入進行索引以便快速檢索,并將其存儲到向量數(shù)據(jù)庫中,并利用用戶的問題從向量數(shù)據(jù)庫中搜索并獲得相關(guān)文檔。然后將這些文檔與問題一起作為提示呈現(xiàn)給ChatGPT。有了這個添加的場景,ChatGPT就可以像在內(nèi)部數(shù)據(jù)集上訓(xùn)練一樣進行響應(yīng)。
另一方面,如果使用Pathway的LLM App,甚至不需要任何矢量數(shù)據(jù)庫。它實現(xiàn)了實時內(nèi)存數(shù)據(jù)索引,直接從任何兼容的存儲中讀取數(shù)據(jù),而無需查詢矢量文檔數(shù)據(jù)庫,而這會增加準備工作、基礎(chǔ)設(shè)施和復(fù)雜性等成本。保持源和矢量同步是很痛苦的。此外,如果帶下劃線的輸入數(shù)據(jù)隨時間變化而需要重新索引,則會更加困難。
ChatGPT自定義數(shù)據(jù)使用LLM App
下面這些簡單的步驟解釋了使用LLM App為數(shù)據(jù)構(gòu)建ChatGPT應(yīng)用程序的數(shù)據(jù)管道方法。
- 收集:用戶的應(yīng)用程序從各種數(shù)據(jù)源(CSV、 JSON Lines、SQL數(shù)據(jù)庫、Kafka、Redpanda、Debezium等)實時讀取數(shù)據(jù),當(dāng)流模式與路徑啟用時或者也可以在靜態(tài)模式下測試數(shù)據(jù)攝取。它還將每個數(shù)據(jù)行映射到結(jié)構(gòu)化文檔模式中,以便更好地管理大型數(shù)據(jù)集。
- 預(yù)處理:可以選擇通過刪除可能影響回答質(zhì)量的重復(fù)、不相關(guān)信息和嘈雜數(shù)據(jù),并提取需要進一步處理的數(shù)據(jù)字段,從而輕松地進行數(shù)據(jù)清理。此外,在這個階段,可以屏蔽或隱藏隱私數(shù)據(jù),以避免將它們發(fā)送到ChatGPT。
- 嵌入:每個文檔都嵌入了OpenAI API,并檢索嵌入的結(jié)果。
- 索引:在實時生成的嵌入上構(gòu)建索引。
- 搜索:給定來自API友好界面的用戶問題,從OpenAI API生成查詢的嵌入。使用嵌入,根據(jù)與查詢的相關(guān)性動態(tài)檢索向量索引。
- 提問:將問題和最相關(guān)的部分插入到GPT的信息中。返回GPT的答案(聊天完成端點)。
為銷售構(gòu)建ChatGPT Python API
在對LLM App的工作過程有了清晰的了解之后,可以按照下面的步驟來了解如何構(gòu)建折扣查找器應(yīng)用程序。其項目源代碼可以在GitHub上找到。如果想快速開始使用這個應(yīng)用程序,可以跳過這一部分直接克隆存儲庫,并按照README.md文件中的說明運行代碼示例。
項目目標示例
受到一篇關(guān)于企業(yè)搜索的文章的啟發(fā),這一示例應(yīng)用程序應(yīng)該在Python中公開一個HTTP REST API端點,通過從各種來源(CSV、Jsonlines、API、消息代理或數(shù)據(jù)庫)檢索最新交易來回答用戶對當(dāng)前銷售的查詢,并利用OpenAI API嵌入和聊天完成端點生成式人工智能助理響應(yīng)。
步驟1:數(shù)據(jù)收集(自定義數(shù)據(jù)攝取)
為了簡單起見,可以使用任何JSON行作為數(shù)據(jù)源。這個應(yīng)用程序采用discounts.jsonl等JSON Lines文件,并在處理用戶查詢時使用這些數(shù)據(jù)。數(shù)據(jù)源希望每行都有一個文檔對象。確保首先將輸入數(shù)據(jù)轉(zhuǎn)換為Jsonline。下面是一個帶有單個raw的Jsonline文件的示例:
{"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(u30c0u30f3u30edu30c3u30d7u30eau30d5u30a1u30a4u30f3u30c9)', 'image': 'https://m.media-amazon.com/images/I/41yFkNSlMcL.jpg', 'deal_price_lower': {'value': 35.48, 'currency': 'USD', 'symbol': '$', 'raw': '35.48'}, 'deal_price_upper': {'value': 52.14, 'currency': 'USD', 'symbol': '$', 'raw': '52.14'}, 'deal_price': 35.48, 'list_price_lower': {'value': 49.99, 'currency': 'USD', 'symbol': '$', 'raw': '49.99'}, 'list_price_upper': {'value': 59.99, 'currency': 'USD', 'symbol': '$', 'raw': '59.99'}, 'list_price': {'value': 49.99, 'currency': 'USD', 'symbol': '$', 'raw': '49.99 - 59.99', 'name': 'List Price'}, 'current_price_lower': {'value': 35.48, 'currency': 'USD', 'symbol': '$', 'raw': '35.48'}, 'current_price_upper': {'value': 52.14, 'currency': 'USD', 'symbol': '$', 'raw': '52.14'}, 'current_price': {'value': 35.48, 'currency': 'USD', 'symbol': '$', '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(u30c0u30f3u30edu30c3u30d7u30eau30d5u30a1u30a4u30f3u30c9)', 'rating': 4.72, 'ratings_total': 6766, 'page': 1, 'old_price': 49.99, 'currency': 'USD'}"}
最酷的是,這個應(yīng)用程序總是能意識到數(shù)據(jù)文件夾中的更改。如果添加另一個JSON Lines文件,LLM App就會發(fā)揮神奇的作用,自動更新人工智能模型的響應(yīng)。
步驟2:數(shù)據(jù)加載和映射
使用Pathway的JSON Lines輸入連接器,將讀取本地JSONlines文件,將數(shù)據(jù)條目映射到模式中,并創(chuàng)建一個路徑表。可以參閱app.py中的完整源代碼:
...
sales_data = pw.io.jsonlines.read(
"./examples/data",
schema=DataInputSchema,
mode="streaming"
)
將每個數(shù)據(jù)行映射到結(jié)構(gòu)化文檔模式。可以參閱App.py中的完整源代碼:
class DataInputSchema(pw.Schema):
doc: str
步驟3:數(shù)據(jù)嵌入
每個文檔都嵌入了OpenAI API,并檢索嵌入的結(jié)果。可以參閱app.py中的完整源代碼:
...
embedded_data = embeddings(cnotallow=sales_data, data_to_embed=sales_data.doc)
步驟4:數(shù)據(jù)索引
然后在生成的嵌入上構(gòu)建一個即時索引:
index = index_embeddings(embedded_data)
步驟5:用戶查詢處理和索引
創(chuàng)建一個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(cnotallow=query, data_to_embed=pw.this.query)
步驟6:相似性搜索和提示工程
通過使用索引來識別查詢嵌入的最相關(guān)匹配來執(zhí)行相似性搜索。然后構(gòu)建一個提示,將用戶的查詢與獲取的相關(guān)數(shù)據(jù)結(jié)果合并,并將消息發(fā)送到ChatGPT完成端點,以生成正確且詳細的響應(yīng)。
responses = prompt(index, embedded_query, pw.this.query)
當(dāng)制作提示符并在prompt.py中向ChatGPT添加內(nèi)部知識時,遵循了相同的場景學(xué)習(xí)方法。
prompt = f"Given the following discounts data: \n {docs_str} \nanswer this query: {query}"
步驟7:返回響應(yīng)
最后一步就是將API響應(yīng)返回給用戶。
# Build prompt using indexed data
responses = prompt(index, embedded_query, pw.this.query)
步驟8:將把所有步驟放在一起
現(xiàn)在,如果將上述所有步驟放在一起,就擁有了用于自定義折扣數(shù)據(jù)的支持LLM的Python API,可以在app.py Python腳本中看到實現(xiàn)。
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(cnotallow=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(cnotallow=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 (可選):添加交互式UI
為了讓應(yīng)用程序更具互動性和用戶友好性,可以使用Streamlit來構(gòu)建一個前端應(yīng)用。
運行應(yīng)用程序
按照README. Md文件中“如何運行項目”一節(jié)中的說明,可以開始詢問有關(guān)折扣的問題,API將根據(jù)添加的折扣數(shù)據(jù)源做出響應(yīng)。
在使用UI(應(yīng)用數(shù)據(jù)源)將這些知識提供給GPT之后,看看它是如何回復(fù)的:
這個應(yīng)用程序考慮了Rainforest API和discount .csv文件文檔(立即合并來自這些來源的數(shù)據(jù)),實時對其進行索引,并在處理查詢時使用這些數(shù)據(jù)。
進一步的改進
通過向ChatGPT添加折扣等領(lǐng)域特定知識,發(fā)現(xiàn)了LLM應(yīng)用程序的一些功能。還可以做更多的事情:
- 整合來自外部API的額外數(shù)據(jù),以及各種文件(例如Jsonlines、PDF、Doc、html或Text格式),PostgreSQL或MySQL等數(shù)據(jù)庫,以及來自Kafka、Redpanda或Debedizum等平臺的流數(shù)據(jù)。
- 維護數(shù)據(jù)快照以觀察銷售價格隨時間的變化,因為Pathway提供了一個內(nèi)置功能來計算兩次更改之間的差異。
- 除了通過API訪問數(shù)據(jù)之外,LLM App還允許用戶將處理過的數(shù)據(jù)中繼到其他下游連接器,例如商業(yè)智能(BI)和分析工具。例如,設(shè)置它在檢測到價格變化時接收警報。
原文標題:How To Use ChatGPT API in Python for Your Real-Time Data,作者:Bobur Umurzokov