扫码打开虎嗅APP
本文来自微信公众号: 叶小钗 ,作者:叶小钗
最近AI圈又开始流行一种很魔幻的东西:同事.skill。

而后就是产品经理.skill、运营总监.skill、销售冠军.skill,这些都还算正常,最离谱的是我还看到了法外狂徒张三.skill这种东西...
怎么说呢,这东西有点疯,比如你真的敢让一个写着精通刑法、刑诉法的skill,来给你做法律判断吗?
更进一步,如果有人跟你说:我已经把公司最强客服、最强销售蒸馏成了一个skill,你会相信吗?
你如果相信,那么今天的问题就很大了,会被内行笑话的。
因为你真拆开看就会发现,很多所谓的蒸馏同事,蒸馏出来的不是一个人的完整能力,而是他工作中最容易整理、也最容易自动化的那一部分。

这部分内容不叫判断力,也不存在什么经验,它更接近一个词:Workflow。
换句话说,skill可以教AI怎么做,却不一定能让AI知道为什么这么做。
如果你真的想去蒸馏某个人的某部分知识,那么一定离不开今天的主角:RAG:


很多人对Skills有误解,以为他能很好的完成知识库的功能,这种想法是比较浅的,就现在的技术范式来说:
skill解决的是流程复制,那么RAG解决是知识调用

skill告诉模型第一步做什么、第二步做什么、RAG告诉模型做这件事时,需要参考哪些资料、哪些历史经验,以及这些信息从哪里来。
这两者一组合,就真的有点蒸馏那个意思了,比如:
你公司有个销冠,,大家都说他厉害,于是你准备蒸馏这个销冠,你会怎么做?
大概率是整理他的话术、跟进流程、异议处理方式等,然后写成一堆规则文档,再喂给模型。
这样做有没有价值?
当然有,但问题是——这只是他的外显动作,不是他的真实能力。因为真正的销冠,脑子里还有另一套系统:
公司所有产品的细节参数
不同行业客户的采购习惯
历史成交案例
哪些承诺能给,哪些不能给
...
这些隐性的知识,才决定他为什么说这句话,为什么给这个报价。而这些内容,当然不可能全部写进一个prompt里。所以你最后一定会发现:
skill负责复刻动作,RAG负责补足认知

所以,很多所谓的同事.skill,要变成真正能工作的AI同事,至少需要三层能力:
Workflow层:知道这件事该怎么做;
Knowledge层:知道做这件事要参考什么资料;
Judgement层:知道在复杂情况下如何权衡;
Skill主要解决第一层,RAG主要解决第二层,第三层则取决于模型能力、业务边界和人类兜底机制。
受小龙虾OpenClaw的影响,Skills的书写大家已经很熟悉了,那RAG到底怎么做?
今天我们不抽象讲概念,直接拿一个最常见的工具来说:Dify知识库。
PS:本来这里是想用AI Coding的,但经过学员反馈,很多公司实际在运转的依旧是Dify和Coze体系,所以这里还是用Dify算了...
只是要注意:Dify在这里不重要,知识库的思维都是这套,写代码也行
现在很多企业都在想办法落地AI知识库,常见做法是把散落在各处的手册、文档、FAQ集中起来,让大模型来回答员工或客户的问题。

能做这种工作的方法很多,最常见的就是Coding,除此之外也有一些低代码平台如Coze、Dify、FastGPT、RAGFlow等,就我的使用经验来说,当前Dify是比较均衡的:
有完整的知识库管理;
编排体验比较好;
开源≈可控性;
能私有化部署;
对企业场景比较友好;
PS:不得不说,就算是低代码平台的知识库,其实也不好用、不太友好
但如今Agentic RAG的框架还没看到比较好又开源的,如果NoteBookLM开源,我会无脑推
为什么我们会说不好用呢?因为很多同学在配置Dify知识库的时候,都会卡在这些选项上:
怎么设置分块?
索引模式选高质量还是经济?
检索方式选向量检索、全文检索,还是混合检索?
Top K到底填3、5还是10?
Score阈值设置为0.5还是0.7?
Rerank模型要不要打开?
...
其实熟悉RAG的同学就懂了,这些问题不仅是Dify会遇到,你写代码也懵逼啊...
进一步,这些问题看起来相互独立,其实互相关联性挺大的,要完整回答这些问题,就得搞清楚RAG的完整链路...

