news 2026/9/29 18:50:04

Agent知识获取管道:从零搭建RAG的完整实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Agent知识获取管道:从零搭建RAG的完整实战指南

这几天在整理AI Agent系列的时候,后台收到好多朋友的私信,说前面三篇把Agent的整体框架、规划能力和工具调用都聊完了,但一落地就卡在一个问题上:Agent的知识到底从哪里来?问点公司内部的东西就哑火,问点训练截止日期之后的事就胡编。这其实就是缺了知识获取这块拼图。作为这个系列的第四篇,咱们把知识获取管道这个核心环节彻底聊透,也就是RAG(检索增强生成)的基础。这篇会从Why讲到How,再带你把最小可用的RAG管道亲手搭起来,把里头的坑都踩一遍。

如果你正在从0到1搭Agent,或者已经在用LangChain、Spring AI这类框架做开发,但总觉得检索效果不稳、回答幻觉压不住,那这篇就是给你准备的。我尽量用做工程的思路来讲,不堆术语,保证看完能直接上手改自己项目里的那套RAG。

1. 为什么Agent需要一条“知识获取管道”

先说个直觉。你把大模型当成一个刚毕业、脑子极其聪明但没上过班的实习生,它脑子里装的是学校里学的通识内容,但公司的产品手册、售后工单、技术规范、项目总结,它一概不知道。你总不能让每个实习生入职前都重新回炉重训一遍,那就太慢了。所以公司一般会给他配一个资料库,让他遇到不懂的问题就去查。这个“资料库+查资料的流程”,放到Agent身上就是RAG。

1.1 Agent的知识从哪来:三件套的补位逻辑

很多人一提到Agent的知识,第一反应就是“继续训练”或者“微调”。但实际上,一个合格的Agent会同时使用三种知识来源,它们的定位完全不同。

第一是参数记忆,也就是模型在预训练阶段从海量语料里学到的知识,沉淀在权重里。这类知识覆盖面广,但有两个明显问题:一个是时效性差,训练截止之后的新事件完全不知道;另一个是精度不足,模型只能记得“大概有这么回事”,记不住具体的编号、日期、私有细节。

第二是上下文窗口,也就是你在调用模型时直接塞给它的内容。这部分知识准确、可控,但容量有限。现在虽然各家都把上下文拉到了几十万甚至上百万token,但塞多了之后模型注意力会稀释,而且成本直线上升,每次调用都得多付好几倍的token费,响应时间也会明显变长。

第三就是外部检索,也就是RAG。它把知识放在模型外部,需要的时候通过检索把最相关的那一小部分内容捞出来,拼进上下文里让模型参考。跟你让实习生去翻资料库是一个逻辑,不依赖训练,不依赖大窗口,知识随时可以更新,还能精确追溯到来源。

这里我想强调的是,这三者不是互相替代的关系,而是各管一段的补位关系。基础通识靠参数记忆,少量精确事实靠窗口写入,大量动态私有知识靠RAG。我见过不少人非要用微调去解决“公司文档检索”的问题,结果训完一轮发现文档改几个字就又得重训,典型的用错工具。

1.2 RAG不是新概念,但Agent让RAG变了

RAG这个思路其实早在2020年前后就有了,最初是Lewis那篇经典的检索增强生成论文。但当年RAG的用法很单一——用一个检索器从非结构化文本里取段落,拼接给生成器。到了今天做Agent,RAG不再只是一个“查文档+生成”的静态流程,而是变成了Agent行动链路里的一根管道,需要跟规划、工具调用、记忆管理这些模块频繁交互。

这套系列一路走到第四篇,你应该有感受:Agent本质上是个循环系统,感知外部信息、决策下一步动作、调用工具、观察结果再继续。RAG在这套体系里的角色,是作为Agent的一个“外部知识接口”,平时不用,用到的时候再按需去取。

而且Agent场景下的RAG比传统问答复杂得多。传统问答是单轮检索就能答上来的问题,Agent场景里经常是多跳的,比如“找出上季度所有产品线里退货率最高的SKU,再对比这个SKU在口碑渠道的表现”,这需要先拆解子问题,做多轮检索,再汇总推理。这也正是现在最热门的Agentic RAG要解决的问题,也是为什么我建议你先把基础RAG吃透,因为那些花哨的演变,底层还是这套索引、检索、生成的管道。

