news 2026/8/31 12:39:20

RAG工程实践:从分块、向量化到生产排错的完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RAG工程实践:从分块、向量化到生产排错的完整指南

AI、LLM、GenAI 是当前技术社区讨论热度最高的几个词,但真正要把这些能力落到业务系统里,RAG 是无法绕开的关键工程路径。RAG 的全称是 Retrieval-Augmented Generation,也就是检索增强生成:先从知识库中检索出与问题相关的资料片段,再让大模型基于这些片段生成回答。它解决的是大模型训练数据截止后的知识盲区、私有数据隔离、以及回答幻觉三个实际问题。

这篇内容定位在 AI 与 LLM 工程实战学习路径的第三阶段,重点不是再讲一遍大模型 API 怎么调用,而是围绕 RAG 做完整的工程化落地:从最小链路搭起,到分块、向量化、检索、生成的关键参数,再到知识库指标、进阶架构和生产排错。适合已经会调用大模型接口、写过一个简单 Demo,但准备把知识库问答做成可用系统的开发者。

读完这篇文章,你可以独立搭建一个 RAG 问答原型,知道哪些参数会影响效果,能够用指标而不是肉眼判断来评估知识库质量,并且遇到“回答不对、引用不对、检索不到”的问题时,知道按哪条链路去排查。

1. 先理解RAG在LLM工程里的位置,再决定要不要用RAG

1.1 RAG解决的核心问题:知识时效、私有数据和幻觉

先给RAG一个通俗的定义。大模型本身像一个知识面很广、但训练数据截止之后就很难更新的专家。你问它常识问题,它可以回答得很好;你问它公司内部最近更新的项目文档,它要么说不知道,要么凭训练数据里的近似内容编一个答案。RAG 的思路就是把这个场景变成“开卷考试”:先让检索器从知识库里找出相关资料,再让大模型结合资料作答。

从技术定义上看,RAG 是一个由检索器(Retriever)和生成器(Generator)组成的框架。检索器负责从外部知识库中召回与用户问题相关的文档片段,生成器负责把这些片段作为上下文输入给大模型,最终生成回答。这套思路在 2020 年 Lewis 等人的论文《Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks》中得到了系统化表述,之后成为知识密集型 NLP 任务的主流方案之一。

RAG 能解决三类问题:

  1. 知识时效性。大模型训练数据有截止时间,而业务文档、行业规范、技术方案可能每天都在变化。RAG 可以在查询阶段实时检索最新内容,不需要重训模型。
  2. 私有知识。公司内部文档、协议、专利、日志、业务规则不可能进入公开训练数据。RAG 可以在不修改模型权重的前提下,把这些私有内容放进知识库,让模型按需读取。
  3. 幻觉。大模型在没有事实依据时容易编造内容。RAG 通过把回答范围限制在检索出的上下文里,大幅降低无依据生成的概率。

这里要强调一个容易误解的点:RAG 不能保证 100% 消除幻觉,它只是把幻觉的来源从“模型记忆”转移到了“检索上下文”。如果检索器召回的内容本身不正确、不完整,或者被切碎导致语义丢失,生成器依然会基于错误上下文给出错误答案。所以做 RAG 项目时,不能只盯着生成端的模型能力,检索质量往往是决定效果上限的地方。

1.2 RAG 和微调、长上下文、Agent 怎么选

RAG 不是唯一的知识注入方式。实际项目中经常有人问:到底该用 RAG、微调、长上下文,还是引入 Agent?它们解决的问题有重叠,但适用边界不一样。

方案核心思路适合场景主要成本
RAG检索外部知识后生成知识更新频繁、需要引用来源、私有数据隔离索引构建、检索链路、向量库运维
微调用训练数据调整模型权重固定写作风格、领域术语、能力塑造GPU 训练资源、数据标注、版本管理
长上下文把大量文档直接放入 Prompt一次性分析少量长文档、跨章节连续理解Token 费用、接口延迟、上下文窗口占用
Agent让模型规划多步工具调用多轮查询、跨库汇总、需要调用多个 API编排复杂度、错误传播、调试成本

