☰
Advanced-RAG三段式优化:LlamaIndex检索增强生成实战
2026/10/27 3:02:15 网站建设 项目流程

检索增强生成这套东西,刚上手的人几乎都会撞上同一个落差:demo 阶段效果惊艳,接进真实文档库之后回答就开始飘,要么答非所问,要么把三段本不相干的原文缝成一段读起来通顺、实际上站不住的结论。我在几个内部知识库项目里反复碰到这个问题,最后一轮排查下来,病灶基本不在模型身上,而在那条“切块—向量化—相似度 top-k—塞进提示词”的流水线本身太粗糙。**Advanced-RAG(高级检索增强生成)**要解决的正是这件事:它不换模型,而是把这条流水线拆成预检索、检索、后检索三段,逐段加固。这篇就按我自己的落地顺序讲,从每个环节为什么这么设计,一直讲到用LlamaIndex把整套东西拼成能跑的代码,中间会把参数怎么算、坑在哪、怎么验收都摊开说。

1. 先把朴素 RAG 的断点找出来

1.1 一条直线跑不通的三个位置

最基础的 RAG 链路只有四步:文档切块、向量化入库、按问题向量做相似度召回、把召回片段塞进提示词让模型作答。这条链路在文档量小、问题指向明确的时候表现不错,所以很多人第一版就这么上线了,然后被真实流量教育。问题集中在三个位置,而这三个位置恰好对应 Advanced-RAG 的三段式改造。

第一个断点在切块。固定长度切块会无情地切断语义单元,一个表格被拦腰截断,一段定义的前半句在 A 块、后半句在 B 块。检索命中 A 块,模型看到的是一个没有主语的句子,只能靠猜。第二个断点在召回方式。纯向量召回擅长语义近似,但对专有名词、型号编码、条款编号这类精确匹配非常不敏感——“GB/T 1234”和“GB/T 1235”在向量空间里几乎是同一个点。第三个断点在上下文组织。top-k 取 5 还是 20 全凭手感,取少了漏信息,取多了噪声淹没信号,而且模型对长上下文中间部分的注意力天然偏弱,塞得越满,真正有用的那句越容易被稀释。

把这三件事分开处理,就是 Advanced-RAG 的基本框架。预检索阶段改造索引与查询,让“该被找到的东西更容易被找到”;检索阶段改造召回策略,多路并行再融合;后检索阶段改造上下文,压缩、重排、回填。三段各管一段,出了问题能定位,不会一锅粥。

1.2 为什么我优先改索引而不是改提示词

新手最容易走的弯路是死磕提示词。回答不好就加一句“请严格依据原文作答”,再不好就加“如果原文没有请说不知道”。这些约束有用,但天花板很低,因为它们只能约束模型怎么用已有的信息,不能让凭空缺失的信息出现。如果召回的三个片段里根本没有答案,提示词写得再花哨也是零。

我实际的经验排序是:先修索引与切块,再修召回融合,再修重排压缩,最后才调提示词。前两步做完,通常能看到肉眼可见的提升;提示词微调带来的收益往往是个位数百分比,而且很容易过拟合到你手头那几十条测试问题上。这个顺序也决定了后面实战章节的组织方式——所有代码都围绕“让正确的片段进入候选集”来写。

还有一个容易被忽略的判断依据:如果错误回答里的信息完全来自召回的片段但被张冠李戴,那是生成层问题;如果错误回答里出现了原文根本没有的内容,那是没召回导致的模型自由发挥。前者调提示词和重排,后者必须回去改索引。分不清这两类,优化就会在原地打转。

2. 预检索:切块方式和索引结构决定天花板

2.1 分块尺寸不是拍脑袋定的,算一遍就知道

切块尺寸是整条链路里影响最大、也最容易被随手填一个 512 就过去的参数。它有两个硬约束。上界来自嵌入模型的最大输入长度,很多中文向量模型的有效长度是 512 token,超长部分直接被截断,等于白切;下界来自语义完整性,一段完整的操作规程通常需要 200 到 400 字才能自洽。所以实际可用区间往往很窄。

我的计算习惯是这样:先统计文档的段落长度分布,取中位数作为基准;再确认嵌入模型的有效长度;最后用“块大小 = min(模型有效长度 × 0.8, 段落中位数 × 1.2)”定初值。乘以 0.8 是给特殊符号和长词留余量,乘以 1.2 是允许跨段落合并。重叠比例取 10% 到 15%,用来兜住跨块边界的信息,但别超过 20%,否则索引体积和重复召回都会变难看。

