Embedding相似度虚高,如何用langchain+Milvus搭建CRAG解决?

Embedding相似度虚高,如何用langchain+Milvus搭建CRAG解决?

图片
最近后台经常会收到一个提问,就是我的RAG经常打捞上来一个相似性分数极高,但是完全不可用的内容,到底要怎么办?
这背后,其实是个传统 RAG在设计最底层的想当然:相似度高 = 结果好。但这套逻辑在生产环境里根本站不住脚。因为高分文档可能早就过期了,或者讲的是完全不匹配的场景、甚至核心信息缺斤短两。
而 CRAG 的核心价值,就是在检索和生成之间引入了一道评估环节,对检索结果做三元判决(正确 / 模糊 / 错误),在错误信息进入大模型推理环节之前,就把它拦截、修正或者补充完整,从根源上解决检索不靠谱的问题。
接下来,本文将展示如何用langchain+Milvus搭建一套
CRAG系统。
这里先总结一下传统 RAG的几个问题。
第一,检索偏差
我们之前做了个运维助手,用户查 “如何在 Nginx 上配置 HTTPS 证书”,检索出来的 Top3 高分文档,分别讲的是 Apache 的配置方法、早就停更的旧版本教程、甚至是 HTTPS 的原理解析。可以看到,语义相似,和能解决问题,在这时候其实完全是两码事。
第二,时效性缺失
比如你查 “Python 异步编程最佳实践”,它可能会同时捞上来2018 年早就废弃的写法,和 2024 年官方推荐的写法。而哪一个更契合,则取决于你需要最新的方案,还是需要了解历史项目的演进逻辑。
第三,也是最无解的记忆污染。一旦检索到过时的 API 用法,生成了错误代码,这段错误内容又被存进了记忆库,接下来就是彻底的恶性循环:新旧版本内容共存,向量检索次次都能命中旧内容,越用越错,连回滚都找不到抓手。
也是因此,引入检索质量评估是RAG与Agent 系统的必选项。
传统 RAG 只有 用 / 不用的二元处理,但绝大多数检索结果都是部分相关但不全对的模糊状态,二元处理要么丢有效信息,要么带进错误内容。
也是因此,CRAG (Corrective Retrieval-Augmented Generation)的核心改进,就是把传统 RAG的检索→生成两步走,改成 检索→评估→纠正→生成四步闭环。
具体来说,CRAG 会将检索结果分为三种:正确(直接精炼使用)、模糊(补充外部知识)、错误(丢弃检索结果)。
但只有做检索内容的判断,还远远不够。传统 RAG 还有个致命误区:检索到文档就直接全文塞给大模型。 token 浪费只是其次,一堆无关信息混进去,很容易就把大模型带偏,平白无故多出很多幻觉。
CRAG 的改进在于:绝不直接用检索全文,而是先做一轮知识精炼,把无效信息全筛掉,只留和查询最相关的核心内容。
原论文方案中里用了知识条带(Knowledge Strips)+ 启发式规则,不过,我们日常工程落地,用简化的关键词匹配方案就能搞定;如果是生产环境,也可以换成 LLM 摘要、结构化提取,进一步提升精炼质量。
整个精炼流程如下图所示,分三步:
文档分解(从 2000 tokens 提取 500 tokens 关键片段)、查询重写(将模糊查询改写为精确搜索词)、知识选择(对结果去重、排序、截断)。
做完精炼之后,就进入最核心的评估器环节。
这里先划个重点:不要用gpt 教程评估器做复杂推理,评估器的核心使命是快速筛选,在几毫秒里判断内容能不能用。
所以 CRAG 原论文里,用的是微调后的 T5-Large,而不是通用大模型。给大家列个直观的对比:
评估完之后,就会引入一个新问题,如果内部检索的资料不够,怎么办?
CRAG 设计了一套内部检索 + Web 搜索的协同机制,说人话就是当内部检索结果错误、或者信息不足的时候,系统会自动触发 Web 搜索补充最新信息,解决时效性问题。
聊完了 CRAG 的核心逻辑,很多朋友会问:这套机制跑起来,对底层的向量数据库有没有要求?
当然有。我们当时试了好几个向量数据库,最后线上落地用 Milvus,就是因为它的架构设计,刚好踩中了 CRAG 生产落地的三个核心刚需:多租户隔离(数百个 Agent 实例独立记忆)、混合检索(应对语义漂移)、动态 Schema(记忆结构随系统迭代演化)。

Partition Key 实现零成本多租户隔离

做 Agent 系统的都懂,你可能要同时跑几百个 Agent 实例,每个用户、每个场景的记忆必须完全独立,不能串数据。之前我们试过给每个租户建单独的 Collection,管理起来扩容、运维全是坑。
Milvus 的 Partition Key 功能,直接实现了零成本的多租户隔离。你只要在 Schema 定义时给 agent_id 字段加上is_partition_key=True,查询时系统会自动路由到对应分区,不用手动维护一大堆 Collection。
实测下来,在 1000 万向量、100 个租户的场景中,配合 Clustering Compaction,直接带来了 3-5 倍的 QPS 提升。