从这些对比可以看出,RAG 的核心优势是知识可更新、答案可溯源。当你需要回答“这个问题来自哪份文档的哪一段”时,RAG 天然比微调和长上下文更合适。微调更适合改变模型的行为和风格,而不是更新事实性知识。长上下文适合单次读取大文档,但每次都把全部内容塞进 Prompt 会非常昂贵,也不适合频繁更新的数据。

Agent 和 RAG 不是对立关系,而是组合关系。Agent 负责判断“这个问题需要几步、调用哪些工具”,RAG 可以作为 Agent 的一个工具,负责从知识库检索。后面讲 Agentic RAG 时会再展开。

1.3 学习环境与生产环境的差异

很多教程只演示了脚本级别的 RAG,读者照做之后觉得“跑通了”,但把它放在生产环境立刻就会出现问题。差异主要体现在几个方面:

维度学习环境生产环境
数据量级几份文档、几百个分块几十万甚至上百万分块
向量库Chroma、FAISS 本地存储Milvus、pgvector、Elasticsearch 等独立服务
请求模式单线程手工调用高并发、超时、限流
数据更新手动重新建库增量更新、数据版本管理
权限控制无或极简按用户、部门、文档级别隔离
日志监控全链路日志、检索耗时、指标监控
异常处理报错就重跑降级、重试、告警

学习阶段最重要的是把链路跑通,理解每个环节的作用;生产阶段则要考虑知识库替换、权限隔离、检索延迟和成本。文章后面会单独讲生产落地问题。

2. 搭建最小可运行的RAG链路

这一部分从零开始搭建一个 RAG 最小系统。技术栈选择 Python 生态的 LangChain 作为编排工具,Chroma 作为本地向量库,HuggingFace 的本地 Embedding 模型做向量化,LLM 使用任意兼容 OpenAI Chat 接口的服务或本地部署模型。下面示例用于说明完整流程,实际项目要结合自己的包名、路径和模型版本调整。

2.1 环境准备与依赖版本

建议使用 Python 3.9 以上版本。安装依赖时不需要一次性装完所有 LangChain 相关包,只需要当前链路需要的部分:

python --version pip install langchain langchain-community langchain-huggingface chromadb sentence-transformers pypdf

各依赖的作用:

  • langchain:提供文本分割、Chain 编排、Prompt 模板等核心能力。
  • langchain-community:提供非核心的文档加载器、向量库封装等集成组件。
  • langchain-huggingface:提供HuggingFaceEmbeddings,用于加载本地 Embedding 模型。
  • chromadb:轻量级本地向量数据库,适合学习和小规模原型。
  • sentence-transformers:Embedding 模型的推理依赖。
  • pypdf:用于解析 PDF 文件。

注意:LangChain 在 0.1、0.2、0.3 等多个版本中 API 变化较大,很多类从langchain.xxx迁移到了langchain_community.xxx。如果你使用的是旧版教程代码,导入报错时优先检查包名是否已经迁移。

2.2 文档加载与解析全流程

RAG 第一步是把原始文档变成可以被后续处理的 Document 对象。不要把整个 PDF 直接扔给模型,因为 PDF、Word 等格式本质上是排版文件,里面包含页眉、页脚、表格、图片等复杂结构,不解析就直接切分会产生大量噪声。

先看一个加载 PDF 的示例:

from langchain_community.document_loaders import PyPDFLoader loader = PyPDFLoader("docs/project_manual.pdf") pages = loader.load() print(f"加载页数: {len(pages)}") print(pages[0].page_content[:200]) print(pages[0].metadata)

loader.load()返回的是一个Document列表,每个Document包含page_contentmetadatametadata中通常会包含页码、来源路径等信息,这些信息在后续做来源引用时非常有用。

如果是批量加载文本类文件,可以使用DirectoryLoader

