RAG系统设计

目前LLM应用集中在开发所谓AI智能体,理想中的AI智能体能够自主感知环境并作出决策,与环境的变化不断反馈,同时具备记忆,反思和工具能力.而目前的AI应用中,效果最好,成本也低的还是RAG.

RAG应用场景

RAG全称是“Retrieval-Augmented Generation”,即“检索增强的生成”。当设计一个LLM问答应用,模型需要处理用户的领域问题时,尽管大模型通常表现出色,但有时提供的答案并不准确,甚至可能出现错误。当用户需要获取实时信息时,模型无法及时提供最新的答案。这种现象在LLM应用中较为常见。

这些模型仍然存在一些无法忽视的局限性。其中,领域知识缺乏是最明显的问题。大模型的知识来源于训练数据,这些数据主要来自公开的互联网和开源数据集,无法覆盖特定领域或高度专业化的内部知识。

信息过时则指模型难以处理实时信息,因为训练过程耗时且成本高昂,模型一旦训练完成,就难以获取和处理新信息。

此外,幻觉问题是另一个显著的局限,模型基于概率生成文本,有时会输出看似合理但实际错误的答案。最后,数据安全性在企业应用中尤为重要,如何在确保数据安全的前提下,使大模型有效利用私有数据进行推理和生成,是一个具有挑战性的问题。

image-20260113140539536

RAG系统的应用场景主要集中在专业领域和企业场景,

RAG的核心思想是利用外部知识库或数据集来辅助模型的生成过程。具体来说,RAG通常包含以下关键步骤。

  1. 检索阶段:首先,模型会根据输入的查询或问题,从预先构建的索引中检索出最相关的数据、文档或文本片段。
  2. 生成阶段:随后,模型会使用这个综合的表示来生成答案或输出文本。在问答任务中,这通常意味着生成一个对原始查询的直接回答。

选择RAG而不是直接将所有知识库数据交给大模型处理,主要是因为模型能够处理的token数有限,输入过多token会增加成本。更重要的是,提供少量相关的关键信息能够带来更优质的回答

RAG模型的核心思想在于通过检索与生成的有机结合,弥补大模型在处理领域问题和实时任务时的不足。传统的生成模型在面对复杂问题时,往往由于知识储备不足,生成出错误或无关的回答。而RAG通过检索模块获取相关的背景信息,使生成模块能够参考这些信息,从而生成更具可信度和准确性的答案。这种方法不仅增强了生成内容的准确性,还提高了模型在应对特定领域知识和动态信息时的适应能力。

image-20260113141707928

RAG标准流程由索引(Indexing)、检索(Retriever)和生成(Generation)三个核心阶段组成。

  1. 索引阶段,通过处理多种来源多种格式的文档提取其中文本,将其切分为标准长度的文本块(chunk),并进行嵌入向量化(embedding),向量存储在向量数据库(vector database)中。
  2. 检索阶段,用户输入的查询(query)被转化为向量表示,通过相似度匹配从向量数据库中检索出最相关的文本块。
  3. 最后生成阶段,检索到的相关文本与原始查询共同构成提示词(Prompt),输入大语言模型(LLM),生成精确且具备上下文关联的回答。

索引是RAG系统的基础环节,包含四个关键步骤。

  1. 首先,将各类数据源及其格式(如书籍、教材、领域数据、企业文档等,txt、markdown、doc、ppt、excel、pdf、html、json等格式)统一解析为纯文本格式。
  2. 接着,根据文本的语义或文档结构,将文档分割为小而语义完整的文本块(chunks),确保系统能够高效检索和利用这些块中包含的信息。
  3. 然后,使用文本嵌入模型(embedding model),将这些文本块向量化,生成高维稠密向量,转换为计算机可理解的语义表示。
  4. 最后,将这些向量存储在向量数据库(vector database)中,并构建索引,完成知识库的构建。这一流程成功将外部文档转化为可检索的向量,支撑后续的检索和生成环节。

检索是连接用户查询与知识库的核心环节。首先,用户输入的问题通过同样的文本嵌入模型转换为向量表示,将查询映射到与知识库内容相同的向量空间中。通过相似度度量方法,检索模块从向量数据库中筛选出与查询最相关的前K个文本块,这些文本块将作为生成阶段输入的一部分。通过相似性搜索,检索模块有效获取了与用户查询切实相关的外部知识,为生成阶段提供了精确且有意义的上下文支持。

生成是RAG流程中的最终环节,将检索到的相关文本块与用户的原始查询整合为增强提示词(Prompt),并输入到大语言模型(LLM)中。LLM基于这些输入生成最终的回答,确保生成内容既符合用户的查询意图,又充分利用了检索到的上下文信息,使得回答更加准确和相关,充分使用到知识库中的知识。通过这一过程,RAG实现了具备领域知识和私有信息的精确内容生成。

Fine-tuning vs RAG

Fine-tuning 作为一种直接针对预训练语言模型进行额外训练的方法,能够让模型更好地适应特定领域或任务。这种方法的核心优势在于,能够显著提升模型在目标任务上的表现。通过使用领域特定的数据集,Fine-tuning 可以让模型学习到行业术语、专业知识结构和特定的表达方式。这使得Fine-tuned模型在处理专业领域的问题时,能够提供更加准确、相关的回答。例如,在极客时间,我们把作者的实战经验从文章中提取出来,然后基于开源模型进行微调,让 LLM 可以输出生产环境直接可用的技术方案,而不是一些通用解决方案。

微调更适合需求稳定、领域知识固定且不需要频繁更新知识库的场景。通过使用特定领域的数据对模型进行深度优化,微调可以提升模型在特定任务或领域中的推理能力,确保输出内容的专业性和一致性。因此,当任务侧重于某一特定领域,并且对实时信息的依赖较低时,微调更能满足这些需求

此外,Fine-tuning 后的模型响应速度快,无需在运行时检索外部知识库,这使得它特别适合需要实时响应的场景,比如在线客户服务或实时决策支持系统。举个例子,在我们的用户对话功能中,有时候人工客服可能不在线,用户提问如果能快速得到响应,及时解答用户问题,可以大大提高用户的信任感。

当然,使用 Fine-tuning 也要付出一些额外的成本。它需要大量的标注数据和较高的计算资源,这对许多企业来说可能是一个门槛。而且,一旦模型经过 Fine-tuning,要更新其知识就需要重新训练,如果是经常变化的知识,可能成本就非常高了。