这套链路大致分为两个阶段:
离线阶段:数据入库
在线阶段:检索生成
离线阶段主要做:
文档解析→数据清洗→文档分块→向量化→建索引
在线阶段主要做:
用户提问→查询改写/知识库选择→召回→重排→Top K过滤→拼接上下文→大模型生成回答
只有理解完这条链路,再去看Dify的配置项,就不会觉得它们是孤立参数,而是一组有因果关系的控制点了。
下面我们用一个非常常见的场景来讲:

假设我们用Dify搭了一个智能客服,上传了一份产品售后手册。
我们希望用户问下面这些问题时,客服助手能准确回答:
怎么退货?
订单超过7天还能退吗?
SKU-20260315这款商品支持换货吗?
大促订单是否支持无理由退款?
海外订单退货运费谁承担?
这类问题看起来简单,但背后其实涉及:
售后政策;
商品规则;
订单状态;
SKU特殊规则;
大促活动条款;
如果没有RAG,模型只能靠通用知识回答,那么大家可能就会看到这种正确而无用的废话了:
一般情况下,商品是否支持退货取决于商家的售后政策,建议您查看订单详情或联系客服。
这句话没有错,但对企业来说没有任何价值,企业要的是:
根据《售后政策》第3.2条,普通商品签收后7天内支持无理由退货;
但SKU-20260315属于定制类商品,不支持无理由退货。
如商品存在质量问题,可在签收后15天内申请售后。
这才是RAG要解决的问题:基于企业自己的知识,给出有依据的回答。
要实现这种效果的话,就首先要进入第一步,离线阶段:数据入库

我们上传一份产品售后PDF,页面显示嵌入处理中...
很多人看到这几个字,以为系统只是在把文档存进去。其实不是,这背后就复杂了,Dify至少要完成四件事:
解析;
清洗;
分块;
索引;
这四步任何一步出问题,都会影响后面的检索质量和回答质量。而且这里要先强调一个非常重要的判断:
知识库效果的上限,往往不是由模型决定的,而是由入库质量决定的
很多团队知识库效果不好,第一反应是换模型、调Top K、调Score阈值、换向量数据库。
但真实情况大概率是:文档从一开始就没处理好。
第一步:先把文档读出来
系统拿到我们上传的PDF文件后,首先要做的是把它变成纯文本,这一步是最容易出问题的地方。

PDF不像Markdown那样天然就是结构化文本,一份PDF里可能混着:
正文;
表格;
页眉页脚;
水印;
图片说明;
脚注;
目录;
页码;
扫描图片;
...
解析器需要把这些东西分辨清楚,只保留真正有价值的正文内容,这里其实就可以用所谓的skill去处理了,虽然挺“大材小用”的...
如果是Word导出的PDF,解析效果通常还不错,因为底层有文本层可以直接提取。
但如果是扫描件生成的PDF,本质上就是一张图片,系统需要先OCR,把图片里的文字识别出来,这个过程天然容易出错:比如:
“0”被识别成“O”;
“SKU-20240315”被识别错;
表格里的列关系丢失;
页眉页脚被当成正文;
两栏排版被解析成错乱顺序;
...
这也是为什么同样是上传PDF,有的知识库效果很好,有的却总是答非所问。
这跟大模型无关,而是它拿到的原始文本从一开始就不干净。这里也有个重要启示:
知识库的质量跟你处理的细节是成正相关的
如果你对知识库效果要求很高,最好在上传之前就把文档格式处理好。

一般来说,适合知识库的文档格式优先级是:
| 文档类型 | 适合程度 | 原因 |
|---|---|---|
| Markdown | 很高 | 结构清晰,标题、段落、列表天然可解析 |
| 纯文本 | 很高 | 解析稳定,但结构信息较少 |
| Word | 较高 | 如果格式规范,解析效果不错 |
| 中等 | 取决于是否有文本层,扫描件风险很高 | |
| Excel | 较低 | 表格语义容易丢失 |
| PPT | 较低 | 信息分散,依赖视觉布局 |
| 图片/扫描件 | 很低 | 依赖OCR,错误率较高 |
文档被正确读出来之后,还不能直接进入知识库。

