構(gòu)建具有AI驅(qū)動的文檔檢索系統(tǒng):使用Docling和Granite 3.1的實戰(zhàn)教程
来自Granite的食谱,
在这个食谱中,你将学会使用高级工具来构建基于人工智能的文档检索系统。它将引导你完成以下步骤:
- 文档处理: 学习如何解析文档并将其转换成可用格式,并使用Docling将其存储在向量数据库中。
- 检索增强生成(RAG): 了解如何将大型语言模型(LLM)如Granite 3.1与外部知识库连接起来,以增强查询响应并生成有价值的见解。
- LangChain的工作流集成: 学会使用LangChain来简化和协调文档处理和检索工作流程,使系统中的不同组件能够无缝对接和交互。
这个食谱采用了三种最新的技术:
- Docling:一个开源工具包,用于解析和转换文档,名为Docling。
- Granite™ 3.1:一个通过Replicate, 提供的最先进的LLM,可通过API访问,提供强大的自然语言能力。
- LangChain:一个用于构建由语言模型驱动的应用程序的强大框架,旨在简化复杂的业务流程并无缝集成外部工具。
完成这个食谱后,你就能:
- 精通文档处理和切分文档。
- 集成向量数据库来提高检索效果。
- 利用检索增强生成技术(RAG)高效准确地为实际应用检索数据。
这份指南是为希望增强文档管理和高级自然语言处理知识的AI开发者、研究人员以及爱好者设计的。
前提条件- 熟悉Python编程。
- 对大型语言模型和自然语言处理的基本概念有初步了解。
请确保你在新创建的虚拟环境中运行 Python 3.10 或 3.11 版本。
import sys
assert sys.version_info >= (3, 10) and sys.version_info < (3, 12), "请确保使用Python 3.10或3.11来运行这个代码。"
第二步:安装依赖
! pip install "git+https://github.com/ibm-granite-community/utils.git" \
transformers \
langchain_community \
langchain_huggingface \
langchain_milvus \
docling \
replicate
# 安装相关库
第三步:挑选系统组件
选择一个你喜欢的词嵌入模型吧
指定用于从文本生成嵌入的模型。这里我们将使用其中一个新Granite Embeddings 模型。
要使用其他供应商的模型,请用此链接中的代码单元格替换当前的代码单元格。这里 Embeddings 模型配方
从langchain_huggingface导入HuggingFaceEmbeddings()
从transformers导入AutoTokenizer()
tokenizer = AutoTokenizer.from_pretrained("ibm-granite/granite-3.1-8b-instruct") # 初始化tokenizer
embeddings_model = HuggingFaceEmbeddings(model_name="ibm-granite/granite-embedding-30m-english") # 初始化embeddings_model
embeddings_tokenizer = AutoTokenizer.from_pretrained("ibm-granite/granite-embedding-30m-english") # 初始化embeddings_tokenizer
使用 Granite 3.1 这个模型
从 Replicate 上的 [ibm-granite](https://replicate.com/ibm-granite)
组织选择一个 Granite 模型。在这里,我们使用 Replicate Langchain 客户端来连接这个模型。
要开始使用Replicate,可以参阅《Replicate入门指南》(https://github.com/ibm-granite-community/granite-kitchen/blob/main/recipes/Getting_Started/Getting_Started_with_Replicate.ipynb)。
为了连接到非Replicate提供商的模型,请用来自LLM组件食谱中的代码替换此代码。
from langchain_community.llms import Replicate
from ibm_granite_community.notebook_utils import get_env_var
model = Replicate(
model="ibm-granite/granite-3.1-8b-instruct",
replicate_api_token=get_env_var("REPLICATE_API_TOKEN"),
model_kwargs={
"max_tokens": 1000, # 设置生成输出的最大token数为1000。
"min_tokens": 100, # 设置生成输出的最小token数为100。
},
)
我们现在有了下载好的模型,我们来试一试看看它会对我们的提问作出什么反应。
查询 = "谁在UFC 310的潘托哈对阵朝仓的比赛中获胜了?"
对话模板 = """\
<|start_of_role|>用户<|end_of_role|>{prompt}<|end_of_role|>
<|start_of_role|>助手<|end_of_role|>"""
对话 = 对话模板.format(prompt=查询)
输出 = model.invoke(对话)
print(输出)
现在我知道UFC 310是在2024年举办的,这看来并不是正确的潘托哈。模型似乎不知道答案,但至少它知道这场比赛其实没发生过。看看它是否了解一些具体的UFC规则。
query1 = "在UFC的非冠军比赛中,选手可以有多少体重浮动范围?"
prompt = prompt_guide_template.format(prompt=query1)
output = model.invoke(prompt)
print(output)
根据官方UFC规则,这里提到的情况也是不正确的。试着找一些包含相关信息的文件给模型。
选择你的向量数据库吧指定用于存储和检索词嵌入向量的数据库。
要连接到非 Milvus 的其他向量数据库,请将此代码单元格替换为此向量存储教程中的一个。
from langchain_milvus import Milvus
import tempfile
db_file = tempfile.NamedTemporaryFile(prefix="milvus_", suffix=".db", delete=False).name
print(f"向量数据库将保存到 {db_file} 目录下")
vector_db = Milvus(
embedding_function=embeddings_model,
connection_args={"uri": db_file},
auto_id=True,
enable_dynamic_field=True,
index_params={"index_type": "自动索引"},
)
步骤 4:构建向量存储
在这个例子中,我们从一系列源文档开始,使用Docling将文档转换为文本,然后将文本拆分成若干片段,利用嵌入模型生成嵌入向量,并将这些向量加载到向量数据库中。创建这个向量数据库将使我们能够轻松地在文档中进行搜索,从而可以方便地使用RAG。
使用Docling下载文件,转为文本,并拆分我们找到了一个提供UFC 310信息的网站,还有一个官方UFC规则的PDF文件。接下来我们会看到,Docling不仅可以将这两个文档拆分,还可以进行转换。
# 导入 Docling
from docling.document_converter import DocumentConverter
from docling_core.transforms.chunker.hybrid_chunker import HybridChunker
from docling_core.types.doc.labels import DocItemLabel
from langchain_core.documents import Document
# 这里是我们的文档,您可以随意添加更多 Docling 支持的文档格式
sources = [
"https://www.ufc.com/news/main-card-results-highlights-winner-interviews-ufc-310-pantoja-vs-asakura",
"https://media.ufc.tv/discover-ufc/Unified_Rules_MMA.pdf",
]
converter = DocumentConverter()
# 将文档转换并拆分成片段
i = 0
texts: list[Document] = [
Document(page_content=chunk.text, metadata={"doc_id": (i:=i+1), "source": source})
for source in sources
for chunk in HybridChunker(tokenizer=embeddings_tokenizer).chunk(converter.convert(source=source).document)
if any(filter(lambda c: c.label in [DocItemLabel.TEXT, DocItemLabel.PARAGRAPH], iter(chunk.meta.doc_items)))
]
print(f"创建了 {len(texts)} 个文档片段")
# 打印所有创建的文档
for document in texts:
print(f"文档 ID: {document.metadata['doc_id']}")
print(f"来源: {document.metadata['source']}")
print(f"内容:\n{document.page_content}")
print("以下是一条分割线,便于区分") # 以下是一条分割线,便于区分
向量数据库填充
注意:向量数据库的填充过程可能需要超过一分钟,这取决于您的嵌入模型和服务。
ids = vector_db.add_documents(texts)
print(f"向向量数据库添加了{len(ids)}篇文档")
步骤五:使用花岗岩的RAG
现在我们已经成功地完成了文档的转换处理,并把它们向量化了,我们可以搭建我们的RAG流程了。
提取相关内容在这里我们将测试 as_retriever 方法,以在我们新建立的向量数据库中查找与最初查询相关的内容。
定义一个检索器从向量数据库
retriever = vector_db.as_retriever()
调用检索器根据查询获取文档
docs = retriever.invoke(query)
打印获取的文档
print(docs)
看来它拉取了一些我们可能需要的信息片段。咱们接着构建RAG流程吧。
为Granite 3.1创建提示我们构建提示流水线。这将创建一个提示,包含之前搜索中检索到的片段,并将这些片段作为回答我们问题所需的信息提供给模型。
from langchain.prompts导入PromptTemplate as PromptTemplate
from langchain.chains导入create_retrieval_chain
from langchain.chains.combine_documents导入create_stuff_documents_chain
# 创建一个用于问题回答的提示模板,其中包含检索到的上下文。
prompt_template = """<|start_of_role|>system<|end_of_role|>\
{{
下文是上下文信息。\n---------------------\n{context}\n---------------------\n仅根据以下上下文信息回答问题,不依赖任何先验知识。\n问题: {input}\n答案:\n
}}
}}<|end_of_text|>
<|start_of_role|>user<|end_of_role|>{input}"""
# 组装增强检索的生成链以生成最终答案。
qa_chain_prompt = PromptTemplate.from_template(prompt_template)
combine_docs_chain = create_stuff_documents_chain(model, qa_chain_prompt)
rag_chain = create_retrieval_chain(vector_db.as_retriever(), combine_docs_chain)
生成增强检索的问答
使用相似性搜索得到的片段作为上下文,Granite RAG 3.1 的响应以 JSON 格式接收。接着,这个单元格会解析 JSON 文件,找出回应中的句子及其相关的句子元数据,这些元数据可以用来指导显示的输出。
输出是通过调用 rag_chain
并以 {'input': query}
作为参数得到的结果。然后打印输出中的 'answer'
部分。
太好了!看起来模型已经解决了我们第一个问题。看看它是否找到了我们想要的规则。
output = rag_chain.invoke({"input": query1})
print(output['answer'])
太好了!我们现在可以确认,我们已经成功创建了一个利用多种文档类型的流程进行生成的系统。
下一步是- 探索其他行业的高级RAG工作流程
- 尝试使用其他类型的文档和更大的数据集。
- 优化提示工程以获得更好的Granite响应效果
- Granite(专有名词)
谢谢您用这个食谱!
链接共同學(xué)習(xí),寫下你的評論
評論加載中...
作者其他優(yōu)質(zhì)文章