5.Implementing the RAG flow
此文档由 学习AI的1000天 翻译制作(抖音,B站,YouTube)
邮箱: szqshan@gmail.com | 微信: szqshan
网址: www.xueai.org
==================================================
现在我们从概念上理解了RAG流程,让我们逐步实现它。我们将通过一个完整的示例来演示如何分块文本、生成嵌入向量、将它们存储在向量数据库中,并执行相似性搜索。
五步RAG实现
我们的实现遵循之前讨论的相同五个步骤:
- 按章节分块文本
- 为每个分块生成嵌入向量
- 创建向量存储并将每个嵌入向量添加到其中
- 为用户的问题生成嵌入向量
- 搜索存储以找到最相关的分块

此图表显示了我们如何将用户查询转换为嵌入向量,并搜索我们的向量数据库以找到最相关的内容。
步骤1:分块文本
首先,我们加载文档并将其分割成可管理的部分:
with open("./report.md", "r") as f:
text = f.read()
chunks = chunk_by_section(text)
chunks[2] # 测试查看目录
我们使用之前相同的 chunk_by_section 函数将文档分割成逻辑部分。
步骤 2:生成嵌入向量
接下来,我们一次性为所有分块创建嵌入向量:
embeddings = generate_embedding(chunks)
嵌入函数已经更新,可以同时处理单个字符串和字符串列表,使批量处理更加高效。
步骤3:存储到向量数据库
现在我们创建向量存储并用嵌入向量及其关联的文本填充它:
store = VectorIndex()
for embedding, chunk in zip(embeddings, chunks):
store.add_vector(embedding, {"content": chunk})
注意我们同时存储了嵌入向量和原始文本内容。这一点至关重要,因为当我们稍后进行搜索时,需要返回实际的文本,而不仅仅是数值型的嵌入向量值。
为什么要存储原始文本?
当我们查询向量数据库时,仅仅获得嵌入向量的数字是没有用的。我们需要用于生成这些嵌入向量的实际文本。这就是为什么我们在数据库中每个嵌入向量旁边都要包含原始文本块(或至少是对它的引用)。
步骤4:处理用户查询
当用户提出问题时,我们为他们的查询生成一个嵌入向量:
user_embedding = generate_embedding("What did the software engineering dept do last year?")
步骤5:查找相关内容
最后,我们搜索向量存储以找到最相似的文档块:
results = store.search(user_embedding, 2)
for doc, distance in results:
print(distance, "\n", doc["content"][0:200], "\n")
这个搜索返回两个最相关的文档块以及它们的相似度分数(余弦距离)。

搜索结果向我们展示了文档中哪些部分与用户问题最相关,同时提供了相似度分数。
理解结果
当我们运行关于软件工程部门的示例查询时,我们得到:
- 第2节:软件工程,距离为0.71(最接近的匹配)
- 方法论章节,距离为0.72(第二接近的匹配)
较低的距离值表示更高的相似性,因此第2节与我们的查询最相关。
下一步是什么?
这个实现在基本情况下运行良好,但在某些场景下表现不如预期。在接下来的章节中,我们将探索改进方法,使我们的RAG系统更加稳健和准确。
关键要点是,RAG本质上是将文本转换为数字(embeddings),高效地存储这些数字,然后在用户提问时使用数学相似性来找到相关内容。
==================================================
此文档由 学习AI的1000天 翻译制作(抖音,B站,YouTube)
邮箱: szqshan@gmail.com | 微信: szqshan
网址: www.xueai.org