当前位置: 首页 > news >正文

禅道测试用例 RAG 系统 3:让 AI 更懂你 —— QUERY 改写如何提升检索准确率

禅道测试用例 RAG 系统 3:让 AI 更懂你 —— QUERY 改写如何提升检索准确率

同一个问题,换种问法,检索结果天差地别。
本期我们聊聊如何通过 QUERY 改写,让 RAG 系统在模糊表达、关键词缺失的情况下,依然能精准召回相关用例。


一、问题背景:为什么“问得好”这么重要?

在上一期评估系统中,我们发现一个现象:查询表达方式直接影响检索效果

原始查询 问题 检索结果
如何测试跟车? 关键词不足(只有“跟车”) 召回大量不相关用例
月租车怎么延期? 表达方式单一 漏掉“月卡续期”“包月车延期”等用例

问题根源在于:用户输入与用例库的语义表达存在 Gap
用户习惯用口语、简写,而用例库的标题和步骤往往是结构化、技术化的描述。

解决方案:在检索前对用户查询进行改写,用多种方式表达同一意图,扩大召回面。


二、核心方案:QUERY 改写引擎

2.1 整体思路

原始查询 ──▶ 改写引擎 ──▶ 多个候选查询 ──▶ 并行检索 ──▶ 结果合并排序│├─ 同义词扩展(规则)├─ 关键词补充(统计)└─ 问题改写(LLM)

2.2 三种改写策略

策略1:规则同义词扩展

基于停车场领域建立同义词表,快速扩展:

SYNONYMS = {"测试": ["测试", "验证", "检查", "校验"],"跟车": ["跟车", "连续通过", "连续入场"],"月租车": ["月租车", "月卡", "包月车", "月租用户"],"延期": ["延期", "续期", "续费", "延长"]
}def expand_by_synonyms(query):words = query.split()candidates = [query]for word in words:if word in SYNONYMS:for syn in SYNONYMS[word][1:]:  # 跳过自身candidates.append(query.replace(word, syn))return list(set(candidates))

示例

  • 输入:如何测试跟车
  • 输出:如何测试跟车如何验证跟车如何测试连续通过

策略2:LLM 智能改写

用大模型生成多个表达方式,弥补规则覆盖不到的复杂表达:

def rewrite_with_llm(query):prompt = f"""请把下面这个问题改写成3个不同的表达方式,保留核心关键词,保持语义不变,输出JSON数组格式。原问题:{query}示例输出:["如何测试跟车?", "跟车功能怎么验证?", "连续入场场景测试方法"]"""response = llm.generate(prompt)return [query] + json.loads(response)  # 保留原查询

优势:能处理“车辆压地感后云支付”这类复杂场景,生成“地感触发云支付验证”等同义表达。

策略3:基于用例库的关键词提取

从用例库中统计高频词,自动补充领域术语:

from collections import Counterdef extract_keywords_from_corpus(chunks, top_k=20):# 简单分词(实际可用 jieba)words = []for chunk in chunks:words.extend(chunk.split())counter = Counter(words)return [word for word, _ in counter.most_common(top_k)]# 高频词示例:["测试", "车辆", "跟车", "月租车", "延期", "云支付", ...]

在改写时,如果查询中缺少这些高频领域词,可以自动补充。


三、数据流设计:并行检索 + 结果合并

                    ┌─────────────────────────────────────────┐│           QUERY 改写模块                │└─────────────────────────────────────────┘│┌──────────────────────────┼──────────────────────────┐▼                          ▼                          ▼┌──────────────┐          ┌──────────────┐          ┌──────────────┐│ 策略1: 规则  │          │ 策略2: LLM   │          │ 策略3: 统计  ││ 同义词扩展   │          │ 智能改写     │          │ 关键词补充   │└──────────────┘          └──────────────┘          └──────────────┘│                          │                          │└──────────────────────────┼──────────────────────────┘│▼┌────────────────┐│  合并候选查询  ││  [Q1, Q2, Q3] │└────────────────┘│┌──────────────────────────┼──────────────────────────┐▼                          ▼                          ▼┌──────────────┐          ┌──────────────┐          ┌──────────────┐│  ChromaDB    │          │  ChromaDB    │          │  ChromaDB    ││  检索 Q1     │          │  检索 Q2     │          │  检索 Q3     │└──────────────┘          └──────────────┘          └──────────────┘│                          │                          │└──────────────────────────┼──────────────────────────┘│▼┌────────────────┐│  结果合并排序  ││  (RRF算法)    │└────────────────┘│▼┌────────────────┐│  最终Top5结果  │└────────────────┘

结果合并算法:RRF(Reciprocal Rank Fusion)

RRF 是经典的结果融合算法,根据文档在不同查询结果中的排名计算综合得分:

def rrf_merge(results_list, k=60):"""results_list: 每个查询的检索结果列表,每个元素格式为 [{id, content, ...}]k: 平滑参数,通常取 60"""scores = {}for results in results_list:for rank, doc in enumerate(results):doc_id = doc['id']# 排名从 0 开始,所以 rank+1 作为实际排名scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank + 1)# 按综合得分降序排序sorted_docs = sorted(scores.items(), key=lambda x: x[1], reverse=True)return [doc_id for doc_id, _ in sorted_docs]