相比之下,RAG 技术提供了一种更为灵活的解决方案,可以更好地处理 “经常变化” 的知识。RAG 通过将大语言模型与外部知识库结合,在生成回答时实时检索相关信息。这种方法非常灵活,由于是自己设计的知识库,可以做各种优化操作,保证把最准确的知识呈现给用户。企业可以随时更新知识库中的信息。

RAG 的另一个重要优势是其可解释性。由于每个回答都可以追溯到具体的知识来源,这大大增强了AI系统的可信度和透明度。在需要严格监管或高度问责的行业,如金融服务或政府部门,这一特性尤为重要。然而,RAG也有其局限性。由于需要实时检索知识库,RAG系统的响应速度可能不如 Fine-tuned 模型快。此外,RAG的效果高度依赖于知识库的质量检索算法的效率,这要求我们投入大量资源来维护和优化知识库。

在实际应用中,我们可以将 Fine-tuning 和 RAG 结合使用,以充分发挥两种方法的优势。这种混合方法可以应对更复杂的场景和挑战。例如,要做一个极客时间客服系统,我们可以使用 Fine-tuned 模型来处理常见的、结构化的查询,比如一些通识或者固定不变的知识,保证快速、准确的响应。同时,对于涉及最新产品信息或政策变更的问题,系统可以切换到 RAG 模式,利用实时更新的知识库来提供最新、最相关的信息。在产品研发过程中,可以使用企业内固定的技术相关文档进行 Fine-tuning,让 LLM 回答的内容都是符合企业开发技术范围,再配合上 RAG 把一些外部的技术文档作为补充知识库,两者结合,在内部就可以很好地辅助产研人员工作。

未来方向

第一个方向是动态知识图谱的集成。传统的RAG系统通常使用静态的知识库,而动态知识图谱将为RAG带来更智能、更灵活的知识管理能力。这种系统不仅能够实时更新知识,还能自动建立知识之间的关联。

在前面课程中提到的 Mem0 记忆框架,最近更新了一个特性,就是 graph memory。它把用户的记忆拆分成记忆节点和关系,通过使用图数据库,保存下这些关系和节点,在使用记忆的时候,会通过图检索技术找到记忆之间的关联,从而找到关键的记忆点,然后结合当时的详细记忆,最终给出回答。这种技术可以让用户在海量记忆中去查询问题的答案,相比传统的 RAG,极大程度地提高了记忆的相关性和连续性。

还有就是最近大火的GraphRAG。GraphRAG 本身是一个理论,这个项目是由微软开源的,它包括从原始文本中提取知识图,构建社区层次结构,为这些社区生成摘要,然后在执行基于 RAG 的任务时利用这些结构等等功能。

第二个方向是个性化 RAG。未来的RAG系统将能够根据用户的背景、偏好和使用历史来动态调整其检索和生成策略。

例如,一个个性化的 RAG 系统可以根据用户的知识水平、学习风格和关注点来推荐内容和解答用户问题。这种个性化不仅限于内容的选择,还包括表达方式的调整,使得AI助手能够以最适合每个用户的方式进行交流,可以根据不同用户的喜好风格,调整 AI 小助手的说话方式。这将大大提高用户体验,使AI系统更加贴近人类的交互需求,带给用户更多的亲切感。

第三个方向是多模态 RAG。上述的讨论都建立在文本模型上,如果再加上视觉模型,让大模型能像人眼一样观察世界,再把看到的东西内化到知识库中,这将会大大拓宽 RAG 的应用范围,让更多的业务能够用上大模型技术。

比如,在医疗领域,使用多模态 RAG 系统可能会同时分析病人的症状描述(文本)、X光片(图像)、心电图(时序数据)和医生的口头诊断(音频)。系统不仅能够理解每种模态的信息,还能够在这些不同模态之间建立联系,提供更加全面和准确的诊断建议。相对于只有文本内容,这种方式能够得出更加准确和有深度的诊断,也更加符合医生的诊断习惯。通过与多模态结合,将会让大模型在更多领域发挥价值,甚至会产生新的产品形态或者服务方式。企业在这个方向上进行探索,会带来创新性的收获。

统一多源文档格式

票据,扫描件,手写,文件里的嵌入表格和数学公式

Word文件

文档格式.doc,docx,是Word文档的OPen XML格式.

块的分布 块与块之间的关系

image-20260113144028000

文档解析工具

python-docx,langchain document loader,springlangchain4j,spring ai

文档解析逻辑

文字通过库直接解析,图片使用路径表示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
def parse_docx(self, docx_path):
doc = DocxDocument(docx_path)

content = []

image_map = self._extract_images_from_docx(doc)

def parse_paragraph(paragraph):
def append_image_link(image_id, has_drawing, target_buffer):
"""Helper to append image link from image_map based on relationship type."""
rel = doc.part.rels[image_id]
if rel.is_external:
if image_id in image_map and not has_drawing:
target_buffer.append(image_map[image_id])
else:
image_part = rel.target_part
if image_part in image_map and not has_drawing:
target_buffer.append(image_map[image_part])

def process_run(run, target_buffer):
# Helper to extract text and embedded images from a run element and append them to target_buffer
if hasattr(run.element, "tag") and isinstance(run.element.tag, str) and run.element.tag.endswith("r"):
# Process drawing type images
drawing_elements = run.element.findall(
".//{http://schemas.openxmlformats.org/wordprocessingml/2006/main}drawing"
)
has_drawing = False
for drawing in drawing_elements:
blip_elements = drawing.findall(
".//{http://schemas.openxmlformats.org/drawingml/2006/main}blip"
)
for blip in blip_elements:
embed_id = blip.get(
"{http://schemas.openxmlformats.org/officeDocument/2006/relationships}embed"
)
if embed_id:
rel = doc.part.rels.get(embed_id)
if rel is not None and rel.is_external:
# External image: use embed_id as key
if embed_id in image_map:
has_drawing = True
target_buffer.append(image_map[embed_id])
else:
# Internal image: use target_part as key
image_part = doc.part.related_parts.get(embed_id)
if image_part in image_map:
has_drawing = True
target_buffer.append(image_map[image_part])
# Process pict type images
shape_elements = run.element.findall(
".//{http://schemas.openxmlformats.org/wordprocessingml/2006/main}pict"
)
for shape in shape_elements:
# Find image data in VML
shape_image = shape.find(
".//{http://schemas.openxmlformats.org/wordprocessingml/2006/main}binData"
)
if shape_image is not None and shape_image.text:
image_id = shape_image.get(
"{http://schemas.openxmlformats.org/officeDocument/2006/relationships}id"
)
if image_id and image_id in doc.part.rels:
append_image_link(image_id, has_drawing, target_buffer)
# Find imagedata element in VML
image_data = shape.find(".//{urn:schemas-microsoft-com:vml}imagedata")
if image_data is not None:
image_id = image_data.get("id") or image_data.get(
"{http://schemas.openxmlformats.org/officeDocument/2006/relationships}id"
)
if image_id and image_id in doc.part.rels:
append_image_link(image_id, has_drawing, target_buffer)
if run.text.strip():
target_buffer.append(run.text.strip())

