ARTICLE DETAIL

资讯详情

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

RAG效果总是一成不变?别怪模型,是你喂给它的Context总是那几条“老面孔”!

RAG效果总是一成不变?别怪模型,是你喂给它的Context总是那几条“老面孔”! 前言被“锁死”的RAG上下文在Coze上搭建基于RAG检索增强生成的智能体时我们经常会遇到一个诡异的现象用户明明问的是不同的问题或者即使是相同的问题我们也希望模型能给出不同角度的回答。但结果呢大模型引用的那几段参考资料Context/Input永远就是数据库里的那2、3条。这就导致了一个尴尬的局面RAG变成了“精准复读”。无论你的大模型节点多么强大Temperature调得再高只要输入给它的检索结果Input是固定的那几个它生成的最终答案就不可能有太大的波澜。很多开发者会下意识地认为是Embedding模型不行或者是Prompt写得不好。但其实罪魁祸首往往是数据库检索环节的LIMIT 设置太保守了。今天我们就来聊聊如何通过调整数据库调用策略打破RAG输入内容的“固化诅咒”。一、问题的本质RAG的“候选池”枯竭在RAG架构中有一个简单的公式检索质量 召回率是否找得全 × 精确度是否找得准当你在数据库节点或知识库检索节点中设置LIMIT 5 时你实际上是在人为地截断召回率。1. 向量检索的“近邻”特性向量数据库在检索时会根据余弦相似度排序。如果你只取Top 5意味着* 只有相似度最高的5条数据能进入视野。* 第6名到第100名的数据哪怕内容相关也直接被过滤掉了。2. “伪随机”的假象你可能会说“我在代码节点里加了随机算法啊”但请清醒一点 如果你的数据库节点只吐回来5条数据你的代码节点只能在这5条里随机。这就好比让一个厨师用“白菜、萝卜、土豆、洋葱、猪肉”这5样食材做100道菜哪怕摆盘再怎么变菜品的本质还是那几样。用户看到的就是RAG给出的Input部分永远在重复那几个固定的条目。二、为什么你的RAG Input总是那几条除了LIMIT 太小还有一个容易被忽视的原因排序的固化。1. 相似度排序的陷阱默认按相似度降序排列。如果知识库中有一部分内容被优化得很好比如SEO做的好或者向量化得特别标准它们会长期霸占Top 5的位置。2. 缺乏“探索机制”传统的RAG检索是贪婪的它只想找“最像”的而不想找“可能相关且有趣”的。这导致长尾知识永远没有出头之日。结果就是你的智能体看起来很聪明因为它总能找到那几条最相关的但看起来也很笨因为它永远只知道那几条。三、破局之道RAG的“宽进严出”策略为了解决RAG输入固化的问题我们需要引入“粗排召回”与“精排筛选”的两阶段策略。核心思路在数据库检索阶段粗排多拿一点比如20条在代码节点精排再从中挑选出最合适、最多样的组合喂给大模型。1. 调整数据库节点从LIMIT 5 到LIMIT 20在Coze的数据库节点中大胆地将返回行数改为20在100行的平台上限内。* 好处极大扩展了候选池。现在代码节点有了20个“食材”可以挑选而不是原来的5个。2. 代码节点多样性筛选算法拿到了20条候选我们不能简单地随机选5条因为那样可能会丢掉最相关的信息。我们需要一种兼顾“相关性”与“多样性”的算法。以下是一个在Coze代码节点中使用的加权随机筛选策略import randomfrom typing import Dict, Anyasync def main(args: Dict[str, Any]) - Dict[str, Any]:# 接收数据库返回的20条候选记录params args.paramsrecords params.get(input, [])if len(records) 5:return {output: records}# 假设每条记录都有 score (相似度得分) 和 content (内容)# 1. 提取相似度分数作为权重基础# 为了增加多样性我们可以人为地“平滑”权重避免高分绝对垄断# 例如使用 log(1score) 或者给一个基础权重weights []for r in records:# 相似度越高权重越大但不是绝对的线性关系# 这里加1是为了防止权重为0similarity_score r.get(score, 0.5)# 引入随机扰动因子增加探索性noise random.uniform(0.8, 1.2)weights.append((similarity_score 0.1) * noise)# 2. 使用加权随机选取5条# random.choices 会根据权重分布进行有放回抽样# 这保证了高相关性的内容大概率被选中但低相关性的内容也有露脸机会selected_indices random.choices(range(len(records)), weightsweights, k5)# 去重因为choices是有放回的selected_indices list(set(selected_indices))# 如果去重后数量不足5用高权重高相似度的填补while len(selected_indices) 5:for i in range(len(records)):if i not in selected_indices:selected_indices.append(i)breakselected_records [records[i] for i in selected_indices]# 3. 按相似度重新排序可选让大模型先看到最相关的selected_records.sort(keylambda x: x.get(score, 0), reverseTrue)return {output: selected_records}3. 为什么这个方法有效* 打破固化第6-20名的数据现在有机会通过“随机扰动”进入最终的Top 5。* 保留核心高相似度的数据因为权重高依然有很高的概率被选中保证了RAG的准确性。* 增加变化即使检索结果相似由于代码节点的随机扰动每次喂给大模型的Context组合也会不同从而生成角度各异的回答。四、进阶引入“热度”与“时效性”权重为了让RAG更智能你还可以在数据库表中增加字段进一步优化权重计算1. 热度权重hot_score记录被点击或引用的次数。热门内容权重更高。2. 时效性权重time_decay新发布的内容权重更高或者根据时间进行衰减。3. 多样性惩罚如果某条内容的语义向量与已选内容过于接近降低其权重避免内容同质化。新的权重公式可以是final_weight (相似度 × 0.6) (热度归一化值 × 0.3) (时效性衰减因子 × 0.1) 随机扰动五、总结下次当你发现你的Coze智能体RAG输出总是那几样内容时请先别急着调Prompt也别怪模型不给力。请回头检查你的数据库节点1. 是不是LIMIT 设得太小了建议改为202. 是不是排序太死板了引入随机性和权重记住RAG的质量上限取决于你喂给大模型的Context质量。只有当你打破了数据库调用环节的“固化诅咒”让RAG的Input变得丰富多样你的智能体才能真正“活”起来给出令人惊喜的回答。
返回列表