最近对rag的一些想法和实践

2026-04-11 14:561阅读0评论SEO资源
  • 内容介绍
  • 文章标签
  • 相关推荐
问题描述:

去年这会儿,大家都在搭rag,从dify, coze到ragflow,但是经常会遇到一个问题,demo好整,但是效果嘛,不好说。现在已经有一些解决方案,比如用easydataset做qa对,用Hyde扩展回答的范围,用RAG去扩展问题的范围。但是还是有一个我认为不能理解的,那就是向量相似度不等于语义相关性。如果不做qa对,仅仅按chunk切分,会导致什么问题呢,三重语义断裂——代词指代丢失、跨句依赖断裂、术语定义分离。更恼火的还有,Embedding导致的多个不确定的方面:比如模型选择、分块策略、相似度阈值导致相同的查询返回不同的结果。现在其实也有很多项目已经认识到这点,抛弃embbeding,比如:pageindex,sirchmunk,tree-search等等等,我研究了这些agentic+no embbeding的方案,然后有了一些自己的想法和实践。

解决之道是Agentic RAG范式转换:把语义理解还给LLM,检索系统只负责提供确定性结构
以下是具体的实现方法和路径:
用SQLite+FTS5替代向量数据库,保留文档原始层级(章节-条款-段落),通过BM25关键词匹配+迭代收敛算法(自动调整查询词直到命中2-3篇核心文档),让LLM像查阅目录般精准导航。同时保留检索路径,这样整个过程完全可审计,每次查询轨迹都有完整记录。
这套机制的工程价值在于:零外部依赖单人可维护(确定性代码易调试)。很适合法规合规、企业SOP、医疗指南等需要"精确溯源"的场景。

核心思想是信任LLM的理解与推理能力——不需要系统替它猜答案,只需要系统可靠地帮它找到内容。
注意:这个技术方向不是通用的,对于实时对话要求很高的来说,不太适用。
实践项目在这里:yang478/auditable-knowledge-packs
使用方法,放在skills下,用LLM来进行知识库skills的构建,再用该skills问问题就可以了。

感谢多个项目:
pageindex,sirchmunk
ragflow的博客文章:从 RAG 到 Context - RAG 2025 年度回顾 | RAGFlow 引擎
等等等,不一一列举了。

附上一篇我知乎文章:https://zhuanlan.zhihu.com/p/2018830163186566801
欢迎讨论和分享,谢谢。

网友解答:
--【壹】--:

传统的检索有很多东西都可以再深入研究


--【贰】--:

不太一样,他还是用了embbeding模型的,不过也挺有意思


--【叁】--: alphaply:

很多时候update一下metadata(用于初筛),默认也会把content(非结构化内容)再过一遍embedding模型

现在我就遇到这种情况了,之前没有考虑metadata,后来发现如果想要在语义搜索时限制查询范围,需要全量跑一遍embedding。metadata变一次就得重新跑一次。


--【肆】--:

一个非常简单的想法和思路。

其实要看具体的使用场景,因为rag的检索结果是不稳定的,每次检索出来的分数,顺序基本上都是不一样的,叠加agentic针对用户的同一个问题,query甚至都可以不一样。

具体场景具体分析,检索的内容是从1000个当中检索50个,和从10000个chunk当中检索100个,难度是完全不一样的。

一个简单的做法就是,在检索之前先进行过滤,类似于搜广推当中的协同过滤概念一样,先进行初筛,然后精筛,最后重排(没错 看起来没用的rerank是来自于搜广推的思路,个人觉得对于强大的模型,chunk的前后顺序应该影响不会很大)

第二就是维护性的角度了,维护一个巨大的向量数据库比传统数据库麻烦很多,很多时候update一下metadata(用于初筛),默认也会把content(非结构化内容)再过一遍embedding模型。此外,就是构建这玩意的过程了,怎么切分,切分的配置参数,集合的划分,metadata的细节设计等等等。

哦,说到agentic的方式,如果llm是使用那些强大的模型,也就意味着速度是巨慢的,有一段thinking过程,包括高峰时期算力紧张,上下文长度太长等等,agentic rag的话可能更偏好那些小模型进行,也就意味着高度定制化是不可分割的。