我们上传的售后手册PDF,可能每一页都有页眉、页脚,正文中还有一堆网址、邮箱、版权声明、水印文案......
这些内容对回答用户问题没有任何帮助。如果不清理掉,后面分块的时候就会被切进知识片段里,最终污染检索结果。
比如用户问:超过7天还能退货吗?
系统本来应该召回退货时效规则。结果因为每一页都有一段版权声明:本文档归XX公司所有,未经授权不得复制传播。如果这些内容大量重复,就会进入很多chunk,影响向量表示,甚至在检索结果中反复出现。
所以Dify在分块之前会做数据清洗,比如去掉:
连续空格;
多余换行符;
制表符;
URL;
电子邮件;
一些明显无意义字符;
...
这里也是需要特别注意的,不管是Dify还是其他知识库平台,系统自带的清洗能力都是有限的。它能处理一些通用噪音,但处理不了所有业务噪音,比如:
过期条款;
重复政策;
错误版本;
内部讨论备注;
不适合对外暴露的信息;
表格转文本后的结构错乱;
制度之间的冲突;
...
这些东西更多需要我们在上传前处理。对应到实际操作,就是一个很朴素的原则:
不要把未经整理的资料一股脑上传到知识库,数据处理越细致,后面效果越好
很多团队RAG技术说的倒是头头是道,但一到数据处理就容易烦躁,最后搞得很粗糙,最终的结果就是在做垃圾进,垃圾出。
文档质量不行,后面再好的Embedding模型、Rerank模型、向量数据库,都只是把垃圾更快地找出来。
PS:所以我们才说,好的RAG 80%的时间在搞数据呢

清洗完成后,系统会把一篇完整文档切成若干个小片段,这一步叫Chunking,也就是文档分块。
很多人第一次接触RAG时不理解为什么要切?原因很简单:
检索时,系统不可能把整篇文档都返回给大模型,而是只返回跟用户问题最相关的几个片段
如果不分块,检索的最小单位就是整篇文档,那用户问一个很小的问题,比如:
订单超过7天还能退吗?
系统可能把整份几十页的售后手册都塞给模型。这样会带来几个问题:
上下文太长;
无关信息太多;
成本太高;
响应变慢;
模型注意力被干扰;
关键信息反而被淹没;
...
所以分块的本质是:定义知识检索的最小返回单位。
但所有的分块都是个麻烦事,因为他的效果好不好只能不停测试,纯靠经验,分块有一个经典两难:太大,不精准;太小,不完整。
如果切得太大,一个片段里包含多个主题,向量模型在把它转成向量的时候,语义表达会变得模糊。比如一个chunk里同时写了:
退货规则;
换货规则;
发票规则;
运费规则;
...
那这个chunk的向量到底表示什么?它试图同时表示很多件事,结果哪件事都表示不精准。
反过来,如果切得太小,一个片段只有半句话,也不行。比如:
超过7天后
单独看这一句没有任何意义。模型不知道超过7天后怎么样,是不能退,还是可以换,还是要人工审核。所以好的分块要满足几个要求:
语义完整:每个块最好能独立表达一个完整意思;
长度合适:不能超过Embedding模型的输入限制;
粒度适中:既不能太粗,也不能太碎;
上下文连贯:边界处的信息不能被切断;
检索友好:用户问一个问题时,相关块能被稳定召回;
只不过这里看起来建议很多,真的如何切还是要不停的做测试,这也是为什么RAG项目一周出60分Demo,经常半年后还是60分的原因...
以下是一些常见分块策略,大家可以好好看看,这块很容易懵逼的:
一、固定长度分块
固定长度分块最简单。比如每500个token切一块。

优点是:
实现简单;
速度快;
适合快速验证;
缺点也很明显:
不理解语义;
可能把一句话切断;
可能把一个表格切烂;
可能把标题和正文分开;
比如原文是:
商品签收后7天内支持无理由退货,但定制类商品、虚拟商品、已拆封影响二次销售的商品除外。
如果固定长度刚好切在中间,就可能变成:
块1:
商品签收后7天内支持无理由退货,但定制类商品、
块2:
虚拟商品、已拆封影响二次销售的商品除外。
这两个块单独看都不完整。所以固定长度分块不太适合严肃生产场景,除非文档本身高度规整。
二、语义边界分块
更常见的是按自然语言边界分块,比如:
按段落;
按句号;
按换行;
按标题;
这种方式比固定长度更合理,因为它尽量在自然边界上切。

