dot 未来速度将在您所在的城市举行一场活动。

加入我们在 Redis 发布会

使用 Redis、LangChain 和 OpenAI 构建电子商务聊天机器人

鉴于最近人工智能赋能 API 和 Web 开发工具的激增,似乎每个人都在将其应用程序构建到他们的应用程序中。想看看其中涉及什么?以下是一个概述。

一个新的(并且非常流行)框架,LangChain,使开发与语言模型和外部数据或计算源交互的应用程序变得容易。它通过关注构建所有必要构建块的清晰和模块化抽象来做到这一点;然后它构建常用的“链”,它们是构建块的组合。例如,对话检索链 使用户能够与外部存储中的数据进行“对话”。

它是怎么做到的?OpenAI 语言模型没有在您公司的特定数据上进行过训练,当然也没有针对它进行过微调。如果您希望聊天机器人依赖它,您需要在运行时向 OpenAI 提供您的数据。检索步骤使用向量相似性搜索 (VSS) 从 Redis 中获取与用户查询相关的 数据,然后将数据与原始问题一起传入语言模型。它要求模型使用提供的来源(我们在 AI 圈中称为“上下文”)来回答问题。

此链中的大部分复杂性都归结为检索步骤。这就是为什么我们对在 LangChain 和 Redis Enterprise 作为向量数据库 之间添加集成感到如此兴奋。这种组合使在不费吹灰之力的情况下弥合复杂的人工智能和产品开发之间的差距成为可能。

不相信我们?在这个简短的教程中,我们构建了一个对话式零售购物助理,帮助客户找到埋藏在产品目录中的感兴趣商品。 您可以关注完整代码

构建您的聊天机器人

在我们深入之前,我们要感谢 LabLab AI 的法比安·斯泰尔,他组装了这个演示的初始原型。我们对其进行了扩展,并添加了额外的 LangChain 组件以使其功能更强大。

首先,让我们收集项目所需的所有部分。

安装 Python 需求

该项目需要几个 Python 库。这些库存储在 requirements.txt 文件中,位于 github 存储库 中。

pip install langchain==0.0.123
pip install openai==0.27.2
pip install redis==4.5.3
pip install numpy
pip install pandas
pip install gdown

获取和准备产品数据集

对于零售聊天机器人,我们选择使用 Amazon Berkeley Objects 数据集。这包括大量亚马逊产品,非常适合生成零售助理。从链接下载文件,或使用 gdown 命令行界面从 托管链接 下载文件。

gdown --id 1tHWB6u3yQCuAgOYc-DxtZ8Mru3uV5_lj

我们使用 pandas Python 库来加载和预处理数据集。在加载时,我们截断较长的文本字段。这样做是为了使数据集更精简,从而节省内存和计算时间。

import pandas as pd

MAX_TEXT_LENGTH=1000  # Maximum num of text characters to use

def auto_truncate(val):

    """Truncate the given text."""

    return val[:MAX_TEXT_LENGTH]

# Load Product data and truncate long text fields

all_prods_df = pd.read_csv("product_data.csv", converters={

    'bullet_point': auto_truncate,

    'item_keywords': auto_truncate,

    'item_name': auto_truncate

})

我们的产品数据集完全加载后,我们执行一些最终的预处理步骤来清理关键字字段并删除缺失值。

# Replace empty strings with None and drop

all_prods_df['item_keywords'].replace('', None, inplace=True)

all_prods_df.dropna(subset=['item_keywords'], inplace=True)

# Reset pandas dataframe index

all_prods_df.reset_index(drop=True, inplace=True)

如果您在 github 上关注代码,请查看带有 all_prods_df.head() 的数据帧。完整数据集包含超过 100,000 个产品,但对于这个聊天机器人,我们将它限制为 2,500 个子集。

# Num products to use (subset)
NUMBER_PRODUCTS = 2500  

# Get the first 2500 products
product_metadata = ( 
    all_prods_df
     .head(NUMBER_PRODUCTS)
     .to_dict(orient='index')
)

# Check one of the products
product_metadata[0]

以下是我们需要处理的其中一个产品 JSON 对象的示例。