1.3 微调 vs RAG:两个旋钮怎么选

聊完Agent的三件套,我来把微调和RAG的适用场景做个清晰的区分,因为这是每次技术选型时都绕不过去的权衡。

先看一组对比维度:

对比维度微调RAG
更新成本高,每次数据变化都要重训低,换掉文档重建索引即可
知识来源固化在参数里,不可溯源保留原文,可引用来源
精确性容易编造只要检索到了就能精确复述
数据量要求需要一定规模的标注样本少量文档也能干
改风格/改能力擅长,比如让模型按特定口吻说话不擅长,这不是检索能解决的
延迟与成本推理成本不变额外增加检索与拼接成本

我个人的经验是,如果你想让模型学会一种“行为模式”,比如按特定格式输出、学会某种解析逻辑、或者迁移某种语言风格,那就用微调;如果你想让模型知道“事实”,比如产品参数、内部规范、项目记录,那就用RAG,别犹豫。市面上90%的“知识类”需求,其实都是事实类需求,用RAG都能解决。

还有人问我,能不能微调和RAG一起上?当然可以,实际工程里两者往往是组合使用的。比如先微调一个小模型让它的指令遵循能力变强,再挂上RAG管道补知识。但前提是先把RAG这层做好,因为RAG的检索质量直接决定了Agent的上限,这跟地基是一个道理。

2. RAG管道的核心拆解:索引、检索、生成

RAG之所以被叫做“管道”,是因为它是由几个串在一起的环节组成的。每一环都在做一件事:把不可直接检索的原始文档,变成模型可以直接消费的上下文。这一节我把三个核心环节逐一拆开讲,每个环节的细节都直接影响最终效果。

2.1 索引阶段:从文档到向量的全流程

索引阶段要解决的问题是:怎么让机器大海捞针变成精准捞针。原始文档是PDF、Word、HTML、Markdown,机器读不懂语义,我们要做的是把这些文档处理成“可以被语义检索的结构”。

先把完整流程列出来:加载 → 解析 → 切分 → 向量化 → 入库。

加载和解析这一步看起来简单,其实坑最多。PDF要区分是否带OCR,扫描件必须先OCR;表格数据要考虑保留表头;Word里可能混着图片、批注、页眉页脚。我用过很多种解析方案,常见的比如PyPDF、pdfplumber、unstructured、markitdown。如果你处理的文档格式特别杂,我建议直接用unstructured这类容器级解析器,它对格式的包容度高得多。

切分这一步是索引质量的重中之重。一个常见的错误是把整个文档作为一条记录扔进向量库,结果检索时召回的是整个文档,塞进上下文既占窗口又不精确;另一个极端是把文档切得特别碎,一句话就切一块,结果每块内容语义不完整,检索出来也拼不出完整答案。切分要遵循的核心原则是:语义完整性优先,字符数其次。

接下来的向量化,是把文本转成高维向量表示,让相似的语义在向量空间里距离更近。这一步的决定权在Embedding模型手里。关于模型选型我放在2.4节细讲。

最后一步入库,就是把文本和向量存储到向量数据库里,并建立索引加速检索。常见的选型有开源的向量库(Chroma、Qdrant、Weaviate、Milvus)和带向量能力的传统数据库(Postgres的pgvector、Elasticsearch的向量检索)。我建议,如果并发量不大、数据量在百万级以下,先不要上重型的分布式向量库,直接用pgvector或Qdrant单机版就够了,等量级上来了再迁移。

2.2 检索阶段:不只是向量,还要考虑召回质量

检索阶段的目标是在给定的Query下,从向量库中取出最相关的K个片段。我们通常用召回率和**命中率(hit rate)**来衡量检索质量:给你一组标准问题和答案文档,如果检索出包含答案的那篇文档,就是一次命中;再细化一点衡量排序质量的指标是MRR(Mean Reciprocal Rank),它更关注正确答案排在第几位。