比如Dify的通用分段法,默认分段标识符是双换行符,也就是优先按段落切,这符合大多数文档的写作习惯。
一个段落通常表达一个相对完整的意思,所以按段落切比按固定字符数切更安全。
三、递归分块
现实文档不会都那么规整。有些段落特别长,一个段落可能几千token。这时候只按段落切就不够了。

所以很多系统会采用递归分块策略:
先尝试按大边界切,比如章节、段落;
如果还是太长,再按句子切;
如果句子还是太长,再按空格切;
最后实在不行,才按字符切;
这其实就是尽量保留语义边界,不得已再降级。
Dify在分段最大长度超过限制时,也会采用类似思路:先尽量按自然边界切,最后才使用更粗暴的方式。
这比简单固定长度要靠谱得多。
四、结构感知分块
如果文档结构比较明确,比如Markdown、HTML、技术文档,就可以按结构分块。比如:
一级标题;
二级标题;
代码块;
表格;
FAQ问答对;
列表项;

这种方式非常适合技术文档、产品手册、制度文档。比如FAQ文档,最理想的分块方式不是按500 token切,而是按一个完整Q&A切:
Q:订单超过7天还能退吗?
A:普通商品签收超过7天后不支持无理由退货,但如存在质量问题,可在15天内申请售后。
这个块天然就是一个完整知识单元。如果你把Q和A切开,检索效果就会明显下降。
五、智能语义分块
更高级的方式是用模型判断语义边界。

比如通过Embedding计算相邻句子的语义相似度,当语义突然变化时,说明话题发生切换,可以在这里切分。
或者直接让大模型阅读文本,判断哪些内容应该放在同一个chunk。
这种方式效果可能更好,但成本更高,也更复杂。所以一般适合:
高价值知识库;
文档复杂;
对准确率要求很高;
数据规模没有特别大;
对于大多数企业知识库,一开始不需要这么复杂。先把文档整理好,再用递归分块或结构化分块,通常已经能解决大部分问题。
只不过,往往做到一定阶段会发现,还是得请专家按照智能语义做分块,甚至引入更复杂的树形分块逻辑。
好,至此我们回归Dify。
Dify:三个核心参数

Dify提供了通用分段法,里面有三个关键参数:
分段标识符;
分段最大长度;
分段重叠长度;
分段标识符
分段标识符决定在哪里切。默认是双换行符,也就是按段落边界切。
如果你的文档有自己的分隔标记,也可以自定义。比如:
FAQ文档可以用“Q:”作为边界;
Markdown文档可以按标题切;
政策文档可以按“第X条”切;
客服话术可以按“场景:”切;
这里的核心是让系统尽量按业务语义切。比如售后政策里经常有这种结构:
第1条:退货范围
第2条:退货时效
第3条:不支持退货的情形
第4条:退货运费承担
如果你能按“第X条”切,效果通常比纯粹按段落切更好。因为每一条本身就是一个规则单元。
分段最大长度
分段最大长度决定每块最大多大。Dify默认是1024 token。
这个值不是越大越好:块越大,上下文越完整,但检索越不精准、块越小,检索越精准,但信息可能不完整。
一般来说,可以从下面这个经验出发:
| 文档类型 | 建议块大小 |
|---|---|
| FAQ | 200-500 tokens |
| 客服话术 | 300-700 tokens |
| 产品说明 | 500-1000 tokens |
| 技术文档 | 500-1200 tokens |
| 法务/制度文档 | 600-1200 tokens |
| 学术/长报告 | 800-1500 tokens |
但要注意,这只是建议,正如我们之前说的:效果好不好,只能不停的做测试。所以真的好不好还是要看后续的观测指标,比如:用户的问题能不能稳定召回完整答案。下面给个案例:
订单超过7天还能退吗?
最理想的chunk里应该同时包含:
普通商品退货时效;
特殊商品例外;
质量问题特殊处理;
大促订单规则;
...
如果块太小,只召回一句“超过7天不支持退货”,可能会漏掉“质量问题可售后”的例外条件。这就会导致回答不完整,甚至产生业务风险。
分段重叠长度
分段重叠是为了解决一个很现实的问题:关键信息刚好被切断了怎么办?比如:
块1:
普通商品签收后7天内支持无理由退货。
块2:
但定制类商品、虚拟商品、已拆封影响二次销售的商品除外。
如果用户问:
定制商品能退吗?
块1和块2都可能不够完整,重叠的意思是,相邻两个片段之间共享一部分内容。
这样即使边界切得不够完美,也至少有一个片段包含完整上下文。
Dify默认重叠50 token,官方建议一般设为最大长度的10%-25%。
比如最大长度1000 token,那么重叠可以设置在100-250 token之间。
但也不能重叠太多。重叠过多会带来几个问题:
存储变多;
向量化成本变高;
检索结果重复;
大模型看到大量相似片段;
最终回答可能变啰嗦;
以上就是Dify知识库从设计角度想要解决的问题,其他知识库大差不差,而Dify这里还提供了个特别的能力:
父子分块