更稳妥的做法是放弃“切块”改用“结构化切分”的思路。Markdown 按标题层级切,HTML 按标签切,PDF 走版面分析先分出标题、正文、表格,再分别处理。表格单独整块保留并转成文本描述,比把它切碎后让模型自己拼要可靠得多。代码片段同理,按函数或类切,别按行数切。

2.2 元数据和多表示:给每个片段配一份说明书

一个孤立的片段最大的问题是失去上下文。它可能写着“该值不得低于 0.35”,但读者不知道“该值”指什么。**元数据(metadata)**就是解决这个的常规手段:给每个节点挂上来源文件、章节路径、生效日期、文档类型、版本号。检索时既可以用元数据做前置过滤(比如只查最新版、只查技术类文档),也可以在拼装上下文时把章节路径作为前缀补进提示词,让模型知道这段话的出处。

更进一步是多表示索引(multi-representation indexing):同一个原始文档块,存两份表示。一份是大块,用于生成回答时提供完整上下文;一份是从大块提炼出的小摘要或若干假设性问题,用于向量检索。检索命中的是小表示,返回给模型的却是它对应的大块。这样做的好处很直接——小表示语义集中,向量质量高;大块信息完整,回答不缺料。两者各司其职,不用在“块大一点还是小一点”上纠结。LlamaIndex 里的父子文档检索、句子窗口检索,本质都是这个思路的工程化实现。

还有一类做法是给每个块自动生成 3 到 5 个“这个块能回答的问题”,把问题和块一起入索引。用户提问时,问题与问题的语义距离通常比问题与正文的距离更近,召回率能抬一截。代价是索引构建阶段要多跑一遍模型推理,文档量大时构建时间会明显拉长,建议只在核心知识库上做。

2.3 查询侧也要改造:HyDE 与查询改写

预检索不只改索引,也改查询。用户的问题往往很短、口语化、缺主语,跟文档的书面语表述存在天然的语义鸿沟。**HyDE(假设性文档嵌入)**的思路是:先让模型根据问题编一段“假设的答案”,再用这段答案去检索。假设答案的措辞、句式更接近真实文档,向量距离自然更近。它有效的前提是模型对该领域有基本认知,能编出个八九不离十的框架;如果模型完全不懂这个领域,编出来的东西会把检索带偏,这时候不如老老实实用原问题。

查询改写更朴素一些:把“这个怎么弄”改写成“某功能的配置步骤是什么”,把指代词补全,把口语词替换成文档里的术语。多轮对话场景下这一步是必需的,因为“那它呢”这种问题直接拿去检索,召回结果基本靠运气。改写和原问题要同时参与检索,两路结果融合,而不是只保留改写后的版本——改写可能改错,原问题里往往有实体线索。

3. 检索阶段:单路召回是赌博,多路融合才稳

3.1 混合检索:向量和关键词根本不是替代关系

向量召回和 BM25 这类关键词召回,能力边界几乎正交。向量擅长“意思差不多但字不一样”,比如用户问“设备过热怎么办”,文档里写的是“温度异常处置流程”,向量能连上,关键词连不上。BM25 擅长“字面必须一模一样”,比如型号、编号、人名、条款号,向量在这儿经常掉链子。真实业务里这两类查询混在一起,所以混合检索不是可选项,是必需品。

融合方式有两种主流做法。一种是分数归一化后加权,把两路分数缩放到同一区间再加权求和,权重用 alpha 控制,alpha 偏向向量还是关键词要看你文档的查询类型分布;另一种是倒数排序融合(RRF),不看绝对分数只看排名,公式是每个结果累加 1/(k + rank),k 通常取 60。RRF 的优势是不用处理两路分数量纲不一致的问题,我在跨库检索场景里更倾向用它,省心且效果稳定。加权融合的优势是可以精细调,比如你发现关键词召回的 top1 特别准,就可以给它更高权重。

一个实测细节:混合检索之后不要立刻取 top-k 送进模型,先做一步去重。同一个段落被两个检索器同时命中是很常见的,重复内容进入上下文除了浪费 token 没有任何好处,还会让模型误以为这个信息被反复强调。

3.2 查询路由:先判断问题该去哪找

