N8N中文教程
高级 AI

在 n8n 中使用 RAG#

什么是 RAG#

检索增强生成(Retrieval-Augmented Generation, RAG) 是一种通过将语言模型与外部数据源结合来提升 AI 响应质量的技术。RAG 系统不依赖于模型内部的训练数据,而是检索相关文档,使响应基于最新、特定领域或专有的知识,从而实现 有据可依(grounded) 的输出。RAG 工作流通常依赖向量数据库(vector store)来高效地管理和搜索这些外部数据。

什么是向量数据库?#

向量数据库(vector store) 是一种专门设计用于存储和搜索高维向量的数据库,这些向量是文本、图像或其他数据的数值化表示。当你上传一份文档时,向量数据库会将其分割成多个片段(chunks),并使用 嵌入模型(embedding model) 将每个片段转换为一个向量。

你可以通过相似性搜索查询这些向量,其结果基于 语义含义 而非关键词匹配。这使得向量数据库成为 RAG 及其他需要从大量知识中检索并进行推理的 AI 系统的强大基础。

如何在 n8n 中使用 RAG#

从 RAG 模板开始 👉 使用 RAG 入门模板(RAG Starter Template) 在 n8n 中尝试 RAG。该模板包含两个预置工作流:一个用于上传文件,另一个用于查询这些文件。

将数据插入向量数据库#

在智能代理(agent)能够访问自定义知识之前,你需要先将数据上传至向量数据库:

  1. 添加用于获取源数据所需的节点。
  2. 插入一个 Vector Store 节点(例如 Simple Vector Store),并选择 Insert Documents 操作。
  3. 选择一个 嵌入模型(embedding model),用于将文本转换为向量嵌入。有关如何选择合适模型的更多信息,请参阅 FAQ 中的 如何选择合适的嵌入模型。
  4. 添加一个 默认数据加载器(Default Data Loader) 节点,用于将内容切分为片段。你可以使用默认设置,也可以自定义分块策略:
    • 字符文本分割器(Character Text Splitter):按字符长度进行分割。
    • 递归字符文本分割器(Recursive Character Text Splitter):优先按 Markdown、HTML、代码块或普通字符递归分割(推荐用于大多数场景)。
    • Token 文本分割器(Token Text Splitter):按 token 数量进行分割。
  5. (可选)为每个片段添加 元数据(metadata),以丰富上下文信息,并便于后续更精准的过滤。

查询你的数据#

你可以通过两种主要方式查询数据:使用 agent 或直接通过节点。

使用 agent#

  1. 在工作流中添加一个 agent。
  2. 将向量存储(vector store)作为 工具(tool) 添加,并为其提供一个 描述(description),以帮助 agent 判断何时使用它:
    • 设置 limit(限制) 来定义返回多少个文本块(chunks)。
    • 启用 Include Metadata(包含元数据) 以提供每个文本块的额外上下文。
  3. 添加与插入数据时使用的相同的 嵌入模型(embedding model)

提示 为了在昂贵的模型上节省 token,你可以先使用 Vector Store Question Answer 工具 检索相关数据,然后再将结果传递给 Agent。要查看实际应用,请参考 此模板。

直接使用节点#

  1. 将你的向量存储节点添加到画布,并选择 Get Many(获取多个) 操作。
  2. 输入查询或提示(prompt):
    • 设置 limit(限制) 以指定返回多少个文本块。
    • 如有需要,启用 Include Metadata(包含元数据)

常见问题(FAQs)#

如何选择合适的嵌入模型?#

合适的嵌入模型因情况而异。 通常来说,较小的模型(例如 text-embedding-ada-002)速度更快、成本更低,因此适用于短文本、通用文档或轻量级 RAG 工作流。较大的模型(例如 text-embedding-3-large)具有更强的语义理解能力,更适合长文档、复杂主题或对准确性要求较高的场景。

我的应用场景下最佳的文本切分方式是什么?#

这同样很大程度上取决于你的数据:

  • 较小的文本块(例如 200 到 500 个 token)适合细粒度检索。
  • 较大的文本块可能携带更多上下文,但也可能变得稀释或含有噪声。

选择合适的重叠大小对于 AI 理解文本块(chunk)的上下文非常重要。这也是为什么使用 Markdown 或代码块分割方法通常有助于生成更优文本块的原因。

另一个有效的方法是为文本块添加更多上下文信息(例如,该文本块来自哪份文档)。如果你想深入了解这一主题,可以阅读 Anthropic 的这篇优秀文章。