除了通用分段法,Dify还提供了父子分块。这个能力很重要,因为它解决了RAG里一个非常核心的矛盾:
检索需要小块,生成需要大块。
这里有个矛盾:小块语义更聚焦,更容易精准匹配用户问题,比如用户问:
SKU-20240315支持换货吗?
如果有一个小块刚好写着:
SKU-20240315属于定制类商品,不支持无理由退货,但支持质量问题换货。
这个小块会非常容易被召回。
但如果只把这个小块丢给模型,模型可能缺上下文,不知道这个规则属于哪个政策、是否有适用范围、是否有时间限制。
所以生成回答时,模型又需要更完整的上下文。父子分块的思路就是:
入库时同时切成大块和小块;
检索时用小块匹配;
命中后返回对应的大块给模型;
换句话说:
用小块提高召回精度,用大块保证回答完整性
这很有点树形结构,和知识图谱的意思,是处理复杂场景的利器
这非常适合长文档、制度文档、产品手册、技术文档。比如一章售后政策是父块,其中每一条规则是子块。
用户问题先命中某一条规则,然后系统把整个相关章节返回给模型
这比单纯大块或单纯小块都更稳。
如果你做的是企业知识库,我很建议优先关注父子分块,尤其是文档比较长、规则之间有关联的时候。并且市面上有些类似的开源框架,比如:PageIndex,之前使用效果一般般,现在怎么样大家可以自己去试试。
分块完成后,这些知识片段还只是一堆文本,文本本身没法被高效语义检索,接下来要做的,就是给它们建立索引。