dify中word提取逻辑,Word 文档(.docx)本质上是一个压缩的 XML 文件。D通过解析这些底层的 XML 标签来重构表格和布局。

  1. 图片转存逻辑
  • 处理位置_extract_images_from_docx(self, doc) 方法。
  • 具体细节
    • 它遍历 doc.part.rels(文档关系表)。
    • 如果是内部图片,直接读取 rel.target_part.blob
    • 如果是外部图片 URL,使用 ssrf_proxy.get(url) 下载(重点:通过代理下载以防止 SSRF 攻击)。
    • 存储与映射:调用 storage.save() 将图片存入系统,并向数据库 UploadFile 表写入记录。最后返回 image_map,其 Key 是图片在 XML 中的 ID,Value 是 Markdown 格式的链接:![image](预览地址)
  1. 表格转 Markdown 逻辑
  • 处理位置_table_to_markdown(self, table, image_map) 及其调用的 _parse_row_parse_cell
  • 具体细节
    • 对齐处理:计算表格的最大列数 total_cols
    • 格式构造:手动拼接 Markdown 的分隔符 | --- |
    • 单元格合并处理:在 _parse_row 中,通过 cell.grid_span 获取单元格跨越的列数,确保合并单元格在 Markdown 转换后不会导致列偏移,保持数据结构的对齐。
  1. 复杂文本与链接提取
  • 处理位置parse_paragraph(在 parse_docx 内部定义的函数)。
  • 具体细节
    • 普通文本:遍历 run.text
    • 现代超链接:处理 w:hyperlink 标签。
    • 旧式超链接 (Field):这是最难处理的部分,代码通过正则匹配 HYPERLINK "url" 并结合 w:fldChar(字段开始/分隔/结束状态机)来提取那些隐藏在 Word 指令字段中的链接。

直接提取纯文本会丢失表格的行级/列级对应关系。转换为 Markdown 后,大模型能够通过分隔符明确识别表格数据的关联性,减少幻觉。

实际研发场景中,使用 Document Loader 文档加载器模块时,需要根据具体的业务需求编写自定义的文档后处理逻辑。针对业务需求,开发者可以自行编写和实现对不同文档内容的解析,例如对标题、段落、表格、图片等元素的特殊处理。

PDF解析

尽管PDF文件的内容在表达图像、文字和表格信息,但其本质上是一系列显示和打印指令的集合。,即使是一个仅包含 “Hello World” 文字的简单PDF,其文件内容也是一长串的打印指令。

image-20260113151406760

PDF文件的显示效果不受设备、软件或系统的影响,但对计算机而言,它是一种非数据结构化的格式,储存的信息无法直接被理解。此外,大模型的训练数据中不包含直接的PDF文件,无法直接理解。

PDF解析,对于纯文本格式可以转换为文本字符串,而对于包含多种元素的复杂格式,选择 MarkDown 文件作为统一的输出格式最为合适。这是因为MarkDown文件关注内容本身,而非打印格式,能够表示多种文档元素内容。MarkDown格式被广泛接受于互联网世界,其信息能够被大模型理解。

PDF文件分为电子版和扫描版。PDF电子版可以通过规则解析,提取出文本、表格等文档元素。目前,有许多开源库可以支持,例如 pyPDF2、PyMuPDF、pdfminer、pdfplumber和papermage 等。这些库在 langchain_community.document_loaders 中基本都有对应的加载器,方便在不同场景下切换使用。

在基于规则的开源库中,pdfplumber对中文支持较好,且在表格解析方面表现优秀,但对双栏文本的解析能力较差;pdfminer和PyMuPDF对中文支持良好,但表格解析效果较弱;pyPDF2对英文支持较好,但中文支持较差;papermage集成了pdfminer和其他工具,特别适合处理论文场景。开发者可以根据实际业务场景的测试结果选择合适的工具,pdfplumber或pdfminer都是当前不错的选择。

扫描版PDF

PDF扫描版需要经过文本识别和表格识别PDF扫描图像,才能提取出文档中的各类元素。同时要真正实现文档解析的目标,无论扫描版还是电子版均需进行版面分析和阅读顺序的还原,将内容解析为一个包含所有文档元素并且具有正确阅读顺序的MarkDown文件。单纯依赖规则解析是无法实现这一目标的.

目前支持这些功能的多为基于深度学习的开源库,如 Layout-parser、PP-StructureV2、PDF-Extract-Kit、pix2text、MinerU、marker等

由于PDF文档解析整体流程用到了多个深度学习模型组合,真正在生产场景中会遇到效率问题。商业闭源库由于其部署的云端集群可以做并行处理和工程效率优化,所以在精度和效率上都能做到生产中的级别,比如TextIn.com、Doc2x、mathpix、庖丁PDFlux、腾讯云文档识别等,当然商业库会存在成本问题,你可以按需选择。

PDF内容提取逻辑,参考dify

  1. 图片格式识别(Magic Bytes)
  • 实现位置:类属性 IMAGE_FORMATS_extract_images 内部。
  • 逻辑:代码通过检查文件头的“魔数”(Magic Bytes)来精准识别图片格式(如 JPEG 的 \xff\xd8\xff,PNG 的 \x89PNG),而不是简单依赖文件后缀。这保证了即使 PDF 内部图像流没有明确标签,也能正确保存为 .jpg.png
  1. 图像转存与持久化
  • 处理位置_extract_images(self, page)
  • 具体细节
    • 对象过滤:使用 filter=(pdfium_c.FPDF_PAGEOBJ_IMAGE,) 仅提取页面中的图像对象。
    • 二进制提取:调用 obj.extract()。注意其中的 fb_format="png",这意味着对于非 JPEG 格式的图像,代码会自动将其回退(Fallback)并渲染为 PNG 格式以保证兼容性。
    • 存储与数据库:图片字节流被存入 storage,同时向 UploadFile 数据库表写入元数据。返回的 Markdown 链接允许前端或大模型直接通过 URL 预览提取到的图片。
  1. 内存与资源管理
  • 处理位置parse 方法中的 finally 块及 autoclose=True
  • 逻辑:代码显式调用 text_page.close()page.close()pdf_reader.close()。在处理包含数千张图片的 PDF 时,及时释放 C 级底层的 PDF 句柄是防止内存泄漏的关键。

