星期天傍晚,程序员阿凯走进常去的那家小馆。老板娘迎上来:“今天吃点什么?”“来点下饭的。”“咱家毛血旺最下饭。”“上次那个微辣的还行吗?”“有汤吗?”“有,那就微辣毛血旺,再给您加碗汤。” 注意,阿凯第三句话只说“有汤吗”——老板娘却听懂了,他要的是“微辣、下饭、有汤”的一道菜。她能听懂,靠的是记住前面几轮对话。传统的搜索引擎遇到这种情况就抓瞎了:你搜“有汤吗”,它返回一堆“西红柿鸡蛋汤的做法”。对话式搜索要做的事,就是让搜索引擎像老板娘一样,把前几轮对话“记在心里”,再理解你这句话到底想要什么。 本文要讲两个代表模型——CAST和CONVKNRM,它们就像两位性格不同的服务员。一位会做笔记(CAST),把聊天要点整理成一句完整的需求再去找菜;另一位不写笔记但熟记菜谱(CONVKNRM),拿当前这句话和记忆里的线索,在同一本菜单上做多维度“软匹配”,也能猜得八九不离十。

岗位关联

掌握对话式检索的两种核心思路(上下文增强与软匹配),是在搜索/问答产品中落地“多轮追问答疑”的关键技能,也是从传统搜索架构迈向对话式智能检索的一道必考题。

目录
  1. 可视化演示
  2. 认识对话式搜索:从“一句入菜”到“连点三句”
  3. 对话历史建模:老板娘的记忆管理
  4. CAST模型原理:先补齐需求单再上菜
  5. KNRM软匹配原理:老师傅的多维度软匹配
  6. 双模型对比:两位服务员谁更强
  7. 评估指标:怎样考核服务员称职
  8. 应用与展望:把好服务员请进每个行业
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示多轮对话搜索流程、CAST上下文感知语义转换、CONVKNRM卷积核匹配及查询改写机制。

本节配有交互动效(进入视口后自动加载,约 3KB)。

多轮对话搜索流程 每轮查询依赖前序上下文构建完整搜索意图 多轮查询联合表示提升检索准确率 Score(qt, d) = f(q1...qt, d) 会话级评估指标衡量整体检索质量

认识对话式搜索:从“一句入菜”到“连点三句”

想象一个只按一句话上菜的餐馆:你说“来点辣的”,它端来剁椒鱼头;你又说“不要太辣了”,它又端来一道水煮牛肉——完全没意识到你是在修正上一句。这就是传统单轮搜索的困境:每一句话都被当成独立请求,用户被迫把完整需求塞进一行关键词里。而对话式搜索不同,它像川菜馆老板娘那样,把“来点下饭的”“上次微辣的”“有汤吗”三句话串起来,最终端出“微辣毛血旺加汤”。

技术上说,对话式检索在时间步 $t$ 收到用户当前输入 $q_t$ 时,需要结合之前 $t-1$ 轮的历史 $C_{1:t-1}$,共同决定搜索意图。这两部分的关系可以用一个统一的公式描述:

明白了这个公式,就理解了对话式搜索的本质:它不再是“听一句话,找一批结果”,而是“听一段话,找一遍结果”。老板娘和阿凯的对话中,“有汤吗”三个字离开了前文就是一道汤的做法,放进上下文里就是一道菜的限定条件。这第一层认知,是所有后续模型的地基。

q~t=Φ(qt,C1:t−1)\tilde{q}_t = \Phi(q_t, C_{1:t-1})
意思是:真正去检索用的不是用户刚说的那句话,而是“那句话 + 之前聊过的所有有效信息”融合后的新查询。
  1. 当前查询 $q_t$第 $t$ 轮用户刚输入的原话,比如“有汤吗”。
    qt=当前轮用户输入q_t = \text{当前轮用户输入}
  2. 历史上下文 $C_{1t-1}$:前 $t-1$ 轮对话的内容编码,比如“来点下饭的”“上次微辣的”。
    C1:t−1={u1,u2,…,ut−1}C_{1:t-1} = \{u_1, u_2, \ldots, u_{t-1}\}
  3. 融合函数 $\Phi(\cdot)$负责把原话与历史“对齐、取舍、压缩”的模型,CAST 和 CONVKNRM 正是两种不同的 $\Phi$。
    Φ:(当前话,历史)↦完整意图\Phi: (\text{当前话}, \text{历史}) \mapsto \text{完整意图}
  4. 增强查询 $\tilde{q}_t$融合后的新查询表示,替代原始输入去检索文档。
    q~t∈Rd,d 为向量维度\tilde{q}_t \in \mathbb{R}^d, \quad d \text{ 为向量维度}