from langchain_community.document_loaders import DirectoryLoader, TextLoader loader = DirectoryLoader( "docs/", glob="**/*.txt", loader_cls=TextLoader, loader_kwargs={"encoding": "utf-8"}, ) documents = loader.load() print(f"加载文档数: {len(documents)}")

加载完成后,还需要做一轮文本清洗。PDF 解析经常出现页眉页脚重复、多余换行、多余空格等情况:

import re def clean_text(text: str) -> str: # 合并连续三个以上换行 text = re.sub(r"\n{3,}", "\n\n", text) # 合并连续空格和制表符 text = re.sub(r"[ \t]+", " ", text) return text.strip() for doc in documents: doc.page_content = clean_text(doc.page_content)

这里的检查点很简单:加载完成后,打印总字符数和文档条数,快速判断内容是否完整、是否出现大量乱码或空页。一个常见问题是扫描版 PDF,它本质上是一张张图片,pypdf解析出来可能只有空白内容,此时需要 OCR 技术配合处理,这属于另一条技术线。

2.3 文本分块策略与参数

大模型的上下文窗口有限,Embedding 模型通常也只适合处理一段几百字以内的文本,所以必须把长文档切分成多个文本块。分块质量直接影响后续检索质量。

推荐使用 LangChain 的RecursiveCharacterTextSplitter,它会按优先级逐级尝试分隔符,尽量保持语义完整:

from langchain.text_splitter import RecursiveCharacterTextSplitter text_splitter = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=50, separators=["\n\n", "\n", "。", "!", "?", ".", " ", ""], ) chunks = text_splitter.split_documents(documents) print(f"分块数量: {len(chunks)}") print(chunks[0].page_content)

参数含义:

  • chunk_size:每个文本块的最大字符数。
  • chunk_overlap:相邻文本块之间重叠的字符数。
  • separators:切分时使用的分隔符优先级列表。

为什么需要chunk_overlap?因为如果一句话被恰好切到上一块末尾,下一块没有开头,语义就断掉了。重叠部分可以让前后块之间保留上下文衔接。

分块大小对检索效果的影响可以用下表简单概括:

chunk_size优点缺点适合场景
偏小(200 左右)检索粒度细,定位准确上下文信息少,容易语义不完整事实型问答、关键词检索
适中(500 左右)平衡召回率和上下文中等长度,需要结合 overlap大多数通用文档
偏大(1000 以上)上下文完整,适合总结向量平均化严重,检索精度下降需要大段理解的技术报告

这里提到的“向量平均化”是指:当一段文本包含多个主题时,Embedding 会把所有信息压缩成一个向量,导致这段文本与任何单个问题的相似度都不高,检索阶段反而召不回相关内容。所以分块并不是越大越好。

2.4 向量化、存储与检索

文本块准备好之后,需要把它们转换成向量。向量化这一步由 Embedding 模型完成,它的目标是把语义相近的文本映射到向量空间里相近的位置。

中文场景可以优先选择支持中文的 Embedding 模型。下面使用BAAI/bge-m3,它是一个支持中英双语的模型,效果和本地部署成本都比较均衡:

from langchain_huggingface import HuggingFaceEmbeddings embedding_model = HuggingFaceEmbeddings( model_name="BAAI/bge-m3", encode_kwargs={"normalize_embeddings": True}, )

首运行时会下载模型权重到本地缓存目录。如果网络环境受限,可以提前在其他机器下载权重,放到本地目录后再通过model_name指定本地路径。

向量存储和检索使用 Chroma:

from langchain_community.vectorstores import Chroma vectorstore = Chroma.from_documents( documents=chunks, embedding=embedding_model, persist_directory="./chroma_db", )

执行完成后,./chroma_db目录下会保存向量索引。后续再次运行可以通过Chroma(persist_directory="./chroma_db", embedding_function=embedding_model)重新加载,而不需要重新分块和向量化。

检索最小示例如下:

query = "项目的部署环境有哪些要求?" retrieved = vectorstore.similarity_search(query, k=4) for i, doc in enumerate(retrieved): print(f"--- 第 {i + 1} 个结果 ---") print(doc.page_content[:150])

