找回密码
 立即注册
首页 业界区 业界 Python学习:PocketFlow中的RAG例子

Python学习:PocketFlow中的RAG例子

杜优瑗 2025-9-25 20:59:49
运行效果

1.png

例子地址:https://github.com/The-Pocket/PocketFlow/tree/main/cookbook/pocketflow-rag
什么是RAG(用PocketFlow作者通俗的话来理解)

想象RAG就像在AI回答问题之前给了它一个个人的研究图书馆员。以下是这个魔法如何发生的:
文档收集:你把你的文档(公司手册、文章、书籍)提供给系统,就像书被添加到图书馆一样。
切片:系统将这些文档分解成易于消化的小块——就像图书馆员将书籍按章节和部分划分,而不是处理整本书。
嵌入:每个小块被转换成一种特殊的数字格式(向量),能够捕捉其含义——类似于创建能够理解概念而不仅仅是关键词的详细索引卡。
索引:这些向量被组织在一个可搜索的数据库中——就像一个理解不同主题间关系的神奇卡片目录。
检索:当你提问时,系统会查阅其索引,找到与你的查询最相关的片段。
生成:AI利用你的问题和这些有用的参考,生成一个比仅依赖其预先训练的知识更优秀的回答。
结果?AI不会编造信息或提供过时的信息,而是基于你的特定文档来构建其回答,提供准确、相关且符合你信息的回应。
2.png

在这个例子中作者使用了两个工作流,一个是offline工作流一个是online工作流:
3.png

offline工作流包含切片、嵌入与创建索引节点。
online工作流包含询问嵌入、检索文档与生成回答节点。
认识一下切片(用PocketFlow作者通俗的话来理解)

切块:将文档分成易于管理的小部分
在我们的RAG系统能够有效工作之前,我们需要将文档分解成更小、更易于消化的部分。
想象一下切块就像为客人准备饭食——你不会未经切片就直接上整只火鸡!
为什么分块很重要?
分块的大小直接影响你的RAG系统的质量:
分块过大:系统检索到过多的无关信息(就像提供整只火鸡)
分块过小:你失去了重要的上下文(就像只提供单一的豌豆)
恰到好处的分块:系统能够准确找到所需信息(完美的分量!)
有一些实用的分块方法
1、固定大小分块:简单但不完美
  1. def fixed_size_chunk(text, chunk_size=50):
  2.     chunks = []
  3.     for i in range(0, len(text), chunk_size):
  4.         chunks.append(text[i:i+chunk_size])
  5.     return chunks
复制代码
这段代码会逐次处理文本中的50个字符。
让我们看看它在示例段落上是如何工作的:
Input Text:
  1. The quick brown fox jumps over the lazy dog. Artificial intelligence has revolutionized many industries. Today's weather is sunny with a chance of rain. Many researchers work on RAG systems to improve information retrieval.
复制代码
Output Chunks:
  1. Chunk 1: "The quick brown fox jumps over the lazy dog. Arti"
  2. Chunk 2: "ficial intelligence has revolutionized many indus"
  3. Chunk 3: "tries. Today's weather is sunny with a chance of "
  4. Chunk 4: "rain. Many researchers work on RAG systems to imp"
  5. Chunk 5: "rove information retrieval."
复制代码
注意问题了吗?单词 "Artificial" 被拆分在第1块和第2块之间。"Industries" 被拆分在第2块和第3块之间。这使得我们的系统难以正确理解内容。
2、句子级别的切分:尊重自然边界
一种更智能的方法是按完整的句子进行切分:
  1. import nltk  # Natural Language Toolkit library
  2. def sentence_based_chunk(text, max_sentences=1)
  3.     sentences = nltk.sent_tokenize(text)
  4.     chunks = []
  5.     # Group sentences, 1 at a time
  6.     for i in range(0, len(sentences), max_sentences):
  7.         chunks.append(" ".join(sentences[i:i+max_sentences]))
  8.     return chunks
复制代码
此方法首先识别完整的句子,然后逐个将它们分组:
Output Chunks:
  1. Chunk 1: "The quick brown fox jumps over the lazy dog."
  2. Chunk 2: "Artificial intelligence has revolutionized many industries."
  3. Chunk 3: "Today's weather is sunny with a chance of rain."
  4. Chunk 4: "Many researchers work on RAG systems to improve information retrieval."
复制代码
好多了!每个片段现在都包含了一个完整的意思完整的句子。
其他切片策略
根据您的文档,以下方法也可能适用:
基于段落:在段落分隔处切分文本(通常由换行符标记)
语义切分:按主题或意义对文本进行分组(通常需要AI辅助)
混合方法:结合多种策略以获得最佳效果
尽管存在许多复杂的切分方法,但对于大多数实际应用而言,“简单愚蠢”(KISS)原则适用。从每块大约1,000字符的固定大小切分开始通常已经足够,并且可以避免系统过于复杂。
最佳的切分方法最终取决于您的具体文档和用例——就像厨师根据菜肴和客人调整份量一样!
认识一下嵌入(用PocketFlow作者通俗的话来理解)

嵌入:使检索成为可能
现在我们已经将文档切分,系统是如何找到与我们的问题最相关的片段的?这就是嵌入的作用!嵌入是驱动我们检索系统的魔法。没有它们,我们就无法为问题找到正确的信息!
什么是嵌入?
嵌入将文本转换为一个数字列表(向量),以捕捉其含义。可以将其视为在意义空间中创建一个特殊的“位置”,相似的想法会靠近放置。
例如,如果我们取这三个句子:

“猫坐在垫子上。”
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册