向量搜索实战:RAG系统中决定答案质量的底层引擎

1. 这不是“又一个搜索功能”,而是RAG系统里真正决定答案质量的底层引擎

你有没有遇到过这样的情况:给大模型喂了一堆PDF、数据库文档、内部知识库,结果它回答得似是而非,甚至一本正经地胡说八道?我去年帮一家医疗SaaS公司做知识助手升级时,客户反复反馈:“你们的AI好像没看过我们最新版的诊疗指南。”——可我们明明把PDF全切片入库了。后来花三天时间逐层排查,发现根本问题不在模型,也不在提示词,而在于向量搜索这一步:相似度打分严重失真,top-3召回的片段里,有两条压根不相关,真正关键的那页却被排在第17位。Vector Search(向量搜索)从来就不是RAG流水线里那个安静的“配角”,它是整个生成链条的守门人——它决定模型“看什么”,直接决定了“说什么”。它不像传统关键词搜索那样靠字面匹配,而是把文本、图像、音频统统压缩成一串数字(比如1536维浮点数组),再用数学距离衡量语义亲疏。这背后牵扯到嵌入模型选型、索引结构设计、相似度度量选择、查询重排序策略等一系列硬核决策。很多人以为装个ChromaDB、跑个 query_embedding = model.encode("发烧怎么办") 、再调个 .similarity_search() 就完事了,实则连冰山一角都没碰着。本文要讲的,就是怎么从零开始,亲手搭一套真正扛得住业务压力、召回准、响应快、能解释结果的向量搜索系统。它不依赖任何黑盒云服务,所有参数可调、所有过程可观测、所有瓶颈可定位。适合正在落地RAG项目的产品经理、需要调优检索效果的算法工程师、以及想搞懂“为什么我的AI总答非所问”的技术负责人。核心关键词: 向量搜索、RAG、嵌入模型、ANN索引、余弦相似度、重排序、混合检索

2. 为什么不能只靠“默认设置”?向量搜索的四大设计陷阱与真实业务代价

很多团队在RAG初期会直接套用LangChain或LlamaIndex的默认示例,用OpenAI的text-embedding-ada-002 + ChromaDB,几行代码就跑通了。这就像用家用轿车去拉矿石——短途代步没问题,一旦上坡、重载、连续作业,底盘发飘、变速箱过热、油耗飙升。我在三个不同行业的RAG项目里都踩过这个坑,下面拆解四个最致命的设计陷阱,以及它们在真实业务中引发的具体故障:

2.1 陷阱一:嵌入模型与业务语义完全错配

text-embedding-ada-002是通用英文模型,在金融合同条款识别上F1值只有0.41;而我们换成专门微调过的FinBERT-Embedding后,对“不可抗力”“交叉违约”等术语的召回准确率从58%跃升至92%。这不是玄学,是训练数据分布决定的:通用模型在Wikipedia和Common Crawl上训练,学的是大众百科知识;而医疗报告里的“室性早搏”和“房颤”在通用向量空间里可能比“苹果”和“香蕉”还远。我做过一个实验:用同一段患者主诉“胸闷气短3天,夜间阵发性呼吸困难”,分别用ada-002和MedCPT生成向量,计算它们与“急性左心衰竭”向量的余弦相似度——ada-002得分0.63,MedCPT得分0.89。差值0.26,意味着在top-k=5的召回中,前者大概率漏掉关键诊断依据。 选嵌入模型不是选API,而是选语义世界的坐标系 。你必须明确:你的知识库是什么语言?专业领域是什么?用户提问风格是口语化(如“肚子疼咋办”)还是正式(如“腹痛鉴别诊断”)?这些直接决定嵌入模型的底座。

2.2 陷阱二:暴力扫描(Brute Force)在10万+文档时彻底失效

ChromaDB默认用HNSW索引,但很多团队为了“简单”手动切到 collection.add() 后直接 query() ,实际触发的是线性扫描。当知识库从1万条扩展到50万条(比如某车企的全部维修工单),单次查询耗时从80ms暴涨到2.3秒——用户还没输完问题,页面已经转圈3次。更糟的是,线性扫描的延迟随数据量线性增长,而HNSW等近似最近邻(ANN)索引是亚线性增长。我用FAISS测试过:100万条768维向量,暴力扫描P95延迟2100ms,IVF-Flat索引(聚类+局部搜索)P95仅47ms,提速44倍。但这不是免费午餐:IVF需要预设聚类中心数(nlist),太少则召回率暴跌,太多则内存爆炸。我们最终在nlist=2000时取得平衡,内存占用增加18%,但召回率保持在99.2%(对比暴力扫描的100%)。 延迟和精度永远在博弈,没有银弹,只有根据你的SLA(比如要求P95<100ms)反向推导索引参数

