ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

RAG与Agent搜索中相关性优化的关键路径

RAG与Agent搜索中相关性优化的关键路径 大语言模型、Agent 框架和 RAG 知识库组合起来的智能搜索系统正在把“相关性”从检索模块的内部指标变成整个问答链路的核心变量。一个 Agent 回答错往往不是模型不会答而是检索内容本身与问题不相关。相关性决定了召回内容能否覆盖问题排序能否把最关键的片段送到生成器面前也决定了整条链路是一次答对还是多次调用工具后仍然失败。本文围绕相关性这个切入口说明它在 RAG 和智能体搜索中出现的位置分析切块、召回、重排、上下文裁剪、评估和排错如何影响最终精度并给出一个最小可运行示例和一份可复用的上线检查清单。正在做 RAG 项目、想在 Agent 搜索链路里优化精度或者排查“检索到了但答不对”这类问题的开发者可以直接按文章顺序实践。1. RAG 和 Agent 搜索里相关性到底卡在哪个环节1.1 一次问答涉及的六步链路在检索系统里相关性可以理解为给定一个查询某条文档在多大程度上提供了回答问题所需的信息。到了 RAG 和 Agent 场景这个定义还要扩展一步相关性不仅是“文档与查询是否相关”还要考虑“这条文档是否足以支撑最终答案”。两者不一致时系统最常见的表现就是检索到的内容看起来沾边但无法直接用。一次典型的智能体搜索会经过六步查询解析。Agent 判断用户问题是否需要检索必要时改写查询例如把“数据库连接串配置在哪里”改写成“数据库连接串 配置文件”。候选召回。从索引里按向量相似度、关键词匹配或元数据过滤取出候选文档块。相关性排序。对候选块做加权排序或重排决定哪些块优先进入上下文。上下文组装。把排序靠前的若干块拼进 prompt同时控制长度。生成或工具执行。大语言模型基于上下文生成答案或继续调用其他工具。输出验证。Agent 判断当前答案能否满足任务不满足则改写查询、继续检索或直接返回“资料不足”。相关性问题可能出现在第 2、3、4 步但会被第 6 步放大。一次不相关的候选召回可能让 Agent 反复改写问题、反复重试最终既慢又贵。1.2 相关性为什么同时影响“准”和“快”相关性对“准”的影响最直接。RAG 本质上不是把知识保存在模型参数里而是从外部知识库临时取知识再把取到的内容当作生成依据。如果 top 5 候选块里没有正确答案再强的大模型也无法凭空推导出答案。更危险的情况是候选块里存在“看似相关但实际错误”的内容模型会基于错误材料生成一段结构完整的错误答案这就是幻觉的主要来源之一。相关性对“快”的影响同样明显。当检索结果相关时Agent 可以一次性完成生成整体耗时很短。当检索结果不相关时Agent 会走“改写查询 - 再次检索 - 再次重排 - 再次生成”的重试链路。每一次重试都意味着额外的 token 消耗、向量检索开销和接口延迟。在本地部署大语言模型的场景里算力和并发能力通常比云端受限相关性低会导致长尾问题拖垮服务。把相关性优化当作性能优化来做对生产环境尤其重要。1.3 相关性不足的典型症状如果系统出现以下现象优先怀疑相关性而不是模型能力答非所问。检索结果与问题“话题相似”但“信息无关”例如问跨库事务方案返回的是单库事务介绍。上下文有据但答案无据。模型补全了文档里没有的细节说明上下文相关性不够强模型只能靠参数记忆“圆场”。同一问题换一种问法效果差异巨大。这是典型的检索召回不稳定而不是生成不稳定。Agent 反复重试但无法收敛。部分框架日志里会出现类似agent terminated due to error, you can prompt the model to try again or start的提示说明 Agent 在多次工具调用后没有得到可供生成使用的可靠上下文。引用对不上号。答案写“根据文档 3”但打开文档 3 后找不到对应内容。这些症状单独出现时容易被归因于 prompt 写得不好但实际根因往往在检索层。调试时先打印候选块人工判断相关性比反复改 prompt 更快。2. 相关性的质量分布切块、召回、重排、上下文裁剪2.1 文档切块在源头决定相关性切块是 RAG 项目中最容易被低估的环节。切块的目标是让每个检索单元尽量满足“独立、完整、可命中”三个条件。独立表示一个块能单独被理解完整表示它包含足够上下文可命中表示它能被查询语义命中。chunk_size 没有统一标准常见范围在 256 到 1024 token 之间。块越小向量检索时语义越容易被精确匹配但上下文容易断裂块越大上下文完整性更好但无关噪声也会进入同一个向量检索精度下降。overlap 通常取 50 到 200 token用来缓解跨块信息断裂例如一句话被切到上一块末尾关键主语却落在下一块开头。更关键的是元数据。标题、章节路径、页码、来源、更新时间、权限范围都要随块一起保存。这些元数据不只是用来展示引用还用于检索前的过滤和检索后的溯源。比如公司内部知识库按部门隔离时先按权限过滤再做相关性排序可以从源头避免越权信息进入上下文。常见做法是父子块策略。子块用于向量检索内容较短、命中率高命中子块后把更大粒度的父块作为上下文交给生成阶段。这样既保留小块的精确命中能力又避免上下文只剩下孤立片段。实际项目里固定一种切块粒度通常不够需要根据文档类型设置多档切块再在检索阶段按查询特征选择。2.2 召回策略单路向量召回不够相关信号要互补向量召回擅长处理语义相似和同义改写但存在明显盲区对精确数字、型号、内部编号、大小写规则不敏感。张三问“数据库连接串里的 server 参数”向量模型可能把问题理解成“数据库连接”召回一篇文章却不包含具体参数位置BM25 或关键词召回反而能通过 “server” 这个精确词直接命中。因此成熟 RAG 项目通常采用混合召回向量召回语义匹配覆盖“换一种说法”的查询。关键词召回精确词匹配覆盖专有名词、参数名、编号类查询。元数据过滤按时间范围、部门、文档类型、权限等先过滤再进入排序。融合打分向量分数、BM25 分数、元数据加分按权重合并。一个常用的基础公式是score w1 * normalize(vector_score) w2 * normalize(bm25_score) w3 * metadata_bonus这里的normalize很关键。向量余弦相似度通常在 0 到 1 之间BM25 分数可能是几十分甚至上百分直接相加会让 BM25 主导结果导致语义召回失效。落地时要把不同来源的分数先做 min-max 归一化或排序百分位转换再按权重融合。2.3 重排序从粗召回高召回率到精排高精度召回阶段的目标是不遗漏排序必须“够宽”所以 top_k 经常取 50 到 100。但把这么多块全部塞进 prompt 不现实既超过窗口限制也会稀释 LLM 的注意力。第二阶段需要通过更精细的排序模型从候选集中选出真正有用的 top 5 到 top 10。重排序阶段常用三种方案双编码器模型。查询和文档分别编码适合粗召回阶段精度有限但速度快。交叉编码器模型。把查询和文档拼接后一起过模型能捕捉更细的交互信息精度更高但速度慢适合作为第二段排序。大模型重排。让 LLM 对候选文档逐条打分或排序效果可能最好但成本和延迟最高适合对精度要求极高、并发量可控的场景。重排序不是可选项。只有在粗召回阶段刻意放宽候选范围再通过重排把正确答案提到前面相关性才能同时满足召回率和精度。2.4 Agent 搜索链路中的相关性判断给 Agent 增加停止条件Agentic RAG 比普通 RAG 多了一层不确定性Agent 可以改写查询、调用工具、多轮检索。相关性在这个链路里不仅是检索分数还是 Agent 是否继续行动的决策条件。建议给 Agent 增加四个控制点最低分阈值。当检索结果低于阈值时Agent 不应硬编答案而应改写查询或换一种检索策略。已尝试记录。记录已经用过的查询改写和已经检索到的块 ID避免同一问题反复检索相同内容。这个能力通常依赖 Agent 记忆和会话状态。最大重试次数。限制 Agent 在同一任务上的检索轮数防止低相关性导致死循环。框架日志里出现 “agent terminated due to error” 类提示时多数和这个控制点缺失有关。明确失败语义。当多轮检索始终低分时Agent 应该回答“暂无足够资料”而不是生成一个看似完整但无依据的答案。把相关性从“检索分数”升级为“Agent 决策条件”是 RAG 项目进入 agentic 阶段后最值得做的事。3. 一个最小可运行的相关性优化流程示例下面用一个最小示例演示“切块 - 混合召回 - 重排 - 阈值判断”的流程。示例使用英文文本避免中文分词带来的额外依赖中文项目需要把分词器替换成合适的中文分词方案。import re import numpy as np from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity docs [ RAG retrieves relevant documents before generation and reduces hallucination., Relevance ranking determines whether search results cover the core question., An agent can rewrite the query based on relevance feedback during multi-turn search., ] # 这里每段文本已经是一个逻辑块真实项目需要按章节、段落和 token 上限切块 chunk_texts docs vectorizer TfidfVectorizer().fit(chunk_texts) chunk_vectors vectorizer.transform(chunk_texts) query Why can RAG reduce hallucination? def vector_score(q, vectors): q_vec vectorizer.transform([q]) return cosine_similarity(q_vec, vectors).flatten() def keyword_score(q, text): q_tokens set(re.findall(r[a-z0-9], q.lower())) d_tokens set(re.findall(r[a-z0-9], text.lower())) if not q_tokens: return 0.0 return len(q_tokens d_tokens) / len(q_tokens) # 混合召回向量分 关键词重叠分 hybrid [] for i, text in enumerate(chunk_texts): vec vector_score(query, chunk_vectors)[i] kw keyword_score(query, text) score 0.7 * vec 0.3 * kw hybrid.append((i, score, text)) hybrid.sort(keylambda x: x[1], reverseTrue) for i, score, text in hybrid: print(fchunk{i} score{score:.3f} text{text})这个示例里查询句包含 RAG、reduce、hallucination 三个关键词同时向量相似度也会把语义对齐到第一句所以正常情况下第一块得分最高。运行结果能直观看到“哪一块因为什么信号进入候选”。生产环境的差异在于向量部分要替换为真实 embedding 模型关键词部分要替换为 BM25 或 Elasticsearch 查询切块部分要根据文档结构处理。这里提供的价值是骨架而不是最终实现。重排阶段可以用一个接口说明第二段排序def rerank(query, candidates, top_n2): # 生产环境建议使用 cross-encoder 或 LLM 打分 # 这里用“原始分数 词重叠奖励”演示接口形式 scored [] for idx, base_score, text in candidates: bonus len(set(query.lower().split()) set(text.lower().split())) scored.append((idx, base_score 0.1 * bonus, text)) scored.sort(keylambda x: x[1], reverseTrue) return scored[:top_n]得到重排后的候选块后再组装上下文reranked rerank(query, hybrid, top_n2) context \n.join([f[{idx}] {text} for idx, _, text in reranked]) prompt fUse the context below to answer the question. If the context is unrelated, reply: I dont know. Context: {context} Question: {query} 这里尤其要注意如果分数低于阈值不要组装 prompt而是让 Agent 改查询或返回“资料不足”。阈值可以放在重排之后也可以放在分组上下文之前具体看系统设计。注意不要只验证示例程序能输出分数还要验证分数与人工判断是否一致。如果你的查询和文档是中文请先确认中文分词不会把整句当成一个 token否则向量和关键词信号都会失真。4. 相关性如何度量检索指标、生成指标与任务指标4.1 离线检索指标优化相关性之前先要能度量相关性。离线阶段建议同时关注四个指标指标计算关注点适用场景RecallK前 K 条中命中的真实相关文档占全部相关文档的比例判断召回是否漏掉答案PrecisionK前 K 条中相关文档占比判断排序是否干净MRRK第一个正确答案在结果列表中的位置适合只取第一条结果的场景NDCGK按位置加权越靠前的相关文档贡献越大评估整体排序质量RAG 项目里 RecallK 和 NDCGK 最常用。Recall 代表候选集里有没有答案NDCG 代表答案是否排在足够靠前的位置。只调 top_k 却不看这两项指标很容易盲目放大候选范围。4.2 生成侧与 Agent 侧指标检索指标不能覆盖完整链路因为相关性对生成的影响还要看最终答案。建议补充忠实度。生成内容是否被检索结果充分支持。引用命中率。答案引用的文档块 ID 是否真实存在且对应文本能支撑观点。任务成功率。Agent 在 N 步内给出用户满意答案的比例。平均检索轮数。相关性差时Agent 需要更多轮重试这个指标会明显上升。平均检索轮数特别适合作为生产环境的监控指标。它不只是性能指标也是相关性质量的间接反馈。当这个指标连续多日上升大概率是知识库内容变化或检索配置被改动。4.3 用 Spearman 相关分析验证分数与人工判断的一致性相关性排序的最终标准应该和用户或业务方的人工判断一致。操作方法是准备一批 query 和候选文档让人工对每个“查询-文档”对打 1 到 5 分的相关度同时记录检索系统的相关性分数。然后把两套分数都转换成秩次计算 Spearman 秩相关系数。Spearman 度量的是两套排序的一致性不关心绝对分数大小因此非常适合检索排序场景。如果系数偏低说明模型给出的分数顺序和人工预期严重错位这时调整权重、换向量模型或换重排模型才有依据。注意人工打分的样本量最好在 50 条以上覆盖常见问题、长尾问题和容易混淆的负样本否则排序一致性分析很容易被个别极端样本带偏。4.4 阈值不是拍脑袋要结合错误分布score_threshold 不能靠感觉填一个 0.5 就完事。建议按下面的步骤定准备 100 到 300 条真实查询并人工标注哪些候选块可以支撑答案。让检索系统输出每条查询的分数。画出阈值与准确率、召回率的变化曲线。观察两类错误误拒即能答对的查询因为分数低被拦截误放即低分垃圾内容进入上下文导致错误答案。根据产品语义选择平衡点。不同问题类型分开定阈值。问“参数值”和问“整体方案”的分数分布可能完全不同全局单一阈值会顾此失彼。5. 工程落地中的关键参数、常见坑与排查链路5.1 关键参数速查表以下参数在不同项目里差异很大表格给出的是常见范围和调整思路参数作用常见范围举例调大后果调小后果配置建议chunk_size检索单元大小256-1024 token上下文更完整但噪声增加命中更准但信息易断裂按文档类型设置多档overlap相邻块重叠50-200 token减少断裂但索引变大容易丢跨块信息优先用段落边界切top_k粗召回数量50-100候选更全但重排压力
返回列表