k=4表示召回与问题最相似的 4 个文本块。这一步是 RAG 中最关键的动作,后续生成质量完全取决于这 k 个文本块是否正确。

2.5 生成回答并验证

最后一步是把检索到的文本块和用户问题一起交给大模型。这里使用一个通用 Prompt 模板:

from langchain.prompts import PromptTemplate template = """你是一个严谨的知识库问答助手。请只根据下面的上下文回答问题。 如果上下文中没有足够信息,请直接回答“根据当前资料无法确定”,不要编造。 回答时尽量简洁,并注明信息来源。 上下文: {context} 问题:{question} 回答:""" prompt = PromptTemplate( input_variables=["context", "question"], template=template, )

通过 LangChain 的RetrievalQA串联检索和生成:

from langchain.chains import RetrievalQA # 假设 llm 已经初始化,具体初始化方式取决于你使用的模型服务 llm = None # 替换为你的 LLM 实例 qa_chain = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", retriever=vectorstore.as_retriever(search_kwargs={"k": 4}), return_source_documents=True, chain_type_kwargs={"prompt": prompt}, ) result = qa_chain({"query": "项目的部署环境有哪些要求?"}) print(result["result"])

需要把llm替换成真实可用的模型实例。常见的接入方式包括 OpenAI 兼容的 Chat 接口、Ollama 本地模型、vLLM 部署的服务等,使用哪种取决于你的资源和场景。

运行之后有两个校验点:

  1. 回答是否忠于检索上下文,还是出现了上下文里没有的内容。
  2. 返回的source_documents中是否真的包含能支撑回答的片段。

这两点往往比“回答流不流畅”更重要。如果回答流畅但内容完全来自模型自身记忆,那 RAG 的约束就没有起作用。

3. 影响RAG效果的关键参数与调优

很多 RAG 项目第一版跑通后效果不佳,问题往往不是出在大模型上,而是出在分块、向量化、检索策略和 Prompt 这几个环节。

3.1 分块大小与重叠参数

分块是 RAG 效果波动最大的环节之一。chunk_sizechunk_overlap需要根据文档类型调整:

  • 对于条款类文档,比如协议、规范,一个条款通常就是一个语义完整单元,可以按条款编号、章节标题切分,比固定字符数切分更可靠。
  • 对于技术手册,段落之间有较强上下文关联,建议使用较大的chunk_overlap,比如 80 到 100 字符。
  • 对于表格和代码块,固定字符切分会破坏结构,最好先把表格转成 Markdown 表格、代码块保持整体,再做切分。

判断分块是否合理的信号有三个:

  1. 检索召回的前 k 个块中,是否总包含正确答案所在的片段。
  2. 单个块内部是否只讲一个主题。
  3. 关键术语是否在块内首次出现时就有合理解释。

这里常犯的错误是直接照抄教程里的 500/50 参数。不同的 Embedding 模型对文本长度敏感度不同,落地前应该用你自己的文档做一组小实验,对比不同分块参数下的召回效果。

3.2 Embedding 模型与向量库选型

Embedding 模型决定“语义相似”怎么计算。中文场景常用的几类选择:

模型特点适用场景
BAAI/bge-m3中英双语,支持长文本,效果稳定多数中文知识库
m3e-base / m3e-large中文优化,轻量中文问答、小规模项目
text2vec-large-chinese中文匹配效果好中文短文本检索
商业 Embedding API调用简单,维护成本低对数据外发无限制的项目

这里有一个容易被忽略的点:检索阶段使用的 Embedding 模型必须和入库阶段一致。如果文档入库存量时用的是 A 模型,查询时换成了 B 模型,两个模型的向量空间不兼容,检索结果会完全不可用。

向量库选型同样重要:

向量库部署方式适合规模特点
Chroma本地/嵌入式小规模原型零运维,入门快
FAISS本地/服务中等规模检索性能高,无内置数据管理
Milvus独立服务大规模生产分布式、过滤、权限控制完整
pgvectorPostgreSQL 插件中等规模与业务库同库,避免多系统
Elasticsearch独立服务混合检索场景原生支持关键词和向量检索

学习阶段用 Chroma 就够了,生产环境则要考虑数据规模、并发、备份和权限,这些不是本地嵌入式向量库能直接承担的。

3.3 检索策略参数

RAG 生成质量的上限由检索决定。下面几个参数是排查效果问题时的重点关注对象。

k(召回数量):

  • 默认常见值是 3 到 5。
  • k太小,可能漏掉正确答案。
  • k太大,会引入噪声块,稀释上下文。
  • 调参时先看一个直观现象:正确答案通常排在第几位。如果正确答案稳定排在第一位,k=3通常够用;如果正确答案经常排到第五位以后,应该优先优化分块和 Embedding,而不是继续增大k

相似度阈值:

retriever = vectorstore.as_retriever( search_type="similarity_score_threshold", search_kwargs={"score_threshold": 0.5, "k": 4}, )

score_threshold表示只保留相似度超过阈值的文档。阈值调太高,容易召回为空;调太低,噪声块大量涌入。不同 Embedding 模型产出的分数范围不一致,不要直接套用别的项目的阈值,先打印一批真实查询的相似度分数,再决定阈值。

混合检索:

向量检索擅长语义匹配,但遇到精确 ID、编号、型号、全文包含的专有名词时,关键词检索往往更可靠。生产项目常见做法是向量检索 + BM25 关键词检索,再把两类结果做合并和去重,之后进入 Rerank 阶段。

Rerank:

召回阶段为了召回率会保留较多候选文档,Rerank 用一个专门的排序模型对这些候选重新打分,把最相关的文档排到最前面。这在文档数量较大的知识库中提升明显。常用的方案有bge-reranker等模型,使用时把它放在向量检索之后、生成之前。

3.4 Prompt 模板设计

Prompt 在 RAG 中承担的任务不是“让模型更有创意”,而是“把模型约束在事实范围内”。一份合格的 RAG Prompt 通常包含四类指令:

  1. 角色和身份:告诉模型它是知识库问答助手。
  2. 任务描述:要求基于上下文回答,而不是凭记忆。
  3. 约束条件:不确定时明确说不知道,不要编造。
  4. 输出格式:是否需要引用来源、是否使用列表、回答长度。

上面第 2.5 节给出的模板已经覆盖了前三点。再补充一个带来源引用的示例:

template = """你是知识库问答助手。请基于下面的上下文回答问题。 在回答末尾,列出你参考的文档编号。 约束: 1. 只使用上下文中的信息。 2. 如果上下文不足,回答“根据当前资料无法确定”。 3. 不要输出上下文外的推测。 上下文: {context} 问题:{question} 回答: 【结论】 【参考文档】 """

实际项目可以在context中携带文档的 metadata,例如来源:project_manual.pdf 第 3 页,模型就能在回答时引用具体来源。

3.5 从“能跑”到“精准”的建设路径

如果现有 RAG 表现不稳定,按下面的顺序逐层调优:

  1. 先确认文档加载和清洗是否正确,有没有乱码和空白页。
  2. 再检查分块是否切碎关键句子。
  3. 然后检查检索 TopK 里是否包含正确答案。
  4. 接着检查 Rerank 是否把正确答案排到前面。
  5. 最后检查 Prompt 是否把生成约束在上下文中。

很多团队跳过前几步直接换大模型,结果换了更强的模型,回答依然错误。原因往往是检索层已经丢了正确答案,生成端再强也没有用。

4. RAG知识库指标:怎么选、怎么理解、怎么用

判断 RAG 效果不能只靠肉眼抽查几条回答。肉眼看不全面,也无法在文档更新后做回归对比。要建立一套可重复的评测方式,把检索质量和生成质量分开衡量。

4.1 为什么要单独评测

