使用混合搜索与产品PDF手册聊天

时间: 120 分钟级别: 高级输出: GitHubOpen In Colab

随着数字手册的普及和对快速准确客户支持需求的增加,拥有一个能够有效解析复杂PDF文档并提供精确信息的聊天机器人,对于任何企业来说都可能是一个改变游戏规则的因素。

在本教程中,我们将引导您完成构建基于RAG的聊天机器人的过程,该机器人专门设计用于帮助用户理解各种家用电器的操作。 我们将涵盖构建系统所需的基本步骤,包括数据摄取、自然语言理解以及客户支持用例的响应生成。

组件

Architecture diagram

步骤

检索增强生成(RAG)将搜索与语言生成相结合。使用外部信息检索系统来识别可能提供与用户查询相关的信息的文档。这些文档与用户的请求一起传递给文本生成语言模型,生成自然的响应。

这种方法使语言模型能够回答问题并从比它原本能看到的更大的文档集中访问信息。语言模型在生成响应时只查看文档的几个相关部分,这也有助于减少无法解释的错误。

服务托管的 Kubernetes,由欧洲领先的云服务提供商OVH Public Cloud Instances提供支持。内置OVHcloud负载均衡器和磁盘。OVHcloud Managed Kubernetes提供高可用性、合规性和CNCF一致性,让您能够专注于容器化的软件层,并具有完全的可逆性。

先决条件

在DigitalOcean上部署Qdrant混合云

数字海洋Kubernetes (DOKS) 是一项托管的 Kubernetes 服务,允许您部署 Kubernetes 集群,而无需处理控制平面和容器化基础设施的复杂性。集群与标准的 Kubernetes 工具链兼容,并原生集成 DigitalOcean 负载均衡器和卷。

  1. To start using managed Kubernetes on DigitalOcean, follow the 平台特定文档.
  2. Once your Kubernetes clusters are up, 您可以开始部署 Qdrant 混合云.
  3. Once it’s deployed, you should have a running Qdrant cluster with an API key.

开发环境

然后,安装所有依赖项:

!pip install -U  \
    llama-index  \
    llama-parse \
    python-dotenv \
    llama-index-embeddings-jinaai  \
    llama-index-llms-huggingface  \
    llama-index-vector-stores-qdrant  \
    "huggingface_hub[inference]"  \
    datasets

.env文件中设置密钥值:

JINAAI_API_KEY
HF_INFERENCE_API_KEY
LLAMA_CLOUD_API_KEY
QDRANT_HOST
QDRANT_API_KEY

加载所有环境变量:

import os
from dotenv import load_dotenv
load_dotenv('./.env')

实现

连接Jina嵌入和Mixtral LLM

LlamaIndex 提供了对 Jina 嵌入 API 的内置支持。要使用它,您需要使用您的 API 密钥和模型名称初始化 JinaEmbedding 对象。

对于LLM,你需要将其包装在llama_index.llms.CustomLLM的子类中,以使其与LlamaIndex兼容。

# connect embeddings
from llama_index.embeddings.jinaai import JinaEmbedding

jina_embedding_model = JinaEmbedding(
    model="jina-embeddings-v2-base-en",
    api_key=os.getenv("JINAAI_API_KEY"),
)

# connect LLM
from llama_index.llms.huggingface import HuggingFaceInferenceAPI

mixtral_llm = HuggingFaceInferenceAPI(
    model_name = "mistralai/Mixtral-8x7B-Instruct-v0.1",
    token=os.getenv("HF_INFERENCE_API_KEY"),
)

为RAG准备数据

这个例子将使用家用电器手册,这些手册通常以PDF文档形式提供。 LlamaPar 在data文件夹中,我们有三个文档,我们将使用它从PDF中提取文本内容,并将其用作简单RAG中的知识库。

免费的LlamaIndex云计划足以满足我们的示例需求:

import nest_asyncio
nest_asyncio.apply()
from llama_parse import LlamaParse

llamaparse_api_key = os.getenv("LLAMA_CLOUD_API_KEY")

llama_parse_documents = LlamaParse(api_key=llamaparse_api_key, result_type="markdown").load_data([
    "data/DJ68-00682F_0.0.pdf", 
    "data/F500E_WF80F5E_03445F_EN.pdf", 
    "data/O_ME4000R_ME19R7041FS_AA_EN.pdf"
])

将数据存储到Qdrant

下面的代码执行以下操作:

  • 使用Qdrant客户端创建一个向量存储;
  • 使用Jina Embeddings API获取每个块的嵌入;
  • 结合sparsedense向量进行混合搜索;
  • 将所有数据存储到Qdrant中;

必须从一开始就启用与Qdrant的混合搜索 - 我们可以简单地设置enable_hybrid=True

# By default llamaindex uses OpenAI models
# setting embed_model to Jina and llm model to Mixtral
from llama_index.core import Settings
Settings.embed_model = jina_embedding_model
Settings.llm = mixtral_llm

from llama_index.core import VectorStoreIndex, StorageContext
from llama_index.vector_stores.qdrant import QdrantVectorStore
import qdrant_client

client = qdrant_client.QdrantClient(
    url=os.getenv("QDRANT_HOST"),
    api_key=os.getenv("QDRANT_API_KEY")
)

vector_store = QdrantVectorStore(
    client=client, collection_name="demo", enable_hybrid=True, batch_size=20
)
Settings.chunk_size = 512

storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(
    documents=llama_parse_documents, 
    storage_context=storage_context
)

准备一个提示

在这里,我们将创建一个自定义的提示模板。这个提示要求LLM仅使用从Qdrant检索到的上下文信息。在使用混合模式查询时,我们可以分别设置similarity_top_ksparse_top_k

  • sparse_top_k 表示从每个密集和稀疏查询中检索多少个节点。
  • similarity_top_k 控制返回节点的最终数量。在上述设置中,我们最终得到10个节点。

然后,我们使用提示来组装查询引擎。

from llama_index.core import PromptTemplate

qa_prompt_tmpl = (
    "Context information is below.\n"
    "-------------------------------"
    "{context_str}\n"
    "-------------------------------"
    "Given the context information and not prior knowledge,"
    "answer the query. Please be concise, and complete.\n"
    "If the context does not contain an answer to the query,"
    "respond with \"I don't know!\"."
    "Query: {query_str}\n"
    "Answer: "
)
qa_prompt = PromptTemplate(qa_prompt_tmpl)

from llama_index.core.retrievers import VectorIndexRetriever
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core import get_response_synthesizer
from llama_index.core import Settings
Settings.embed_model = jina_embedding_model
Settings.llm = mixtral_llm

# retriever
retriever = VectorIndexRetriever(
    index=index,
    similarity_top_k=2,
    sparse_top_k=12,
    vector_store_query_mode="hybrid"
)

# response synthesizer
response_synthesizer = get_response_synthesizer(
    llm=mixtral_llm,
    text_qa_template=qa_prompt,
    response_mode="compact",
)

# query engine
query_engine = RetrieverQueryEngine(
    retriever=retriever,
    response_synthesizer=response_synthesizer,
)

运行测试查询

现在你可以根据数据提问并接收答案:

问题

result = query_engine.query("What temperature should I use for my laundry?")
print(result.response)

答案

The water temperature is set to 70 ˚C during the Eco Drum Clean cycle. You cannot change the water temperature. However, the temperature for other cycles is not specified in the context.

就是这样!你可以随意扩展到任意数量的文档和复杂的PDF。

这个页面有用吗?

感谢您的反馈!🙏

我们很抱歉听到这个消息。😔 你可以在GitHub上编辑这个页面,或者创建一个GitHub问题。