原生混合检索,搞定边界场景的检索失效

纯向量检索有个天然的短板:遇到用户查专有名词、型号编码(比如 “SKU-2024-X5″)、精确版本号这类场景,很容易直接失效 。
Milvus 2.5 原生支持Dense 稠密向量(语义)+ Sparse 稀疏向量(BM25)+ 元数据过滤的混合检索,还自带 RRF 融合排序,不用搭多路检索再做融合,省了大量开发成本。
实测数据:100 万向量规模下,Milvus Sparse-BM25 检索延迟仅 6ms,完全不拖 CRAG 全流程的后腿。

JSON 字段,支持记忆结构灵活演化

系统不是一成不变的。随着 CRAG 评估机制的完善,我们要不断给记忆新增 confidence、verified、source 这类字段,要是用传统结构化数据库,改表结构就得停机维护,对线上业务太不友好。
Milvus 的 JSON 字段,可以灵活扩展元数据字段,想加什么直接加,完全不用停机改 Schema。
这是个极简的 Schema 定义示例
另外,Milvus还有个关键优势是平滑迁移:Milvus 提供 Lite / Standalone / Distributed 三种部署模式,代码完全兼容。我们在本地 Lite 上开发,生产环境切换到 Distributed,只需修改连接字符串。
教程开始前,多说一句选型的思路。很多人做 CRAG,喜欢用 LangGraph 画一堆节点和边,状态流转搞的特别复杂,维护起来巨麻烦。
我们踩过这个坑之后,最后选了 LangGraph 1.0 的middleware 模式,它能在模型调用前直接拦截请求,一站式完成检索、评估、纠正全流程,不用手动管理状态图的节点和边,代码量少、可读性高,出问题也好排查。
整个流程一共分四步:
检索:从 Milvus 获取 Top-3 相关文档,自带租户隔离
评估:用轻量级模型完成三元判决,判断文档质量
纠正:根据判决结果,执行精炼、补充搜索、兜底替换策略
注入:把处理好的上下文,通过动态提示词注入给大模型
环境变量配置
Milvus Collection 创建
在运行代码前,需要先创建 Collection 并定义 Schema:
本文代码基于 LangChain 1.0 的 middleware 特性实现。Middleware 是 LangChain 1.0 的核心特性,但具体 API 可能随版本更新而变化。
plaintext 评估器的进阶优化
上述代码中的_evaluate_relevance() 方法采用了简化实现,适合快速验证。如果需要更完善的评估器(包含置信度和可解释性),可以采用以下实现:
知识精炼和托底的实现比较简单:文档精炼提取包含查询关键词的句子,Web 搜索在检索失败时触发 Tavily 补充外部知识。关键是在 merge 节点合并内部记忆和外部知识,形成最终上下文。
最后,分享一些CRAG 的生产部署建议,大家将 CRAG 部署到生产环境,可以重点关注三个问题:
第一,成本控制:一定要选对评估器
评估器是 CRAG 流程里调用频次最高的环节,选型直接决定了系统的延迟和成本。
如果是高并发的线上生产场景,优先选微调的 T5-Large 这类轻量级模型,延迟 10-20ms,成本可控;如果是快速验证、小流量场景,用 gpt-4o-mini 这类托管模型,不用自己运维,落地快,就是延迟和成本会高一些。

第二,可观测性:把监控体系搭起来

线上系统,看不见的问题才是最致命的。但好在,Milvus 原生支持 Prometheus 指标,可以重点盯这三个核心数据:milvus_query_latency_seconds(查询延迟分布)、milvus_search_qps(每秒查询数)、milvus_insert_throughput(写入吞吐量),这是检索环节的生命线。
另一方面,CRAG 的评估判决分布、Web 搜索触发率、置信度分布,也必须接入监控。不然线上出了问题,都不知道是检索崩了,还是评估器判歪了。

第三,长期治理:严防记忆污染

Agent 跑的越久,记忆库里的垃圾信息就越多,可以提前引入以下机制:
前置过滤:检索时就只返回 confidence>0.7 的高置信度记忆,从源头减少垃圾信息进入流程
时间衰减:给记忆加半衰期权重(建议 30 天,可根据业务场景调整),越旧的记忆检索权重越低,避免过期内容长期霸榜
定期清理:设置定时任务,每周删除低置信度、从未被验证过的旧记忆,给记忆库定期瘦身,从根源上避免恶性循环。

作者介绍

图片

Zilliz黄金写手:尹珉


图片
图片

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/273370.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月12日 下午12:29
下一篇 2026年3月12日 下午12:29


相关推荐

关注全栈程序员社区公众号