当知识库规模上去之后,把所有文档塞进一个索引会让召回质量明显下降,因为不同领域的向量分布互相干扰。这时候要引入路由:先判断问题属于哪个领域、该查哪个索引,再派发过去。路由可以基于规则(关键词表)、基于分类模型,也可以让模型做少样本分类。第三种最灵活,代价是多一次模型调用,延迟会增加几百毫秒,得看你的场景能不能接受。

比路由更细的是子问题拆解。复合问题像“对比 A 方案和 B 方案在成本与工期上的差异”,一次性检索很难同时命中两套方案的关键信息。拆成“A 方案成本”“A 方案工期”“B 方案成本”“B 方案工期”四个子问题分别检索,再把四组证据汇总作答,准确率提升非常明显。代价是检索次数翻倍,而且拆解本身可能出错,所以我在实现时会加一层判断——问题里出现“对比”“分别”“以及”“同时”这类并列信号时才触发拆解,简单问题不走这条路。

3.3 重排序:把“差不多相关”筛成“确实命中”

向量相似度高不等于真的相关。这是向量检索最反直觉的地方:一段讲“数据备份”的文字和一段讲“数据恢复”的文字,向量距离可能非常近,因为它们共享大量词汇和语境,但对具体问题的价值完全不同。**重排序(rerank)**就是来解决这个的。

做法是把初筛的候选(比如 30 条)送进一个交叉编码器模型,让它把问题和每一条拼在一起逐对打分,再按新分数取前 N 条。交叉编码器能看到问题和文档之间的细粒度交互,精度比双塔向量高出一大截,缺点是慢,只能用在少量候选上。所以标准范式是“向量粗召回 30 到 50 条,重排精筛 5 到 8 条”,粗召回保证覆盖率,重排保证精度。

重排模型的选择上,中文场景里 bge-reranker 系列是比较稳的起点,能在本地跑,不需要外部服务。top_n 怎么定?我一般按上下文体量反推:假设上下文预算 6000 token,每块平均 350 token,那么理论能放 17 块,但实际有效信息随块数增加边际递减,实测 5 到 8 块是甜点区,再多模型容易在长上下文里迷路。所以 top_n 就先定 6,用评估集验证后再微调。

4. 后检索:上下文窗口不是垃圾桶

4.1 压缩与回填,让每一条都值钱

后检索阶段最容易被跳过,但它对最终质量的影响不亚于前面两段。第一个动作是压缩:把召回片段里与问题无关的句子删掉,只留核心句。可以用小模型做句子级筛选,也可以用规则做滑窗截取。压缩的收益是双向的——既省 token,又减少噪声,让模型的注意力集中在有效信息上。风险是误删,所以压缩比例不要超过 60%,保留一定的冗余是有必要的。

第二个动作是窗口回填。如果你在索引阶段用的是小颗粒切块(比如单句),检索精度会很高,但返回给模型的上下文会碎得没法读。这时候用句子窗口检索:命中某个句子后,把它前后各若干句一起取出来作为上下文。这个思路的好处是检索粒度细、生成上下文完整,两个目标同时满足,不必在块大小上做妥协。

第三个动作是去重与排序。同一个信息点可能被多个片段覆盖,去重后按相关度或按原文顺序排列。顺序这件事有讲究:把最相关的放在开头和结尾,中间放次要信息,因为模型对上下文首尾的注意力更强。这是很实用的一个小技巧,改动成本几乎为零。

4.2 让模型自己判断“证据够不够”

再往上一层是自反思式检索:模型拿到初步证据后,先评估这些证据是否足以回答问题,不够就触发二次检索,补充查询条件再找一轮。这种做法能显著降低“硬答”的情况,代价是延迟和调用次数上升。工程上一般设一个重试上限(比如最多两轮),避免陷入死循环。

与之配套的是证据约束输出:要求模型在给出结论时标注依据来自哪个片段。这不仅能提升可解释性,还让评估变得可行——你可以逐条核对引用是否真实存在。我通常会要求模型在无法从证据中得出结论时明确说“现有资料未覆盖”,宁可拒答也不要编造。这句话写进系统提示里,配合前面的重排和压缩,编造率能压得很低。

5. LlamaIndex 实战:把三段拼成一条能跑的流水线

5.1 数据接入与 Ingestion Pipeline

先从最基础的搭建说起。整个工程的骨架是:文档读取 → 解析 → 切块 → 元数据抽取 → 向量化 → 入库。LlamaIndex 的 IngestionPipeline 好处是支持缓存,重复跑不会重复计算,改一个环节也只重跑受影响的部分,这在反复调试切块参数时能省大量时间。