Dify里有两种常见选择:
高质量模式;
经济模式;
这两个名字有点产品化,我们翻译成技术语言就很好理解:
高质量模式:向量索引;
经济模式:关键词索引;
高质量模式:向量化
如果选了高质量模式,系统会调用我们指定的Embedding模型,把每个知识片段转换成一组数字,也就是向量:
向量是用数学方式表示文本语义,语义相近的文本,向量距离也更近
比如:怎么退货、商品退换流程、售后申请方式,这几句话字面上不完全一样,但语义接近,Embedding模型会把它们映射到相近的位置。
这样用户问怎么退货时,即使文档里没有完全一样的关键词,也能找到商品退换流程。
这是向量检索比传统关键词检索强的地方。但这里有一个非常关键的工程原则:文档和查询必须使用同一个Embedding模型,也就是:
离线阶段,文档chunk被Embedding模型转成向量
在线阶段,用户问题也要被同一个模型转成向量
只有这样,它们才在同一个语义空间里,才能比较距离。
如果文档用模型A向量化,查询用模型B向量化,那就像两套坐标系,检索结果会非常不稳定。
这也是RAG系统里一个常见坑,不瞒各位,最初我在这里栽过跟头...
经济模式:关键词索引
如果选了经济模式,系统不做向量化,而是用分词器从每个片段中提取关键词,建立关键词索引。
中文里常见的是Jieba分词。这种方式的优点是:
不需要调用Embedding模型;
成本低;
入库速度快;
对精确词匹配友好;
但缺点也很明显:它只能做字面匹配,不理解语义。
比如用户问:
怎么退货?
文档里写的是:
商品退换流程。
关键词不一致,可能就匹配不到。
但如果用户问:
SKU-20240315支持换货吗?
关键词检索反而很有优势,因为SKU、订单号、产品型号、人名、编号这类精确信息,向量检索不一定敏感,关键词检索通常更稳定。
所以经济模式不是完全没用。它适合:
成本极度敏感;
文档规模不大;
查询以精确关键词为主;
只是做简单搜索;
不需要复杂语义理解;
先阶段还流行一种做法,用经济模式筛选前会用模型去做关键词的泛化比较,这样也既能追求精确性又能追求泛化性,是我们在工作中常见的手段。
这里有个特别重要的点要说下:
索引模式是源头决策,不是后面调Top K、调Score阈值就能补回来的
比如你一开始选了经济模式,后面再问为什么用户换种说法就搜不到,为什么同义词匹配不上,为什么语义召回效果不好,那就不好回答了...
因为系统从一开始就没有把知识放进语义空间里。
建索引
向量化完成后,还没结束。
因为这些向量如果只是简单存起来,用户每问一个问题,系统都要把问题向量和库里的所有chunk一个个比较。
如果你的知识库只有几百个chunk,问题不大;但如果你的知识库有几十万、几百万个chunk,搜索就非常慢了。
所以系统还需要建索引,索引的作用很简单:
让系统更快找到可能相关的知识。
有索引的知识库,就像书有了目录、章节和页码,可以先定位到售后政策,再定位到退货规则,再找具体条款。
向量数据库里常见的HNSW、IVF、PQ、FAISS这些词,本质上都是在解决同一个问题:
如何在大量向量里,又快又准地找到相似内容。
但对Dify用户来说,不需要一开始就深入这些算法,你只要先理解一件事:
Embedding决定能不能理解语义,索引决定能不能高效检索
到这里,离线阶段才算真正结束。
我们上传的售后手册,已经从一份PDF,变成了可以被搜索、可以被召回、可以被大模型引用的一组知识片段。
接下来,就进入用户真正感知到的部分:

当用户问:
SKU-20260315这款商品超过7天还能退吗?
一个健壮的RAG系统又会进入链路:
用户提问→查询改写/知识库选择→召回→重排→TopK过滤→拼接上下文→大模型生成回答
第一步:查询改写
用户的问题往往不是标准检索语句。比如用户问:
这个东西过了7天还能不要了吗?
人能理解他大概率是在问退货,但知识库里可能写的是:
商品签收后7天内支持无理由退货。
这时候如果直接检索,效果可能不稳定。
所以很多RAG系统会先做查询改写,把用户口语化、模糊化的问题,改写成更适合检索的表达。比如改写成:
商品签收超过7天是否支持退货
或者进一步拆成几个检索意图:
退货时效;
超过7天;
无理由退货;
特殊商品例外;
这一步的目标不是回答问题,而是让问题更容易搜到正确资料。当然,查询改写也不是越复杂越好。
如果改写过度,反而可能改变用户原意,所以在企业知识库里,查询改写最好只做澄清和标准化,不要替用户脑补太多。
总之一句话:所有的改写都应该往知识库靠。
第二步:知识库选择
企业场景通常不是一个知识库,而是一堆知识库,这会加大检索难度:
产品说明知识库;
售后政策知识库;
物流规则知识库;
...
用户问:
大促订单超过7天还能退吗?
这个问题看起来是售后问题,但它可能同时涉及:
售后政策;
大促活动规则;
订单时效规则;
如果系统只去售后库里找,可能漏掉活动条款、如果系统所有知识库一起搜,又可能召回一堆不相关内容。
所以这里要决定:到底先判断问题属于哪个知识库,还是直接全库检索?
一般来说有两种方式:
第一种是先让模型判断问题属于哪个知识库,再去对应知识库检索。优点是结果更干净、成本更低、缺点是如果判断错了,后面就直接漏掉答案。
第二种是多知识库一起检索,然后合并结果。优点是不容易漏、缺点是召回结果更杂,后面重排压力更大,这里一般建议是:
| 场景 | 建议 |
|---|---|
| HR、财务、法务边界很清楚 | 可以先做知识库选择 |
| 售后、物流、活动规则经常交叉 | 优先多库检索 |
| 项目早期还没摸清问题分布 | 先多库检索,再慢慢优化路由 |
RAG里有个原则很重要:前面可以多召回一点,特别注意不要一开始就把正确答案排除掉。
第三步:召回
确定去哪找之后,就进入真正的召回。召回就是从知识库里先捞出一批可能相关的候选片段。
这一步几乎就是能拿出多少就拿多少出来,召回阶段追求的是:快,并且别漏掉关键数据。