{'item_id': 'B07T2JY31Y',
 'marketplace': 'Amazon',
 'country': 'IN',
 'main_image_id': '71vX7qIEAIL',
 'domain_name': 'amazon.in',
 'bullet_point': '3D Printed Hard Back Case Mobile Cover for Sony Xperia Z1 L39H Easy to put & take off with perfect cutouts for volume buttons, audio & charging ports. Stylish design and appearance, express your unique personality. Extreme precision design allows easy access to all buttons and ports while featuring raised bezel to life screen and camera off flat surface. Slim Hard Back Cover No Warranty',
 'item_keywords': 'mobile cover back cover mobile case phone case mobile panel phone panel LG mobile case LG phone cover LG back case hard case 3D printed mobile cover mobile cover back cover mobile case phone case mobile panel phone panel Sony Xperia mobile case Sony Xperia phone cover Sony Xperia back case hard case 3D printed mobile cover mobile cover back cover mobile case phone case mobile panel phone panel Sony Xperia mobile case Sony Xperia phone cover Sony Xperia back case hard case 3D printed mobile cover mobile cove',
 'material': 'Wood',
 'brand': 'Amazon Brand - Solimo',
 'color': 'others',
 'item_name': 'Amazon Brand - Solimo Designer Leaf on Wood 3D Printed Hard Back Case Mobile Cover for Sony Xperia Z1 L39H',
 'model_name': 'Sony Xperia Z1 L39H',
 'model_number': 'gz8056-SL40528',
 'product_type': 'CELLULAR_PHONE_CASE'}

将 Redis 设置为向量数据库

LangChain 围绕 Redis 有一个简单的 包装器,可以帮助您加载文本数据并创建 嵌入 来捕捉“含义”。在这段代码中,我们准备产品文本和元数据,准备文本嵌入提供者 (OpenAI),为搜索索引指定一个名称,并提供一个 Redis URL 用于连接。

import os

from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores.redis import Redis as RedisVectorStore

# set your openAI api key as an environment variable
os.environ['OPENAI_API_KEY'] = "YOUR OPENAI API KEY"

# data that will be embedded and converted to vectors
texts = [
    v['item_name'] for k, v in product_metadata.items()
]

# product metadata that we'll store along our vectors
metadatas = list(product_metadata.values())

# we will use OpenAI as our embeddings provider
embedding = OpenAIEmbeddings()

# name of the Redis search index to create
index_name = "products"

# assumes you have a redis stack server running on local host
redis_url = "redis://#:6379"

此时,我们已成功处理亚马逊产品数据集并将其加载到带有向量嵌入的 Redis 数据库中。

然后我们将所有内容整合在一起以创建 Redis vectorstore

# create and load redis with documents
vectorstore = RedisVectorStore.from_texts(
    texts=texts,
    metadatas=metadatas,
    embedding=embedding,
    index_name=index_name,
    redis_url=redis_url
)

现在,我们已准备好创建一个聊天机器人,该聊天机器人使用产品数据(存储在 Redis 中)来提供对话信息。

创建 LangChain 对话链

聊天机器人非常受欢迎,因为它们可以非常有用。在我们下面构建的场景中,我们假设您需要时尚建议。您可以向机器人寻求帮助,寻找一双适合休闲外出和工作出行的鞋子。您想要一些引人注目的东西,但不会造成太多干扰。根据我们已经输入的数据,我们的聊天机器人应该能够推荐几双符合要求的鞋子。

现在该引入更多 LangChain 功能了。为此,我们需要导入几个 LangChain 工具。

from langchain.callbacks.base import CallbackManager
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
from langchain.chains import (
    ConversationalRetrievalChain,
    LLMChain
)
from langchain.chains.question_answering import load_qa_chain
from langchain.llms import OpenAI
from langchain.prompts.prompt import PromptTemplate

如引言中所述,该项目使用 ConversationalRetrievalChain 来简化聊天机器人开发。

Redis 存储着我们的产品目录,包括元数据和 OpenAI 生成的嵌入,这些嵌入捕捉了产品内容的语义属性。在幕后,使用 Redis 向量相似性搜索 (VSS),聊天机器人查询目录,查找与购物者正在寻找的商品最相似或最相关的商品。无需进行花哨的关键字搜索或手动过滤;VSS 会为您处理所有这些。

