全新大模型框架Haystack,搭建RAG pipeline
大家好,在AI应用开发的赛道上,目前Haystack以其开源框架的优势,成为LLM技术领域的一匹黑马,对现有竞争者构成挑战。本文将介绍Haystack的亮点优势,并分析它为何能在众多LLM框架中脱颖而出,通过RAG应用实例来展示Haystack的实际应用能力。
1.Haystack简介
Haystack是一个强大的工具包,帮助开发者用少量代码创建AI应用,尤其擅长处理大量文本或文档;能够简化开发实用LLM应用的过程。简单来说,Haystack就像一套多功能的积木,可以灵活组合,可以搭建出各式各样的AI系统。
使用Haystack,能够实现多种应用场景,例如:
-
基于大量文档回答问题的聊天机器人
-
能够从众多文档中查找和提取特定信息的系统
-
能够理解和处理文本、图像和其他类型数据的应用
在Python 3.10环境下,可以通过以下命令安装Haystack:
pip install haystack-ai
2.Haystack工作原理
Haystack的运作依赖于两个核心概念:
-
组件:可以视为独立的工具,每个工具都承担着特定的任务。比如,某个组件可能专门用来检索相关文档,而另一个则负责生成文本回答。
-
管道:决定了组件之间的连接方式。通过管道,我们定义了组件的工作顺序以及它们之间信息的传递路径。
利用这些组件的不同组合,开发者能够构建出处理复杂任务的AI系统。
3.Haystack核心优势
-
灵活性:可以与许多不同的AI模型(如OpenAI、HuggingFace等)和数据存储系统(如ChromaDB、Pinecone,甚至是Neo4j)无缝协作。
-
易用性:即使不精通AI的复杂技术细节,开发者也能轻松上手Haystack。
-
可定制性:开发者可以根据特定需求,创建或调整组件。Haystack采用Pydantic结构,定制过程更加简便。
-
应用多样性:支持构建不同类型的AI系统,从问答到信息提取。
4.构建RAG管道
安装好Haystack之后,接下来只需安装trafilatura和lxml,这两个工具用于提取HTML文档:
pip install trafilatura lxml_html_clean
这里将构建两个管道:一个负责文档的清洗与处理,另一个则用于实现RAG功能。
导入相关包:
import urllib.request
from haystack import Pipeline
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack.components.retrievers import InMemoryEmbeddingRetriever
from haystack.components.converters import HTMLToDocument
from haystack.components.preprocessors import DocumentCleaner, DocumentSplitter
from haystack.components.embedders import OpenAIDocumentEmbedder, OpenAITextEmbedder
from haystack.components.writers import DocumentWriter
from haystack.components.builders import PromptBuilder
from haystack.components.generators import OpenAIGenerator
from dotenv import load_dotenv
load_dotenv()
将OpenAI密钥放在.env文件中:
OPENAI_API_KEY = 'YOUR KEY'
提取我们的文本,将其存储在文件夹中。
urllib.request.urlretrieve("https://www.oreilly.com/openbook/freedom/ch01.html", "free_as_in_freedom.html")
我们从连接两个管道的组件着手,这个组件负责将处理后的文档存储在内存中:
document_store = InMemoryDocumentStore()
接下来是管道的第一个组件和输入部分。利用之前创建的HTML文件:
text_file_converter = HTMLToDocument()
这个转换器可以接受路径、字符串或字节流作为输入,并返回一个文档列表。这些文档需要经过清洗,以提高可读性。这便是管道的下一步:
cleaner = DocumentCleaner()
cleaner
组件的任务是提升文本文档的可读性,可以通过它删除空行、多余空格或重复的子字符串等。
随后,根据RAG模型的要求,需要将文档切割成块。这对于处理超出语言模型最大文本长度限制的长文本非常有用,同时也能加快问答的处理速度。在我们的案例中,将文档按句子分割,每块包含5个句子:
splitter = DocumentSplitter(split_by="sentence", split_length=5)
文档切割完成后,准备将其嵌入。这里使用OpenAI提供的OpenAIDocumentEmbedder
,它负责计算文档列表的嵌入向量,并将这些向量存储在每个文档的嵌入字段中:
embedder = OpenAIDocumentEmbedder()
最后通过riter
组件,它是第一个管道的输出部分,负责将文档列表写入最初定义的文档存储中,以便在下一个管道中使用:
writer = DocumentWriter(document_store)
如果想添加其他类型的文档,如Excel或PDF,需创建一个新的管道或调整现有管道,并将其存储在InMemoryDocumentStore
组件中。在管道中逐个添加组件:
indexing_pipeline = Pipeline()
indexing_pipeline.add_component("converter", text_file_converter)
indexing_pipeline.add_component("cleaner", cleaner)
indexing_pipeline.add_component("splitter", splitter)
indexing_pipeline.add_component("embedder", embedder)
indexing_pipeline.add_component("writer", writer)
将这些组件连接起来:
indexing_pipeline.connect("converter.documents", "cleaner.documents")
indexing_pipeline.connect("cleaner.documents", "splitter.documents")
indexing_pipeline.connect("splitter.documents", "embedder.documents")
indexing_pipeline.connect("embedder.documents", "writer.documents")
运行管道:
indexing_pipeline.run(data={"sources": ["free_as_in_freedom.html"]})
输出结果:
Calculating embeddings: 100%|██████████| 2/2 [00:01<00:00, 1.10it/s]
{'embedder': {'meta': {'model': 'text-embedding-ada-002', 'usage': {'prompt_tokens': 5191, 'total_tokens': 5191}}}, 'writer': {'documents_written': 39}}
整个过程非常直接,在启动文档处理流程之前,需要指定HTML文件作为待处理的输入数据。
通过执行以下代码,可以查看第一个管道的结构:
indexing_pipeline.show()
现在已经集齐了构建RAG部分所需的所有组件,它们将助力系统最终能够响应我们的各种查询。
5.RAG管道
首先,要确定用于文本嵌入的模型。Haystack支持多种嵌入选项,包括OpenAI和HuggingFace,同时也在不断集成更多。为了简化操作,选择使用OpenAI的嵌入器:
text_embedder = OpenAITextEmbedder()
接下来,利用之前处理好并存储在document_store中的文档。可以根据业务需求,选择不同的检索策略,如topk、scalescore或filter等:
retriever = InMemoryEmbeddingRetriever(document_store)
这个组件负责输出经过处理、准备好进行嵌入的文档列表。现在完成RAG管道的最后两个部分,构建提示和选择语言模型(LLM)。
定义一个基本的提示模板:
template = """Given these documents, answer the question.
Documents:
{% for doc in documents %}
{{ doc.content }}
{% endfor %}
Question: {{query}}
Answer:"""
prompt_builder = PromptBuilder(template=template)
对于LLM,同样选择使用OpenAI模型:
llm = OpenAIGenerator()
将这些组件串联起来,正如之前所做的:
rag_pipeline = Pipeline()
rag_pipeline.add_component("text_embedder", text_embedder)
rag_pipeline.add_component("retriever", retriever)
rag_pipeline.add_component("prompt_builder", prompt_builder)
rag_pipeline.add_component("llm", llm)
连接各个组件:
rag_pipeline.connect("text_embedder.embedding", "retriever.query_embedding")
rag_pipeline.connect("retriever.documents", "prompt_builder.documents")
rag_pipeline.connect("prompt_builder", "llm")
输出的组件和连接概览如下:
Components
- text_embedder: OpenAITextEmbedder
- retriever: InMemoryEmbeddingRetriever
- prompt_builder: PromptBuilder
- llm: OpenAIGenerator
Connections
- text_embedder.embedding -> retriever.query_embedding (List[float])
- retriever.documents -> prompt_builder.documents (List[Document])
- prompt_builder.prompt -> llm.prompt (str)
最后,查看管道的完整结构:
rag_pipeline.show()
RAG管道构建完成,它将能够根据提供的文档回答各种问题。
6.评估RAG管道
以Richard M. Stallman为例,他是麻省理工学院人工智能实验室的一位软件程序员,曾经历过一次设备故障的苦难。
query = " What is the profession of Richard M. Stallman and where does he works ?"
result = rag_pipeline.run(data={"prompt_builder": {"query":query}, "text_embedder": {"text": query}})
print(result["llm"]["replies"][0])
得到的答案是:
Richard M. Stallman is a software programmer and he works at the Massachusetts Institute of Technology's Artificial Intelligence Laboratory.
另一次,当他到达实验室时,发现打印机托盘里只有四页纸,而这四页还属于其他用户。更糟糕的是,这意味着Stallman的打印任务和另一位用户的打印任务的一部分,仍然卡在实验室计算机网络的电子管道中。
query = "Why did Stallman get frustrated when he tried to retrieve his print job from the new Xerox printer ?"
输出结果:
Stallman got frustrated when he tried to retrieve his print job from the new Xerox printer because only four pages in the printer's tray belonged to another user, meaning that Stallman's print job and the unfinished portion of somebody else's print job were still trapped somewhere within the electrical plumbing of the lab's computer network.
两次查询都完美回答,此外还可以查看请求中使用的令牌数量,以跟踪使用情况:
result['llm']['meta'][0]['usage']
#{'completion_tokens': 65, 'prompt_tokens': 1476, 'total_tokens': 1541}
综上所述,Haystack是开发者手中的得力助手,专门用来打造处理海量文本或文档的LLM人工智能应用。它配备了丰富的组件,这些组件能够像乐高积木一样,通过不同的组合方式,拼装出各种AI解决方案。尽管掌握Haystack需要一些编程技能,但它的核心目标是让AI应用的开发变得更加亲民,让广泛的开发者都能轻松驾驭。