Dify这里主要提供三种检索方式:
向量检索;
全文检索;
混合检索;
一、向量检索
向量检索是把用户问题转成向量,然后去向量数据库里找最相近的chunk。
它擅长处理语义相似。比如用户问:
怎么退货?
文档里写:
商品退换流程如下。
虽然字面不一样,但意思接近,向量检索有机会命中。
这就是向量检索的优势:用户怎么说不重要,意思接近就有机会搜到。
但它也有短板。比如用户问:
SKU-20260315支持换货吗?
SKU这种编号本身没有太多语义,向量检索不一定敏感,它可能会召回一堆换货规则,但没有命中这个具体SKU。
二、全文检索
全文检索依赖关键词匹配,对精确词非常友好,比如:
SKU;
订单号;
合同编号;
错误码;
...
只要文档里出现了这些词,它就容易找到,当他是没有语义能力的。
三、混合检索
很多大聪明应该都想到了,对:我全要,所以出了混合检索。Dify的混合检索,就是同时走这两路,然后把结果合并。
在大多数企业知识库场景里,如果只求交差拿尾款,无脑选择混合检索就好。
尤其是客服、售后、技术支持、内部制度问答这类场景,用户问题通常不是纯语义,也不是纯关键词,而是两者混在一起。
而且这东西在初期数据量不大的时候,表现挺不错的...
第四步:重排

召回之后,系统手里会有一批候选片段。但候选片段只是可能相关,不代表真的最相关。比如用户问:
Python异步编程最佳实践
系统可能召回:
Python异步编程指南;
Python编程最佳实践;
JavaScript异步编程最佳实践;
这三个都沾边,但真正最相关的是第一个。
召回阶段很难做这么细的判断,因为它追求的是快和全,所以后面需要重排。重排的作用是:把召回回来的候选片段,再按照和用户问题的真实相关性重新排一遍。
你可以这么理解:召回是海选,重排是复试。
PS:总而言之,大家也看出来模型项目开发的特性了,也不过是用更多的Token判断去拿到更精准的结果
综上,在做切片和索引的时候就一定要追求相关性被更多的被找出、而在做重排时候,又要保证拿到真正需要的数据
Rerank模型
这里如果使用Rerank模型,系统会把用户问题和候选chunk一起交给重排模型,让它判断每个chunk到底和问题有多相关。
它比单纯向量相似度更细,因为它不是只比较两个向量距离,而是会更深入地看问题和文本之间的匹配关系。
所以Rerank通常能明显提升最终效果,代价也很清楚:成本和效率。
所以要不要开Rerank,取决于场景。如果只是内部知识助手,可以先不开,把链路跑通。
如果是客服、售后、法务、医疗、金融、技术支持这种对准确性要求高的场景,还是尽量开。这些场景里,答错的成本通常比多花一点调用成本高得多。
第五步:Top K过滤