现在的检索方式我建议至少从这三个角度去考虑:

  • 向量检索:适合语义匹配,能搜出表面用词不同但意思相近的文本,但对精确的专有名词、编号、代码片段不太友好。
  • 关键词检索(BM25):适合精确匹配,搜人名、型号、政策编号这种,命中率高,但理解不了同义改写。
  • 混合检索:把向量检索和BM25结果合并,再做rerank。这是目前最稳妥的方案,能同时兼顾语义和精确匹配。

我在实际项目中几乎都会上混合检索,因为很多企业文档里都有大量“精确词”,比如产品型号SR-1000、工单号TK20260113,纯靠向量检索很容易漏,因为模型没把型号作为最重要的特征来编码,而BM25对这种词是天然强项。

检索出来之后,还有一个经常被忽略的环节:重排序(Rerank)。初次检索的Top-50里可能有10条是相关的,但你给模型的上下文窗口装不下50条,只能放Top-5。如果直接用初次检索的分数来决定Top-5,效果往往不理想,因为向量分数和真正的相关度并不是完美对齐。这时候用一个专门的Rerank模型(比如bge-reranker系列)把这50条重新打分排序,再取Top-5,效果会有质的提升。这是RAG最容易出效果的细节之一,代价只是多几十毫秒延迟。

2.3 生成阶段:Prompt设计决定了RAG的上限

检索拿到的片段不会自己变成答案,它们必须被合理组织进Prompt里,约束模型的动作。很多人以为RAG就是把检索到的文本一股脑塞给模型,让它“自由发挥”,结果模型还是按自己记忆答,或者直接编造。生成阶段的Prompt设计,是RAG里最能以小博大的部分。

一个合格的基础RAG Prompt至少需要包含这几个要素:

  1. 角色与背景:告诉模型它是一个“基于给定知识库回答问题的助手”,不是随便聊天。
  2. 知识上下文:把检索到的片段原样放进去,最好标注出处,比如“【文档1】产品手册第3页”,方便模型在回答时引用。
  3. 严格指令:明确“只基于给定上下文回答,如果上下文中没有,直接回答不知道,不要编造”。
  4. 回答格式:约定是否分点、是否带引用、长度上限等。

用一段伪代码来描述这种结构就是:先设定角色,再给知识上下文,再下指令限制。不过这里有个体验上的关键点,就是我们虽然要求模型“不知道就直说”,但在实际产品里,直接返回“不知道”往往不够友好,我们更希望它顺着已有资料给出“基于现有资料能确认的部分”和“无法确认的部分”,这类交互设计需要结合业务场景调,不是一次能调好的。

2.4 基础设施选型:Embedding模型与向量库

选型和工程质量强相关。我把我踩过坑之后总结的选型经验直接写出来。

先看Embedding模型。目前中文场景里,国产的开源Embedding模型已经非常能打了,常见的有BAAI的bge系列(bge-large-zh、bge-m3)、阿里的text2vec系列、智源的text2vec-bge,以及OpenAI的text-embedding-3-small/large这类商业API。我的建议是,如果你的文档以中文为主、又有私有化诉求,优先用bge-m3,它支持中英双语,还能处理最多8192长度的文本,对长文档切分宽容度高;如果预算允许、追求极致效果,可以考虑商业API,但要接受数据出境或调用成本的代价。

再来是向量库的选型,我用过几种典型的,简单对比一下:

向量库适合场景优点注意点
Chroma本地原型、小规模零配置、起服务快生产可靠性一般
Qdrant中规模生产过滤器丰富、API顺手需要单独部署
Milvus大规模生产性能强、分布式运维成本高
pgvector已有Postgres复用数据库、事务友好大并发稍弱

我的个人意见是,基础项目、学习阶段用Chroma就行;做到真实产品,先考虑Qdrant或者pgvector。别一上来就堆Milvus,你可能会花很多时间在运维而不是业务上。

3. 实操:从零搭一条最小可用的RAG管道

理论聊再多,不如上手跑一遍。这一节我会带你从零构建一个最简但完整可用的RAG管道,用到的技术栈是Python + LangChain + Qdrant(或Chroma)+ bge-m3。你可以直接照着我这套流程跑通,然后再去替换成你业务里的组件。

3.1 环境准备与数据准备

先准备好环境。我建议用Python 3.10以上版本,建一个干净的虚拟环境。

