旅行助手 AgenticRAG 系统的五次迭代优化实录

给 trplanning 多智能体旅行助手接 Agentic RAG 知识库的时候,我想得挺简单——切一切文档丢进向量库就完事了。结果第一次跑 RAGAS 评估,综合质量分 42.00%。忠实度 73%,检索召回 23%。说实话看到这个数字还是挺打击的。

后面花了点时间慢慢打磨,每改一轮跑一次评估,看数据说话。五轮迭代下来,自己写的测试脚本的综合质量分从 42% 提到了 76%,忠实度从 73% 拉到 98%,检索召回从 23% 干到 75%。这篇文章把整个过程记录下来——每轮做了什么、为什么这么做、效果怎么样。


背景

trplanning 是一个基于 LangGraph 的多智能体旅行助手,能够帮用户查火车票、查天气、规划行程。但它有一个明显短板——缺少领域知识。契机是当我问“徐州有什么好吃的”时候,他回答的没有我们所熟知的“徐州烧烤”“肉酱米线”,而是干拌面这种过时的信息。

于是有了 Agentic RAG:让 Agent 自主决策何时检索、检索什么,将静态旅行攻略知识注入对话。技术栈选型:

组件 选型 理由
向量数据库 Milvus Lite 可以部署在低配置的服务器上
Embedding BGE-M3 中文效果好,1024 维,支持稀疏+稠密双表征
混合检索 BM25 + Dense 关键词 + 语义双路召回
重排序 BGE-Reranker 重排序,生成更精准
评估 RAGAS 忠实度、相关性、精度、召回四维量化

一、优化全景

1
2
V1 初始上线 ──→ V2 三阶段重构 ──→ V3 检索策略深挖 ──→ V4 召回精度打磨 ──→ V5 上下文质量收官
42.00% 45.97% 51.02% 54.54% 76.05%

下面逐一拆解每轮迭代做了什么、为什么这样做、效果如何。


二、初始上线(综合分 42.00%)

对应提交bb8d34d — AgenticRAG 构建添加

第一版的目标很简单:把整个 RAG 流水线跑通。用的是最经典的方案:

  • Dense 检索:BGE-M3 Embedding → Milvus 向量检索 Top-K
  • BM25 检索:基于 jieba 分词的稀疏检索
  • 融合方式:加权求和(Dense 0.7 + BM25 0.3)
  • 重排序:BGE-Reranker 模型
1
2
3
4
5
6
7
8
9
📊 RAGAS 指标(V1):
忠实度:73.48%
答案相关性:47.40%
检索精度:23.33%
检索召回:23.78%
hit_rate@5:86.67%
mrr:82.22%
───────────────────────────
综合质量分:42.00%

问题诊断

  • 检索精度和召回双双偏低(~23%),说明大量相关文档没被召回
  • 答案相关性不到 50%,LLM 拿到的上下文质量不够好
  • 加权求和的融合方式太粗糙——Dense 和 BM25 的分数分布差异大,简单加权容易”一边倒”

三、三阶段重构(综合分 45.97%)

对应提交b848d65 — RAG优化(文本切割优化、元数据增强、混合检索三阶段)

这一轮我做了三件事,也是后续所有优化的基础:

1. 文本切割优化