重排之后,系统会得到一组排好序的片段,但不是所有片段都要给大模型:Top K决定最多给模型几个片段。
比如Top K=3,就只取前三个片段拼进上下文。很多人觉得Top K越大越好,这其实不对。
大模型不是看到越多资料就越聪明。如果你塞进去10个片段,其中3个相关,7个不相关,模型反而可能被噪音带偏。
PS:说白了,还是因为不确定性,需要大量的重试所致
比如,在政策类知识库里,不同规则经常有适用范围:
普通商品支持7天无理由;
定制商品不支持无理由;
大促商品按活动规则执行;
质量问题可以走售后;
海外订单运费另算;
如果上下文塞太多,模型可能把规则混在一起,给出一个看似完整但其实不严谨的答案,那么这里给模型多少条数据,就很可能是个综合性选项了。
根据经验,一般可以先这样设置:
| 场景 | Top K建议 |
|---|---|
| FAQ问答 | 3-5 |
| 客服政策 | 3-6 |
| 技术文档 | 5-8 |
| 长文档总结 | 8-12 |
| 多规则综合判断 | 5-10 |
如果chunk比较大,Top K就小一点
如果chunk比较小,Top K可以适当大一点
如果用了父子分块,返回的是父块,那Top K不能太大,否则上下文很快就会爆
第六步:Score过滤
除了Top K,还有一个很重要的参数:Score阈值:
Top K是数量控制。
Score阈值是质量控制。
即使某个片段排进了Top K,但如果相关性分数低于阈值,也应该被过滤掉,这个参数主要防止系统硬凑答案。
PS:还是那句话,模型第一步检索希望越多越好,到重排和Score阶段,就希望越少越好了,说白了还是因为模型特性所致,没办法做到特别稳定
比如用户问:
你们公司创始人喜欢喝什么咖啡?
知识库里根本没有相关内容。但检索系统总能找出几个相对最像的片段。如果没有Score阈值,这些片段就会被塞给模型,模型很可能开始硬编。
所以Score阈值的意义是:知识库里没有依据时,不要强行回答。
一般来说:
阈值低,召回更宽,但噪音更多;
阈值高,结果更干净,但可能漏掉答案;
所以初期可以从0.5-0.7之间开始,根据真实日志慢慢调。
如果经常答非所问,就提高阈值。如果明明有答案却经常找不到,就降低阈值。高风险场景里,宁可保守一点:当前知识库中没有找到足够依据,建议转人工处理。
第七步:拼接上下文
经过召回、重排、过滤之后,系统会拿到最终片段,这些片段会被拼接进prompt,和用户问题一起交给大模型。
关于如何拼接虽然已经是最后一步,也是比较简单的一步,但还是有些技巧的,一般至少要告诉模型三件事:
只能基于已提供资料回答;
资料不足时要明确说不知道;
回答时尽量标注依据来源;
比如客服场景里,prompt里最好明确:
请基于以下知识片段回答用户问题。
如果知识片段中没有足够依据,不要编造,请提示转人工。
涉及退货、退款、换货等政策时,必须说明适用条件和例外情况。
这样模型才不会拿通用知识乱补。
全程可观测性
最后,大模型基于用户问题和检索到的知识片段生成回答。理想情况下,它应该做到:
回答用户问题;
引用知识库依据;
说明适用条件;
区分普通情况和例外情况;
资料不足时拒绝乱答;
但这里问题就来了,就是回答的不好怎么办?
RAG项目可观测性和飞轮系统,就是今天留给大家的思考题了
对吧,我们常常说回答的像不像人不重要,但回答得有依据、可追溯、可控制就很重要了。

现在我们再回头看Dify的配置项,就会发现它们不是孤立参数,而是分别控制RAG链路里的不同环节:
| 配置项 | 对应环节 | 本质作用 |
|---|---|---|
| 索引模式 | 向量化/建索引 | 决定用语义检索还是关键词检索 |
| 分块方式 | 文档分块 | 决定知识片段颗粒度 |
| 分段最大长度 | 文档分块 | 控制chunk大小 |
| 分段重叠长度 | 文档分块 | 防止边界信息丢失 |
| 检索方式 | 召回 | 决定按语义找、关键词找,还是两者都用 |
| Rerank | 重排 | 决定候选片段怎么重新排序 |
| Top K | 上下文过滤 | 决定最多给模型多少片段 |
| Score阈值 | 上下文过滤 | 决定低相关内容是否丢弃 |
所以调知识库,不应该上来就问:AI客服回答得很操蛋,该怎么办?
而应该先问:
文档本身干净吗?
chunk切得合理吗?
索引模式选对了吗?
召回方式适合业务问题吗?
是否需要Rerank?
真实问题日志里到底漏召回多,还是噪音多?
如果前面文档质量和分块都没做好,后面再怎么调Top K,都只是修修补补。
所以比较合理的调优顺序是:
文档质量→分块策略→索引模式→检索方式→重排→Top K/Score阈值→Prompt约束
这就是为什么我一直说,知识库不是一个简单功能,而是一个数据工程,Dify只是把这些能力做成了配置界面。
但配置背后的因果关系,你还是得懂!