希望我的回答能对你有所启发。


--【伍】--:

哈哈,我只能说demo上的500个chunk返回50个,和5000个chunk返回50个完全就是两码事,rag这种高度定制化的场景,也许就是未来小厂的主要业务之一了。


--【陆】--:

很多老板觉得向量数据库很神奇,但我觉得还不足以替代掉传统数据库,维护起来是灾难性的,现在仍缺乏一个很高效的方案,现在rag大多是agentic式的,要求agent在一定迭代次数内努力命中到想要搜索的东西,这些内容有可能是本身就会,有可能是可能猜得到,有可能是完全不会,这些都要交给llm根据context来进行判断。金钱燃烧的气息是香喷喷的,也许就像人类一样,大家都在一个互联网,条件背景不一样,信息差也是不一样的。agentic的方式,以及高度定制化(低代码也好,写代码也好),rag的未来如果没有一个神乎其神的妙计,可能就朝着这两个方面挖掘价值。个人更加偏向高度定制化,因为token的算力需求也好,能源需求也好,以及等待的时间,llm的分薪比人高。。。


--【柒】--: yyy2024:

对于实时对话要求很高的来说,不太适用

对于语义检索,有一个问题值得深思

这张显卡的价格30000

这张显卡的价格2999

我要查询,假设是纯语义进行检索。

“价格3000左右的显卡” 假设这就是query

哪一个chunk的分数比较高?


--【捌】--: yyy2024:

认识到这点,抛弃embbeding,比如:pageindex

挺好的方向,就是完成一次查询会非常慢。我记得之前graphrag里就引入了类似的机制,举个例子,在用户查询一个问题后,它会在后台用LLM重写5个用户可能问到的问题,然后进行语义检索。完成上面5个查询后,它会将这5个问题和最初问题放在上下文里,让LLM再生成5个问题,在进行一轮。然后还可以一轮一轮的运行。比如设置每次问5个问题,然后重复3轮。或者每次问20个问题,重复5轮。
但是非常慢就是了。

yyy2024:

用SQLite+FTS5替代向量数据库,保留文档原始层级(章节-条款-段落),通过BM25关键词匹配+迭代收敛算法

这种方式感觉思路不错,特别是对于短文本,感觉短文本向量化代价比长文本大很多,存储是个问题,之前短文本向量化后体积比原文大了十多倍……
明天研究试试


--【玖】--: alphaply:

对于语义检索,有一个问题值得深思

这张显卡的价格30000

这张显卡的价格2999

我要查询,假设是纯语义进行检索。

“价格3000左右的显卡” 假设这就是query

哪一个chunk的分数比较高?

语义搜索,也许是可以理解2999的,2999的排在30000前面。

>>> for i, score in enumerate(scores): ... print(f"文本: {chunks[i]} | 得分: {score:.4f}") ... 文本: 这张显卡的价格30000 | 得分: 0.6643 文本: 这张显卡的价格2999 | 得分: 0.6706

佬友问的可能是这个问题:

chunk: 这张显卡的价格30003000 这张显卡的价格2999 query: 价格3000左右的显卡

最终是30003000的分数显著高于2999。但是我们理解的,应该是2999更高。

>>> for i, score in enumerate(scores): ... print(f"文本: {chunks[i]} | 得分: {score:.4f}") ... 文本: 这张显卡的价格30003000 | 得分: 0.7354 文本: 这张显卡的价格2999 | 得分: 0.6706

如果之后还接入reranker模型,可能还会进一步放大这种差距。

重排后的顺序和得分: 得分: 0.9255 | 文本: 这张显卡的价格30003000 得分: 0.2485 | 文本: 这张显卡的价格2999

但是如果只有少量的显卡价格相关数据,对上面的影响很小,可以将他们都交给LLM,让LLM进一步判断。
毕竟embed只是负责尽可能的召回数据,但是数据是不是准确,可以交给LLM去识别。
不过听说如果embed返回大量无关的信息,可能会造成LLM幻觉,还没有实际遇到这种场景,不太了解。

感觉这种问题无法直接在embedding阶段解决,只能交给后面的流程解决。