一个端到端的 RAG 系统由“检索”和“生成”两个阶段组成。如果最终回答错误,可能是检索召回的内容不对,也可能是检索正确但生成时没有正确利用上下文。如果不分开评测,你就无法定位问题在哪一层。

所以评测要拆成两个维度:

  • 检索质量:模型有没有把正确答案对应的文本块召回出来。
  • 生成质量:模型有没有基于召回的文本块生成忠实回答。

4.2 检索质量指标

构建评测集时,准备若干条问题,并为每个问题标注“正确答案所在的文本块编号”。然后让检索器返回TopK结果,计算以下指标:

Hit Rate(命中率)

  • 含义:在数据集中,TopK结果里至少包含一个正确答案的查询占比。
  • 用途:判断检索是否基本可用。
  • 示例:10 个问题中有 8 个在 Top5 里召回了正确答案,Hit Rate@5 = 0.8。

MRR(Mean Reciprocal Rank,平均倒数排名)

  • 含义:对每个查询,取第一个正确答案的排名倒数,再对所有查询取平均。
  • 用途:判断正确答案排名是否尽量靠前。
  • 示例:两个查询中正确答案分别排在第一位和第三位,MRR = (1/1 + 1/3) / 2 = 0.667。

Recall@K 和 Precision@K

  • Recall@K:TopK 召回的相关文档占全部相关文档的比例。
  • Precision@K:TopK 中相关文档占 TopK 的比例。
  • 用途:在“一个查询对应多个相关片段”的场景中使用。

下面是一个模拟命中率计算的 Python 示例:

def hit_rate(retrieved_ids, ground_truth_ids): hit_count = 0 for retrieved, truth in zip(retrieved_ids, ground_truth_ids): if set(retrieved) & set(truth): hit_count += 1 return hit_count / len(retrieved_ids) # 示例数据 retrieved_ids = [ [12, 34, 56, 78], # 第一个查询召回的块ID [10, 20, 30, 40], # 第二个查询召回的块ID ] ground_truth_ids = [ [56], # 第一个查询的正确答案块ID [99], # 第二个查询的正确答案块ID ] print(hit_rate(retrieved_ids, ground_truth_ids)) # 输出 0.5

这段代码只是用 Python 原生列表模拟计算,实际项目中把向量库返回的Documentmetadataid传入即可。

4.3 生成质量指标

生成质量的评估比检索更复杂,因为它涉及语义判断。社区中比较常用的三类指标:

Faithfulness(忠实度)

  • 含义:回答内容是否完全由上下文支持,没有编造。
  • 判断方式:逐个检查回答中的事实点,是否都能在上下文中找到依据。
  • 典型场景:回答中出现了“根据文档,该系统支持 XX 功能”,但上下文中根本没有提到 XX,则忠实度低。

Answer Relevance(答案相关性)

  • 含义:回答是否针对用户问题,而不是答非所问。
  • 判断方式:删除上下文后,单独看回答和问题的相关性。
  • 典型场景:用户问“部署需要什么硬件”,回答却介绍软件架构,答案相关性低。

Context Relevance(上下文相关性)

  • 含义:检索出的上下文是否与问题相关。
  • 判断方式:逐句检查上下文中的内容有多少比例和问题相关。
  • 典型场景:问题问的是“配置项怎么改”,召回结果却全是“产品简介”的内容,上下文相关性低。

这三类指标在 Ragas 等评测库中有对应的实现思路。Ragas 采用 LLM 辅助打分,即把上下文、问题、回答组织成评测 Prompt,让一个强模型输出打分。使用时要留意:LLM 辅助评测本身也有偏差,因此评测模型最好与生成模型不同,避免自评偏差。

4.4 评测集和落地方式

一个完整的 RAG 评测流程包含:

  1. 构建评测集。从真实场景中收集 50 到 200 条问题,越多越能反映真实分布。问题要覆盖简单事实查询、组合查询、边界查询。
  2. 标注正确答案。为每条问题标注检索层面的正确块 ID 和生成层面的期望回答要点。
  3. 运行评测。分别计算检索指标和生成指标。
  4. 对比回归。修改分块参数、更换 Embedding 模型、调整 Prompt 后,重新运行同一套评测集,用指标对比效果变化。