对话历史建模:老板娘的记忆管理

老板娘不是把所有话都记在小本子上。阿凯上周说“不要香菜”,这周说“微辣”,老板娘会记住最近的、最重要的;绝不会把三年前的闲聊也翻出来影响今天上菜。对话历史建模,就是给搜索引擎设计一套“记忆管理”规则。

最朴素的做法是把全部历史文本拼起来喂给模型,但历史越长噪声越多,计算成本也越高。所以工业界普遍采用三种手段:截断(只保留最近 K 轮)、关键信息抽取(只记实体、约束、否定词)、时间衰减(越早的历史权重越低)。时间衰减用一个简单的指数权重公式表示:

回到小馆,阿凯说“上次那个微辣的还行吗”这句话时,老板娘脑子里“上次”对应的记忆已经有折扣,但“还挺清楚”;而更多年前的事早已模糊。时间衰减让模型既不会忘事,也不会被陈年旧账干扰。历史建模是整个对话式搜索的“记忆系统”,CAST 和 CONVKNRM 都建在这套记忆之上。

wi=γ t−i,0<γ<1w_i = \gamma^{\,t-i}, \quad 0 < \gamma < 1
第 $i$ 轮历史在当前第 $t$ 轮被参照的权重,与间隔轮数成指数反比。间隔越远,记忆越模糊。
  1. 轮次差 $t-i$当前轮与历史第 $i$ 轮的间隔,间隔越大代表越久远。
    Δ=t−i\Delta = t - i
  2. 衰减因子 $\gamma$每经过一轮,记忆保留的比例(如 0.9)。这是超参数,由验证集调出。
    0<γ<10 < \gamma < 1
  3. 权重 $w_i$历史第 $i$ 轮被利用的强度。$\gamma=0.9$ 时,间隔 3 轮的权重约为 $0.9^3 \approx 0.73$。
    wi=γΔw_i = \gamma^{\Delta}

CAST模型原理:先补齐需求单再上菜

假设店里有一位特别细心的前台,她会把客人的每句话整理成一张“完整需求单”:客人说“来点下饭的”,她写上“主食+下饭”;客人说“上次微辣的还行吗”,她补上“微辣+之前点过”;客人说“有汤吗”,她写“要有汤”。厨房照单做菜,永远不会误解“有汤吗”是“要一碗汤”。CAST 模型的核心思想正是如此——先把上下文补全成完整查询,再去做检索。

CAST(Context-Aware Search Transformer)用一个 Transformer 编码器同时读入当前查询和对话历史,然后通过注意力机制让当前查询的每个词“主动去看”历史里哪些词更相关。注意力权重最大的历史词,会被融合进当前查询的向量表示里,最终形成增强查询 $\tilde{q}_t$。注意力权重的计算公式如下:

有了这份“需求单”,CAST 的优势一目了然:检索模块拿到的永远是完整句,不需要自己猜省略和指代。就像厨房永远拿到的是“微辣+下饭+有汤”的完整单子,而不是一句“有汤吗”。代价是,如果历史里混进了错误信息(比如客人改口了),这一句错话也会被当成金科玉律写进需求单。