--【拾】--:

和字节的openviking 思路是不是有点类似

问题描述:

去年这会儿,大家都在搭rag,从dify, coze到ragflow,但是经常会遇到一个问题,demo好整,但是效果嘛,不好说。现在已经有一些解决方案,比如用easydataset做qa对,用Hyde扩展回答的范围,用RAG去扩展问题的范围。但是还是有一个我认为不能理解的,那就是向量相似度不等于语义相关性。如果不做qa对,仅仅按chunk切分,会导致什么问题呢,三重语义断裂——代词指代丢失、跨句依赖断裂、术语定义分离。更恼火的还有,Embedding导致的多个不确定的方面:比如模型选择、分块策略、相似度阈值导致相同的查询返回不同的结果。现在其实也有很多项目已经认识到这点,抛弃embbeding,比如:pageindex,sirchmunk,tree-search等等等,我研究了这些agentic+no embbeding的方案,然后有了一些自己的想法和实践。

解决之道是Agentic RAG范式转换:把语义理解还给LLM,检索系统只负责提供确定性结构
以下是具体的实现方法和路径:
用SQLite+FTS5替代向量数据库,保留文档原始层级(章节-条款-段落),通过BM25关键词匹配+迭代收敛算法(自动调整查询词直到命中2-3篇核心文档),让LLM像查阅目录般精准导航。同时保留检索路径,这样整个过程完全可审计,每次查询轨迹都有完整记录。
这套机制的工程价值在于:零外部依赖单人可维护(确定性代码易调试)。很适合法规合规、企业SOP、医疗指南等需要"精确溯源"的场景。

核心思想是信任LLM的理解与推理能力——不需要系统替它猜答案,只需要系统可靠地帮它找到内容。
注意:这个技术方向不是通用的,对于实时对话要求很高的来说,不太适用。
实践项目在这里:yang478/auditable-knowledge-packs
使用方法,放在skills下,用LLM来进行知识库skills的构建,再用该skills问问题就可以了。

感谢多个项目:
pageindex,sirchmunk
ragflow的博客文章:从 RAG 到 Context - RAG 2025 年度回顾 | RAGFlow 引擎
等等等,不一一列举了。

附上一篇我知乎文章:https://zhuanlan.zhihu.com/p/2018830163186566801
欢迎讨论和分享,谢谢。

网友解答:
--【壹】--:

传统的检索有很多东西都可以再深入研究


--【贰】--:

不太一样,他还是用了embbeding模型的,不过也挺有意思


--【叁】--: alphaply:

很多时候update一下metadata(用于初筛),默认也会把content(非结构化内容)再过一遍embedding模型

现在我就遇到这种情况了,之前没有考虑metadata,后来发现如果想要在语义搜索时限制查询范围,需要全量跑一遍embedding。metadata变一次就得重新跑一次。


--【肆】--:

一个非常简单的想法和思路。

其实要看具体的使用场景,因为rag的检索结果是不稳定的,每次检索出来的分数,顺序基本上都是不一样的,叠加agentic针对用户的同一个问题,query甚至都可以不一样。

具体场景具体分析,检索的内容是从1000个当中检索50个,和从10000个chunk当中检索100个,难度是完全不一样的。

一个简单的做法就是,在检索之前先进行过滤,类似于搜广推当中的协同过滤概念一样,先进行初筛,然后精筛,最后重排(没错 看起来没用的rerank是来自于搜广推的思路,个人觉得对于强大的模型,chunk的前后顺序应该影响不会很大)

第二就是维护性的角度了,维护一个巨大的向量数据库比传统数据库麻烦很多,很多时候update一下metadata(用于初筛),默认也会把content(非结构化内容)再过一遍embedding模型。此外,就是构建这玩意的过程了,怎么切分,切分的配置参数,集合的划分,metadata的细节设计等等等。

哦,说到agentic的方式,如果llm是使用那些强大的模型,也就意味着速度是巨慢的,有一段thinking过程,包括高峰时期算力紧张,上下文长度太长等等,agentic rag的话可能更偏好那些小模型进行,也就意味着高度定制化是不可分割的。

希望我的回答能对你有所启发。