from llama_index.core import SimpleDirectoryReader, Settings from llama_index.core.ingestion import IngestionPipeline from llama_index.core.node_parser import SentenceSplitter from llama_index.core.extractors import TitleExtractor, QuestionsAnsweredExtractor from llama_index.embeddings.huggingface import HuggingFaceEmbedding from llama_index.core.storage.docstore import SimpleDocumentStore # 嵌入模型:中文场景优先选 bge 系列,本地跑,无外部依赖 Settings.embed_model = HuggingFaceEmbedding( model_name="BAAI/bge-large-zh-v1.5", max_length=512, normalize=True, ) documents = SimpleDirectoryReader("./knowledge_base").load_data() pipeline = IngestionPipeline( transformations=[ SentenceSplitter(chunk_size=380, chunk_overlap=60), TitleExtractor(nodes=5), # 自动补章节标题,缓解片段失上下文 QuestionsAnsweredExtractor(questions=3), # 每块生成 3 个可回答的问题,一并入索引 Settings.embed_model, ], docstore=SimpleDocumentStore(), ) nodes = pipeline.run(documents=documents, show_progress=True, num_workers=4) pipeline.persist("./pipeline_cache")

这里的参数是算出来的,不是抄的。嵌入模型有效长度 512,乘 0.8 得 410;文档段落长度中位数大约 320 字,乘 1.2 得 384。两者取小,落在 380 左右。重叠 60 字,占比约 16%,在 10% 到 20% 的安全区间内。num_workers设 4 是因为再往上加,本地模型推理会争抢显存,反而变慢,这个值要在自己机器上压测一遍。

TitleExtractor和QuestionsAnsweredExtractor都要调模型,文档上千篇时构建时间会翻倍。我的做法是只在核心库上开,边缘库关掉,用元数据里的文件路径替代标题抽取。另外这两个抽取器都会消耗 token 配额,如果模型服务按量计费,先算一笔账再决定。

5.2 索引层:向量、关键词、摘要三件套并存

索引不要只建一个向量索引。我的标准配置是三份:向量索引管语义召回,关键词索引管精确匹配,文档摘要索引管“这类问题该去哪篇文档里找”。三份索引共享同一个 docstore,节点 ID 一致,融合时天然对齐。

from llama_index.core import VectorStoreIndex, StorageContext from llama_index.core.storage.index_store import SimpleIndexStore from llama_index.retrievers.bm25 import BM25Retriever storage_context = StorageContext.from_defaults( docstore=pipeline.docstore, index_store=SimpleIndexStore(), ) vector_index = VectorStoreIndex( nodes, storage_context=storage_context, show_progress=True, ) vector_index.storage_context.persist("./storage_vector") # 关键词索引:与向量索引共用同一批节点 bm25_retriever = BM25Retriever.from_defaults( docstore=pipeline.docstore, similarity_top_k=12, stemmer=None, # 中文不需要词干还原 language="zh", )

关键词索引这块有个中文特有的坑:BM25 默认按空格分词,中文不切词就等于没效果。必须显式配置中文分词,或者把文本预先用分词工具处理一遍再入库。我之前有次忘了这回事,关键词检索召回的 top10 全是包含单个高频汉字的随机段落,排查了半天才反应过来。

similarity_top_k设 12 也有依据。粗召回阶段要保证覆盖率,取最终结果数的两到三倍比较合理,最终要 6 条,那粗召回 12 到 18 条都在合理范围。设太大重排压力大,设太小重排没得选。

5.3 检索器组合:混合、融合、自动合并

真正的核心在检索层。LlamaIndex 提供了一整套现成组件,关键是知道什么场景用哪个。

from llama_index.core.retrievers import ( VectorIndexRetriever, QueryFusionRetriever, AutoMergingRetriever, ) from llama_index.core.retrievers import RecursiveRetriever # 向量召回 vector_retriever = VectorIndexRetriever( index=vector_index, similarity_top_k=12, ) # 混合检索:向量 + 关键词,用 RRF 融合 hybrid_retriever = QueryFusionRetriever( retrievers=[vector_retriever, bm25_retriever], similarity_top_k=8, num_queries=1, # 不额外生成改写查询,避免延迟翻倍 mode="reciprocal_rerank", # RRF,不依赖两路分数同量纲 use_async=True, verbose=False, )