python -m venv rag_env source rag_env/bin/activate pip install langchain langchain-community langchain-huggingface chromadb qdrant-client bge-m3 fastapi uvicorn

安装过程里最可能出问题的就是torch和transformers,bge-m3依赖它们。如果你的机器没有GPU,也完全可以跑,就是Embedding的批量计算会慢一点,不影响功能。

数据准备方面,我这次用一个我比较常用来演示RAG的案例:拿几篇关于某智能家居产品的手册和售后FAQ文档。你也可以用自己手头的任何Markdown或PDF文档来替换,但我建议控制在5到10篇、每篇几千字的规模,先把流程跑通,不要第一次就上几十万字的资料库,否则出问题都定位不到是哪一环的数据导致的。

实际动手前,先把文档统一放入一个data目录:

data/ ├── 产品手册.md ├── 售后常见问题.md └── 安装调试指南.md

3.2 索引链路代码

找到管道的第一棒,加载并切分文档。我直接贴一份可运行的代码,然后逐段解释。

from langchain_community.document_loaders import DirectoryLoader, TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_huggingface import HuggingFaceEmbeddings from langchain_community.vectorstores import Chroma # 1. 加载目录下所有md文件 loader = DirectoryLoader("./data", glob="*.md", loader_cls=TextLoader) docs = loader.load() print(f"加载了 {len(docs)} 份文档") # 2. 切分文档 splitter = RecursiveCharacterTextSplitter( chunk_size=300, chunk_overlap=60, separators=["\n\n", "\n", "。", "!", "?", ";", " ", ""], ) chunks = splitter.split_documents(docs) print(f"切分为 {len(chunks)} 个片段") # 3. 加载Embedding模型 embeddings = HuggingFaceEmbeddings( model_name="BAAI/bge-m3", encode_kwargs={"normalize_embeddings": True}, ) # 4. 写入向量库 vectorstore = Chroma.from_documents( documents=chunks, embedding=embeddings, persist_directory="./chroma_db", ) print("索引构建完成")

这里有几个细节值得展开讲。

第一个是分割符的选择。中文文档跟英文文档不一样,英文天然按空格和换行切,中文你如果不把句号、问号、分号加进separators,切出来的片段可能会从句子中间硬切开,语义完整性就很差。上面代码里我把中文标点放在比较靠前的位置,就是为了让切分器优先在句子边界处断开。

第二个是chunk_size用了300。这个数字不是拍脑袋,是从实际效果出发的。如果chunk_size太小,片段可能只有一句话,检索出来信息量不够;如果太大,比如1000甚至2000,虽然窗口利用率高,但检索的粒度变粗,容易把不相关的内容一起卷进来,精度下降。300到500这个区间,是绝大多数中文字档的甜点区。

第三个是Embedding模型传参。normalize_embeddings=True会让向量归一化。因为很多向量库计算相似度用的是余弦相似度,而对向量做归一化之后,内积就等价于余弦相似度,这样可以在某些计算场景下提升速度,同时也不影响语义表达。

3.3 检索链路代码

索引建好之后,就是检索环节。这一节先把最简单的向量检索跑通,然后再加混合检索和Rerank。

from langchain_community.vectorstores import Chroma vectorstore = Chroma( persist_directory="./chroma_db", embedding=embeddings, ) # 基础向量检索 query = "设备无法连接Wi-Fi,应该怎么排查?" retriever = vectorstore.as_retriever(search_kwargs={"k": 4}) results = retriever.invoke(query) for i, doc in enumerate(results): print(f"Top {i+1}: {doc.page_content[:80]}...") print(f"来源: {doc.metadata}")

如果你只用向量检索,到这里其实已经能跑通一个最简RAG了。但我前面提过,纯向量检索对精确词匹配有盲区,所以在真实项目里建议直接上混合检索。LangChain里可以用EnsembleRetriever把BM25检索器和向量检索器组合使用。

from langchain_community.retrievers import BM25Retriever from langchain.retrievers import EnsembleRetriever # 把切分好的chunks转成BM25检索器 bm25_retriever = BM25Retriever.from_documents(chunks) bm25_retriever.k = 4 # 向量检索器 vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 4}) # 组合检索器,权重各一半 ensemble_retriever = EnsembleRetriever( retrievers=[bm25_retriever, vector_retriever], weights=[0.5, 0.5], ) results = ensemble_retriever.invoke(query)