构成聊天机器人的 ConversationalRetrievalChain 分为三个阶段

  1. **问题创建**评估输入问题,并使用 OpenAI GPT 模型将其与来自先前对话交互(如果有)的知识相结合。
  2. **检索**根据购物者表达的兴趣商品,在 Redis 中搜索最佳可用产品。
  3. **问题解答**获取来自向量搜索查询的产品结果,并使用 OpenAI GPT 模型帮助购物者浏览选项。

尽管 LangChain 和 Redis 极大地加快了此工作流程,但与大型语言模型 (LLM)(如 GPT)进行交互需要一个“提示”来进行通信。我们人类创建一个提示(一组指令)来引导模型的行为,使其朝着预期的结果发展。为了从聊天机器人中获得最佳结果,可能需要进一步的 提示工程

请查看我们为上述步骤 1 和步骤 3 定义的两个提示。您可以始终从这些提示开始,并根据自己的场景进行改进。

template = """Given the following chat history and a follow up question, rephrase the follow up input question to be a standalone question.
Or end the conversation if it seems like it's done.
Chat History:\"""
{chat_history}
\"""
Follow Up Input: \"""
{question}
\"""
Standalone question:"""

condense_question_prompt = PromptTemplate.from_template(template)

template = """You are a friendly, conversational retail shopping assistant. Use the following context including product names, descriptions, and keywords to show the shopper whats available, help find what they want, and answer any questions.

It's ok if you don't know the answer.
Context:\"""

{context}
\"""
Question:\"
\"""

Helpful Answer:"""

qa_prompt= PromptTemplate.from_template(template)

接下来,我们定义两个 OpenAI LLM,并将它们分别包装在用于问题生成和问题解答的链中。streaming_llm 允许我们将聊天机器人响应逐个标记地传送到 stdout,从而带来迷人且类似聊天机器人的用户体验。

# define two LLM models from OpenAI
llm = OpenAI(temperature=0)

streaming_llm = OpenAI(
    streaming=True,
    callback_manager=CallbackManager([
        StreamingStdOutCallbackHandler()
    ]),
    verbose=True,
    max_tokens=150,
    temperature=0.2
)

# use the LLM Chain to create a question creation chain
question_generator = LLMChain(
    llm=llm,
    prompt=condense_question_prompt
)

# use the streaming LLM to create a question answering chain
doc_chain = load_qa_chain(
    llm=streaming_llm,
    chain_type="stuff",
    prompt=qa_prompt
)

最后,我们使用包装所有三个步骤的 ConversationalRetrievalChain 将所有内容整合在一起。

chatbot = ConversationalRetrievalChain(
    retriever=vectorstore.as_retriever(),
    combine_docs_chain=doc_chain,
    question_generator=question_generator
)

体验您友好的虚拟购物助理

请记住,这不是一个无所不能的存在。但借助 Redis(它存储了示例的整个产品库存知识库),我们创造了一种相当不错的体验。

# create a chat history buffer
chat_history = []
# gather user input for the first question to kick off the bot
question = input("Hi! What are you looking for today?")

# keep the bot running in a loop to simulate a conversation
while True:
    result = chatbot(
        {"question": question, "chat_history": chat_history}
    )
    print("\n")
    chat_history.append((result["question"], result["answer"]))
    question = input()

机器人实时与您互动,并根据目录中的内容帮助您缩小范围,找到感兴趣的产品选择。以下是一个简单的示例

Hi! What are you looking for today?

>> gold-plated earrings

Hi there! I'm happy to help you find the perfect earrings. Do you have a preference for yellow gold plated sterling silver or platinum or gold-plated sterling silver?

>> My preference is the yellow gold plated sterling silver

Hi there! Are you looking for yellow gold-plated sterling silver earrings with Swarovski Zirconia or Topaz gemstones? We have a few options that might fit the bill. We have yellow gold-plated sterling silver Swarovski Zirconia fancy green stud earrings, yellow gold-plated sterling silver honey topaz stud earrings made with Swarovski Topaz gemstones, and yellow gold-plated sterling silver antique drop earrings set.