2.3 陷阱三:余弦相似度在长尾分布下严重失真

余弦相似度假设向量均匀分布在单位球面上,但真实嵌入向量高度聚集。我们分析过某法律知识库的10万条向量模长分布:72%的向量模长在0.85~0.95之间,但有3%的向量模长低于0.3(多为停用词堆砌的无效段落),还有5%高于1.1(多为超长条款引用)。当查询向量模长为0.9时,与一个模长0.3的向量算余弦相似度,结果被大幅拉低——即使语义很相关。我们改用内积(dot product)后,对低模长有效片段的召回提升27%。但内积又带来新问题:它对向量长度敏感,容易偏向长文本。最终方案是 归一化内积(Normalized Dot Product) :先将所有向量L2归一化,再计算点积。这既保留了内积对方向敏感的优势,又消除了模长干扰。公式很简单: score = (q/||q||) · (d/||d||) ,但背后是上百次AB测试的结果。

2.4 陷阱四:忽略查询理解,把“搜索”当成“匹配”

用户问“iPhone 15 Pro发热怎么解决”,传统做法是直接向量化整句去搜。但这句话包含实体(iPhone 15 Pro)、问题(发热)、动作(解决)。如果知识库中只有一条记录叫《iOS 17.2发热修复指南》,而标题里没提“iPhone 15 Pro”,单纯向量匹配可能失败。我们引入 查询扩展(Query Expansion) :用LLM(如Phi-3-mini)将原查询重写为3个变体——“iPhone 15 Pro 手机发烫异常处理”“iOS 17.2 系统更新后设备过热”“Apple 官方关于15系列温度管理的说明”。再对每个变体单独检索,最后合并结果并去重。实测在客服场景中,首屏命中率从68%提升至89%。这不是加模型炫技,而是承认一个事实:用户的自然语言和知识库的结构化表达,天然存在语义鸿沟。向量搜索必须承担起“翻译官”的角色,而不是冷冰冰的“匹配器”。

提示:别迷信“开箱即用”。每一个默认参数背后都是特定场景的妥协。你的业务数据分布、用户行为模式、SLA要求,才是唯一真实的标尺。我建议在项目启动第一周,就用真实业务query抽样100条,建立基线评测集,后续所有优化都围绕这个基线展开。

3. 从零搭建高可用向量搜索:嵌入、索引、检索、重排四层架构详解

一个工业级向量搜索系统不是单个工具,而是一套分层协作的架构。我把它拆成四层:嵌入层(Embedding Layer)、索引层(Indexing Layer)、检索层(Retrieval Layer)、重排层(Re-ranking Layer)。每一层都可独立替换、压测、监控。下面以我们为某省级政务知识库搭建的系统为例,全程使用开源组件,无任何闭源依赖。

3.1 嵌入层:不止于“调API”,如何让向量真正理解你的业务

我们放弃OpenAI API,选用本地部署的 BGE-M3 (BAAI General Embedding),原因有三:支持中英双语、提供稀疏+密集+多向量三种模式、在中文法律/政务语料上SOTA。但直接用官方checkpoint效果一般,因为它的训练数据不含“政务服务事项指南”这类文本。我们做了两件事:

第一,领域适配微调(Domain Adaptation Fine-tuning)
用政务知识库中的5000对高质量问答对(Q-A pair)构造训练数据。不是简单做对比学习,而是构建三元组(Anchor, Positive, Negative):Anchor是用户提问,Positive是该问题对应的标准答案段落,Negative是从其他无关事项中随机采样的段落。损失函数用TripletMarginLoss,margin设为0.3——这个值是通过网格搜索在验证集上确定的,太小导致区分度不足,太大则模型难以收敛。微调仅用1个A10 GPU跑8小时,embedding维度从1024压缩到768(节省25%内存),在政务QA测试集上的MRR@10从0.71提升至0.86。