混合检索的本质是一个加权投票逻辑。两路检索器各自捞出候选,然后按权重合并,取最终得分最高的Top-K。这样做的好处是,语义相关但字面上不匹配的内容靠向量一路捞出来,型号、编号、术语这类精确匹配靠BM25一路保住,两边互补,基本不会翻车。

如果想让结果再上一个台阶,可以再接一个Rerank。Rerank模型和Embedding模型是两种不同的模型,Embedding只需要把Query和文档编码成向量,Rerank则是直接把Query和文档拼起来,输入模型打分。这个过程的语义交互更充分,所以排序更准,但代价是需要多一次模型推理。这里我给出一个用FlagEmbedding加载bge-reranker的示例:

from FlagEmbedding import FlagReranker reranker = FlagReranker("BAAI/bge-reranker-v2-m3", use_fp16=True) # 先混合检索出Top-20 candidates = ensemble_retriever.invoke(query) # 设 k=20 # 再对候选结果打分排序 pairs = [[query, doc.page_content] for doc in candidates] scores = reranker.compute_score(pairs, normalize=True) sorted_results = sorted( zip(candidates, scores), key=lambda x: x[1], reverse=True, )[:5] for doc, score in sorted_results: print(f"Score: {score:.4f}, 内容: {doc.page_content[:60]}")

注意,Rerank的输入语序是query在前、文档在后,不要反了;用normalize=True可以拿到0到1之间的分数,方便你设置过滤阈值。我在生产环境里的经验是,可以把阈值设在0.35左右,低于这个分数的片段,相关性太低,大概率会干扰生成质量,干脆不喂给模型。

3.4 生成链路与完整对话闭环

检索到了,接下来是让大模型基于检索结果生成回答。这一步比较简单,但Prompt的写法很关键。我贴一个我自己在用的Prompt模板。

from langchain_core.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI prompt = ChatPromptTemplate.from_messages([ ("system", """你是知识库问答助手。请严格基于以下备选知识片段回答用户问题。 规则: 1. 只使用知识片段中的信息,不要依赖你的内部记忆。 2. 如果片段内容不足以回答,请明确说“根据现有资料无法回答”,不要编造。 3. 回答时尽量在句末标注参考片段编号,格式如[1]、[2]。 4. 用简洁、通顺的中文作答,不要复述片段原文。 知识片段: {documents} """), ("human", "{question}"), ]) llm = ChatOpenAI(model="gpt-4o-mini", temperature=0) def format_docs(docs): return "\n\n".join( f"[{i+1}] {doc.page_content}" for i, doc in enumerate(docs) ) # 组装最终查询 docs = sorted_results # 或者直接用 retriever 的结果 chain_input = { "documents": format_docs(docs), "question": query, } response = llm.invoke(prompt.format_messages(**chain_input)) print(response.content)

这里我特别注重temperature=0。RAG场景本质是“查到什么答什么”,不需要创造性,温度调高只会增加自由发挥的概率,幻觉就是这么来的。如果你想验证模型是否引用了正确的片段,可以在代码里限定“只使用[1]、[2]编号内容”之类的约束。

到这里,最简RAG管道已经完整闭环了:文档加载 → 切分 → Embedding → 入库 → 检索 → Rerank → 拼Prompt → 模型生成。你可以把这段代码封装成一个RAGEngine类,再包上FastAPI对外提供服务,一个基础的Agent知识管道就成型了。

3.5 参数调优:chunk_size、top_k的取舍

管道能跑通之后,下一步就是调参。我重点说两个最影响效果的参数。

chunk_size的取舍:切分太小,比如100,片段语义碎片化,检索时即使召回了也可能只是答案的半个上下文;切分太大,比如1000,会把很多无关信息包裹进同一个片段,导致检索精度下降。以中文文档为例,我建议从300开始,配合overlap 60。如果你的文档以技术手册、条款类为主,句子较长、逻辑严密,可以把chunk_size提到400到500;如果你的文档是FAQ、对话记录这种短句居多的类型,200到300会更合适。不管选什么,overlap建议控制在chunk_size的15%到20%之间,保证相邻片段之间不丢上下文。