αtj=exp⁡(qt⋅hj)∑k=1t−1exp⁡(qt⋅hk)\alpha_{tj} = \frac{\exp(\mathbf{q}_t \cdot \mathbf{h}_j)}{\displaystyle\sum_{k=1}^{t-1} \exp(\mathbf{q}_t \cdot \mathbf{h}_k)}
当前查询向量 $\mathbf{q}_t$ 与第 $j$ 轮历史向量 $\mathbf{h}_j$ 越相似,该轮历史获得的注意力权重越高,在融合时被吸收得越多。
  1. 相似度点积 $\mathbf{q}_t \cdot \mathbf{h}_j$衡量当前查询和第 $j$ 轮历史在语义空间中的相关程度。
    etj=qt⋅hje_{tj} = \mathbf{q}_t \cdot \mathbf{h}_j
  2. softmax 归一化对原始分数取指数并除以所有历史分数的总和,使权重和为 1。
    αtj=eetj∑keetk\alpha_{tj} = \frac{e^{e_{tj}}}{\sum_k e^{e_{tk}}}
  3. 增强查询 $\tilde{\mathbf{q}}_t$把各轮历史按注意力权重加权求和后,叠加到当前查询上。
    q~t=qt+∑j=1t−1αtj hj\tilde{\mathbf{q}}_t = \mathbf{q}_t + \sum_{j=1}^{t-1} \alpha_{tj} \, \mathbf{h}_j

KNRM软匹配原理:老师傅的多维度软匹配

另一位老师傅从另一家川菜馆学成归来,他从来不写需求单。客人说“有汤吗”,他脑海里自动浮现“微辣”“下饭”“有汤”几个模糊线索,然后对着菜谱一道道盘算:毛血旺和“微辣”完全契合,但没有汤;番茄牛腩汤有汤、够微辣,还带点下饭。他不追求每个字都对齐,而是从多个“接近程度”维度打分——这,就是 CONVKNRM(基于核函数的神经相关性匹配模型)的哲学。

CONVKNRM 先把查询和文档用卷积神经网络切成一堆 n-gram(连续词的片段),然后两两计算余弦相似度 $m_{ij}$。接着用一组高斯核把这些相似度“软分桶”:完全一致的分到“精确匹配”桶,比较接近的分到“近似匹配”桶,不太相关的分到“弱相关”桶。每一桶内累计命中次数,最终加权求和得到相关性得分。核池化的核心公式是:

老师傅的这种“软匹配”格外宽容:用户口语化、说错字、句子残缺,只要语义上沾边,都能在不同桶里获得信号。它不像 CAST 非要“补全一句完整的话”,而是直接带着线索去文档里捞——捞得多、捞得准,分数就高。

Kk(q,d)=∑ilog⁡(1+∑jexp⁡(−(mij−μk)22σk2))K_k(q,d) = \sum_i \log \left(1 + \sum_j \exp\left(-\frac{(m_{ij} - \mu_k)^2}{2\sigma_k^2}\right)\right)
第 $k$ 个核桶的匹配强度:查询每个 n-gram 在文档里找到的“软命中”数量,经过对数压缩后累加。$\mu_k$ 控制桶的中心位置(完全匹配还是近似匹配),$\sigma_k$ 控制桶的容忍宽度。
  1. 相似度矩阵 $m_{ij}$查询第 $i$ 个 n-gram 与文档第 $j$ 个 n-gram 的余弦相似度,取值在 -1 到 1。
    mij=gi⋅gj∥gi∥⋅∥gj∥m_{ij} = \frac{\mathbf{g}_i \cdot \mathbf{g}_j}{\|\mathbf{g}_i\| \cdot \|\mathbf{g}_j\|}
  2. 高斯核函数把相似度 $m_{ij}$ 换算成“距中心 $\mu_k$ 的软命中”,相似度越接近 $\mu_k$,输出越接近 1。
    exp⁡(−(mij−μk)22σk2)\exp\left(-\frac{(m_{ij}-\mu_k)^2}{2\sigma_k^2}\right)
  3. 内层累加对同一个查询片段,统计文档中所有片段的软命中之和。
    ∑jexp⁡(−(mij−μk)22σk2)\sum_j \exp\left(-\frac{(m_{ij}-\mu_k)^2}{2\sigma_k^2}\right)
  4. 对数压缩与外层累加$\log(1+\cdot)$ 抵消命中次数线性增长带来的主导效应,最后把每个查询片段的贡献加总成该桶强度。
    Kk(q,d)=∑ilog⁡(1+soft_hitsi)K_k(q,d) = \sum_i \log\left(1 + \text{soft\_hits}_i\right)

双模型对比:两位服务员谁更强