第二,动态分块与嵌入策略
政务文档结构复杂:有政策原文、解读文件、办事指南、常见问题。我们不再用固定512字符切块,而是按语义单元切分:

  • 法律条文:以“第X条”为界,每条独立成块
  • 办事指南:以“办理条件”“申请材料”“办理流程”等二级标题为界
  • 常见问题:每个Q&A对作为一个块
    然后对每个块,用BGE-M3的 multi-vector mode 生成多个向量:主向量(全文摘要)、关键词向量(TF-IDF提取前5词再嵌入)、实体向量(用spaCy识别出的人名/地名/机构名再嵌入)。这样,一个办事指南块会产出3个向量,存储时用同一个doc_id关联。查询时,也对用户问题生成这三类向量,分别检索再融合分数。实测对“残疾人证怎么办理”这类复合查询,召回相关材料清单的准确率提升41%。
# BGE-M3 multi-vector embedding 示例
from FlagEmbedding import BGEM3FlagModel

model = BGEM3FlagModel('BAAI/bge-m3', use_fp16=True)
text = "办理残疾人证需提供:1. 身份证原件及复印件;2. 2寸免冠照片3张;3. 医院出具的残疾评定表。"

# 生成三类向量
dense_vec, sparse_vec, _ = model.encode(
    text, 
    batch_size=12,
    return_dense=True,
    return_sparse=True,
    return_colbert_vecs=False
)

# dense_vec.shape = (1, 1024), sparse_vec 是字典 {term_id: weight}

3.2 索引层:FAISS实战——如何在100万向量下做到毫秒响应

FAISS是Meta开源的ANN库,但直接用 IndexFlatIP (暴力扫描)毫无意义。我们采用**IVF-PQ(Inverted File with Product Quantization)**组合,这是在精度、速度、内存间取得最佳平衡的方案。

IVF部分:聚类加速
核心思想是“先粗筛,再精排”。把所有向量聚成k个簇(centroids),查询时只计算与最近的nprobe个簇的距离,再在这些簇包含的向量中做精确搜索。关键参数:

  • nlist :簇的数量。我们知识库100万向量,设为4000。计算依据: nlist ≈ sqrt(N) 是经验公式,但需实测。我们从1000试到8000,发现nlist=4000时,召回率下降仅0.3%,但P95延迟降低35%。
  • nprobe :查询时搜索的簇数。默认是1,我们设为16。这意味着每次查询只扫描约0.4%的向量(16/4000),却保持99.1%的召回率。

PQ部分:内存压缩
PQ把高维向量(如768维)拆成m段(sub-vectors),每段用k-means聚成256个码本(codebook),用1字节存储每个段的聚类ID。我们设 m=48 (768/48=16),即每段16维,用256个码本表示。内存占用从100万×768×4字节=3GB,压缩到100万×48字节=48MB,降幅98%!但精度损失可控:在我们的测试集中,PQ后MRR@10仅下降0.02。

完整FAISS构建代码:

import faiss
import numpy as np

# 假设 embeddings 是 (1000000, 768) 的numpy float32数组
dimension = 768
nlist = 4000
m = 48
nbits = 8  # 每个码本2^8=256个聚类中心

# 1. 创建IVF-PQ索引
quantizer = faiss.IndexFlatIP(dimension)
index = faiss.IndexIVFPQ(quantizer, dimension, nlist, m, nbits)
index.nprobe = 16

# 2. 训练(必须!用知识库向量的子集)
faiss.omp_set_num_threads(16)  # 利用多核
index.train(embeddings[:100000])  # 用10万向量训练聚类

# 3. 添加全部向量(可分批)
batch_size = 50000
for i in range(0, len(embeddings), batch_size):
    batch = embeddings[i:i+batch_size]
    index.add(batch)

# 4. 保存索引
faiss.write_index(index, "gov_knowledge_ivfpq.index")

注意:FAISS训练必须用真实数据子集,不能用随机向量!否则聚类中心无法反映真实分布。我们曾因偷懒用 np.random.randn() 训练,导致上线后召回率暴跌至30%。

3.3 检索层:超越“similarity_search”,实现混合检索与上下文感知

纯向量检索在政务场景有两个硬伤:一是无法处理精确匹配(如身份证号“11010119900307231X”必须完全一致),二是无法利用结构化元数据(如“事项类型=户籍服务”,“适用对象=外地户籍”)。我们采用 混合检索(Hybrid Retrieval)

第一步:向量检索(Dense Retrieval)
用FAISS查出top-100候选,每个返回 score doc_id

第二步:关键词检索(Sparse Retrieval)
用BM25算法(Elasticsearch内置)对同一query进行关键词搜索,也返回top-100,带 bm25_score