原来的切割方式太粗暴——按固定 token 数硬切,经常把一段完整攻略切成两半。新方案:

  • 先按 Markdown 标题(#/##/###)做语义边界切分
  • 再在标题内部做递归语义切分,保证每个 chunk 是自包含的信息单元
  • chunk_size 从 512 调整到 768,chunk_overlap 从 64 调整到 128

2. 元数据增强

每个 chunk 自动注入结构化元数据:

1
2
3
4
5
6
7
{
"city": "北京",
"category": "美食攻略",
"subcategory": "烤鸭",
"title": "北京必吃美食推荐",
"chunk_index": "3/8"
}

这对后续检索过滤和 Reranker 重排序至关重要——Reranker 可以根据城市、类别做意图匹配。

3. 混合检索三阶段流水线

1
2
3
4
5
6
7
8
9
Phase 1: 并行召回
├── Dense Search (Milvus) → Top-20
└── BM25 Search (jieba) → Top-20

Phase 2: 融合排序
└── 加权融合 → Top-15

Phase 3: 重排序
└── BGE-Reranker → Top-5
1
2
3
4
5
6
7
📊 RAGAS 指标(V2):
忠实度:84.67%(↑ +11.19%)
答案相关性:47.08%(基本持平)
检索精度:23.33%(未变)
检索召回:28.78%(↑ +5.00%)
───────────────────────────
综合质量分:45.97%(↑ +3.97%)

收益:忠实度大幅提升(+11%),说明元数据增强让 LLM 更容易找到证据支撑。但检索精度和召回改善有限——融合策略仍然是瓶颈。


四、检索策略深度优化(综合分 51.02%)

对应提交45dc46d(RRF 融合 + 意图感知 Reranker)、56f1f3e(HyDE 生成)

这是改动最大、收益最明显的一轮。做了三个关键优化:

1. RRF 融合替代加权求和

加权求和的根本问题是:Dense 分数范围是 0.50.9,BM25 分数范围是 050,直接加权毫无意义。RRF(Reciprocal Rank Fusion) 只看排序位置不看绝对分数:

$$
\text{RRFscore}(d) = \sum_{r \in R} \frac{1}{k + \text{rank}_r(d)}
$$

其中 $k=60$ 是平滑参数(后续改为可配置)。这样两路检索的排序结果可以公平融合,不再有”数值尺度”问题。

2. HyDE 假设性文档生成

这是整个优化中最”聪明”的一步。用户查询通常是短问题(”北京烤鸭哪家好吃”),而知识库文档是长文本。直接做 embedding 相似度匹配,存在 语义鸿沟

HyDE(Hypothetical Document Embeddings)的做法:先让 LLM 根据用户问题生成一篇假设性的旅行攻略片段,再拿这个假设文档去做向量检索

1
2
3
4
5
6
7
8
用户问:"北京烤鸭哪家好吃?"

LLM 生成假设文档:
"北京烤鸭以全聚德、便宜坊、大董等老字号最为知名。
全聚德以前门总店最正宗,便宜坊以焖炉烤鸭见长,
大董则以创新烤鸭和精致环境著称..."

拿这段假设文档做 Embedding → Milvus 检索

这样检索到的真实文档与用户意图的匹配度大幅提升。

3. 意图感知 Reranker

原来的 Reranker 只做纯文本相关性判断。现在在 Rerank 之前先做意图分类:

  • 识别查询类型:美食推荐 / 景点攻略 / 交通出行 / 住宿建议 / 通用问答
  • 根据意图类型调整 Reranker 的权重偏好(如美食类优先匹配”店名””菜品”等实体)
1
2
3
4
5
6
7
8
9
10
📊 RAGAS 指标(V3):
忠实度:90.21%(↑ +5.54%)
答案相关性:51.35%(↑ +4.27%)
检索精度:24.42%(↑ +1.09%)
检索召回:38.10%(↑ +9.32%)
检索相关性(NV):64.29%(新增指标)
hit_rate@5:100.00%(↑ +20.00%)
mrr:95.24%(↑ +15.24%)
───────────────────────────
综合质量分:51.02%(↑ +5.05%)

收益:检索召回暴涨 +9.32%,hit_rate@5 直接拉满到 100%,MRR 冲到 95.24%。RRF + HyDE 的组合拳效果显著。但检索精度仍然偏低——召回太多了,混进了不少不太相关的文档。


五、召回精度打磨(综合分 54.54%)

对应提交ab3a852(相邻 chunk 扩展)、3f84d18(MMR 多样性)、3a8c732(城市软匹配)、6ff109e(BM25 sentinel)、fb49cbb(硅基 Rerank)

V3 召回率上来了,但精度没跟上。这一轮的核心思路是:在不牺牲召回的前提下提高精度

1. 相邻 Chunk 扩展

检索到的 chunk 往往缺少上下文。比如一篇攻略的第 3 段提到了”推荐全聚德”,但前因后果在第 2 段和第 4 段。解决方案:

  • 检索命中 chunk_i 时,自动附带 chunk_{i-1} 和 chunk_{i+1}
  • 去重后合并为完整上下文
  • 这样每次检索实际获取的是”上下文窗口”而非孤立片段

2. MMR 多样性选择

当 Reranker 返回 Top-K 时,经常出现”全是一个主题”的情况——比如 5 条结果都是烤鸭推荐,而用户其实问的是”北京美食”(应该覆盖烤鸭、涮羊肉、炸酱面等)。

MMR(Maximal Marginal Relevance) 的做法:

  • 第 1 轮:选最相关的结果
  • 第 2~K 轮:在”相关性”和”与已选结果的差异性”之间取平衡

$$\text{MMR} = \arg\max_{d_i \in R \setminus S} \left[ \lambda \cdot \text{sim}(d_i, q) - (1-\lambda) \cdot \max_{d_j \in S} \text{sim}(d_i, d_j) \right]$$

参数 $\lambda=0.7$(后续调整为 0.65),保证结果多样性。

3. 城市软匹配 + 加分机制

用户说”京城有什么好吃的”,传统 BM25 搜不到”北京”。解决方案:

  • 建立城市别名映射表:{"京城": "北京", "魔都": "上海", "蓉城": "成都", ...}
  • 检索时自动展开查询词
  • 城市匹配的文档获得额外加分(+0.1)

4. BM25 Sentinel 机制

BM25 需要扫描全量文档做关键词统计。每次请求都全量扫描太慢了。优化方案:

  • 用一个轻量级 sentinel 标记判断语料库是否变更
  • 仅在文档入库/删除时重建 BM25 索引
  • 日常检索直接复用缓存索引

5. 硅基流动 Rerank 模型

BGE-Reranker虽然免费,但是效果不太行,于是切换到硅基流动的 QWen:Rerank。

1
2
3
4
5
6
7
8
9
10
11
📊 RAGAS 指标(V4):
忠实度:87.47%(↓ -2.74%,评估集扩展到35条后难度提升)
答案相关性:43.86%(↓ -7.49%,同上)
检索精度:41.59%(↑ +17.17%)
检索召回:45.24%(↑ +7.14%)
检索相关性(NV):78.57%(↑ +14.28%)
keyword_hit_rate:73.88%(更严格的自定义指标)
context_hit@5:64.29%
mrr:60.71%(评估集从14条扩大到35条)
───────────────────────────
综合质量分:54.54%(↑ +3.52%)

收益:检索精度暴涨 +17%,说明 MMR + 相邻 chunk 的组合有效减少了冗余结果。注意这轮评估集从 14 条扩展到 35 条,难度大幅提升,综合分仍然上涨,含金量很高。


六、上下文质量收官

对应提交01d1188(元数据注入升级)、8c1026e(切分参数调优)、10f27d4(答案去噪)、4813869/fcbacdc(相邻 chunk 扩展调优)

前四轮把检索管道打磨得差不多了,最后一轮聚焦在上下文质量答案生成的细节上。

1. 元数据注入升级:结构化上下文前缀

V2 的元数据只是附着在 chunk 上。V5 将其注入到 chunk 内容本身作为前缀:

1
2
3
4
5
6
原来(chunk 原文):
"全聚德烤鸭是北京最有名的老字号,前门总店最为正宗..."

现在(注入元数据前缀):
"[城市: 北京 | 类别: 美食攻略·烤鸭 | 来源: 北京必吃美食推荐]
全聚德烤鸭是北京最有名的老字号,前门总店最为正宗..."

这样做的好处:Embedding 模型在向量化时会”看到”这些结构化信息,城市+类别的语义信号直接参与相似度计算,而不是仅靠原始文本。

2. 切分参数精细调优

经过多轮 A/B 测试,最终确定的切分参数:

参数 V1 V5 说明
chunk_size 512 1024 更大窗口保留完整语义
chunk_overlap 64 256 更高重叠减少边界截断
标题切分 三级标题 Markdown 结构感知
元数据前缀 结构化注入 提升 Embedding 质量

3. 答案生成去噪

检索返回 Top-15 个 chunk,但并非所有都对答案有用。新增一层相关性过滤

  • 对每个 chunk 计算与 query 的快速相似度(基于 jieba 关键词命中 + 标题匹配)
  • 过滤掉相似度 < 阈值的 chunk(通常是误召回的无关文档)
  • 仅将高相关 chunk 送入 LLM 生成答案

这消除了之前”LLM 被低相关文档带跑偏”的问题。

4. 相邻 Chunk 扩展参数调优

V4 引入了相邻 chunk 扩展,但参数没调好——有时扩展太多导致上下文过长。V5 的调整:

  • 每侧只扩展 1 个相邻 chunk(而非 2 个)
  • 去重后按原始顺序拼接
  • 总上下文控制在 3000 token 以内
1
2
3
4
5
6
7
8
9
10
11
📊 RAGAS 指标(V5 最终版):
忠实度:98.32%(↑ +10.85%)
答案相关性:77.79%(↑ +29.93%)
检索精度:78.60%(↑ +35.01%)
检索召回:79.48%(↑ +35.24%)
检索相关性(NV):100.00%(↑ +21.43%)
keyword_hit_rate:89.05%(↑ +15.17%)
context_hit@5:82.86%(↑ +18.57%)
mrr:69.32%(↑ +9.61%)
───────────────────────────
综合质量分:76.05%(↑ +21.51%)

35 条用例逐条诊断(最终版):

1
2
3
4
5
6
7
8
9
10
11
🟢 西安回民街有什么好吃的?                命中5/5   (100%)
🟢 成都火锅串串哪家好吃? 命中11/11 (100%)
🟢 带孩子去三亚怎么玩? 命中7/7 (100%)
🟢 国内哪里看海最好? 命中8/8 (100%)
🟢 故宫门票怎么预约? 命中14/16 (88%)
🟡 广州三日游怎么安排? 命中6/11 (55%)
缺失: 白云山, 必去, 长隆, 野生, 亲子
🟡 国内有哪些古镇值得去? 命中3/7 (43%)
缺失: 周庄, 西塘, 南浔, 六大
─────────────────────────────────────────
🟢=命中≥60%: 33/35 (94.3%) 🟡=30-60%: 2/35 (5.7%) 🔴=<30%: 0

94.3% 的用例达到绿区(命中≥60%),只有 2 条在黄区,没有红区用例。两个黄区用例(”古镇推荐””广州三日游”)的共性是:知识库覆盖不足——这不是检索管道的问题,而是数据层需要补充。


七、全旅程数据对比

指标 V1 V2 V3 V4 V5 总提升
忠实度 73.48% 84.67% 90.21% 87.47% 98.32% +24.84%
答案相关性 47.40% 47.08% 51.35% 43.86% 77.79% +30.39%
检索精度 23.33% 23.33% 24.42% 41.59% 78.60% +55.27%
检索召回 23.78% 28.78% 38.10% 45.24% 79.48% +55.70%

检索召回提升最大(+51.70%),其次是检索精度(+38.27%)。忠实度最终冲到 98.32%,说明 LLM 生成的回答基本都有据可查。答案相关性虽然也涨了 21%,但 68.79% 仍是最短板——这跟知识库覆盖面直接相关。


八、回头再看

回顾整个历程,有几条在 RAG 优化中反复验证有效的经验:

1. 先修路再跑车

V1→V2 阶段没有急于上高级检索策略,而是先把切分、元数据、流水线架构做扎实。没有好的底座,上层优化都是空中楼阁。

2. 召回和精度是跷跷板

V3 大幅提升召回(HyDE + RRF),但精度没跟上。V4 用 MMR + 去噪拉回精度。先放开召回,再收紧精度,比反过来高效得多。

3. 评估体系必须先行

每一轮优化都有 RAGAS 数据支撑。没有评估体系,你根本不知道改一个参数是正向还是负向。评估集从 14 条扩展到 35 条后,才发现很多”看似有效”的优化在更广的用例上其实是负优化。

4. 元数据是 RAG 的隐性资产

从 V2 的简单标注到 V5 的结构化前缀注入,元数据贯穿始终。好的元数据设计能让 Embedding、检索、Reranker 每一层都受益。

5. 不要过早优化

V1 的加权求和虽然粗糙,但它让我们快速验证了整个流水线是否跑通。如果一开始就花大量时间调 RRF 参数,可能连基础 bug 都没发现。

6. 数据质量 > 算法技巧

最终版仍有 2 条用例在黄区(古镇推荐、广州三日游),问题的根源是知识库覆盖不足,而非检索管道。没有好数据,再好的检索算法也不行


九、技术栈一览

层级 组件 备注
向量数据库 Milvus Lite 3.0 本地 .db 文件,零部署,可平滑迁移
Embedding BGE-M3 1024维,中英文双优,支持稀疏+稠密
稀疏检索 BM25 (jieba 分词) 自建 sentinel 缓存机制
融合算法 RRF (k=60,可配置) 从加权求和演进而来
查询增强 HyDE LLM 生成假设文档桥接语义鸿沟
重排序 硅基流动 Rerank API 从本地 BGE-Reranker 演进
多样性 MMR (λ=0.65) 避免 Top-K 结果冗余
文本切分 Markdown 标题感知 + 递归语义切分 chunk_size=1024, overlap=256
元数据 结构化前缀注入 城市/类别/标题注入 Embedding
评估 RAGAS + 自定义指标 keyword_hit_rate, context_hit@5, MRR
编排 LangGraph Agent Tool 形式嵌入多智能体系统

十、后续方向

  1. 知识库扩充:古镇、小众目的地等长尾内容的覆盖
  2. Query Rewriting:在检索前用 LLM 改写用户查询,进一步提升召回
  3. 多模态 RAG:攻略中的图片(地图、实拍)纳入检索
  4. 用户反馈闭环:根据用户点赞/踩自动调整检索权重
  5. A/B 实验框架:支持多套检索策略在线对比

本文所有数据来自 trplanning 项目的 RAGAS 评估报告。

本作品由 熙衍 于 2026-05-27 00:00:00 发布
作品地址:旅行助手 AgenticRAG 系统的五次迭代优化实录
除特别声明外,本站作品均采用 CC BY-NC-SA 4.0 许可协议,转载请注明来自 熙衍
Logo