现在把细心理查和老师傅请进同一家店,让围观群众评评理。细心理查(CAST)胜在“理解准确”——需求单写全了,厨房照着做,很少出错;但遇到客人自己都说不清楚、或者中间改过口的情况,需求单可能会写错。老师傅(CONVKNRM)胜在“宽容”——不用写全需求单,拿零散线索也能对上几道菜,特别耐受口语噪声;但他的打分过程像黑箱,不太容易解释“为什么推荐这道菜”。

从工程技术看,两个模型也有典型差异:CAST 这类重写+增强路线,需要额外训练一个“历史融合器”,但下游检索器可以复用成熟的关键词/向量检索引擎;CONVKNRM 这类端到端交互式匹配,在相关性判别上更精细,但推理时需要把查询和历史逐项与每个候选文档做核匹配,计算成本更高。现实中两者并非二选一,而可以按权重混合,取长补短:

就像餐厅会让细心理查先记录全部需求,再由老师傅复核一遍菜单,推荐最稳妥的菜。混合模型在公开对话检索评测集(如 TREC CAsT)上通常能同时提升“答案准确率”和“排序稳定性”,这也说明两种思路并非竞争,而是互补。

S(q,d)=λ SCAST(q,d)+(1−λ) SCONVKNRM(q,d)S(q,d) = \lambda \, S_{\text{CAST}}(q,d) + (1-\lambda) \, S_{\text{CONVKNRM}}(q,d)
最终相关性得分是 CAST 路线得分与 CONVKNRM 路线得分的加权和,$\lambda$ 是调解两者信任度的超参数。
  1. CAST 得分 $S_{\text{CAST}}(q,d)$用上下文增强查询 $\tilde{q}_t$ 与文档 $d$ 的向量相似度得分。
    SCAST=cos⁡(q~t,d)S_{\text{CAST}} = \cos(\tilde{\mathbf{q}}_t, \mathbf{d})
  2. KNRM 得分 $S_{\text{CONVKNRM}}(q,d)$多核池化加权求和后的匹配得分。
    SCONVKNRM=∑kWkKk(q,d)S_{\text{CONVKNRM}} = \sum_k W_k K_k(q,d)
  3. 混合权重 $\lambda$在验证集上搜索的最优权重,如 $\lambda=0.4$ 表示更信任软匹配。
    λ∈[0,1]\lambda \in [0,1]

评估指标:怎样考核服务员称职

老板娘称不称职,不能靠感觉,得看数据。比如,给阿凯推荐 10 道菜,他想吃的那道排在第 1 位还是第 8 位?连续聊了 5 轮,有几轮能端出他真正想吃的?这引出了对话式搜索最常用的两把尺子:MRR 和 NDCG。

MRR(Mean Reciprocal Rank,平均倒数排名)衡量“第一个正确答案排得多靠前”。如果每轮都让正确答案排第一,MRR 就是 1.0;如果平均要翻到第 3 位才找到,MRR 就是 0.33。它的公式如下:

MRR 只关注第一个正确答案,NDCG(Normalized Discounted Cumulative Gain,归一化折损累积增益)则关注整个排序列表的质量:每个位置的相关性分数除以位置的对数折损,再除以理想排序(IDCG)归一化。NDCG 的公式为:

除了这两个核心指标,对话式检索还常看 Recall(正确文档被召回的比例)和人工评估(答案是否自然、是否真的帮用户找到信息)。就像考核服务员:MRR 看“第一道菜是否点中”,NDCG 看“整桌推荐菜是否靠谱”,Recall 看“想吃的菜有没有被列上菜单”。

MRR=1N∑n=1N1rankn\text{MRR} = \frac{1}{N} \sum_{n=1}^{N} \frac{1}{\text{rank}_n}
结果的相关性等级越高、排位越靠前,得分越高;排得越靠后,折损越重。NDCG 是衡量“整张榜单”质量的黄金指标。
  1. 相关性等级 $rel_k$第 $k$ 个候选与当前查询的相关性标注(如 0=无关,1=相关,2=高度相关)。
    relk∈{0,1,2}rel_k \in \{0, 1, 2\}
  2. 位置折损 $\log_2(k+1)$排名越靠后,对分数的折扣越大,体现“用户只看前几名”的行为。
    2relk−1log⁡2(k+1)\frac{2^{rel_k}-1}{\log_2(k+1)}
  3. 归一化 $\text{IDCG}_n$按理想排序计算的 DCG,用来把分数压到 0~1,便于跨查询比较。
    NDCG@K=DCG@KIDCG@K\text{NDCG@K} = \frac{\text{DCG@K}}{\text{IDCG@K}}