优化解析逻辑

布局恢复:目前提取的是“平铺”文本,PDF 中的多栏布局或页眉页脚可能会混入正文。可以考虑引入 pypdfium2 的坐标分析功能来过滤页眉页脚,或者使用OCR提取布局信息。

表格识别: pdf底层存储的是字符及其坐标,需要通过定位页面中的表格区域。尝试理解表格的行列逻辑,并将其转换为标准的 Markdown 表格格式|---|)。结合布局分析和表格重建 infiniflow/ragflow

OCR 介入:如果 PDF 是扫描件(图片生成的 PDF),get_text_range() 将返回空。此时应触发 OCR 流程对提取出的图片进行二次文字识别。

表格识别:引入OCR

采取 “混合解析策略”

  1. 预判断:先尝试用 pypdfium2 读取文本,如果返回字符数极少,判定为扫描件,触发 OCR。
  2. 工具选型
    • 追求开源/本地部署:集成 MarkerUnstructured 库。
    • 追求极致效果:使用多模态 API(如 GPT-4o-mini)专门处理表格页。
  3. 标准化输出:无论后端用什么工具,统一输出为 Markdown,因为这能最大程度保留表格的语义逻辑供大模型检索。

推荐工具对比:

需求场景推荐工具集成难度
追求极致速度维持现状 (pypdfium2)-
精准处理多栏/论文集成 Marker中(需要额外 Python 依赖)
完美还原复杂表格Unstructured + PaddleOCR高(环境配置较复杂)
万能适配多模态 LLM 视觉解析低(仅需 API 调用)

在Marker中,使用深度学习模型和启发式算法来解析PDF中的多栏布局和表格。多栏文本通过TextProcessor检测和合并,表格通过TableProcessor进行结构化提取,并可选择性使用LLM增强准确性

开源系统不支持的文件类型

image-20260113162924676

image-20260113164413896

难点

跨页表格怎么自动对齐

在处理 PDF 解析时,跨页表格(Multi-page Tables)是最具挑战性的场景之一。由于 PDF 在分页处会强制打断表格结构,并可能插入页眉、页脚或重复表头,简单的流式提取会导致表格断裂或数据错位。

关键技术方案

表头一致性,判断是否为同一张表的重复表头

表格位置分析,判断相邻页中的表格是否在文档布局中连续

自动拼接与去重,对于相同表头的多个分页表格,按行拼接,并去除重复的表头行

  1. 布局检测

mineru

  1. 文档格式检测
  2. 文档格式识别
  3. OCR处理
  4. 表格预测

数据预处理

image-20260113172147249

构建领域术语词库,识别输入中领域术语,替换

术语混淆直接影响信息检索的精确度与生成内容质量.

术语词库构建与维护

产生术语混淆

术语多义性,同义词,领域差异以及企业专属术语

术语词库构建流程

  1. 收集术语来源
  2. 标准化术语
  3. 建立别名映射关系
  4. 添加上下文信息
  5. 构建术语索引

image-20260113192853262

术语词库与RAG集成

方式1:预处理阶段替换术语

方式2:检索增强

方式3:重排序

方式4:后处理解释

维护术语词库

分块策略与Embedding技术

image-20260113172431541

数据分块(Chunking/切片) 的质量直接决定了检索的精准度。如果切片太小,会丢失上下文;如果切片太大,会引入噪声并稀释语义。

Token-based chunking TokenTextSplitter 严格限制模型窗口时物理边界控制精准

SentenceSplitter 通用文本文档语义保真度高,配置简单 目标是在保持语义完整性的前提下,尽可能按句子边界切分。

工作原理:它会尝试按照段落 (\n\n)、换行 (\n)、句子、单词的优先级递归切分。

核心作用:它能确保切片不会在句子中间断开

关键参数chunk_size(块大小)和 chunk_overlap(重叠大小)。

窗口切分, SentenceWindowNodeParser

文档类型推荐切片类 (LlamaIndex)选择理由
标准说明书/公文SentenceSplitter段落结构清晰,按句子切分能最大程度保留语义。
README/技术手册MarkdownNodeParser强推。 必须按 H1-H3 标题切分,否则正文会脱离标题,导致检索到正文却不知道在说哪个产品。
代码库 (Python/JS)CodeSplitter依据语法树(AST)切分,保证一个函数或一个类在一个 Chunk 里。
扫描件/复杂 PDFSemanticSplitter慎用。 建议先用 Marker 转为 Markdown,再用 MarkdownNodeParser 处理。

