检索增强生成 (RAG)
如果你正在使用 Ollama,请注意它默认的上下文长度为 2048 个 token。这会严重限制检索增强生成 (RAG) 的性能,特别是对于网络搜索,因为检索到的数据可能根本不会被使用或仅被部分处理。
检索增强生成 (RAG) 是一种通过结合不同来源的上下文来增强聊天机器人对话能力的技术。它的工作原理是从广泛的来源检索相关信息,如本地和远程文档、网页内容,甚至像 YouTube 视频这样的多媒体来源。然后将检索到的文本与预定义的 RAG 模板结合,并作为用户提示词的前缀,从而提供更丰富且与上下文更相关的响应。
RAG 的主要优势之一是它能够访问并整合来自多种来源的信息,使其成为复杂对话场景的理想解决方案。例如,当用户提出与特定文档或网页相关的问题时,RAG 可以检索该来源的相关信息并将其融入到对话响应中。RAG 还可以检索并整合来自 YouTube 视频等多媒体来源的信息。通过分析这些视频的转录或字幕,RAG 可以提取相关信息并将其整合到对话响应中。
本地和远程 RAG 集成
首先必须通过工作区(Workspace)的“文档”(Documents)部分上传本地文档,然后才能在查询前使用 # 符号访问它们。点击聊天框上方出现的格式化 URL。选择后,Send a message(发送消息)上方会出现一个文档图标,表示检索成功。
需要清理多个已上传的文档或审计您的存储?您现在可以使用位于 设置 > 数据控制 > 管理文件 (Settings > Data Controls > Manage Files) 的集中式**文件管理器**。在那里删除文件将自动清理其相应的 RAG 嵌入数据。
您还可以通过以 # 开头并紧跟一个 URL 来开始提示,将带有访问权限的文档加载到工作区。这有助于将网页内容直接融入到您的对话中。
用于 RAG 的网络搜索
致 Ollama 用户的上下文长度警告: 即使经过内容提取,网页通常包含 4,000-8,000 多个 token,包括主要内容、导航元素、页眉、页脚和元数据。如果只有 2048 个可用 token,您获得 的内容不到页面内容的一半,通常会丢失最相关的信息。甚至 4096 个 token 对于全面的网页内容分析也常常是不够的。
修复方法: 导航至(您的 Ollama 模型的)管理面板 > 模型 > 设置 (Admin Panel > Models > Settings) > 高级参数 (Advanced Parameters),并将上下文长度增加到 8192+(或最好超过 16000)个 token。此设置特别适用于 Ollama 模型。对于 OpenAI 和其他集成模型,请确保您使用的是具有足够内置上下文长度的模型(例如,具有 128k token 的 GPT-4 Turbo)。
对于网页内容的集成,在聊天中以 # 开头开始查询,并紧跟目标 URL。点击聊天框上方出现的方框中的格式化 URL。选择后,Send a message 上方会出现一个文档图标,表示检索成功。如果可以,Open WebUI 将从该 URL 获取并解析信息。
网页通常包含诸如导航和页脚等无关信息。为了获得更好的结果,请链接到该页面的原始或适合阅读的版本。
RAG 模板自定义
从 管理面板 (Admin Panel) > 设置 (Settings) > 文档 (Documents) 菜单自定义 RAG 模板。
Markdown 标题拆分
启用后,文档将首先按照 markdown 标题 (H1-H6) 进行拆分。这保留了文档结构,并确保尽可能将同一标题下的章节保存在一起。生成的语块然后由标准的字符或 token 拆分器进一步处理。
使用 Chunk Min Size Target 设置(位于 管理面板 > 设置 > 文档 中),在 markdown 拆分后智能合并较小的章节,从而提高检索的连贯性并减少数据库中的向量总数。
语块化配置
Open WebUI 允许您微调文档如何被拆分成块以进行嵌入。这对于获得最佳检索性能至关重要。
- Chunk Size (语块大小):设置每个语块的最大字符(或 token)数。
- Chunk Overlap (语块重叠):指定相邻语块之间共享多少内容以维持上下文。
- Chunk Min Size Target (语块最小尺寸目标):尽管 Markdown 标题拆分 在保留结构方面非常出色,但它通常会产生微小且碎片化的语块(例如,独立的副标题、目录条目、单句段落或短列表项),这些语块缺乏足够的语义上下文来进行高质量嵌入。您可以通过设置 Chunk Min Size Target 智能合并这些小片段及其相邻片段来解决此问题。
为什么使用 Chunk Min Size Target?
在 markdown 拆分后智能合并较小的章节可提供几个主要优势:
- 提高 RAG 质量:消除微小、无意义的片段,确保每个检索到的语块都有更好的语义连贯性。
- 减小向量数据库大小:更少的语块意味着需要存储的向量更少,从而降低存储成本并减少内存使用。
- 加快检索和嵌入速度:较小的索引搜索速度更快,且较少的语块需要的嵌入 API 调用更少(或更少的本地计算资源)。这在向聊天或知识库上传文件时显着加速了文档处理,因为需要向量化的数据较少。
- 效率和 影响:测试表明,良好配置的阈值(例如,针对 2000 的块大小设置 1000 的阈值)可以使语块数量减少 90% 以上,同时提高准确性,加快嵌入速度,并通过维护语义上下文提高整体检索质量。
合并算法的工作原理(技术细节)
对于大多数用户,上述解释已足够:小语块与其邻居合并,可以用更少的向量获得更好的检索结果,并在性能、成本和存储方面带来好处。但如果您好奇确切的逻辑和设计理念,以下是它的内部工作机制。
为什么基于标题的拆分需要合并
Markdown 标题拆分是一种较好的结构化分块方法,因为标题是文档作者放置的明确语义边界。您利用了人类对于一个主题在哪里结束和另一个主题在哪里开始的判断,这通常比可能在段落中间或思想中间切断的固定大小窗口化产生更连贯的块。
然而,真实的文档通常具有结构上的特性:目录、简短的介绍章节、在自己标题下的单句段落或内容极少的深层嵌套副标题。这些会产生造成问题的微小语块:
- 它们缺乏足够的上下文,在被单独检索时用处不大
- 它们会产生嘈杂的检索结果(在有限信号上匹配但没贡献什么有用信息)
- 非常短的文本有时嵌入可靠性较低
- 它们浪费向量存储空间并减慢检索速度
- 许多语块的嵌入时间比具有相同总内容的更少语块的嵌入时间要长
- 更多的嵌入操作意味着更多的 API 调用(成本)或更多的本地计算
合并算法通过在遵守文档结构和大小限制的同时智能地组合过小的块来解决这个问题。
算法:单次前向传递
合并逻辑特意设计得很简单——对所有语块进行一次单向前向传递:
- 以第一个语块作为“当前”累加器开始。
- 对于每个后续语块,检查它是否可以被吸收到当前语块中。
- 如果满足所有三个条件,则可以吸收该语块:
- 当前累加的内容仍低于
CHUNK_MIN_SIZE_TARGET - 合并不会超过
CHUNK_SIZE(最大值) - 两个语块属于同一源文档
- 当前累加的内容仍低于
- 如果可以吸收,合并它们(使用
\n\n分隔以保留视觉结构),然后继续检查下一个语块。 - 如果无法吸收,确定当前语块,并以下一个语块作为新的累加器重新开始。
- 重复,直到处理完所有语块。
关键点:大小检查是针对累加内容的,而不是单独的块。这意味着多个连续的微小块(如具有许多小条目的目录)将不断折叠在一起,直到合并后的大小达到阈值,或者直到合并下一个语块会超过最大值。