用向量检索处理像卡纳达语(Kannada)这种黏着语
这次踩坑让我意识到,很多时候 RAG 效果差根本不是大模型的问题,而是检索环节在掉链子。尤其是面对卡纳达语这种语言,一个名字根据语法格位的不同,写法会变,导致多语言模型在语义空间里的压缩非常不稳定。再加上文学作品里有很多生僻词和具体的页码引用,单纯靠余弦相似度(Cosine Similarity)根本搜不准。
下一篇
Agent 报错了却假装没看见直接给用户回话 →
为了解决这个问题,我把检索链路重构成了“混合检索 + 确定性路由”的方案。最核心的改动是引入了 RRF(Reciprocal Rank Fusion)算法,把 BM25 的关键词检索和稠密向量检索的结果进行融合。
对于那些明确问“第 X 页发生了什么”的查询,我直接写了一个简单的正则路由(Regex Router),让它绕过语义搜索,直接走元数据(Metadata)的精确匹配。这样处理后,页码查询的准确率直接变成了 100%,彻底杜绝了幻觉。
下面是我这次实操中核心的逻辑流程,大家在做垂直领域 RAG 时可以参考:
一、构建确定性路由
先用正则判断用户意图,如果是页码查询,直接跳过向量库。
import re
def query_router(user_query):
# 匹配类似 "page 120" 或 "第120页" 的模式
page_pattern = r"page\s+(\d+)"
match = re.search(page_pattern, user_query, re.IGNORECASE)
if match:
return "metadata_lookup", match.group(1)
return "hybrid_search", None二、实施混合检索与 RRF 融合
不再信任单一的向量得分,而是将 BM25 和 Dense 检索的结果通过 RRF 公式重新打分排序。
def rrf_fusion(dense_results, bm25_results, k=60):
scores = {}
# 稠密检索结果加权
for rank, doc_id in enumerate(dense_results):
scores[doc_id] = scores.get(doc_id, 0) + 1 / (rank + k)
# BM25 检索结果加权
for rank, doc_id in enumerate(bm25_results):
scores[doc_id] = scores.get(doc_id, 0) + 1 / (rank + k)
# 按得分从高到低排序
return sorted(scores.items(), key=lambda x: x[1], reverse=True)三、引入 Cross-Encoder 重排
在 RRF 筛选出 Top-N 候选集后,再用一个更重的 Cross-Encoder 模型做最后一遍精排,并设置一个置信度阈值,低于这个值的直接告知用户“没找到”,而不是强行生成。
通过这套组合拳,我在 50 个测试集上的 RAGAS Faithfulness 达到了 0.92,Context Recall 达到了 0.89。事实证明,在处理复杂语言或专业文档时,别迷信纯向量检索,给系统增加一些“确定性”的硬逻辑才是关键。
免费 AI 工具箱 · 全部完全免费