
调了两个月提示词效果纹丝不动最后改的是检索链路——这是我对 RAG 最深的印象之一。不少团队刚上手 RAG 时下意识把精力全放在提示词上觉得模型输出不对就改提示词结果 Paper 里那些华丽模板换了一轮又一轮模型回答依旧东拼西凑甚至一本正经地胡说八道。后来我才意识到RAG 这条链路里真正决定天花板的从来不是最后那段提示词而是喂进上下文窗口里的检索内容本身。这个认知一旦转过来很多看起来神秘的问题瞬间就变得有迹可循。这篇文章就是想把这一路踩过的坑、总结出的判断方法以及最终沉淀下来的调试顺序写清楚。适合那些已经在做 RAG 应用、或正准备从 Demo 走向可用状态的开发者参考——如果你发现自己总在提示词上做文章但效果止步不前那这篇文章尤其值得读一读。1. 一次现场事故提示词调不动任何问题先讲一个让我彻底改变思路的具体案例。当时我们做一个内部知识库问答系统文档是几百篇设备维护手册和技术规范用户会问某型号设备告警后第一步该做什么这类问题。系统第一版跑通后回答质量非常一般最常见的毛病是模型会把不同型号的参数混在一起说或者回答得特别笼统像在背教科书目录而不是真正回答问题。团队当时的直觉反应完全一致提示词写得不够细。于是我们开始给系统提示词加各种限定比如你是一个设备维护专家请严格基于给定材料回答如果材料不足请明确说明甚至尝试了 few-shot在提示词里塞了几个标准问答对。一轮下来输出风格确实变了说话更像一个专业助手但内容层面的错误一点没少——该混淆的型号还是混淆该找不对的资料还是找不对。事情出现转机是某天我随手把一次糟糕回答对应的检索结果打印出来一条一条肉眼看。看完当场就愣住了召回的 5 个文档片段里有 3 个和问题基本无关剩下 2 个相关的里面关键参数那一段因为切分位置不对被拦腰截断。也就是说模型根本没拿到正确回答问题所需要的信息这时候提示词写得再好也无非是把错误信息组织得更流畅而已。模型不是不会答是压根没看到该看的东西。这个案例让我意识到一个被很多人忽视的事实RAG 系统的回答质量受限于上下文质量而非提示词技巧。提示词能优化的是怎么答的呈现方式但拿什么来答完全取决于前面的索引、检索、排序、组装这一整条链路。后者出了问题前者再怎么雕花也没有意义。从那以后我给自己定了一条硬规矩凡是 RAG 效果不好第一步永远先看检索结果的原始材料人能不能凭这些材料给出正确答案。如果人看了都答不对问题一定出在上下文而非提示词。这条规矩帮我省掉了大量无用功也直接引出了后文要讲的整套调试方法。2. 从原理上理解为什么上下文是上限提示词只是风格要真正认同上下文比提示词重要 10 倍这句话光靠一两个案例还不够得从模型的工作机制上理解这件事。LLM 在推理时的核心逻辑是根据当前输入的所有 token 预测下一个 token而回答问题的依据无非来自两个渠道一个是模型在预训练阶段内化进参数的记忆另一个是这次请求中实时提供的上下文。RAG 最大的意义就是用实时检索到的外部知识补足和校正模型参数记忆里的知识缺口。模型本身可能知道一点设备维护常识但具体到某个型号的告警代码、某批次固件的已知缺陷、某套系统的私有配置它不可能全部记住就算记住了也可能是错的、过时的。RAG 引入的上下文正是为了把这些模型不可能知道的信息送到模型的眼前。因此模型最终能答到什么程度直接被上下文里有没有正确答案锁死。这里有个容易被误解的地方。很多人觉得模型很聪明提示词里引导一下它就能从上下文中理解出正确答案。这个想法在上下文质量尚可时是成立的——一段连贯、相关、信息完整的材料加上一句基于材料回答模型通常能准确提取答案。但一旦上下文本身残缺、噪音大、分布混乱模型的理解能力就会急剧下降。它可能被高相关度的片段带偏被冗余内容干扰甚至因为关键信息被切碎而完全找不出头绪。拿注意力机制来解释会更直观。Transformer 架构中模型会计算输入序列中各个 token 之间的注意力权重决定生成某个新 token 时应当关注哪些位置。当上下文窗口里塞入大量无关噪音时注意力得分会被稀释真正重要的片段在注意力分配上拿不到足够权重输出自然就偏了。这就好比一个学生考试时桌子上堆着几十份资料草草扫一眼就开始答题他翻到正确答案的概率取决于资料是否整理过、是否标注过、是否去掉了无关内容——而不是取决于监考老师在旁边多说了几句请认真看资料。提示词在这个框架里的真实角色是对上下文进行驾驭方式的微调告诉模型以什么立场回答、输出格式怎么组织、不确定时怎么表态、回答长度大概多少。这些固然重要但它们影响的是输出的表达层而不是信息层。表达层再完善信息层是空的或错的输出依然没用——甚至比没有 RAG 更糟因为模型会用流畅的措辞把错误内容包装得很有说服力。所以我把 RAG 效果拆成两个独立变量来看上下文质量决定答案正确性的上限提示词决定答案呈现质量的下限和风格。在一个正确性都还没保障的系统里把资源投向提示词优化等于先把屋顶刷了漆再考虑地基有没有浇混凝土。这一点是我从那次现场事故里获得的最宝贵认知。3. 索引切分上下文质量的第一道分水岭既然认定了上下文质量是核心那么问题就变成上下文质量由什么决定顺着 RAG 链路往前倒推第一个决定性的环节就是文档切分chunking。这段做不好后面检索、重排做得再好也只能在错误的基础上修修补补。我在不少项目里见过同一种错误按固定字符数无脑切块400 个字符一刀切下去不考虑句子的完整性更不考虑语义边界。这种做法的直接后果是大量语义完整的段落被拦腰截断。比如设备维护手册里有一句严禁在设备运行状态下直接拔插电源模块否则可能导致控制器损坏如果切分点正好落在控制器三个字前面检索回来的片段就只剩半句话语义严重残缺模型当然回答不了。更隐蔽的问题还不止于此。固定窗口切分还容易把两段互不相关的内容硬凑进同一个块里。比如一份文档按排版顺序讲了 A 设备的校准流程紧接着讲 B 设备的日常保养一刀切下去两个主题被缝进同一个块。检索时如果这个块命中了关键词模型的上下文里就会出现跨主题的混乱信息极易产生张冠李戴——这恰恰是很多 RAG 系统混合了不同设备参数这类错误的根源。解决这个问题的思路并不是去追求某种万能切分算法而是要围绕你的文档特点和查询模式来设计切分规则。我实际使用的原则有三条第一以语义完整为底线优先保证切分点落在段落或标题层级边界上第二根据文档类型选择合适的切分粒度长文档用层级切分短文档用语义切分第三适度使用重叠overlap把相邻块的边缘信息保留一部分避免边界信息的丢失。举个具体例子。对于技术规范类文档我通常采用标题层级感知的切分策略如果文档本身有清晰的章节结构就按章节边界切章节太长的再递归切到二级标题或段落级别。这样切出来的块天然具有主题一致性检索时也更容易通过标题元数据实现精准定位。对于没有强结构的对话记录或公告类文本则改用语义切分通过句向量相似度判断句子之间的主题连贯性在相似度明显下降的位置切割。切分粒度的选择也直接影响上下文质量。我曾经在问卷调查类场景中做过对比同样一组文档切分成 200 字小块的召回精度更高但每块信息量少模型需要跨多个片段才能拼出完整答案切成 800 字大块后单块信息完整但噪音也随之增加同一个块里可能混入几个不同维度的问题描述。最终方案是结合业务查询特征来确定粒度——我们的查询大多是单点事实性问题300 到 500 字的块比较合适既保证单块信息完整度又能控制噪音比例。这个数字不是理论推导出来的而是在真实数据上对比后确定的建议不同项目一定跑自己的数据看效果不要直接照搬。切分还有一个很容易被忽略的细节元数据要跟着块走。每个块最好记录来源文档名称、所在章节标题、页码或段落编号。这些元数据在检索阶段可以用来做过滤和排序更重要的是它们最终可以组装进上下文让模型知道这段话出自哪份文档的哪个章节——这个信息对提升回答的可信度非常有用模型能据此判断信息优先级减少跨文档混淆。4. 检索召回劣质上下文的真正源头切分是地基检索就是管道。管道里流进来的内容干不干净直接决定上下文里有没有毒信息。这个环节踩过的坑比切分只多不少。第一类坑是单纯依赖向量相似度做召回。向量检索擅长语义匹配但对精确关键词、专有名称、型号代码这些文本不太友好。比如用户问ALM-233 告警怎么处理如果文档里写的是ALM-233但向量化时被拆分理解成别的含义召回结果可能完全跑偏。我见过最典型的场景是用户问一个非常具体的故障代码向量检索返回的是几篇故障处理相关的泛泛而谈的文档精确的故障代码反而没被召回。后来给检索链路加了 BM25 关键词检索走混合检索情况立刻改善了很多。混合检索的具体做法不难向量检索和 BM25 检索各自跑一遍拿到两个候选集再做融合排序。融合方式我推荐先按各自的分数归一化然后加权合并权重根据文档类型动态调整。对技术文档这类专业术语密度高的内容关键词权重往往比向量得分更重要可以根据实际效果把 BM25 的权重调高一些。这个调整看起来不起眼但对召回精度的提升是实打实的。第二类坑是 top-k 的选择。k 值太小关键信息可能压根没被召回k 值太大噪音会淹没信号。很多人习惯性地设成 5 或 10 就不动了但 k 值其实应该跟上下文窗口大小和文档块粒度联动。我做过的经验总结是在保证能覆盖到正确答案的前提下k 越小越好。因为多塞一个无关块就多一分注意力稀释的风险。比较理想的做法是先用较大的候选集——比如召回 50 个块——再用后面的重排环节压缩到 5 到 8 个块进入上下文而不是一上来就只用向量相似度取前 5 个。第三类坑是完全没有利用元数据做前置过滤。举个例子文档库里有不同版本的手册如果不加过滤老版本的内容可能比新版本更相似而被优先召回直接把过时信息送进上下文。后来我们在索引时为每个块打上了版本号、适用型号、生效日期等标签在检索阶段根据查询意图和用户画像做一些硬过滤或加权效果立竿见影——很多原来模棱两可的回答其实纯粹是版本混杂导致的。这件事让我形成了一个习惯每次看到低质量回答先不急着骂模型或改提示词而是把召回结果拉出来做归因。是没召回还是召回了错误内容还是召回对了但排序太靠后被截断了把问题定位到具体环节再针对性修复。这个归因习惯也是我一直和团队强调的——检索召回是整个 RAG 系统中信息最密集、变量最多的环节不逐项排查你永远不知道问题到底出在哪一环。5. 上下文组装重排、压缩、去噪的顺序与取舍检索拿到了候选集事情还没完。原始检索结果直接塞进上下文通常效果并不好——因为候选块里有相关度高的也有擦边的还有完全无关的。这一步我习惯统称为上下文组装是整个链路里最体现工程功底、也最容易被新手忽略的环节。重排rerank是组装的第一步。向量检索的 Top-5不等于语义上的 Top-5。我实际使用的方案是引入一个专门的重排模型对召回的 50 个候选块重新打分。重排模型相对更擅长精细的相关性判断能把真正对口的块提到前面把噪音压到后面。经过这个环节进入上下文的块质量会有一个肉眼可见的提升。我第一次跑通重排后对比过前后效果同一批问题回答准确率提升了接近 20%而提示词一个字没改。重排之后还有一个关键动作是按需压缩。有些块虽然相关但信息密度很低几百字里只有一两句有用。全量塞进上下文token 浪费严重还会干扰注意力。我试过几种做法一种是用摘要模型把长块压缩成几句话保留下核心信息另一种是提取式压缩直接从块里抽出最关键的那几个句子拼接成紧凑摘要。两者各有取舍——摘要模型保真度更高但会引入额外的模型调用和延迟提取式压缩快但有可能抽出的句子丢失上下文语境。我的建议是在压缩之前先确认你的 token 余量是否真的紧张如果窗口够大不压缩直接塞也问题不大但一旦接近窗口上限压缩基本是必选项。顺序问题同样重要。上下文组装不能是单纯按相关度排序还要考虑引用的逻辑连续性。如果那个问题需要综合三个步骤来回答而三段分别来自同一篇文档的不同章节把它们在上下文里按原文顺序排列模型更容易理解前因后果。我是通过给块附带位置信息和章节路径来实现这一点的组装时先按章节路径聚簇再按原始阅读顺序排列最后才是跨文档的相关度排序。这个细节看起来不起眼但在处理某流程先做 A 再做 B 再做 C这类问题时效果差距非常明显。去噪也是组装的一部分。这里说的去噪不只是过滤掉无关块还包括处理互相矛盾的信息。如果知识库本身存在新旧版本信息冲突重排和排序都无法解决根本问题——模型看到两个互斥说法时很可能选错信源。遇到这种情况需要靠元数据硬规则来干预优先选生效日期最新的文档优先选权威来源的文档或者把冲突信息标出来让模型明确存在新旧说法差异再回答。在规则无法覆盖的场景下我倾向于直接用提示词告知模型若上下文中存在冲突信息请明确指出——这是提示词少数真正派得上用场的场景之一但前提是你先识别出了冲突而不是指望提示词能凭空解决它。组装做完上下文的最终形态基本确定了。到这个阶段再回过头看提示词它需要做的仅仅是定输出格式、定语调、定边界行为——它的职责范围已经缩得很小所以调起来也快得多。6. 调试链路什么时候才轮到提示词出场讲了这么多上下文比提示词重要 10 倍这句话要落到实践中光靠理念还不够最好有一套可执行的调试链路。我在多个项目里逐渐沉淀出来的顺序是先诊断数据再诊断检索然后诊断组装最后才碰提示词。每一步都有明确的检查动作和通过标准没通过就不进入下一步。第一步诊断数据与切分。随机抽几十个典型问题人工去文档库里找正确答案看看答案对应的原文是否能被一个块完整覆盖。如果答案是需要跨多个块拼接说明切分粒度偏小或重叠不够如果原文本身就没有明确答案说明知识库数据覆盖本身就存在缺口这不是任何环节调参能补的如果答案被切分截断了那问题基本锁定在切分策略上。这步做完你就知道数据层面的底子怎么样。第二步诊断检索召回。对于上面抽出的问题把检索结果的原始块列表拉出来人工判断前几个块里是否有正确答案。这时会分出几种情况没有正确答案——召回逻辑需要改优先考虑混合检索、元数据过滤、调 k 值有正确答案但排得很靠后——重排环节或评分权重需要调检查一下仿真是 vector 权重过大还是关键词权重不足正确答案每次都在不同位置——说明查询理解还不够稳可以考虑查询改写或意图识别把用户原始输入先转成更适合匹配的检索式。这一步是排查效率最高的一步绝大多数怎么改提示词都没用的问题都落在这里。第三步诊断上下文组装。把最终要送进上下文的块列出来人工模拟模型的视角读一遍信息是否冗余相关块顺序是否合理冲突信息是否被处理掉每个块是否带有足够的来源信息如果这一步读起来都费劲哪怕提示词写着你是资深专家模型也不可能妙手回春。很多时候人眼扫完马上就能补上组装环节的缺失比如压缩策略、去噪规则、排序逻辑。走到第四步才轮到提示词。这时候提示词的优化目标已经非常明确了无非是输出格式要什么结构、回答风格要偏简练还是偏详细、遇到上下文信息不足时怎么表态、是否需要对多条信息做对比后再回答。这些内容通常用一到两天就能调完而且效果可预期。相比之前花两个月不断堆提示词却毫无收益的处境这个效率反差本身就是最好的说服力。这四步走下来大部分 RAG 项目的质量问题都能被定位到具体环节。我自己的经验是十次效果不满意的 Case 里有七八次问题出在检索或组装剩下两三次是数据和切分的问题真正需要靠提示词来兜底的场景少之又少。想通这一点之后再遇到效果问题我的心路历程已经从提示词还能怎么写变成了上下文这条链路上哪个环节松了。跑过几轮完整调试之后我甚至觉得上下文比提示词重要 10 倍这个说法还算保守了。在朴素 RAG 结构下提示词能争取的边际收益通常是风格层面的修正而上下文质量却能直接把系统从答非所问抬升到引经据典的层次。如果你也在 RAG 效果优化上止步不前建议从今天起换个排查顺序——大概率你会和我一样发现原来瓶颈根本不在提示词上。