QueryFusionRetriever的mode有三个常用值,差异很实际。simple_rerank按分数排序后再插值,对分数分布敏感,两路分数不在一个量纲时容易一路压制另一路。reciprocal_rerank就是 RRF,只看排名不看分数,跨检索器融合时最稳,我的默认选择。relative_score适合你知道各路分数的可靠程度、想精细加权的情况。num_queries设大于 1 会让它自动生成多个改写查询再分别检索,能提升召回,但延迟线性增长,线上场景慎用。

接着处理层级结构。如果文档有父子层级(章节—小节—段落),用自动合并检索器效果很好:检索命中的是子节点,当一个父节点下的子节点命中数量超过阈值,就把父节点整块返回,避免上下文碎片化。

from llama_index.core.retrievers import AutoMergingRetriever from llama_index.core import Document # 需在切块阶段保留层级关系,这里假设已构建好 parent/child 结构 auto_merging_retriever = AutoMergingRetriever( vector_retriever, storage_context=storage_context, simple_ratio_thresh=0.4, # 4 个子节点命中 2 个即合并父节点 )

simple_ratio_thresh设 0.4 是通过试出来的。设 0.5 太保守,经常凑不够比例导致该合并不合并;设 0.3 又太激进,一两个命中就拉出大段父节点,上下文迅速膨胀。0.4 在十几个测试问题上表现最平衡,但这个值跟你的文档层级深浅强相关,必须自己调,别直接抄。

5.4 组装查询引擎:重排、压缩、响应合成一条龙

检索器有了,接下来是后检索处理链。LlamaIndex 的node_postprocessors是个列表,按顺序执行,顺序很关键:先去重,再压缩,再重排,最后截断。