应用与展望:把好服务员请进每个行业

川菜馆的故事讲完了,但这套“会记笔记 + 会软匹配”的服务员,完全可以去别的行业上班。对话式搜索正在走进三个最典型的场景:智能客服(用户先说“我的手机连不上 Wi-Fi”,再问“重启有用吗”,系统需要结合前文判断用户还没重启过);电商导购(“想要适合夏天的裙子”“A 字版型有吗”——把两轮融合成完整商品需求);企业知识库(“报销流程是什么”“需要发票吗”——必须理解“需要发票吗”问的是报销,不是买咖啡)。

这些场景的最终形态,往往是大模型与对话式检索的融合:检索模块负责把对话历史和候选文档捞出来,大模型负责组织语言回答。用公式表达就是:

未来,对话式检索还会走向多模态:用户拍一张照片说“找类似的鞋”,语音输入“上次说的那家店怎么走”——历史的载体不再只是文字,图片、语音、位置都成为上下文的一部分。核心技术仍然是那句朴素的道理:先听懂人说的话,再去找想要的东西。学好了 CAST 和 CONVKNRM 两种思路,无论前端怎么变,你都能为产品配上一位“会聊天、会找菜”的好服务员。

response=LLM(q~t,Dtop-k)\text{response} = \text{LLM}\left(\tilde{q}_t, D_{\text{top-k}}\right)
大模型接收“上下文增强查询”和检索出的 Top-k 文档,生成自然语言答案。检索供粮,模型供嘴,各司其职。
  1. 增强查询 $\tilde{q}_t$由 CAST 或 CONVKNRM 的上下文融合机制得到的完整意图表示,也可直接理解为“补全后的查询文本”。
    q~t=补全后的用户意图\tilde{q}_t = \text{补全后的用户意图}
  2. 候选文档 $D_{\text{top-k}}$向量检索或关键词检索得到的 Top-k 篇高相关文档,作为事实依据。
    Dtop-k={d1,d2,…,dk}D_{\text{top-k}} = \{d_1, d_2, \ldots, d_k\}
  3. 大模型 LLM把“问题 + 证据”组织成通顺、有依据的回答,同时处理“我不确定”等对话技巧。
    response=LLM(问题,证据)\text{response} = \text{LLM}(\text{问题}, \text{证据})

AI 应用场景

电商智能导购

阶段:查询理解与多轮召回

解决的问题:传统电商搜索把每句话当独立查询,用户说“想要夏天的裙子”后追问“A字版型有吗”,系统会忽略“夏天”直接返回所有 A 字裙。CAST 类模型把前一轮的“夏天”与当前轮的“A字版型”融合成“夏天+A字版型裙”,再对商品库做召回,显著提升相关商品的命中率。

具体案例:某头部电商平台在智能导购中引入上下文感知查询表示,用户连续追问 3 轮以上时,点击率提升 18%,“追单但搜不到”的客服投诉明显下降。

企业知识库多轮问答

阶段:文档匹配与排序

解决的问题:企业知识库中,员工提问往往省略主语:“报销流程是什么?”“需要发票吗?”若只看第二句,会误匹配到“发票开具流程”。CONVKNRM 的软匹配机制把历史中的“报销”和当前句的“发票”共同与候选文档做核池化匹配,让“第二句”与“报销手册第四节”稳定关联。

具体案例:某中型科技公司在内部知识库部署 KNRM 式软匹配检索后,多轮问答的 MRR 从 0.42 提升到 0.67,员工查找制度文档的平均时间减少一半。

语音助手搜索

阶段:意图补全与候选取舍

解决的问题:语音输入场景省略和指代最密集:“帮我定一家餐厅”“要安静的”“上次那家附近的”。CAST 的注意力融合可把“上次那家”具体化到历史中的实体,补全为“静安区+安静+上次去过的那家餐厅”,再交给地图/点评检索。

