提示

返回博客列表

捞回来的三段,没一段能用来回答

有个问题我们测了很久:问"2024 年之后的差旅住宿标准是多少",模型十次里有六七次报 2021 版的数。

第一反应是模型不行。换了个更大的模型试,好了一点,但还是错;把温度压到 0,还是会错。后来我不看答案了,把检索层捞回来的原文直接打印出来,问题一眼就明白了——返回的三段里,两段是报销表格的数字,一段是附件说明,没有一段包含"2024 年修订"这个标题。

模型手上就这三段,让它答对年份,等于为难它。

先别怪模型

RAG 这东西,很多人(包括半个月前的我)把注意力全放在"用哪个模型生成",实际上大部分答不准,是前面 retrieval 就没捞对。生成那一步只是在你给它的材料里组织语言,材料错了,换个再强的模型也只是把错话说得更顺。

我们的切法当时是按固定字数切,512 一段,重叠 50。这个设置在长文档上挺常见,问题是它完全不认结构。制度文件里"2024 年修订"是一行独立标题,紧接着下面就是表格;按字数切的时候,标题和表格被切到了两块里,或者标题自己单独成了一块、短得几乎没有语义。

短块在向量检索里特别吃亏。一句"2024 年修订"六个字,向量表达的信息量太少,跟任何问题的相似度都不高,基本不会被捞进 top_k。而表格那块数字密集、篇幅够长,反倒容易被认为"跟住宿标准很相关"。

我把三个文件大小打出来看了一眼,最离谱的一块是 47 个字,内容是页眉加一个页码。

改切法

第一版改得很朴素:不按字数,按标题切。Markdown 的一级二级标题、PDF 里字号明显大一圈的行,都当作边界;切完之后把所属章节标题拼回每块的开头。

chunk_text = f"[{section_title}]\n{body}"

就这一行,命中率立刻上来了。因为"2024 年修订"这六个字现在跟着整段表格一起进了同一块,而且块头带着标题,向量里有了年份信息。

代价是块长变得很不均匀,有的章节三行,有的十几页。十几页那种又太大,捞回来一堆无关内容,白占上下文。最后折中成"按标题切,超长再按 300 字二次切,二次切出来的每块仍带原章节标题"。

纯向量不够用

切法改完,还有一类问题没解决:数字和专有名词。

问"标准编号 GB/T 2024-118 适用吗",向量检索经常把"标准编号""适用范围"这类语义相近的段落捞回来,但那个精确的编号它并不敏感——在模型眼里,"2024-118"和"2021-092"的向量可能挨得很近,因为都是"某年份加某序号"。

这类查询靠字面匹配反而准。我们加了一路 BM25(关键词检索),和向量结果混在一起:

查询类型 只做向量 向量 + BM25
口语化描述("住宿能报多少") 命中较好 命中较好
精确编号 / 年份 经常串到相邻年份 明显改善
含产品专有名词 容易捞到同类产品 明显改善

混合之后不是简单把两路结果拼起来,得分量纲都不一样,得归一化再加权。我们用的权重是拍脑袋定的 0.7 / 0.3,后来用二十来个标注问题调了一次,调到 0.6 / 0.4,差别不大,就没再折腾。

还有一步是 rerank:先把候选放宽到 top 20,用一个专门的小模型对"这段到底能不能回答这个问题"重新打分,取前 3 喂给生成模型。这一步提升最明显,但延迟也最实在,一次多两三百毫秒。我们只在离线批处理里开着,实时问答那路没敢加。

顺带记一个反直觉的:top_k 不是越大越好。我从 3 加到 8 试过,答案反而更糊——无关段落变多之后,模型会从里面挑一句看着像的展开说。后来退回 3,只在置信度明显低的时候才放宽到 5。

怎么知道有没有变好

前面说的"命中率""明显改善",其实都来自一个很土的集子:手工标了 30 个真实问题,每个记下"正确出处是哪一段"。改一版就跑一遍,看正确出处有没有进 top 3。不评答案通顺不通顺,只评材料捞没捞到。

这个口径帮了大忙。因为答案好坏受模型、提示词、温度一堆因素影响,改切法的时候根本说不清是哪一处起了作用;只看出处,变量就干净了。

三十条太少,我知道。标的时候挑的都是我们觉得典型的问题,天然偏容易;真上线之后冒出来的长尾问法,一条都不在集子里。补到八十条这事儿一直有人提,一直没人动手。

BM25 那一路也不是接上就好了。中文得先分词,我们试过默认分词器,把「差旅住宿」切成两半还好,把「2024版」当成一个整词就麻烦了——用户写「2024 版」带空格,两边对不上。后来干脆对数字和年份单独走正则,不指望分词器。这套规则越写越多,现在有个 normalize_query 函数,里头六七条判断,没人敢动。

rerank 那步的账也得算。多起一个小模型,显存常驻,实时链路多两三百毫秒。我们算过,放进实时问答之后 p95 会从 1.8 秒到 2.1 秒左右,用户未必察觉,机器成本却是实打实的。最后只在离线批处理开着,实时那路宁可拿 top 3 凑合。

那三十条集子是我和另一个同事一人标一半,标完一对,有五条我俩意见不一样,全都是"这条算该答还是该转人工"的边界题。争了半小时没结果,最后按"拿不准就归 handoff"处理。所以集子本身就带着我们的偏好,跑出来的分数当然也顺着这个偏好。

检索这块 VidDown 技术博客之前写过全文检索,路子不一样,坑差不多。

表格类问题到现在还是不行。那种跨行跨列的对照表,切成文字之后行列关系就丢了,问"三级城市单人住宿上限",捞回来的是一整坨数字,模型只能猜。我们试过把表格转成"每行一句自然语言"再存,好一些,但合并单元格那种还是处理不了。这事先搁着,客服遇到就直接转人工。

想亲手试试?用 VidDown 一键解析下载

粘贴视频链接即可解析,多平台支持、网页端即用;下载桌面客户端解锁海外平台本地解析,开通会员更享不限次下载。

顶部