top_k的取舍:k太小,可能漏掉关键信息;k太大,即使有Rerank,给模型输入的无关内容也会增多,干扰模型判断。基础场景下我建议k=4到5;如果文档片段普遍偏短,可以适当提到6到8。你还可以根据Rerank分数动态剪裁,把低分片段过滤掉,这比固定k值要可靠得多。

4. 常见问题与排查技巧实录

最后这部分,我把自己在多个RAG项目里踩过的坑和排查思路整理出来。这些问题几乎是每个上手RAG的人都会遇到的,我尽量写得直白,直接给你排查路径和解决办法。

4.1 检索命中率低:先分辨是“没召回到”还是“排序不对”

如果模型回答得驴唇不对马嘴,不要急着改Prompt,先检查检索这层。我提供了一个快速排查方法:写一个评估脚本,把你有标准答案的几十个问题跑一遍,统计Top-5中是否包含正确答案片段。

常见原因和对应的解决办法:

现象可能原因解决方向
Top-5里根本没有答案片段切分不合理,答案被切碎拆分调整chunk_size和overlap
答案在Top-10里但不在Top-5排序不精准加Rerank,调大初筛K值
完全检索不到,连关键词都搜不到文档本身没有该信息,或Embedding模型不够好确认资料库覆盖,更换更强的Embedding模型
检索只命中了部分文档,跨文档内容缺失切分把跨文档关联切断考虑增加父子片段结构或文档摘要

这里我特别推荐一个思路,叫做父文档检索(Parent Document Retriever)。它的逻辑是:索引时切得很细(比如200字),用于精准检索;但检索到后,把该片段所属的父级文档块(比如800字)返回给模型。这样既保证了检索的精度,又让模型拿到更完整的上下文。LangChain里自带ParentDocumentRetriever,可以直接用,很多命中率问题都能被这个方案救回来。

4.2 回答依旧出现幻觉:问题出在“约束”而不是“检索”

如果你的检索明明命中正确片段,模型回答还是离谱,那八成是Prompt约束不够或温度设置太高。我排查幻觉的顺序是:先确认检索结果里是否真的有正确答案,再看Prompt里有没有写清楚“没有资料就直说不清楚”,最后检查temperature参数。

还有个小技巧:在Prompt里强制模型先引用片段编号再回答。比如写成“请先判断哪些知识片段与问题相关,并在回答中标注[编号]”。这一步能让模型在生成时对检索内容保持注意力,而不是自说自话。另外,你可以在生成后加一个事实一致性校验环节,把模型的回答和检索片段同时丢给模型,让它检查回答是否严格被片段支持。这个过程会多花一次模型调用,但能显著降低幻觉,适合对准确性要求高的场景。

4.3 知识割裂与多跳问题:别让RAG停留在“单次检索”

现在回到热词里反复出现的“知识割裂”这个现象。单轮RAG在这类问题上确实会栽跟头:一个复杂问题需要把多个来源的知识组合起来才能回答,靠一次检索根本拼不出完整答案。

比如这样一条查询:“我们上一季度退货率最高的产品线,在社区里的口碑和关键差评点是什么?”这必须拆成两步摞起来:第一步检索产品线退货数据,第二步用这个产品线名字检索社区口碑。这时候基础的“Query → 检索 → 生成”管道就不够用了,得让Agent参与其中。

我在工程上一般分三步走:

  1. Query改写:基于原始问题,用LLM生成多个子查询或改写后的查询,提高召回面。
  2. 多路检索:把每个子查询都跑一遍检索,合并结果,去掉重复。
  3. 多跳推理:把第一轮检索结果作为下一轮查询的上下文,循环迭代,直到答案置信度足够。

这就是从基础RAG过渡到Agentic RAG的路径。你的Agent需要在这个管道里扮演“指挥官”,决定下一步查什么、查到的内容能否支撑当前问题。所以我才一直强调,基础RAG不是只学一个“能跑的demo”就够了,你得理解它是如何被编排进Agent循环里的。