第三步:融合打分(Score Fusion)
不是简单加权平均,而是用 Reciprocal Rank Fusion (RRF) ,它对排名位置敏感,鲁棒性强:

RRF_score(doc) = Σ(1 / (k + rank_dense)) + Σ(1 / (k + rank_bm25))

其中k=60是平滑常数。我们实测RRF比线性加权(0.7 vector + 0.3 bm25)在长尾query上提升12%的NDCG@5。

第四步:上下文过滤(Contextual Filtering)
用户提问“2024年北京积分落户分数线是多少”,我们不仅检索向量,还解析出实体“北京”“2024年”“积分落户”,在元数据字段中强制过滤 city="北京" year=2024 。这步在FAISS检索后、RRF融合前执行,用Python列表推导快速完成,增加延迟<1ms。

3.4 重排层:用轻量模型做精准排序,把MRR@5从0.72干到0.91

FAISS召回的top-100只是“粗筛”,真正影响用户体验的是前5条。我们引入 Cross-Encoder重排 ,但不用BERT-Large(太重),而是用 bge-reranker-base (BAAI开源,384M参数,推理快10倍)。

为什么必须重排?
FAISS用向量距离做全局近似,但无法建模query和document的细粒度交互。比如query“新生儿疫苗接种时间表”,document A是“卡介苗:出生时接种”,document B是“乙肝疫苗:出生24小时内接种”。在向量空间,A和B可能距离相近,但B更符合“时间表”这个query意图。Cross-Encoder把query+document拼成一句输入模型,输出一个0~1的相关分,这才是真正的语义匹配。

工程实现要点:

  • 批处理 :重排只对RRF融合后的top-20执行(不是100),每批送20个(query, doc)对进GPU,显存占用<1.2GB。
  • 缓存 :对高频query(如“社保卡丢了怎么办”)的重排结果缓存1小时,命中率超65%,P95延迟从32ms降至8ms。
  • Fallback机制 :当重排模型GPU负载>90%时,自动降级为FAISS原始分数,保证服务不雪崩。
from FlagEmbedding import FlagReranker

reranker = FlagReranker('BAAI/bge-reranker-base', use_fp16=True)

# query = "新生儿疫苗接种时间表"
# docs = ["卡介苗:出生时接种", "乙肝疫苗:出生24小时内接种", ...]
scores = reranker.compute_score([[query, doc] for doc in docs])
# scores 是 [0.87, 0.92, 0.33, ...] 的list

4. 实战避坑指南:那些只有踩过才懂的12个细节与3个血泪教训

纸上得来终觉浅。我把过去三年在8个RAG项目中积累的、文档里绝不会写的细节整理出来。这些不是理论,是凌晨三点服务器告警时,我盯着日志一行行扒出来的真相。

4.1 关于嵌入模型的5个魔鬼细节

  1. token截断不是“丢文字”,而是“丢语义”
    BGE-M3最大长度为8192,但你的文档平均长度12000。如果粗暴截断后12000字符,末尾的“综上所述”“特此通知”等总结性语句大概率被砍掉,而这些恰恰是判断文档权威性的关键信号。我们的解法是: 优先保留开头300字符(标题/发文机关)+ 结尾500字符(结论/联系方式)+ 中间按TF-IDF权重采样 。用spaCy计算每句的关键词密度,高密度句优先保留。实测在政策文件检索中,关键结论召回率提升33%。

  2. 中文标点会影响嵌入质量
    全角逗号“,”和半角逗号“,”在Unicode中是不同字符,BGE-M3的tokenizer对它们的处理完全不同。我们知识库原始PDF OCR后混用两种标点,导致相同语义的句子向量距离达0.45。解决方案:在嵌入前统一用正则 re.sub(r'[,。!?;:""''()【】《》、]', lambda m: {',':',','。':'.','!':'!','?':'?'}[m.group(0)], text) 替换,再清洗空格。这步让同义句向量距离从0.45降到0.08。

  3. 不要相信“模型自带归一化”
    很多文档说BGE-M3输出已归一化,但实测其dense向量L2范数均值为0.992,标准差0.015。在FAISS中, IndexFlatIP 要求向量必须严格单位长度,否则内积不等于余弦相似度。我们强制执行 vec /= np.linalg.norm(vec) ,否则top-1结果可能错乱。这个细节让某次上线后首屏准确率从82%回升至96%。

  4. 微调时,负样本质量比数量重要10倍
    我们曾用10万条随机负样本微调,MRR@10不升反降。后来发现,随机负样本太“简单”,模型学不到难区分的边界。改为用 hard negative mining :对每个query,取FAISS召回中rank 50~100的向量作为负样本(它们和query向量距离很近但语义无关)。MRR@10立刻提升0.15。

  5. 嵌入模型版本必须锁定
    BGE-M3在v1.0.1和v1.1.0之间,对“人工智能”一词的向量变化达0.21。我们线上服务用v1.0.1,某天运维误升级到v1.1.0,所有query的召回结果全乱。教训:在Dockerfile中写死 pip install flag-embedding==1.0.1 ,并在CI/CD中加入向量一致性校验(抽样100个query,比对新旧模型输出的cosine similarity,偏差>0.05则阻断发布)。