--【伍】--:

哈哈,我只能说demo上的500个chunk返回50个,和5000个chunk返回50个完全就是两码事,rag这种高度定制化的场景,也许就是未来小厂的主要业务之一了。


--【陆】--:

很多老板觉得向量数据库很神奇,但我觉得还不足以替代掉传统数据库,维护起来是灾难性的,现在仍缺乏一个很高效的方案,现在rag大多是agentic式的,要求agent在一定迭代次数内努力命中到想要搜索的东西,这些内容有可能是本身就会,有可能是可能猜得到,有可能是完全不会,这些都要交给llm根据context来进行判断。金钱燃烧的气息是香喷喷的,也许就像人类一样,大家都在一个互联网,条件背景不一样,信息差也是不一样的。agentic的方式,以及高度定制化(低代码也好,写代码也好),rag的未来如果没有一个神乎其神的妙计,可能就朝着这两个方面挖掘价值。个人更加偏向高度定制化,因为token的算力需求也好,能源需求也好,以及等待的时间,llm的分薪比人高。。。


--【柒】--: yyy2024:

对于实时对话要求很高的来说,不太适用

对于语义检索,有一个问题值得深思

这张显卡的价格30000

这张显卡的价格2999

我要查询,假设是纯语义进行检索。

“价格3000左右的显卡” 假设这就是query

哪一个chunk的分数比较高?


--【捌】--: yyy2024:

认识到这点,抛弃embbeding,比如:pageindex

挺好的方向,就是完成一次查询会非常慢。我记得之前graphrag里就引入了类似的机制,举个例子,在用户查询一个问题后,它会在后台用LLM重写5个用户可能问到的问题,然后进行语义检索。完成上面5个查询后,它会将这5个问题和最初问题放在上下文里,让LLM再生成5个问题,在进行一轮。然后还可以一轮一轮的运行。比如设置每次问5个问题,然后重复3轮。或者每次问20个问题,重复5轮。
但是非常慢就是了。

yyy2024:

用SQLite+FTS5替代向量数据库,保留文档原始层级(章节-条款-段落),通过BM25关键词匹配+迭代收敛算法

这种方式感觉思路不错,特别是对于短文本,感觉短文本向量化代价比长文本大很多,存储是个问题,之前短文本向量化后体积比原文大了十多倍……
明天研究试试


--【玖】--: alphaply:

对于语义检索,有一个问题值得深思

这张显卡的价格30000

这张显卡的价格2999

我要查询,假设是纯语义进行检索。

“价格3000左右的显卡” 假设这就是query

哪一个chunk的分数比较高?

语义搜索,也许是可以理解2999的,2999的排在30000前面。

>>> for i, score in enumerate(scores): ... print(f"文本: {chunks[i]} | 得分: {score:.4f}") ... 文本: 这张显卡的价格30000 | 得分: 0.6643 文本: 这张显卡的价格2999 | 得分: 0.6706

佬友问的可能是这个问题:

chunk: 这张显卡的价格30003000 这张显卡的价格2999 query: 价格3000左右的显卡

最终是30003000的分数显著高于2999。但是我们理解的,应该是2999更高。

>>> for i, score in enumerate(scores): ... print(f"文本: {chunks[i]} | 得分: {score:.4f}") ... 文本: 这张显卡的价格30003000 | 得分: 0.7354 文本: 这张显卡的价格2999 | 得分: 0.6706

如果之后还接入reranker模型,可能还会进一步放大这种差距。

重排后的顺序和得分: 得分: 0.9255 | 文本: 这张显卡的价格30003000 得分: 0.2485 | 文本: 这张显卡的价格2999

但是如果只有少量的显卡价格相关数据,对上面的影响很小,可以将他们都交给LLM,让LLM进一步判断。
毕竟embed只是负责尽可能的召回数据,但是数据是不是准确,可以交给LLM去识别。
不过听说如果embed返回大量无关的信息,可能会造成LLM幻觉,还没有实际遇到这种场景,不太了解。

感觉这种问题无法直接在embedding阶段解决,只能交给后面的流程解决。


--【拾】--:

和字节的openviking 思路是不是有点类似