为什么用 RRF?

  • 不依赖绝对分数,只依赖排名,避免不同查询检索分数量纲不一致的问题。
  • 简单高效,在信息检索领域被广泛验证。

四、效果验证

4.1 量化指标对比

在 30 个测试查询上对比改写前后的效果:

指标 改写前 改写后 提升
Recall@5 0.60 0.75 +25%
平均相关性(人工打分) 3.2 3.8 +19%
MRR 0.68 0.79 +16%

4.2 典型案例

查询如何测试跟车?

改写前 Top3 改写后 Top3
1. 天启月卡延期测试 1. 跟车测试用例A
2. 车辆压地感云支付 2. 防止跟车测试用例B
3. 邻道干扰测试 3. 车辆压地感云支付

改写后,期望用例被成功召回并排到前列。

4.3 打分界面增强

在评估系统中增加对比模式,方便人工验证:

┌─────────────────────────────────────────────────────────────────┐
│ 查询对比:如何测试跟车                                            │
├─────────────────────────────────────────────────────────────────┤
│ 改写前:如何测试跟车                                              │
│ 改写后:如何测试跟车 / 跟车测试 / 车辆跟车行为测试                 │
├─────────────────────────────────────────────────────────────────┤
│ 改写后检索结果:                                                  │
│ 1. 跟车测试用例A                     [评分: ★★★★★]              │
│ 2. 防止跟车测试用例B                   [评分: ★★★★☆]              │
│ 3. 车辆压地感云支付                   [评分: ★★☆☆☆]              │
└─────────────────────────────────────────────────────────────────┘

总结

QUERY 改写是 RAG 系统中投入产出比极高的优化点:

  • 成本低:规则改写几乎零成本,LLM 改写调用量可控
  • 见效快:召回率平均提升 20%~30%
  • 可迭代:同义词表可随业务增长持续扩充

下一期,我们将分享如何结合用户反馈数据,实现动态调整改写策略,让系统自适应优化。

如果你也在做 RAG 应用,欢迎在评论区交流你的查询优化经验!

http://www.jsqmd.com/news/540517/

相关文章:

  • Teensy MIDI控制器开发库:物理交互到MIDI映射的工程实践
  • GNSS数据处理效率翻倍:FileZilla+crx2rnx自动化脚本一键下载转换RINEX观测值
  • Windows10家庭版也能用!5分钟搞定FTP服务器搭建(附防火墙配置)
  • 跨境服务数字化转型 JAVA 国际版打手俱乐部陪玩系统完整开发教程
  • 2026生产视黄醇亚油酸酯的厂家推荐及行业选择参考 - 品牌排行榜
  • CTFshow Web15:突破PHP命令执行限制的实战技巧
  • MCP开发环境搭建全攻略(VS Code插件安装避坑白皮书·2024官方认证版)
  • STM32上如何用nanopb实现轻量级protobuf通信(附完整工程配置)
  • 告别Transformer!用PyTorch从零实现MLP-Mixer图像分类(附完整代码与调参技巧)
  • League-Toolkit:英雄联盟玩家的终极自动化助手,一键掌握游戏优势
  • Vision Pro实战入门:从零到一的工业视觉软件安装与配置指南
  • 2026高稳定性视黄醇亚油酸酯厂家排名及行业趋势解析 - 品牌排行榜
  • 华为AR路由器VRRP配置实战:从单点故障到流量黑洞,一个实验全搞定
  • Lunar-Javascript:轻量级日历转换解决方案,让传统历法轻松融入现代应用
  • AI人脸隐私卫士实战指南:根据场景选择最佳打码样式
  • Simulink+HIL实战:如何用CAN总线实现多电机扭矩分配闭环测试(附PID调参技巧)
  • 在 React 中,useRef、ref 属性以及 forwardRef 是处理“引用”(访问 DOM 节点或组件实例)的核心概念
  • STM32上如何用串口BREAK中断优雅处理DMX与RDM协议(附完整代码)
  • NetGen:高质量网格生成的科学计算解决方案
  • 创龙T113 SDK编译实战:从环境配置到疑难排错
  • 双端适配陪玩系统 JAVA 国际版源码 + H5 + 打手俱乐部集成方案
  • 从项目实战出发:用pip和venv搞定Python多版本依赖隔离与离线部署(附requirements.txt最佳实践)
  • 如何用PortProxyGUI简化Windows端口转发配置
  • 光学设计避坑指南:CODEV10.2中那些容易忽略的细节(附练习题解析)
  • Go-Zero + DTM实战:电商订单与库存的分布式事务处理(附完整代码)
  • 从 0 到 1 搭建企业级 UI 自动化测试框架(Python + Selenium + Pytest + Allure)
  • AHT20传感器数据漂移?STM32硬件I2C与软件模拟的稳定性对比测试
  • 量子阱、量子线和量子点有什么区别?从游泳池到楼梯的通俗解释
  • Python实现简易可信度推理引擎:用20行代码复现经典CF模型
  • Cortex-M架构运行Linux的技术挑战与替代方案