具体案例:某语音助手团队在对话式搜索模块中加入上下文重写后,多轮指令的任务完成率提高 25%,用户平均对话轮次从 2.1 降到 1.6。

Python 演示

python70 行
"""CAST 与 CONVKNRM 的简化模拟:多轮查询如何逐步提升文档排序""" import numpy as np VOCAB = ['辣', '微辣', '汤', '牛肉', '下饭', '清淡']DOCS = {    '毛血旺': [1, 0, 0, 0, 1, 0],    '番茄牛腩汤': [0, 0, 1, 1, 0, 1],    '水煮牛肉': [1, 0, 0, 1, 1, 0],    '酸辣汤': [1, 0, 1, 0, 0, 0],}QUERIES = [    ['辣'],    ['微辣'],    ['汤'],]  def to_vec(words):    vec = np.zeros(len(VOCAB), dtype=float)    for w in words:        if w in VOCAB:            vec[VOCAB.index(w)] += 1.0    return vec  def cast_fuse(hist_vecs, cur_vec, gamma=0.8):    """CAST 式上下文融合:注意力加权 + 时间衰减"""    if not hist_vecs:        return cur_vec.copy()    scores = []    for i, h in enumerate(hist_vecs):        s = np.dot(h, cur_vec) + 1e-6        s *= gamma ** (len(hist_vecs) - i)        scores.append(s)    scores = np.exp(scores) / np.sum(np.exp(scores))    fused = cur_vec.copy()    for i, h in enumerate(hist_vecs):        fused += scores[i] * h    return fused / (np.linalg.norm(fused) + 1e-9)  def convknrm_score(q_vec, d_vec):    """CONVKNRM 式核池化:把词命中相似度软分桶后累加"""    q_idx = np.where(q_vec > 0)[0]    d_idx = np.where(d_vec > 0)[0]    sims = [1.0 if i == j else 0.2 for i in q_idx for j in d_idx] or [0.0]    sims = np.array(sims)    mu = np.array([-0.5, 0.0, 0.5])    soft = np.exp(-(sims[:, None] - mu) ** 2 / (2 * 0.5 * 0.5))    pooled = np.log(1 + soft.sum(axis=0))    return float(pooled.sum())  def main():    doc_vecs = {name: to_vec(words) for name, words in DOCS.items()}    hist = []    for turn, q_words in enumerate(QUERIES):        cur = to_vec(q_words)        fused = cast_fuse(hist, cur)        print('--- 第 %d 轮: %s ---' % (turn + 1, ''.join(q_words)))        scores = {name: convknrm_score(fused, d)                  for name, d in doc_vecs.items()}        for name, s in sorted(scores.items(), key=lambda x: -x[1]):            print('%-8s %.4f' % (name, s))        hist.append(cur)  if __name__ == '__main__':    main()
目的:用词袋向量模拟“辣/微辣/汤”三轮对话,cast_fuse 演示了 CAST 的注意力+时间衰减融合,convknrm_score 演示了 CONVKNRM 的高斯核软匹配,最终可以看到第二轮后正确文档排名跃升。
  1. def cast_fuse(hist_vecs, cur_vec, gamma=0.8):定义上下文融合函数,gamma 控制历史衰减速度。
  2. s *= gamma ** (len(hist_vecs) - i)让越久远的历史获得越小的注意力分数,模拟时间衰减。
  3. scores = np.exp(scores) / np.sum(np.exp(scores))softmax 归一化,把注意力分数变成和为 1 的权重。
  4. fused += scores[i] * h按注意力权重把各轮历史叠加进当前查询,这是 CAST 的核心增强操作。
  5. def convknrm_score(q_vec, d_vec):定义核池化打分函数,输入为查询向量和文档向量。
  6. sims = [1.0 if i == j else 0.2 for i in q_idx for j in d_idx] or [0.0]遍历查询词与文档词的命中关系,完全一致记 1.0,语言近似记 0.2。
  7. mu = np.array([-0.5, 0.0, 0.5])三个高斯核中心,分别捕获“弱相关、近似、精确”三个匹配区间。
  8. soft = np.exp(-(sims[:, None] - mu) ** 2 / (2 * 0.5 * 0.5))把每个命中相似度映射到三个核桶,桶中心越近输出越大。
  9. pooled = np.log(1 + soft.sum(axis=0))对每个桶累加软命中数,再取对数压缩大数,防止词频主导。
  10. hist.append(cur)把本轮查询加入历史,模拟对话上下文不断累积的过程。