“全家桶”组合 通常是:

  1. MarkdownNodeParser(用于格式化内容)
    • SentenceSplitter(作为 fallback 处理长段落)
    • MetadataExtractor(注入标题和上下文)
    • RedisCache(放在 IngestionPipeline 里加速重复解析

滑动窗口切分=sentenceSplitter+SentenceWindowSplitter

滑动窗口

滑动窗口结合关键词

  1. 初步切片,使用滑动窗口对文档进行基础分段
  2. 关键词检测,分析每个切片的边界,识别是否存在关键词或语义单元的中断
  3. 动态调整,根据关键词位置和上下文语境,微调切片边界,确保语义完整

语义切分

image-20260113214337874

SemanticSplitter 的工作逻辑可以分为以下四个步骤:

  1. 句子分割:首先将原始文档拆分成一个个基础的句子。
  2. 向量化(Embedding):利用 Embedding 模型将每个句子(或句组)转化为高维向量。
  3. 计算相似度:计算相邻句子之间的余弦相似度(Cosine Similarity)
  4. 设定阈值(Threshold)
    • 如果相邻两句的意思非常接近,它们会被合并在同一个块(Chunk)里
    • 如果相似度突然下降,超过了设定的阈值,系统就认为“话题发生了转换”,并在此处建立切片断点。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from llama_index.core.node_parser import SemanticSplitterNodeParser
from llama_index.embeddings.openai import OpenAIEmbedding

# 1. 定义 Embedding 模型(用于计算句子间的相似度)
embed_model = OpenAIEmbedding()

# 2. 初始化语义切片器
# buffer_size: 计算相似度时考虑的窗口大小
# breakpoint_percentile_threshold: 相似度下降到多少百分位时进行切割
splitter = SemanticSplitterNodeParser(
buffer_size=1,
breakpoint_percentile_threshold=95,
embed_model=embed_model
)

# 3. 对文档进行切片
nodes = splitter.get_nodes_from_documents(documents)

动态切片策略与重叠机制

RecursiveTextSplitter(递归字符切片器)是 RAG 开发中最常用、也是性价比最高的文本切片工具。它被广泛集成在 LangChain 等框架中,旨在解决简单字符切片容易“切断语义”的问题。

它的核心理念是:尽可能保持段落、句子和词语的完整性。

RecursiveTextSplitter 维护了一个分隔符列表(默认通常是 ["\n\n", "\n", " ", ""])。其工作流程如下:

  1. 段落切分:首先尝试用双换行符 \n\n(段落边界)来切分文档。
  2. 检查大小:如果切出来的块小于设定的 chunk_size,则保留。
  3. 降级递归:如果某个块仍然超过了 chunk_size,它会针对这个超长的块,换用下一个分隔符(如单换行符 \n)继续尝试切分。
  4. 最小单位:如果连换行符切完都太大,它会寻找空格 " "(单词边界)。如果连空格都解决不了(比如一个极长的化学单词),最后才会按字符 "" 强制切断。

结构化文档失效:如果你处理的是 Markdown(带有很多 # 标题)或代码,普通的递归切片可能会切断标题和正文的联系。此时应该使用专用的 MarkdownHeaderTextSplitterCodeSplitter

不识别语义转折:它只看物理符号(如换行符),不看意思。如果一个段落里讨论了两个完全不同的主题,它还是会把它们放在一起。这种情况需要 SemanticSplitter

TopicNodeParser

命题化检索

TopicNodeParser 通常利用 LLM 或高精度的 Embedding 模型来识别文档中的“话题转换点”(Topic Drift)。

其工作流程通常如下:

  1. 初始分割:将文档初步拆分为较小的单元(如句子或短段落)。
  2. 主题建模/识别
    • 方法 A(LLM 驱动):让 LLM 扫描文本块,判断:“这里是否开启了一个新话题?”
    • 方法 B(语义聚类):计算连续块之间的相似度,当相似度曲线出现“断崖式”下跌时,判定为主题切换。
  3. 节点构建:将属于同一个主题的所有文本块合并为一个 Node,并自动为该 Node 提取一个主题标签(Topic Label)作为元数据。

上下文割裂:一个关于“安装步骤”的描述可能被切成了两半,检索时只搜到后半部分,导致步骤缺失。

语义混杂:一个 1024 Token 的块里,前一半在说“硬件规格”,后一半在说“软件配置”,这会导致该块的向量表征变得“平庸”,检索相关度下降。

image-20260113221722324

Dify中的父子模式

在普通的切片模式下,开发者常面临一个“鱼与熊掌不可兼得”的困局:

  • 分段太小:检索非常精准(向量表征集中),但由于上下文(Context)太少,LLM 回答时容易断章取义。
  • 分段太大:包含了足够的背景,但一个段落里讲了三个主题,导致向量表征模糊,搜索时很难排在前面。

父子模式的对策:将原本的大段落(父)进一步拆解为多个小片段(子)。

  1. 工作原理

  2. 存储阶段

    • 父分段 (Parent):通常是较长的文本块(如 1000 Tokens),保留了完整的逻辑和上下文。
    • 子分段 (Child):将父分段进一步切碎(如 200 Tokens)。
    • 数据库关联:系统在向量数据库中索引“子分段”,但每一个子分段都关联着其对应的“父分段” ID。
  3. 检索阶段
    • 用户提问后,系统去匹配最相关的子分段
  4. 还原阶段(关键步)
    • 一旦命中了某个子分段,Dify 不会将子分段的内容发给 LLM,而是自动根据关联 ID,找回它所属的父分段内容
  5. 生成阶段
    • LLM 接收到的是语义丰富的父分段,从而能根据完整的背景生成高质量答案

开启“父子模式”通常需要调整以下参数:

  • 父分段规则:设定父块的大小(建议 800-1000 字符)。
  • 子分段规则:设定子块的大小(建议 200-300 字符)。
  • 检索策略
    • 通常配合混合检索(Hybrid Search)使用,即:子分段的向量检索 + 全文检索。

适用文档:逻辑严密但篇幅较长的文档,如法律条文、技术规范、深度行业报告

配合 Rerank:在父子模式下,强烈建议开启 Rerank(重排序)。因为子块召回可能较多,通过 Rerank 选出最准确的子块对应的父块,能显著降低 Token 消耗并提升准确度。

image-20260113222328479

传统的 RAG 工具(如 LangChain 或 Dify 默认模式)往往采用“一刀切”的规则来切片,而 RAGFlow 的模板化逻辑是:先看文档长什么样,再决定怎么拆。

不同的文档有完全不同的逻辑结构。如果用同一种算法去切,会发生以下惨剧:

  • 财务报表:表格被拆散成一堆毫无意义的数字。
  • 科研论文:双栏排版的文字被横向读取,左右两栏混在一起。
  • 调查问卷:问题和选项被强行切断。

RAGFlow 的模板化方案:预设了多种针对特定场景的解析逻辑,确保数据从 PDF/Word 转化为数据库向量时,逻辑依然是完整的。

RAGFlow 提供了多种内置模板,每种模板背后都有一套专门的布局识别(Layout Analysis)算法

切片的核心作用:为后续混合检索,重排,查询转换等提供高质量数据

最后也需要构建评估体系,持续验证与迭代优化

检索增强阶段

在初步召回的基础上,进一步优化检索结果的广度与精度.

image-20260113174601655

查询扩展与重写

生成 3 到 5 个不同表述但语义相同的查询变体。这些变体应从不同的侧重点出发,帮助从向量数据库中找回最相关的文档。其核心依据是语义向量空间的不确定性

利用大语言模型(LLM)将用户的一个问题转化为多个语义相似但措辞不同的问题,然后分别进行检索。

传统的向量检索(Vector Search)高度依赖用户输入的措辞

  • 痛点:如果用户的问题和文档中的词汇不匹配,或者提问比较模糊,向量空间中的距离可能较远,导致检索不到核心内容。
  • 例子:用户问“如何对齐 PDF 表格?”,文档里写的可能是“PDF 表格解析与重组方案”。两者字面上不完全一致。
  1. 查询生成:LLM 接收原始问题,生成 3-5 个不同角度的变体(例如:“PDF 表格错位怎么处理?”、“PDF 跨页表格对齐技术”等)。
  2. 并行检索:将这多个问题同时发给向量数据库,每个问题都会召回一批文档。
  3. 取并集(Union):将所有问题召回的文档汇总在一起。
  4. 去重与排序:剔除重复文档,最后将这组更全面的文档交给 LLM 生成答

假设性文档HyDE

核心思想是与其直接用“问题”去搜答案,不如先让 AI 编一个“假答案”,然后用这个“假答案”去搜“真文档”。

在传统的向量检索中,我们计算的是 问题(Query)文档(Document) 之间的相似度。

  • 痛点:问题通常很短(如“HyDE 是什么?”),而文档通常很长且充满细节。在向量空间里,短问题和长文档的特征向量往往不对称,导致检索不到最相关的片段。
  • HyDE 的逻辑:文档和文档之间是最像的。
  1. 生成假设文档:接收用户的问题,让 LLM(如 GPT-4)在不看任何外部资料的情况下,凭直觉写一篇“伪文档”或“假设性回答”。
  2. 向量化(Embedding):将这篇逻辑通顺但内容可能不准确的假设文档转化成向量。
  3. 检索真文档:用这个“伪向量”去数据库里匹配物理特征最接近的真实文档
  4. 生成最终答案:把检索到的真文档喂给 AI,生成正式的回复。

OCR文件错漏

OCR识别错误可以分为:

字符识别错误,文字遗漏,多字重复,格式混乱

在OCR之前可以及逆行文本图像校正,纠正图像中文档扭曲,倾斜,透视变形等问题,另外进行版面区域检测,对文档图像进行内容解析和区域划分

识别后的内容可以通过LLM修正

生成控制与验证阶段

image-20260113191853638

向量检索引擎

image-20260113233157267

BM25是改进的TF-IDF排序,通过词频,文档长度归一化以及逆文档频率加权.

设计混合检索架构提高多阶段召回率

让AI返回结构化数据

Structured Generation with LLM,是指让LLM按照预先定义的schema,输出符合schema的结构化结果

常见的应用场景有:

  1. 数据处理。主要功能为a -> b,即从源文本中抽取/生成符合schema的结果,例如给定新闻,进行分类、抽取关键词、生成总结等;
  2. Agent。主要功能是Tool Calling,即根据用户query,选择适当的tool和入参

如何从模型输出中准确提取自己所需的信息。例如,当我们希望模型输出 JSON 格式的数据时,由于模型生成的内容并不总是稳定,可能需要额外编写大量的正则表达式来匹配并提取其中的有效信息。然而,由于 LLM 的能力,导致其输出结构并不永远可靠。

现阶段, 让LLM按要求生成特定格式文本的主要方法有几种种:

  • 微调:使模型的输出遵循特定格式
  • OpenAI Json-mode/function-calling/Structured Outputs: 这些功能允许模型生成更严格、结构化的输出,但受限于openAI平台。
  • 格式约束:在decoding阶段进行约束,限制模型的输出,
  • Prompt Engineering: 最简单的办法,但不稳定。
  • 多阶段prompting: 通过多个步骤的提示逐步引导模型生成所需的格式
  1. 提示词工程(Prompt Engineering)

这是最基础的方式,通过在 System Prompt 中明确要求 AI 返回特定的格式。

  • 实现方式:在提示词末尾加上 “请以 JSON 格式返回结果,不要包含任何多余的解释文字”,并给出示例。
  • 优点
    • 低成本:不需要额外的 API 参数或编程逻辑。
    • 灵活性高:可以随时调整字段定义。
  • 缺点
    • 不稳定:AI 可能会在 JSON 前后加上“好的,这是你要的结果”等废话(俗称 Chatty AI)。
    • 解析失败:长文本下可能会出现 JSON 语法错误(如少个括号、引号未转义)。

Kor技术

使用Kor 进行structured generation的流程如下:

  1. 定义schema,包括结构、注释还有例子;
  2. Kor用特定的prompt template,将用户提供的schema和待处理的raw text,组装成prompt;
  3. 将prompt发送给LLM,借助其通用的In Context Learning能力,尽量生成符合schema的内容;
  4. Kor对LLM的输出进行parse,返回符合schema的结构化结果,但也有概率没有返回(当LLM的输出不符合schema时)。

  5. JSON Mode(JSON 模式)

主流模型(如 GPT-4、Gemini 1.5、Claude 3)都提供了专门的开关。

  • 实现方式:在调用 API 时设置 response_format: { "type": "json_object" }
  • 优点
    • 格式强制:模型会确保输出是一个合法的 JSON,极大地减少了解析错误。
  • 缺点
    • 不保证内容 Schema:虽然它是 JSON,但字段名可能会随机变化(比如这次叫 name,下次叫 user_name)。
    • 仍需引导:通常还是需要在 Prompt 中提示它是 JSON,否则模型可能不知道该写什么。

仅特定模型和平台支持,需要在prompt中要求输出json格式,不能保证完全按要求的格式结构输出,Json-Mode 更多是对于输出json的格式进行检查.JSON Mode 的实现原理是受限解码,核心不是让模型“学会”写 JSON,而是在它每产生一个 Token 时,通过一个外部过滤器(Filter)强行剔除掉会导致语法错误的选项。

  1. 函数调用 / 工具调用(Function Calling / Tool Use)

这是目前最推荐、生产环境最常用的方式。

  • 实现方式:预先定义一个函数的参数结构(通常使用 JSON Schema),AI 不直接回答问题,而是通过“调用函数”来填充这些参数。
  • 优点
    • 强类型约束:严格遵循你定义的字段名和数据类型。
    • 逻辑解耦:AI 负责提取信息,你的代码负责处理提取后的数据。
  • 缺点
    • 延迟略高:模型需要额外的思考步骤来决定调用哪个函数。
    • 成本:复杂的函数定义会占用更多的输入 Token。

Function Calling是构建agent的基石,也是各大LLM厂商的标配功能。要做到好的FC,LLM要能做到:

  1. 理解任务与function/tool的关系,知道是否要调用、需调用哪些function/tool、是否缺必要参数;
  2. 返回结构化内容,包括function name、arguments(json格式)
特性普通 PromptJSON ModeFunction Calling
约束目标语义理解(靠 AI 配合)语法合规(保证是 JSON)Schema 合规(保证字段对齐)
字段准确度差,经常乱起名中,字段可能多写或漏写极高,严格遵循定义
复杂结构难以处理深层嵌套较好完美,支持复杂递归嵌套
稳定性易受 Prompt 干扰较稳工业级稳定

Mistral模型的开源FC实现

mistral-nemo这样实现FC:

  1. 将tools按照特定的template,组装到prompt中去;
  2. LLM输出时,也遵循特定的template,call tool时加入特殊标记(TOOL_CALLS),并返回name和arguments。

mistral-nemo在fine-tuning时,按照这样的格式进行训练,FC的“要求”已经被encode到模型的参数中去了;

  1. 结构化输出(Structured Outputs)

很多开发者会用 Function Calling 来实现结构化输出(即使他们并不打算真的调用函数)。

  • 原因:早期的模型不支持独立的 Structured Output 模式,但 Function Calling 训练得非常成熟,能极稳地吐出 JSON 参数包。
  • 现状:现在像 OpenAI 的 Structured Outputs 已经是这两者的结合体——它既可以用在普通的回复里,也可以用在函数调用的参数提取里,保证 100% 的字段匹配。

这是 OpenAI 等厂商近期推出的最高级别约束方案。

  • 实现方式:在 API 请求中提供具体的 json_schema,并开启 strict: true 模式。
  • 优点
    • 100% 可靠:通过受限解码技术(Constrained Decoding),模型输出的每一个字符都受到 Schema 约束,完全不会偏离。
    • 零冗余:不会有任何解释性文字。
  • 缺点
    • 模型限制:目前仅支持部分最新型号(如 GPT-4o 系列)。
    • Schema 校验严格:如果 Schema 写的有问题,请求会直接失败。
  1. 编程框架封装(Pydantic / LangChain / Instructor)

利用开源库在代码层面进行封装和后处理。

  • 实现方式:使用 Python 的 Pydantic 定义类,通过 Instructor 库调用 AI,自动完成“请求 -> 提取 -> 验证 -> 重试”的闭环。
  • 优点
    • 开发体验极佳:像调用普通函数一样获取 AI 结果。
    • 自动重试:如果 AI 第一次返回的 JSON 缺字段,框架会自动反馈错误并让 AI 重写。
  • 缺点
    • 依赖性:增加了项目的库依赖。
需求场景推荐方式稳定等级
快速原型、简单测试提示词工程⭐⭐
需要合法 JSON 但字段多变JSON Mode⭐⭐⭐
生产环境、复杂业务逻辑Function Calling⭐⭐⭐⭐
高严苛金融/政务系统Structured Outputs (Strict)⭐⭐⭐⭐⭐

开源实现

Outlines

对于json schema,outlines首先将其转为正则表达式,然后再转为token-level的Finite State Machine

随后,模型的生成过程就变成在state之间的跳转:首先从初始state出发,随后在有限的输出路径中选一条,到达下一个state,直到到达最后一个state,完成生成。

其中”有限的输出路径“就是前文所提到的tokens输出范围。

Outlines 的精髓在于它不直接处理 JSON,而是处理 FSM(有限状态机)

  1. 解析 Schema:当你传入一个 Pydantic 模型或正则表达式时,Outlines 会解析其结构。
  2. 构建 FSM:它利用 interegular 等库,将复杂的规则(如 JSON 语法或正则)转换成一个高度优化的有限状态机
  3. 状态映射:在这个状态机中,每个状态都代表了当前已经生成的字符串序列。状态机明确知道:在当前状态下,下一个字符可以是哪些,不可以是哪些。
  4. FSM的缺点是无法准确表示复杂的schema。

guidance

Guidance 的本质是将 确定性的程序逻辑不确定性的 AI 生成 缝合在一起。

在生成过程中,Guidance 采取“接力赛”模式:

  • 程序控制阶段:框架直接向模型注入确定的字符串(如 JSON 的键名 {"name":)。这部分不消耗模型的推理计算,是直接“贴”上去的。
  • 模型生成阶段:框架将控制权交给 AI,但限制 AI 只能在指定的“坑”里填空。填完后,框架立刻收回控制权,跳过冗余字符,直接进入下一个字段。

Instructor

主要依赖于 PydanticPython 动态类型以及底层模型的 Function Calling 协议

① 模式转换 (Model to Schema)

当你定义一个 Pydantic 模型并传给 Instructor 时,它会利用 Pydantic 内置的 model_json_schema() 方法,自动将这个 Python 类转换成标准的 JSON Schema

② 协议适配 (Protocol Adaptation)

Instructor 会根据你使用的模型,将 Schema 包装进正确的 API 参数中:

  • 对于 OpenAI:它会将 Schema 放入 tools 或新的 response_format(Structured Outputs)中。
  • 对于 Anthropic/Gemini:它会调整为对应的 Tool UseJSON Mode 格式。

③ 采样约束与解析 (Sampling & Parsing)

模型返回 JSON 字符串后,Instructor 会立即进行 反序列化

  • 它尝试用你定义的 Pydantic 模型去实例化这个 JSON。
  • 关键点:如果 JSON 缺少字段或类型不对,Pydantic 会抛出验证错误(ValidationError)。

④ 自动重试机制 (Self-Correction/Retries)

这是 Instructor 最强大的功能。如果解析失败,它不会直接报错,而是:

  1. 把 Pydantic 抛出的具体错误信息(例如:age 字段缺失)作为新的 User Message 发回给 AI。
  2. 告诉 AI:“你刚才的输出不对,报错如下,请修正后重新生成。”
  3. 这个过程会重复 N 次,直到获取合规数据。

生产实现

在 Java 生态中,尤其是 LangChain4jSpring AI 实现结构化输出的底层逻辑,其实是把“复杂的协议通信”封装成了开发者熟悉的“对象映射”。

实现方式主要分为两类:基于 API 协议的强约束(类似 OpenAI 官方方案)和 基于 Prompt 的后置解析

  1. 强约束方案:基于 Function Calling (推荐)

这是 LangChain4j 等库默认的首选方式。它利用了模型厂商提供的专用接口

  • 实现步骤
    1. 内省 (Introspection):当你定义一个 Java RecordPOJO 时,框架会利用 Java 的反射机制读取字段名、类型和 @Description 注解。
    2. Schema 转换:框架将这些 Java 信息翻译成 JSON Schema
    3. 协议请求:在调用模型 API 时,框架不会把 Schema 塞进 Prompt,而是塞进参数里的 toolsresponse_format 字段。
    4. 模型输出:由于模型底层开启了“受限采样”,它会直接吐出一个干净的 JSON 字符串。
    5. 反序列化:框架内部使用 JacksonGson 将 JSON 字符串瞬间转回 Java 对象。
  1. 弱约束方案:基于指令与 Parser (Spring AI 常用)

如果模型不支持强约束接口(如某些早期的开源模型),Java 框架会回退到这种模式

  • 实现步骤
    1. 注入指令BeanOutputParser 会生成一段非常长且严厉的 Prompt 片段,告诉 AI:“你必须只返回 JSON,字段必须叫 XXX,类型必须是 int…”。
    2. 后置处理:AI 返回一段包含 JSON 的文本。
    3. 正则提取:Java 框架会用正则表达式从一堆废话中捞出 { ... } 这一部分。
    4. 验证与纠错:如果 Jackson 转换失败,部分框架(如 LangChain4j)会把错误日志发回给 AI,说“你刚才生成的 JSON 少了个逗号,请重写”,这就是自动修复机制。

有效评估与改进RAG应用

首先我们要明确业务目标,然后根据业务目标制定指标,再根据实际的指标值改进检索技术。这种方法一步到位,

RAGAS

  1. 与竞品相比,文档相对较完备。
  2. 专业度比较高,专注于做RAG评测。
  3. 支持与LLamaIndex、LangChain等11种RAG框架集成。

Ragas目前实现了十项评估指标,我们挨个来看看。

忠实度(Faithfulness)指标用于衡量生成答案与给定上下文的事实一致性。如果生成答案中的所有声明都可以从给定的上下文中推断出来,则认为该答案是忠实的。

答案相关性(Answer Relevance)侧重于评估生成答案与给定提示的相关性。对于不完整或包含冗余信息的答案,会给出较低的分数,而较高的分数表示更好的相关性。这个指标是通过问题、上下文和答案来计算的。答案相关性定义为原始问题与基于答案生成(逆向工程)的若干人工问题之间的平均余弦相似度。

上下文查准率(Context Precision)用于判断上下文中存在的所有真实相关项,是否都排在了较高的位置。理想情况下,所有相关的信息块都应该出现在顶部排名。这个指标是通过问题、真实答案和上下文来计算的,其值范围在0到1之间,分数越高表示查准率越高。

上下文利用率(Context utilization):上下文利用就像是上下文查准率指标的无参考版本。也就是关注是否利用了所有可用的信息块,而忽略掉它们的顺序如何。

上下文查全率(Context Recall),它衡量的是检索到的上下文与作为真实答案的标注答案的一致程度。该指标是通过问题、真实答案和检索到的上下文来计算的,其值范围在0到1之间,数值越高表示性能越好。为了从真实答案中估计上下文召回率,会分析真实答案中的每个声明,以确定它是否可以归因于检索到的上下文。在理想情况下,真实答案中的所有声明都应该可以归因于检索到的上下文。

上下文实体查全率(Context entities Recall),衡量从真实答案中召回的实体比例的一个指标。具体就是根据真实答案和上下文中存在的实体数量相对于单独在真实答案中存在的实体数量,来衡量检索到的上下文的召回率。

这个指标在有事实依据的用例中很有用,比如旅游咨询台、历史问答等。这个指标可以帮助评估基于与真实答案中实体的比较的实体检索机制,因为在实体重要的情况下,我们需要覆盖这些实体的上下文。

答案语义相似度(Answer semantic similarity),用于评估生成答案与真实答案之间的语义相似度。这个评估是基于真实答案和答案进行的,其值在0到1的范围内。分数越高,表示生成的答案与真实答案间的一致性越好。

答案正确度(Answer Correctness),用衡量生成的答案与真实答案相比的准确性。这个评估依赖于真实答案和答案,分数范围从0到1。分数越高表示生成的答案与真实答案之间的一致性越好,意味着正确度更高。

答案正确度包括两个关键方面:生成答案与真实答案之间的语义相似度以及事实相似度。这些方面通过加权方案结合起来,形成答案正确性分数。用户还可以选择使用一个“阈值”值将结果分数四舍五入为二进制(如果需要)。

特定领域评估(Domain Specific Evaluation),特定领域评估指标用于评估模型在特定领域的性能。评分标准包含了每个分数的描述,通常范围在从1到5分。

摘要分数(Summarization Score),这个指标衡量摘要在捕捉上下文重要信息方面的表现如何。这个指标背后的直觉是,一个好的摘要应该包含上下文所有重要信息。我们首先从上下文中提取一组重要的关键词。然后使用这些关键词生成一组问题。接着我们向摘要提出这些问题,并计算摘要得分为正确回答的问题数与问题总数的比率。

现如果你想直接把刚刚这些Ragas指标用到我们前面实战案例的评估,就会发现门槛还是有点高,难度比较大。为什么呢?因为我们没有评估所需要的基础数据,所以我们需要先采集相关数据。

那如何采集评估所需要的基础数据呢?一种方法是让数据标注员人工提问和标注,这种方法成本很高。目前最常见,也是最容易的方法是让用户直接提供反馈,然后收集这些结果,再让数据标注员分析和标注。

其他RAG技术

GraphRAG

GraphRAG是一种结合了知识图谱的检索增强生成技术,旨在通过构建知识图谱和社区检测算法,提升大模型在理解和生成复杂信息方面的能力。它通过图结构信息,能够更精确地检索和生成与上下文相关的回答,从而在处理大规模数据集时展现出显著的性能提升

规范化RAG应用

RAG链路级优化

image-20260113192018389

从知识入库处理到最终生成评估.

-------------本文结束感谢您的阅读-------------
感谢阅读.

欢迎关注我的其它发布渠道