4.2 关于FAISS索引的4个性能雷区

  1. IVF训练数据必须覆盖查询分布
    FAISS训练只用知识库向量,但用户query的分布可能完全不同。比如知识库全是政策原文,而用户爱问“怎么办”“哪里办”“多久能办”。我们额外收集1万条真实用户query,和知识库向量一起训练IVF聚类中心。这步让query的nprobe=16时召回率从92%升至99.3%。

  2. 不要在索引中存原始文本
    FAISS索引只存向量,原始文本存在PostgreSQL里,用 doc_id 关联。曾有团队为“省事”把文本base64编码后塞进FAISS的 ids 字段,结果索引体积暴涨5倍,加载时间从2秒变成17秒,且无法利用PG的全文检索能力。记住: 向量索引只做向量事,文本检索交给专业数据库

  3. GPU版FAISS不是万能的
    faiss-gpu 在batch size>1000时才比CPU快,而RAG单次查询通常只取top-5。我们实测:单query场景下, faiss-gpu faiss-cpu 慢40%,因为GPU启动开销太大。结论: 小批量查询用CPU,大批量离线计算(如每日全量重索引)才用GPU

  4. 索引文件必须定期合并
    FAISS不支持原地更新,每次 add() 都是追加。我们每天新增5000文档,一周后索引文件碎片化,查询延迟上涨22%。解决方案:每周日凌晨执行 faiss.merge_into(index_full, index_daily) ,用全量重建替代增量添加。停机窗口控制在3分钟内。

4.3 关于重排与服务的3个血泪教训

  1. Cross-Encoder不能直接上生产
    bge-reranker-base单次推理需200ms,如果对top-100重排,P95延迟直接破2秒。我们严格限定只重排top-20,并用 early exit :对每个(query,doc)对,先用轻量版bge-reranker-small(50ms)打分,若分数<0.3则直接剔除,不再送入base版。这步让平均重排延迟从1800ms降至210ms。

  2. HTTP服务必须做请求熔断
    某次重排模型GPU显存泄漏,导致第1001个请求超时。由于没设熔断,后续所有请求排队等待,P99延迟飙升至15秒,触发全站告警。我们在FastAPI中集成 tenacity 库,配置 @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=1, max=10)) ,单请求失败立即fallback到FAISS分数,保障核心链路可用。

  3. 日志必须记录向量距离,而非原始分数
    FAISS返回的 score 是内积值,范围从-1到1,但不同批次、不同索引的分数不可比。我们日志中强制记录 cosine_similarity = score / (norm_q * norm_d) ,并存入ELK。当某天发现召回率骤降,直接在Kibana中查 cosine_similarity < 0.4 的query,30分钟定位到是嵌入模型版本错误。

血泪教训一: 永远不要在生产环境用“demo代码” 。我见过最惨的案例:团队用LangChain的 Chroma.from_documents() 直接入库,没设 persist_directory ,结果服务器重启后整个知识库消失,客户投诉电话打爆。所有数据路径、索引路径、模型路径,必须用绝对路径+环境变量注入,并在启动时校验存在性。

血泪教训二: 监控指标必须和业务目标对齐 。不要只看“QPS”“延迟”,要监控“首屏命中率”(top-3是否含正确答案)、“幻觉率”(答案中出现知识库未提及的事实)。我们用LLM-as-a-judge:对每个answer,调用Phi-3-mini判断“该答案是否能在知识库中找到依据”,准确率92%,比人工抽检效率高100倍。