4.4 从基础RAG到Agentic RAG的演进路线

既然聊到这里,我干脆把RAG的演进谱系也理一下,方便你进阶的时候有个地图。

  • Naive RAG(基础RAG):就是本篇搭建的这条管道。适合知识库问答,单轮检索,实现简单,效果稳定。
  • Advanced RAG(进阶RAG):在基础之上增加了查询改写、Rerank、HyDE(假设性文档Embedding)、父文档检索等优化手段,检索质量和鲁棒性大幅提高。
  • GraphRAG:把知识抽取成图结构,用实体关系来回答多跳复杂问题。适合做“文档间关联分析”,比如跨多份文档找因果关系,但搭建成本高,需要引入图数据库。
  • Agentic RAG(智能体RAG):让Agent自主编排检索策略。它是当前最贴近“知识获取管道”演进的形态,比如Agent先判断要不要搜,搜哪类知识,搜完不够再规划下一步。

这些进阶方向,我会在后续系列文章里逐个展开。但底层的东西,索引怎么做、切分怎么切、检索怎么评、Prompt怎么约束,都是本篇讲的基础,跑不掉。所以你今天搭出来的这条最小管道,并不是白搭的,它就是你后续所有进阶的骨架。

最后再跟你分享一个我自己的习惯做法:每次搭建RAG管道,我都会先写出一个包含50条标准问题的评估集,问题里刻意混合了语义相近但答案不同的内容、跨文档引用的内容、以及知识库根本不覆盖的内容。跑通之后先按4.1里的思路看命中率,再人工检查20条左右的回答质量。这个评估集看着笨,但它能在我每次调整参数的时候给出明确的反馈,也算是给自己装了一个“质检阀”。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 18:49:48

Unity 3D+C#盆景文化虚拟展馆交互漫游系统开发实战

盆景这门东西,外行看是"一盆土加一根弯树",内行看是"缩地成寸、以小见大"的东方空间美学。我接触过不少做数字展馆的项目,大多数团队一上来就堆模型、堆贴图,最后跑起来像在逛一个贴满图片的走廊,…

作者头像 李华
网站建设 2026/9/29 18:49:46

set_clock_groups命令详解:跨时钟域时序约束的最佳实践

1. 开始之前:为什么同步时序设计也绕不开 set_clock_groups做了几年数字 IC 或 FPGA 设计,你一定遇到过这种情况:工程明明综合、实现都过了,时序报告里却冒出一堆红色 violation,点开一看全是跨时钟域的路径&#xff0…

作者头像 李华
网站建设 2026/9/29 18:49:19

AI资讯聚合系统设计与实现要点

我无法根据当前输入生成符合要求的博文。 原因如下: 项目标题为“AI 日报 2026-09-19”,属于一个 未来日期的、无实质内容的命名格式 ,本身不指向任何具体技术实现、应用场景、工具链、问题域或可操作对象; 项目正文为空&a…

作者头像 李华
网站建设 2026/9/29 18:48:31

AI资讯日报系统设计与实现要点解析

我无法根据当前输入生成符合要求的博文。 原因在于:您提供的输入内容中, 项目正文为空 、 关键词为空 、 摘要描述为空 ,仅有一个标题“AI 日报 2026-09-19”和两行无实质信息的占位符(“相关热搜词:”“最新网…

作者头像 李华
网站建设 2026/9/29 18:48:29

C#实现IEC 61131-3梯形图编辑器:语法校验与实时执行

1. 为什么非得自己写一个软PLC梯形图编辑器?——从工业现场的真实断点说起我第一次在客户产线看到那台老式欧姆龙CP1H PLC时,它正卡在“RUN”和“STOP”之间反复闪烁。工程师蹲在控制柜前,手里捏着一张手绘的梯形图草稿,旁边摊开三…

作者头像 李华
网站建设 2026/9/29 18:47:33

AI工程从零到一:RAG知识库问答系统实战指南

先聊个很多人都会问的问题:AI 工程(AI Engineering)到底是不是个“新瓶装旧酒”的概念?我自己的判断是:它不是。早几年我们讲机器学习、深度学习,重心大多放在模型训练——调参、刷榜,谁 AUC 高…

作者头像 李华