常见误区

误区很多新手以为对话式搜索很简单——把“辣的”“微辣”“有汤吗”拼成“辣的微辣有汤吗”当作新查询丢给普通搜索引擎就行,完全不需要改模型。

正解直接拼接会引入大量噪声。用户说“太辣了,换一个”时,“太辣了”是否定性描述,拼进去反而把“要辣”变成“不要辣”。CAST 的做法是用注意力挑选“哪些历史片段对当前查询有用”,而 CONVKNRM 用软匹配容忍噪声;两者都包含特意设计的取舍机制,而不是无脑拼接。

为何常见:从“文本拼接”的直觉出发,忽略了自然语言中否定、指代、修正等复杂现象,以为历史信息越多越完整。

误区认为模型上下文窗口有多大,就把全部历史都塞进去,这样信息最全,效果肯定最好。

正解历史越长,噪声越多,计算成本也线性上涨。好的对话检索系统会做三件事:截断(只保留最近 K 轮)、时间衰减($w_i=\gamma^{t-i}$ 让旧信息淡出)、关键信息抽取(只保留实体、约束、语气反转)。就像老板娘只记最近几道菜和特殊忌口,不会把三年前的闲聊也翻出来。

为何常见:把“信息量”误等同于“信息质量”,忽略了对话里真正决定当前意图的往往只是最近的几轮和少量关键实体。

误区看到高斯核对相似度“软分桶”觉得它像模糊检索,误以为任意两个词都能靠核函数匹配上,词向量/预训练表示不再重要。

正解核函数本身没有语义理解能力,它处理的输入 $m_{ij}$ 仍然是词向量或 n-gram 语义表示算出的相似度。核只是把“连续相似度”翻译成“多个软区间上的命中次数”,真正的语义判断完全依赖底层的向量表示。如果词向量质量差,再好的核函数也算不出正确的菜。

为何常见:把“软匹配”和“不需要精确表示”划等号,混淆了匹配策略与特征表示两个层次。

误区学习模型时总爱“PK 谁更强”,以为产品里只能部署其中一种,另一个就是被淘汰的陪跑者。

正解工程上两者经常搭配使用。CAST 先做上下文重写,把残缺的“有汤吗”补成“微辣+下饭+有汤”;CONVKNRM 再拿着补全后的查询去文档库里做精细的软匹配打分。也可以用线性混合 $S=\lambda S_{\text{CAST}}+(1-\lambda)S_{\text{CONVKNRM}}$,在验证集上调 $\lambda$,让两种互补优势一起生效。

为何常见:论文对比的训练惯性让学习者误以为模型间只有竞争,忽略了真实系统中“重写+精排”的流水线思维。

面试题

Q1. 对话式搜索与传统搜索最本质的区别是什么?

单选题 · easy

  • A.返回结果数量更多
  • B.能结合多轮对话理解当前查询← 正确答案
  • C.只使用深度神经网络
  • D.不需要用户输入关键词

答案:B。对话式搜索的核心是建模上下文,把当前轮省略和指代补全,这正是“老板娘听懂'有汤吗'”的关键。返回更多结果、用深度学习都只是手段,不是本质区别。

Q2. 对话历史采用时间衰减机制的主要动机是什么?

单选题 · easy

  • A.节省模型训练时间
  • B.让最近的表述获得更高权重← 正确答案
  • C.用户一定会忘记早期内容
  • D.避免模型过拟合

答案:B。$w_i=\gamma^{t-i}$ 让越近的对话越被重视,因为最近的表述通常代表了用户最新、最准确的意图。省训练时间和防过拟合与历史权重无关,至于“用户会忘”只是表象,核心是检索效果。

Q3. CAST 模型中注意力权重的主要作用是什么?

