传统的搜索引擎主要依靠关键词匹配和倒排索引,用户输入什么词,系统就精确匹配什么词。这种模式遇到口语化查询、错别字、语义歧义时往往力不从心。比如用户搜索"苹果 手机 价格",他想要的可能是iPhone报价,也可能是水果价格,纯关键词匹配根本无法区分。AI推理的引入让搜索引擎从"字符匹配"进化到"语义理解",其中查询理解和排序打分是最能体现推理价值的两个模块。本文将以一个完整的搜索链路为例,讲解如何在这两个环节落地AI推理技术。

一、查询理解:让搜索引擎听懂用户的真实意图
查询理解是搜索链路的第一环,它把用户的原始输入转化为结构化的检索信号。一个典型的查询理解模块包含四个子任务:意图识别、查询纠错、查询改写和查询扩展。意图识别判断用户属于哪类需求,例如导航类(直接想访问某个网站)、信息类(想了解知识)还是交易类(想购买商品);查询纠错负责处理拼音错误和错别字;查询改写把口语化表达规范化;查询扩展则补充同义词,扩大召回范围。
以意图识别为例,早期方案多用规则加特征工程,现在主流做法是基于预训练语言模型做分类。下面是一个基于BERT的意图识别示例,将查询分为通用搜索、商品购物、影视娱乐等类别:
from transformers import BertTokenizerFast, BertForSequenceClassification
import torch
# 加载意图分类模型(假设已经用自己的搜索日志微调过)
tokenizer = BertTokenizerFast.from_pretrained("bert-base-chinese")
model = BertForSequenceClassification.from_pretrained(
"./intent_model", num_labels=5
)
model.eval()
# 意图类别标签
INTENT_LABELS = ["通用搜索", "商品购物", "影视娱乐", "本地生活", "问答知识"]
def detect_intent(query: str) -> str:
inputs = tokenizer(query, return_tensors="pt",
truncation=True, max_length=32)
with torch.no_grad():
logits = model(**inputs).logits
pred = torch.argmax(logits, dim=-1).item()
return INTENT_LABELS[pred]
print(detect_intent("附近的火锅店哪家好")) # 输出:本地生活
意图识别的结果会直接影响后续的检索策略。例如识别为"商品购物"意图后,系统可以优先走商品垂直索引库,并用价格、销量等特征参与排序;识别为"问答知识"意图则可以直接触发问答式的答案卡片。除了意图识别,查询改写也是提升召回率的关键。一个常见做法是利用同义词典加向量召回,先获取查询的语义向量,再从历史查询库中找到语义相近、但点击效果更好的查询作为改写候选。这样即使用户输入的是"手机掉水里怎么办",系统也能联想到"手机进水 处理方法"这类表达更规范的查询。
二、召回与粗排:从BM25到向量语义检索
查询理解完成后,系统进入召回阶段。传统方案以BM25为代表,它基于词频和逆文档频率计算相关性,实现简单、性能稳定,但对语义的捕捉能力有限——"电脑"和"计算机"在BM25眼里毫无关系。向量检索解决了这个问题:用双塔模型把查询和文档分别编码成向量,通过内积或余弦相似度计算语义相关性,再配合Faiss、Milvus这类向量数据库实现毫秒级检索。
下面是一个混合检索的简单实现,同时使用BM25和向量召回,并通过倒数排序融合(RRF)合并两路结果。这种混合方案在实践中效果往往优于单一路径,因为BM25擅长精确匹配(如型号、人名),向量检索擅长语义泛化,两者互补:
import numpy as np
def bm25_search(query, top_k=20):
"""调用BM25引擎检索,返回[(doc_id, score), ...]"""
# 实际项目中对接 Elasticsearch 或自建索引
return [("doc_101", 8.2), ("doc_205", 7.5), ("doc_330", 6.9)]
def vector_search(query, top_k=20):
"""向量语义检索,返回[(doc_id, score), ...]"""
# 实际项目中先对 query 编码,再查询 Faiss 索引
return [("doc_205", 0.93), ("doc_412", 0.88), ("doc_101", 0.85)]
def rrf_fusion(result_lists, k=60, top_k=10):
"""倒数排序融合,k为平滑常数"""
scores = {}
for results in result_lists:
for rank, (doc_id, _) in enumerate(results):
scores[doc_id] = scores.get(doc_id, 0) + 1.0 / (k + rank + 1)
return sorted(scores.items(), key=lambda x: -x[1])[:top_k]
merged = rrf_fusion([bm25_search("人工智能"), vector_search("人工智能")])
print(merged) # 融合后的文档 doc_205 和 doc_101 排名靠前
粗排阶段通常在召回的数百条候选中快速筛掉明显不相关的文档,保留几十条交给精排。粗排模型一般采用轻量的双塔结构或者浅层的GBDT,重点是计算效率。需要特别注意的是,粗排和精排的训练目标要保持一致性,否则容易出现"粗排筛掉的文档精排反而喜欢"的错位现象,工程上常用的做法是让精排模型的分数蒸馏给粗排模型作为训练信号。
三、精排模型:Learning to Rank与深度排序实践
精排是决定最终搜索体验的核心环节。经典的Learning to Rank有三个范式:点态(Pointwise)、成对(Pairwise)和列表态(Listwise)。点态把每个文档独立打分,训练简单但忽略文档之间的相对顺序;成对比较文档两两之间的先后关系,更贴近排序本质;列表态则直接优化整条列表的指标,如NDCG,效果通常最好。深度精排模型一般采用多任务结构,同时预测点击率、停留时长、点赞收藏等多个目标,再通过加权公式合成最终分数。
下面是一个简化版的精排打分逻辑,展示如何把语义相关性分、静态质量分和用户行为分融合起来:
def final_ranking_score(features: dict) -> float:
"""
features 包含:
- semantic_score: 深度模型输出的语义相关性分,范围 0~1
- quality_score: 文档静态质量分(权威度、原创度),范围 0~1
- ctr_pred: 预估点击率
- freshness: 时效性因子,0~1,越新越接近 1
"""
semantic = features["semantic_score"]
quality = features["quality_score"]
behavior = features["ctr_pred"]
freshness = features["freshness"]
# 各权重由离线调参或在线实验确定
score = (0.45 * semantic +
0.15 * quality +
0.30 * behavior +
0.10 * freshness)
return score
docs = [
{"id": "doc_205", "semantic_score": 0.91, "quality_score": 0.85,
"ctr_pred": 0.12, "freshness": 0.60},
{"id": "doc_101", "semantic_score": 0.83, "quality_score": 0.90,
"ctr_pred": 0.09, "freshness": 0.95},
]
ranked = sorted(docs, key=final_ranking_score, reverse=True)
print([d["id"] for d in ranked]) # 输出排序后的文档ID列表
线上落地时,精排模型的推理性能是绕不开的话题。一个工业级搜索引擎对精排的延迟要求通常在几十毫秒以内,而候选文档可能有上百条。常见的优化手段包括:模型蒸馏,用小模型学习大模型的输出;特征预计算,把文档侧的静态特征离线算好存入缓存;算子融合和INT8量化,降低GPU或CPU的推理开销。此外,大语言模型也开始参与精排环节,例如用LLM对查询和文档做细粒度的相关性判断,但由于推理成本高,通常只用于重排Top几十条结果,形成"小模型粗筛、大模型精选"的两级架构。
四、效果评估与迭代闭环
任何搜索优化都需要可靠的评估体系。离线指标方面,相关性评估常用NDCG、MAP和MRR,NDCG衡量排序质量时会对靠前位置的正确结果给予更高权重,非常契合搜索场景;在线评估则以点击率、首屏满足率和查询改写率为核心指标,通过A/B实验验证收益。构建评估数据集时,建议从真实搜索日志中采样查询,由人工标注员对查询和文档的相关性打分,形成持续迭代的标注池。
迭代闭环的完整流程是:分析badcase,定位是查询理解问题还是排序问题,针对性优化模型或特征,离线评估通过后上线小流量实验,观察在线指标,最后全量发布。特别提醒一点,查询理解和排序是联动的——如果改写模块把查询扩展得过宽,召回文档质量会下降,精排的压力会骤增;反之改写过窄又会漏召回。因此迭代时不要孤立地优化单一模块,而要看端到端的整体指标,这样才能让AI推理真正转化为用户可感知的搜索体验提升。