鉴于最近人工智能支持的API和网络开发工具的激增,似乎每个人都在将聊天机器人集成到他们的应用程序中。

LangChain是一种备受欢迎的新框架,近期引起了广泛关注。该框架旨在简化开发人员与语言模型外部数据计算资源进行交互的应用程序开发过程。它通过清晰且模块化的抽象,关注构建所需的所有构建模块,并构建了常用的”链条”,即构建模块的组合。例如,对话检索链条可以让用户与外部存储中的数据进行交互,实现真实的对话体验。

LangChain是如何实现这一目标的呢?OpenAI的语言模型并没有针对特定企业的具体数据进行训练或优化。如果您的聊天机器人依赖于该框架,您需要在运行时向OpenAI提供数据。在检索步骤中,我们使用向量相似性搜索(VSS)从Redis中获取与用户查询相关的数据,并将这些数据与原始问题一起输入到语言模型中。这要求模型仅使用提供的信息(在人工智能领域中称为”上下文”)来回答问题。

这个链条中的大部分复杂性都归结于检索步骤。因此,我们选择将LangChain与Redis Enterprise集成为一个向量数据库。这种组合为复杂的人工智能和产品开发之间搭建了桥梁。

在这个简短的教程中,我们将展示如何构建一个会话式的零售购物助手,帮助顾客在产品目录中发现那些被埋藏的令人感兴趣的商品。读者可以按照提供的完整代码进行操作。

 

一、构建你的聊天机器人

首先,安装项目所需的所有组件。

(一)安装 Python 依赖项

这个项目需要一些Python库。这些库存储在github仓库的requirements.txt文件中。(Github:https://github.com/RedisVentures/redis-langchain-chatbot)

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

(二)准备产品数据集

1、对于零售聊天机器人,我们选择使用Amazon Berkeley Objects数据集。该数据集包含了大量适用于生成零售助手的亚马逊产品。

2、使用Python的pandas库来加载和预处理数据集。在加载过程中,我们可以截断较长的文本字段。这样一来,我们的数据集会更加精简,从而节省内存和计算时间。

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

 

})

3、在完全加载了我们的产品数据集之后,进行一些最后的预处理步骤,以清理关键词字段并删除缺失值。

# 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)

4、如果你持续在跟进GitHub上的代码步骤,可以使用all_prods_df.head()来查看数据框的前几行。完整的数据集包含超过100,000个产品,但是对于这个聊天机器人,我们将其限制在2500个的子集中。

# 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]

5、下面是我们要处理的产品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作为向量数据库的设置

1、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://localhost:6379”

到这里,我们已经成功处理了Amazon产品数据集,并将其加载到了具有向量嵌入的Redis数据库中。

2、然后,我们将它们整合在一起,创建Redis向量存储。

# create and load redis with documents

vectorstore = RedisVectorStore.from_texts(

    texts=texts,

    metadatas=metadatas,

    embedding=embedding,

    index_name=index_name,

    redis_url=redis_url

)

三、创建 LangChain 对话链

现在我们准备好创建一个聊天机器人,使用存储在Redis中的产品数据来进行对话。聊天机器人因其极大的实用性而非常受欢迎。在我们下面构建的场景中,我们假设用户需要穿搭建议。

1、为了引入更多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

2、正如在介绍中提到的,这个项目使用了一个ConversationalRetrievalChain来简化聊天机器人的开发。

 

Redis作为我们的存储介质,保存了完整的产品目录,包括元数据和由OpenAI生成的捕捉产品内容语义属性的嵌入向量。通过使用底层的Redis Vector Similarity Search(VSS),我们的聊天机器人可以直接查询目录,以找到与用户购物需求最相似或相关的产品。这意味着您无需进行繁琐的关键字搜索或手动过滤,VSS会自动处理这些问题。

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

  1. 问题创建:在这个阶段,聊天机器人评估输入的问题,并利用OpenAI GPT模型将其与之前的对话交互知识(如果有)结合起来。通过这个过程,机器人可以更好地理解购物者的问题,并为后续的检索提供准确的上下文。
  2. 检索:在检索阶段,聊天机器人根据购物者表达的兴趣项,搜索Redis数据库,以获取最佳的可用产品。通过使用Redis Vector Similarity Search(VSS)等技术,机器人能够快速而准确地检索与购物者需求相匹配的产品。
  3. 问题回答:在这个阶段,聊天机器人从向量搜索的查询结果中获取产品信息,并利用OpenAI GPT模型帮助购物者浏览选项。机器人可以生成适当的回答,提供有关产品特征、价格、评价等方面的信息,以帮助购物者做出决策。

 

3、虽然LangChain和Redis极大地提升了工作流程的效率,但与大型语言模型(如GPT)进行交互时需要使用”提示(prompt)”来进行沟通。我们创造出一组指令作为提示,以引导模型的行为朝着期望的结果发展。为了获得聊天机器人的最佳效果,需要进一步完善提示的设置。

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)

4、接下来,我们定义两个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

)

5、最后,我们使用ConversationalRetrievalChain将所有三个步骤封装起来。

chatbot = ConversationalRetrievalChain(

    retriever=vectorstore.as_retriever(),

    combine_docs_chain=doc_chain,

    question_generator=question_generator

)

四、虚拟购物助手已就绪

1、请注意,这并不是一个全能的聊天AI。然而,通过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()

2、该机器人将实时与您交互,并根据目录中的商品帮助您缩小选择范围。以下是一个简单的示例:

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.

3、在聊天机器人用发出“你好!今天你在找什么?”此类的招呼后,尝试一些示例提示,或者自己创建一个。

五、定制您的链条以提高性能

1、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

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

redis_product_retriever = RedisProductRetriever(vectorstore=vectorstore)

 

chatbot = ConversationalRetrievalChain(

    retriever=redis_product_retriever,

    combine_docs_chain=doc_chain,

    question_generator=question_generator

)

3、大功告成!现在你的聊天机器人可以在对话中注入更多的产品信息。以下是另一个短对话的示例:

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!