单选题 · mid

  • A.对文档集合做聚类分组
  • B.决定历史对话中哪些词对当前查询更重要← 正确答案
  • C.压缩查询文本的长度
  • D.为文档生成关键词摘要

答案:B。注意力 $\alpha_{tj}$ 计算当前查询与各轮历史的语义相关性,权重越高说明该轮历史越值得“吸收”进当前查询表示。它不压缩文本、不聚类文档、也不生成摘要,而是做历史选择。

Q4. CONVKNRM 中高斯核函数的主要作用是什么?

单选题 · mid

  • A.把词向量映射到更低维度
  • B.把连续相似度软分桶成多个匹配信号← 正确答案
  • C.生成文档的摘要文本
  • D.计算神经网络梯度

答案:B。高斯核把 $m_{ij}$ 这样的连续相似度映射到多个以 $\mu_k$ 为中心的桶里,每个桶输出一个软命中强度。它既不做降维,也不生成摘要,更不负责梯度计算。

Q5. 下面哪一项是对话式检索的常用评估指标?

单选题 · easy

  • A.显存占用率
  • B.MRR← 正确答案
  • C.词表覆盖率
  • D.训练轮数

答案:B。MRR(平均倒数排名)衡量“第一个正确答案排多靠前”,是对话式检索的标准指标之一。显存、词表覆盖率和训练轮数都是工程或训练层面的统计量,不直接衡量检索效果。

Q6. 当前查询为“它呢”,历史为“我想买微单;预算五千以内”,结合上下文的合理补全是?

单选题 · hard

  • A.推荐微单相机配件
  • B.推荐五千元以内的微单← 正确答案
  • C.推荐其他品牌的手机
  • D.推荐五千元以上的高端相机

答案:B。“它”指代前文提到的“微单”,“呢”延续了“预算五千以内”的限定,因此补全后应检索“五千元以内的微单”。这正是 CAST 注意力融合要解决的问题,其他选项都忽略了指代或预算约束。

Q7. 与 CAST 相比,CONVKNRM 更侧重哪一类技术?

单选题 · easy

  • A.上下文查询重写
  • B.交互式软匹配← 正确答案
  • C.关键词扩展
  • D.索引压缩

答案:B。CONVKNRM 把查询和文档的 n-gram 两两计算相似度,再用高斯核软分桶,属于“边回忆边匹配”的交互式匹配路线。而查詢重写是 CAST 的強項,关键词扩展和索引压缩不是它的核心。

Q8. 关于 NDCG 指标,下列说法正确的有?

多选题 · mid

  • A.对排序位置敏感← 正确答案
  • B.需要标注相关性等级← 正确答案
  • C.NDCG 的值可以大于 1
  • D.NDCG 是 DCG 与 IDCG 的比值← 正确答案

答案:ABD。NDCG 按位置折损,排得越靠后折扣越大,所以对位置敏感;它需要 $rel_k$ 这样的相关性等级标注;NDCG 是 DCG 除以理想排序的 IDCG,因此取值在 0 到 1 之间,不可能大于 1。

Q9. 对话历史建模中常见的处理手段包括?

多选题 · mid

  • A.使用时间衰减权重← 正确答案
  • B.只保留最近 K 轮进行截断← 正确答案
  • C.把全部历史永久保存在输入里
  • D.抽取关键实体和约束信息← 正确答案

答案:ABD。时间衰减($w_i=\gamma^{t-i}$)、最近 K 轮截断、关键实体抽取都是控制历史噪声、降低计算成本的常用手段。把所有历史永久塞进输入既不经济,也容易引入过时信息干扰判断。

Q10. 下列哪些方案可以提升对话式检索在真实产品中的效果?

多选题 · hard

  • A.用 CAST 先补全查询再检索← 正确答案
  • B.用 CONVKNRM 软匹配容忍口语噪声← 正确答案
  • C.用大模型基于检索结果生成最终回复← 正确答案
  • D.放弃排序直接把全部文档返回给用户

答案:ABC。方案 A 解决指代与省略,方案 B 提高对口语噪声的鲁棒性,方案 C 把检索与生成结合(检索增强生成)显著改善回答体验。方案 D 不排序会让用户淹没在无关结果中,反而损害体验。