在聊天机器人用“你好!今天你想找什么?”向您问好后,请尝试以下几个示例提示,或者自己创建。

  • 花哨的银色或金色的耳环
  • 舒适的步行鞋
  • 耐用的 iPhone 手机壳

自定义您的链以获得更好的性能

LangChain 最棒的一点在于,每个类抽象都是为了让您能够扩展或创建自己的类。下面,我们自定义 BaseRetriever 类,在返回结果之前执行一些文档预处理。

import json
from langchain.schema import BaseRetriever
from langchain.vectorstores import VectorStore
from langchain.schema import Document
from pydantic import BaseModel

class RedisProductRetriever(BaseRetriever, BaseModel):
    vectorstore: VectorStore

    class Config:
        arbitrary_types_allowed = True

    def combine_metadata(self, doc) -> str:
        metadata = doc.metadata
        return (
           "Item Name: " + metadata["item_name"] + ". " +
           "Item Description: " + metadata["bullet_point"] + ". " +
           "Item Keywords: " + metadata["item_keywords"] + "."
        )

    def get_relevant_documents(self, query):
        docs = []
        for doc in self.vectorstore.similarity_search(query):
            content = self.combine_metadata(doc)
            docs.append(Document(
                page_content=content,
                metadata=doc.metadata
            ))

        return docs

我们需要更新检索类和聊天机器人,以使用上述自定义实现。

redis_product_retriever = RedisProductRetriever(vectorstore=vectorstore)

chatbot = ConversationalRetrievalChain(
    retriever=redis_product_retriever,
    combine_docs_chain=doc_chain,
    question_generator=question_generator
)

完成!现在,您的聊天机器人可以将更多产品信息融入您的对话中,从而引导您走向电子商务的辉煌!以下是一个简短的对话示例

Hi! What are you looking for today?

>>> fancy footwear for going out

Hi there! We have a few great options for women's shoes and sandals. We have the Amazon Brand - The Fix Women's Giana Open Toe Bootie with Pearl Buckle, bright white leather, 9.5 B US, Flavia Women's Beige Fashion Sandals-7 UK (39 EU) (8 US) (FL/236/BEG), Flavia Women's Blue Fashion Sandals-8 UK (40 EU) (9 US) (FL/211/BLU), and The Fix Women's Faris Flat Slide Sandal with Pearls. All of these shoes feature a variety of styles and colors to choose from. Let me know if you have any questions about any of these items!

>>> These are nice. However, I am looking for men's shoes. Can you help me?

Hi there! We have a great selection of men's formal shoes available. We have Amazon Brand - Symbol Men's Formal Shoes, Amazon Brand - Symbol Men's Leather Formal Shoes, and more. All of our formal shoes are made from high quality materials and feature a variety of closure types, toe styles, and heel types. They also come with a manufacturer's warranty and care instructions to ensure they last. Let me know if you have any questions or need help finding the perfect pair of shoes for you!

>>>Can you show me some more men's options?

Hi there! I'm here to help you find the perfect item for you. We have a few options available for men's formal shoes. We have the Men's Stainless Steel Link Bracelet, the Amazon Brand - Arthur Harvey Men's Leather Formal Shoes, and the Amazon Brand - Symbol Men's Formal Derby shoes. All of these items feature a variety of features such as leather material, lace-up closure, pointed toe, block heel, and more. If you have any questions about any of these items, please let me know. I'm happy to help!

>>> Ok this looks great, thanks!

后续步骤

使用 LangChain 和 Redis 构建非常容易。尝试自己构建 此聊天机器人,或根据您的用例进行自定义。 免费试用 Redis Enterprise 或拉取我们的 Redis Stack docker 容器 来开始使用。

有兴趣亲身体验人工智能吗?我们的合作伙伴 LabLab AI 将在未来一个月内举办 一系列以 Redis 为特色的黑客马拉松。争夺奖品、炒作和名声。事实上,有一个使用 Stable Diffusion 的黑客马拉松 将于 4 月 14 日开始!

Stable diffusion AI hackathon promo image

喜欢泰勒和哈里森关于生成式人工智能的见解吗?在 5 月 24 日的免费虚拟活动 RedisDays 虚拟活动 中,他们将分享更多实用的示例。

详细了解 Redis 中的 向量相似性搜索。您可能会对自己的成就感到惊讶。