评测集分为“检索评测集”和“生成评测集”。检索评测集只包含问题和正确答案块 ID,不需要完整参考答案;生成评测集还需要参考答案或至少标注回答要点。这样拆开,可以在调检索时不重复评估生成。

指标怎么理解要结合场景:

  • 如果业务对答案准确性要求极高,优先保证 Faithfulness。
  • 如果业务关注用户能否快速找到信息,优先优化 Hit Rate 和 MRR。
  • 如果回答经常跑题,先检查 Answer Relevance。
  • 如果回答内容完整但引用的上下文不对,先检查 Context Relevance。

5. 进阶路线:Agentic RAG、Graph RAG、OAG 与工具化平台

基础 RAG 已经能解决不少问题,但面对复杂查询、跨文档整合、高度结构化文档时,需要演进到更高级的架构。

5.1 Agentic RAG:把检索变成可规划的步骤

经典 RAG 是“一问一检”:用户提交问题,系统检索一次,生成一次回答。Agentic RAG 则让大模型作为 Agent,自己判断是否需要检索、检索几次、使用什么工具。

典型场景包括:

  • 用户问题同时涉及多个文档,需要多次检索并整合。
  • 用户问题本身不清晰,Agent 先反问澄清,再检索。
  • 用户需要执行“先查条件,再筛选数据”的复合流程。

实现思路上,Agent 通过 ReAct 循环工作:接收用户问题,决策是否调用检索工具,观察检索结果,再决定下一步动作,最终生成回答。LangChain 的create_retriever_tool可以把检索器包装成一个 Agent 可调用的工具。

Agentic RAG 的优势是灵活,代价是复杂度上升:模型可能做出错误决策、调用次数增加、延迟变高、错误可能被多步放大。生产环境中要给 Agent 设置最大迭代次数、单次检索返回数量上限,并对超时和失败做兜底。

5.2 Graph RAG 与 Ontology RAG:让知识组织更精确

Graph RAG 是在 RAG 链路中引入知识图谱技术。与向量库只存文本块不同,Graph RAG 把实体、关系和属性存成图结构。查询时先通过实体匹配定位到图节点,再沿关系扩展相关上下文,最后把扩展结果交给生成器。

它的典型优势在于处理“实体关系型”问题,比如:

  • “某个协议中,A 网元与 B 网元的接口流程是什么?”
  • “某个专利的权利要求依赖哪些从属权利要求?”
  • “某类故障会导致哪些下游模块受影响?”

这类问题如果只靠向量相似度检索,往往只能召回包含关键词的片段,无法沿着关系链路找到完整答案。Graph RAG 更适合。

Ontology RAG 更进一步,在图中定义清晰的类型、属性和约束关系。比如在 3GPP 协议文档中,定义“网元”“接口”“流程”“参数”等类型,以及它们之间的关联关系。检索时先判断问题涉及的实体类型,再按本体约束检索,能显著提高召回准确率。

它的落地成本也比较高:需要人工或半自动抽取实体关系,构建和维护图谱,对文档结构变化敏感。适合协议、专利、法规等高度结构化、长期稳定的文档领域。

5.3 RAG 与 OAG 的差异

社区讨论中还有一个概念是 OAG,即 Online Augmented Generation,在线增强生成。相对于经典 RAG 的“离线构建索引 + 在线检索生成”,OAG 更强调在线检索与生成的实时联动,典型做法是从搜索引擎、实时 API、实时数据库获取最新信息,并即时组织回答。

这两者的边界在工程中并不需要严格划分。离线知识库适合公司内部私有文档,在线检索适合时效性要求高的公开信息。实际系统往往同时包含两条链路:先查内部向量库,查不到或需要最新资讯时再调用在线搜索引擎,最后统一交给模型生成。设计时重点不是争论概念,而是明确数据源、查询路由和结果合并策略。