from llama_index.core.postprocessor import ( SentenceTransformerRerank, SimilarityPostprocessor, MetadataReplacementPostProcessor, ) from llama_index.core.query_engine import RetrieverQueryEngine from llama_index.core.response_synthesizers import get_response_synthesizer reranker = SentenceTransformerRerank( model="BAAI/bge-reranker-base", top_n=6, ) sim_filter = SimilarityPostprocessor(similarity_cutoff=0.35) response_synthesizer = get_response_synthesizer( response_mode="compact", # 多块先压缩再合成,比 refine 快、比 tree_summarize 省 text_qa_template=QA_TEMPLATE, # 自定义模板,强制标注依据并允许拒答 ) query_engine = RetrieverQueryEngine( retriever=hybrid_retriever, response_synthesizer=response_synthesizer, node_postprocessors=[sim_filter, reranker], )

SimilarityPostprocessor的 cutoff 设 0.35 是经验值,用来砍掉明显跑偏的片段。注意这个阈值依赖嵌入模型的分数分布,换模型就要重新标定,我一般会拿十条明显无关的问题跑一遍,看它们的最高分落在哪个区间,再把 cutoff 定在略低于这个区间上沿的位置。

response_mode的选择也值得说一下。refine是逐块迭代精炼,质量好但调用次数等于块数,慢;compact先把多块塞进尽量少的调用里,速度和质量的平衡点最好;tree_summarize适合“总结归纳”类问题,但成本高。日常问答用compact,需要跨文档归纳时再切tree_summarize。

自定义模板这部分是我改动最多的地方,核心就三条:只依据给定资料作答、每条结论标注来源片段编号、资料不足时明确说未覆盖。模板不要写得太长,规则超过五条模型就开始选择性遵守了。

6. 效果评估:别靠体感验收

6.1 检索层和生成层要分开量

这是我最想强调的一点。多数团队验收 RAG 的方式是“找二十个问题让人看回答像不像样”,这种方式无法定位问题,也看不出改动是不是真的有效。正确的做法是分层评估。

评估层指标测什么用什么算
检索层Hit Rate标准答案所在片段有没有进候选集标注问题-片段对
检索层MRR正确片段排在第几位同上
检索层NDCG@k多个相关片段的整体排序质量同上
生成层忠实度回答是否完全来自给定证据模型评估器
生成层相关性回答是否切题模型评估器
生成层引用准确率标注的来源是否真实存在抽样人工

检索层指标是硬指标,只要标注了“这个问题该由哪段文字回答”,就能算出来,不依赖模型判断。生成层指标可以用模型自动打分,但要有抽检。LlamaIndex 里检索层评估用RetrieverEvaluator,生成层用FaithfulnessEvaluator和RelevancyEvaluator,都能直接跑。

from llama_index.core.evaluation import RetrieverEvaluator retriever_evaluator = RetrieverEvaluator.from_metric_names( ["mrr", "hit_rate", "precision", "recall"], retriever=hybrid_retriever, ) results = await retriever_evaluator.aevaluate_dataset(eval_dataset, workers=4) for name, metric in results.items(): print(f"{name}: {metric.score:.3f}")

评估集不用大,五十到一百条就够看出趋势,但必须覆盖三类问题:精确查询(编号、型号)、语义查询(换个说法问同一件事)、复合查询(需要多段证据拼合)。三类混在一起算总分是没意义的,要分开看,因为混合检索的权重调整对这三类的影响方向完全不同。

6.2 调参优先级:先调收益最大的

参数一多就容易乱调,我按收益排了个序,照着来能少走弯路。

优先级调什么常见初值判断依据
1切块尺寸与重叠380 / 60检索层 Hit Rate 明显变化
2混合检索权重或 RRFRRF k=60精确类问题命中率
3重排 top_n6生成层忠实度与延迟
4相似度阈值0.35无关片段占比
5提示词模板三条硬规则拒答率与引用准确率

切块参数放第一位,因为它一动,后面所有指标都会重排,先调它能避免后面白调。混合检索权重第二位,因为它直接决定候选集质量。重排放第三,因为它只能在候选集里挑,候选集错了它救不回来。提示词放最后,收益最小且容易过拟合。

还有个实操细节:每次只改一个参数,改完跑完整评估集,记录三个分层指标。同时改两个参数,你永远不知道提升来自哪一个。我见过团队一次性把切块、top_k、重排模型全换掉,效果确实好了,但没人说得清为什么好,后面遇到新问题完全无从下手。

7. 踩坑实录与速查表

7.1 我踩过的几个典型坑

第一个坑是中文 BM25 分词。前面提过,不配中文分词时关键词检索等于随机抽样。表现是精确类问题命中率极低,但因为向量那一路还在工作,整体效果看起来“还行”,特别隐蔽。排查方法是单独跑关键词检索,看召回结果是不是围绕查询词聚集,不聚集就是分词没生效。

第二个坑是嵌入模型与查询侧不一致。有些模型要求查询前加指令前缀(比如“为这个句子生成表示以用于检索”),文档侧不加。如果只给文档加了前缀没给查询加,或者反过来,向量空间会错位,相似度普遍偏低且排序混乱。特征是所有问题的 top1 分数都异常低、区分度差。排查方法很土但有效:拿一段文档原文当查询去检索它自己,如果它排不到第一,基本就是这个问题。

第三个坑是元数据过滤把结果过滤空了。加了“只要最新版本”的过滤条件之后,有些问题的候选集直接为空,但代码没做空结果兜底,模型拿到空上下文开始自由发挥。这种错误在日志里不会有任何异常,只有抽查才发现。解决办法很简单:检索后判断结果数,为零就退回不带过滤的检索,同时在日志里打点。

第四个坑是重排模型的输入长度超限被静默截断。候选片段太长时,交叉编码器只看了前半段就打分,后半段的关键信息没参与判断。表现是长文档的排序质量明显低于短文档。处理方式是重排前做长度截断,把每段压到模型上限以内,宁可丢一点信息也要保证打分完整。

7.2 常见问题速查

现象最可能的原因优先查这个
回答张冠李戴重排缺失或 top_n 过大后检索处理器顺序
回答出现原文没有的内容没召回,模型自由发挥检索层 Hit Rate
精确编号类问题答不出关键词检索未生效中文分词配置
长文档效果明显更差重排输入被截断截断长度设置
多轮对话第二轮开始跑偏查询未做指代消解是否带历史上下文改写
上下文塞满但准确率不升块数超过甜点区top_n 与压缩比例
同类问题时好时坏切块切断语义单元分块策略与重叠
响应特别慢融合检索 num_queries 过大是否开启多查询生成

我个人在实际操作中的体会是,Advanced-RAG 这一整套东西听起来组件很多,但真正拉开效果差距的其实只有两处:切块是否尊重语义边界,以及候选集里到底有没有正确答案。后面所有的融合、重排、压缩,本质都是在有正确答案的前提下做优化。候选集里没有答案,后面的工序再精致也是零。所以每次系统效果不及预期,我都先关掉所有花哨的后处理,只跑最朴素的向量召回,看一眼 Hit Rate 是多少——这个数字如果低于 0.7,其他优化都可以先放一放,回去改索引。这个习惯帮我省掉的调试时间,比任何一个具体技巧都多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询