使用LangChain构建RAG应用

LangChain

LangChain 和直接调用 Bedrock 接口有一些区别:

LangChain:

  • 提供了一个高级抽象层,封装了与多种 AI 模型和服务的交互。
  • 支持多种 AI 服务提供商(如 OpenAI、Anthropic、Google 等),允许轻松切换或组合不同的模型。
  • 提供了额外的功能,如提示模板、内存、链式操作等,便于构建复杂的 AI 应用。
  • 通常需要较少的代码来实现相同的功能,API 设计更加用户友好。
  • 提供了更多的定制选项和工具,便于实现复杂的工作流。
  • 可能需要一些时间来学习其概念和 API,但长期来看可以提高开发效率。

直接调用 Bedrock

  • 需要直接处理底层 API 调用和响应格式。
  • 可能需要更多的样板代码来处理请求和响应。
  • 提供原始的控制,但可能需要更多的手动配置。

总的来说,LangChain 提供了更高级的抽象和更多的功能,适合快速开发和复杂的 AI 应用场景。而直接调用 Bedrock 接口则提供了更直接的控制。选择哪种方法取决于具体需求、项目复杂度。

LangChain示例:

from langchain_aws import BedrockLLM as Bedrock
from langchain_core.prompts import ChatPromptTemplate
import boto3

AWS_REGION = "us-west-2"

bedrock = boto3.client(service_name="bedrock-runtime", region_name=AWS_REGION)

#  使用 LangChain 的 Bedrock 接口初始化了一个模型,指定使用 "amazon.titan-text-express-v1" 模型,并传入之前创建的 Bedrock 客户端。
model = Bedrock(model_id="amazon.titan-text-express-v1", client=bedrock)


def invoke_model():
    response = model.invoke("What is the highest mountain in the world?")
    print(response)

invoke_model()

image-20241202065147467

加入chain:

  • 创建一个 ChatPromptTemplate,包含一个系统消息和一个人类消息。
  • 使用 pipe 方法将模板和模型连接起来,形成一个链。
  • 调用链,传入 “bicycle” 作为产品名称。
from langchain_aws import BedrockLLM as Bedrock
from langchain_core.prompts import ChatPromptTemplate
import boto3

AWS_REGION = "us-west-2"

bedrock = boto3.client(service_name="bedrock-runtime", region_name=AWS_REGION)

model = Bedrock(model_id="amazon.titan-text-express-v1", client=bedrock)


def invoke_model():
    response = model.invoke("What is the highest mountain in the world?")
    print(response)

"""
这个函数展示了如何使用 LangChain 创建一个简单的链:
   - 创建一个 ChatPromptTemplate,包含一个系统消息和一个人类消息。
   - 使用 `pipe` 方法将模板和模型连接起来,形成一个链。
   - 调用链,传入 "bicycle" 作为产品名称。
   - 打印响应。
"""
def first_chain():
    template = ChatPromptTemplate.from_messages(
        [
            (
                "system",
                "Write a short description for the product provided by the user",
            ),
            ("human", "{product_name}"),
        ]
    )
    chain = template.pipe(model)

    response = chain.invoke({"product_name": "bicycle"})
    print(response)


first_chain()

image-20241202065534390

使用FAISS创建一个RAG应用

FAISS (Facebook AI Similarity Search) Vector Store 是一个高效的相似性搜索和聚类库,专门用于处理高维向量。它由 Facebook Research 开发,主要用于大规模、高维度向量的快速检索。在自然语言处理、计算机视觉和机器学习等领域广泛应用。

LangChain 提供了与 FAISS 的集成,使得在 AI 应用中使用向量存储变得更加简单。

使用FAISS, 我们来构建以下应用

  1. 将示例数据转换为向量并存储在 FAISS 中。
  2. 使用问题在向量存储中检索相关信息。
  3. 将检索到的信息作为上下文,结合原始问题,生成一个prompt。
  4. 使用 Bedrock 模型处理这个提示,生成最终答案。

这种方法结合了向量检索和语言模型,可以在大量文本数据中找到相关信息,并基于这些信息生成答案,是构建问答系统或聊天机器人的常用方法。

from langchain_aws import BedrockLLM as Bedrock
from langchain_aws import BedrockEmbeddings
from langchain_core.prompts import ChatPromptTemplate
from langchain_community.vectorstores import FAISS
import boto3

my_data = [
    "The weather is nice today.",
    "Last night's game ended in a tie.",
    "Don likes to eat pizza.",
    "Don likes to eat pasta.",
]

question = "What does Don like to eat?"

AWS_REGION = "us-west-2"

bedrock = boto3.client(service_name="bedrock-runtime", region_name=AWS_REGION)
# 初始化 Bedrock 文本生成模型和嵌入模型:
model = Bedrock(model_id="amazon.titan-text-express-v1", client=bedrock)
bedrock_embeddings = BedrockEmbeddings(
    model_id="amazon.titan-embed-text-v1", client=bedrock
)

# 创建 FAISS 向量存储,将文本数据转换为向量并存储在 FAISS 中。
vector_store = FAISS.from_texts(my_data, bedrock_embeddings)
vector_store.save_local('vector_store.txt','index-1')

# create retriever
retriever = vector_store.as_retriever(
    search_kwargs={"k": 2}
)
#  使用问题在向量存储中检索相关信息。
results = retriever.invoke(question)
print(results)

# 将检索结果转换为字符串列表
results_string = []
for result in results:
    results_string.append(result.page_content)

print(results_string)

# build template:
template = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "Answer the users question based on the following context: {context}",
        ),
        ("user", "{input}"),
    ]
)

chain = template.pipe(model)

response = chain.invoke({"input": question, "context": results_string})
print(response)

image-20241202084342390

上面的代码同样将vector store保存到了本地

image-20241202084902613

FAISS 默认情况下是作为内存型向量存储使用的。当数据集较小时,整个索引可以完全加载到内存中,提供最快的搜索速度。 FAISS 也支持将索引保存到磁盘,并从磁盘加载。 对于超大规模数据,FAISS 支持分布式索引和搜索。FAISS 还支持 GPU 加速,可以将索引和搜索操作offload到 GPU 上。