5.4 常用框架与平台选型

工程落地时,选择框架和平台会直接影响开发效率。常见的选择如下:

工具/框架定位适合场景
LangChain开发框架深度定制 RAG 流程、需要细粒度控制
LlamaIndex开发框架文档索引和知识库构建场景
Dify可视化平台快速搭建应用、多人协作、包含工作流
AnythingLLM本地知识库工具个人和小团队快速使用私有知识库
Spring AIJava 生态框架已有 Java 技术栈的团队做 AI 集成

选型原则很简单:如果你的核心能力是业务逻辑和模型策略,直接用 LangChain 或 LlamaIndex;如果团队需要快速做应用演示,Dify 这类平台能省去很多前端和运维工作;如果是 Java 团队,优先考虑 Spring AI,避免引入异构技术栈。

6. 生产落地:常见问题、排查链路和最佳实践

6.1 排查链路:从用户输入到回答逐层定位

RAG 问题的定位顺序应该是:输入 -> 文档加载 -> 分块 -> 向量化 -> 检索 -> 生成。每一层都可能引入错误,排查时按层检查,不要跳过。

排查层核心问题检查方法
用户输入问题本身是否清晰打印原始 query
文档加载文档是否被正确解析检查页数、字符数、乱码
分块内容是否被切碎打印样本块,看语义是否完整
向量化向量是否有效做相似度自检,同一句话检索自己
检索正确答案是否被召回打印 TopK 文档,人工核对
生成模型是否正确利用上下文对比上下文与回答的事实点

6.2 常见坑和解决方案

问题现象常见原因检查方式处理建议
回答总是“不知道”阈值过高或检索结果为空打印检索结果和相似度分数降低score_threshold,检查知识库是否包含答案
回答流畅但与文档不符模型依赖自身记忆,没有遵循上下文对比回答与检索内容强化 Prompt 中的约束,引入来源引用
检索结果全是相近内容分块过大导致向量平均化打印分块内容和检索 TopK减小 chunk_size,按文档结构调整分块
某类关键词永远检索不到向量检索对精确编号不敏感用关键词直接搜索原文档加入 BM25 关键词检索,做混合检索
换模型后检索效果变差入库和查询使用了不同 Embedding检查两个阶段模型名统一入库
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/31 12:38:45

Codex进化简史:从AI编程助手到Agent工作流的工程实践

如果你最近在刷技术社区,大概率会注意到一个现象:关于 Codex 的讨论密度突然变高了。有人问“Codex 官网登录入口在哪里”,有人贴出 unable to locate the codex cli binary 的报错截图,还有人在研究怎么把 Codex 接入 DeepSeek…

作者头像 李华
网站建设 2026/8/31 12:38:39

LVGL 9.0移植到STM32F746G全流程与性能优化指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/8/31 12:28:47

AI任务编排实战:holaOS运行层从单任务到批量落地

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/8/31 12:26:57

用Agentic Workflow啃Legacy HPC代码:以GAMESS双电子积分为例

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/8/31 12:25:53

Ubuntu更改最大化最小化按钮大小,sudo与su

/etc/apt/sources.list#编辑源信息 脚本中使用apt-get,平常在交互式shell中就使用apt apt更新(2014年发布),apt-get(1998年发布) apt解决了apt-get的一些设计错误,但是apt-get是向后兼容的,因此在脚本中使用apt-get#最常用的包管理命令分散在apt-get,apt-cache,apt-config中 #a…

作者头像 李华
网站建设 2026/8/31 12:25:33

渲染实现某个PAGE能对特定组查看

想要实现某个page能对特定组可见&#xff0c;能通过渲染实现 代码如下 加一句visibleWhen“owning_groupDBA” //渲染文档内容 <?xml version"1.0" encoding"UTF-8"?> <!--Copyright 2012. Siemens Product Lifecycle Management Software Inc.…

作者头像 李华