血泪教训三: 上线前必须做“对抗测试” 。准备100条故意刁难的query:错别字(“积份落户”)、口语化(“北京落户要多少分啊”)、多跳推理(“2024年落户分数线比2023年涨了多少”)。这些query在测试环境中暴露了87%的逻辑漏洞,避免了上线后被用户“教做人”。

5. 效果验证与持续迭代:如何用数据证明你的向量搜索真的变强了

技术人的终极尊严,不是写出多炫的代码,而是用数据证明你解决了业务问题。我们为政务知识库设计了一套四级验证体系,从离线到在线,层层递进:

5.1 离线评测:构建不可篡改的黄金测试集

我们从真实用户日志中抽取1000条query,每条由3名政务专家标注“黄金答案”——不是一段文本,而是 精确到知识库中的doc_id + chunk_id 。例如query“港澳居民居住证怎么办理”,黄金答案是 [doc_id: ZJ-2023-089, chunk_id: 3] (对应《港澳居民居住证申领指南》第3段)。这个测试集永不更新,作为所有优化的基准线。

评测指标采用行业标准:

  • MRR@5(Mean Reciprocal Rank) :衡量top-5中第一个正确答案的位置倒数的平均值。MRR@5=0.85意味着平均在第1.18个位置就找到了答案。
  • Hit Rate@3 :top-3中是否至少有一个黄金答案。这是用户首屏体验的直接映射。
  • Precision@1 :第一个结果就是黄金答案的比例。反映“一眼答案”的质量。

初始基线(BGE-M3 + FAISS IVF-Flat + 无重排):MRR@5=0.72,Hit@3=0.68,Prec@1=0.51。经过前述四层优化后:MRR@5=0.91(+19%),Hit@3=0.89(+21%),Prec@1=0.76(+25%)。

5.2 在线AB测试:让真实用户投票

离线评测再完美,也不如用户鼠标点击诚实。我们在前端埋点:当用户点击某个检索结果时,记录 query clicked_doc_id position_in_list time_to_click 。然后用 Interleaving Test (交错测试):对同一query,同时返回A版(旧策略)和B版(新策略)的混合结果,用户无法分辨来源。统计点击流向——如果B版结果被点击更多,说明它确实更相关。我们运行两周,B版点击份额达63.2%,置信度99.9%。

5.3 业务指标挂钩:搜索效果必须翻译成业务语言

技术指标再漂亮,老板只关心一件事: 它让客服人力节省了多少? 我们把向量搜索接入客服工单系统。当用户在APP提交“医保报销比例是多少”,系统自动检索出TOP-3答案并推送至客服工作台。我们统计:

  • 自助解决率 :用户看到推送答案后,未转人工的占比。从41%升至68%。
  • 平均处理时长 :客服处理同类工单的平均时间,从210秒降至135秒。
  • 一次解决率 :首次回复就解决用户问题的比例,从73%升至89%。

这些数字直接换算成成本:该省每月减少12万次人工咨询,年节省人力成本超800万元。这才是向量搜索真正的价值锚点——它不是技术玩具,而是业务杠杆。

5.4 持续迭代机制:让搜索能力像肌肉一样越练越强

系统上线不是终点,而是数据飞轮的起点。我们建立了闭环反馈机制:

  • Bad Case自动捕获 :当用户对推送答案点“不相关”或30秒内关闭页面,该query+当前top-3结果自动进入 bad_case_queue
  • 每周人工复盘 :算法团队每周抽50个bad case,分析根因(是嵌入问题?索引问题?还是知识库缺失?),更新到问题分类表。
  • 月度模型迭代 :用当月新增的1000个高质量bad case,重新微调嵌入模型,发布新版本。
  • 季度架构评审 :评估是否需要升级到更先进的索引(如SCANN)、是否引入多模态(加入政策文件扫描件的OCR文本)。

这个机制让我们的MRR@5在上线后6个月内,从0.91稳步提升至0.94,而竞品同期停滞在0.87。技术没有终点,只有持续进化。

我在实际操作中发现,最有效的优化往往来自最朴素的观察:盯着用户真实的query日志,看他们到底在问什么、哪里卡住了、为什么放弃。那些藏在“404页面”“客服转接”背后的挫败感,才是向量搜索真正需要攻克的堡垒。与其追逐最新论文里的SOTA模型,不如先把你知识库中最常被问到的100个问题,用最笨的办法——人工翻文档、找答案、测召回——跑一遍。这100个case,就是你整个系统的校准器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值