犀牛鸟 2026 研究笔记 estelledc.github.io

RAG/知识库赛道 — 深度对比研究

调研时间:2026-06-22 基于 WeKnora / Dify / RAGFlow / AnythingLLM / FastGPT 源码阅读


一、项目全景定位

项目 一句话定位 设计哲学 核心创新 竞争身位
WeKnora 腾讯 IMA 文档理解 + 三路混合检索 + 自维护 Wiki 检索质量至上——BM25+向量+知识图谱三路融合,知识库能自我巡检 EventManager + Plugin 管线,RRF 融合,PMI 知识图谱,自适应分块 学术+工业混合体,检索深度最强
Dify 144K star 的全栈 LLM 应用平台 拖拽搭建 LLM 应用,RAG 是工具箱里的一把螺丝刀 可视化工作流编排 + 插件市场 + BM25+向量混合 事实标准,生态最大
RAGFlow 深度文档理解 RAG 引擎 检索之前先把文档”看懂”——DeepDoc 引擎对 20+ 格式做深度解析 DeepDoc 引擎(PDF 表格识别、扫描件 OCR、嵌套表格) 文档解析赛道最深
AnythingLLM 61K star 的本地优先全栈 AI 应用 不让数据出本机——单文件部署、内建向量库、隐私第一 11 个向量数据库后端 + 30+ LLM 适配器 + Memory 系统 部署门槛最低
FastGPT 28K star 的企业知识库平台 面向团队和企业——权限管理、多租户、可视化工作流 双路召回 (embedding + MongoDB $text) + 多查询扩展 企业场景深耕

二、跨项目检索策略对比

2.1 检索路数梯度:单路 → 双路 → 三路

五个项目的检索架构差异,可以用”找书的路数”来类比。

单路检索(AnythingLLM):你只有一个图书管理员,你说”帮我找讲性能优化的书”,他凭理解帮你找。找到的很可能不错,但如果你的需求是精确关键词(如”ERR_OOM_KILL_001”),他可能理解不了——”这看起来是个错误码吧,你要不要看其他讲错误的?”

双路检索(Dify / RAGFlow / FastGPT):你有两个管理员,一个按关键词精确查目录(BM25 / 全文检索),一个凭语义理解推荐(向量检索)。两人各找各的,最后合并结果。关键词管理员能找到”ERR_OOM_KILL_001”的精确文档,语义管理员能找到措辞不同但语义相关的文档。

三路检索(WeKnora):除了上面两位管理员,还有第三位——他手里有一张关系网(知识图谱),知道”ERR_OOM_KILL_001”和”内存溢出处理指南”之间有因果关系。即使前两位都没找到某篇文档,第三位通过关系推理也能找到。三路各找各的,用 RRF 把三路排名合并成一个统一排序。

这个梯度可以用一张表来概括:

项目 检索路数 第一路 第二路 第三路 融合方式
AnythingLLM 1 向量语义 - - 无需融合
FastGPT 2 向量语义 MongoDB $text - 单参数加权
Dify 2 向量语义 BM25 - 分数加权 (min-max 归一化)
RAGFlow 2 向量语义 BM25 - 权重融合 (w 可配)
WeKnora 3 向量语义 BM25 PMI 知识图谱 RRF (k=60)

2.2 各融合策略的数学公式

FastGPT:单参数线性插值

final_score = rerankWeight × vector_score + (1 - rerankWeight) × fulltext_score

默认 rerankWeight = 0.5

问题:余弦相似度范围 [0.5, 0.99],MongoDB textScore 范围 [0.1, 5.0],两个量纲不一致,textScore 的绝对值会主导结果。除非 rerankWeight 设得非常高(>0.9),全文分数的贡献几乎被忽略。

Dify:归一化后加权

final_score = α × normalize(vector_score) + (1-α) × normalize(bm25_score)

normalize 使用 min-max 归一化:
  normalize(x) = (x - min) / (max - min)

默认 α = 0.7(向量权重 70%,BM25 权重 30%)

改进:归一化把两路分数映射到 [0, 1],解决了量纲不一致的基本问题。但 min-max 归一化对异常值敏感——如果某次检索中有一个极端高分(如 0.99 的余弦相似度),其他正常分数的区分度被压缩。

RAGFlow:权重融合(可配置权重)

final_score = w × vector_score + (1-w) × bm25_score

w 可配置(默认 0.7)

与 Dify 的区别在于权重可配置性更强,用户可以在界面上调节 w 值。但根本问题相同——分数量纲不一致,依赖归一化的质量。

WeKnora:RRF 排名融合

\[\text{RRF}_{\text{score}}(d) = \sum_i \frac{w_i}{k + rank_i(d)}\]

其中 $k=60$ 为平滑常数,$rank_i(d)$ 为文档 $d$ 在第 $i$ 路检索中的排名(从 1 开始),$w_{\text{向量}}=0.7$,$w_{\text{BM25}}=0.3$,$w_{\text{图谱}}$ 动态调整(根据图谱密度)。

核心差异:完全忽略分数绝对值,只看排名。排名天然是归一化的——第 1 名就是第 1 名,不管分数是 0.99 还是 25.7。

2.3 性能影响的具体对比

用一个真实场景来量化差异。假设用户查询”ERR_OOM_KILL_001 的处理方式”:

融合方式 向量检索 top-3 BM25/全文 top-3 融合后排序 问题
FastGPT 线性插值 “内存溢出排查”[0.92] “错误码参考”[0.88] “性能调优”[0.85] “ERR_OOM_KILL_001 处理”[3.2] “错误码大全”[1.8] “OOM 修复指南”[1.2] “内存溢出排查”[混合后0.92主导] 精确匹配”ERR_OOM_KILL_001”的文档因textScore量纲被淹没
Dify 归一化加权 同上 同上 归一化后两者可比,但极端值影响大 归一化方式依赖当前检索结果的分布
RAGFlow 权重融合 同上 同上 类似 Dify 归一化敏感
WeKnora RRF 向量排名: “内存溢出排查”#1 “错误码参考”#2 “性能调优”#3 BM25排名: “ERR_OOM_KILL_001处理”#1 “错误码大全”#2 “ERR_OOM_KILL_001处理”[多路共识#1] “ERR_OOM_KILL_001”在BM25排第1,RRF赋高权重

RRF 的优势在这个例子中体现得最清楚——精确匹配”ERR_OOM_KILL_001”的文档在 BM25 中排第 1,RRF 给它一个 0.3/(60+1)=0.00492 的贡献。同时它在向量检索中可能排名靠后(比如第 5),RRF 给 0.7/(60+5)=0.01077。总分 0.01569,而”内存溢出排查”虽然在向量排第 1 但在 BM25 中没出现,总分只有 0.7/(60+1)=0.01148。RRF 靠”共识”机制让精确匹配结果脱颖而出。

2.4 从单路到三路的边际收益分析

每增加一路检索,带来多少实际价值?这个问题没有普适答案,但可以按查询类型来分析:

查询类型 例子 单路够不够 双路提升 三路提升
语义查询 “怎么提高性能” 小(BM25 帮助不大) 极小
精确关键词 “ERR_OOM_KILL_001” 不够 大(BM25 必需)
同义表达 “密码重置流程” 够(向量理解同义) 极小
多跳推理 “ERR_OOM_KILL_001 的发明者还写过什么” 不够 不够 大(图谱必需)
模糊描述 “那个让内存变大的参数” 有时够 中(图谱可能推理到具体参数)

结论:双路混合覆盖了 80-90% 的查询场景,三路混合主要解决多跳推理和模糊描述的”最后 10%”。这”最后 10%”在企业场景中可能正是最关键的——高管问的往往是跨领域的问题。


三、RRF 融合深度剖析

3.1 RRF 公式回顾

\[\text{RRF}_{\text{score}}(d) = \sum_i \frac{w_i}{k + rank_i(d)}\]

三个核心参数:

3.2 k 值的数学直觉

k 控制的是”排名第 1 比排名第 10 好多少”。

k 值 第 1 名得分 第 2 名得分 第 10 名得分 第 1/第 10 比值 效果
1 0.500 0.333 0.091 5.5 排名第一的结果一骑绝尘
10 0.091 0.083 0.050 1.8 前 10 名差距适中
60 0.0164 0.0161 0.0143 1.15 前 10 名几乎同一水平,需要多路共识才能脱颖而出
1000 0.001000 0.000999 0.000990 1.01 排名差异被完全抹平,RRF 退化成简单计数

k=60 是 RRF 论文(Cormack et al., 2009)在 TREC 实验上的经验最优值。在这个 k 值下,排第 1 和排第 10 的差距只有 15%,这意味着单路的极端排名不会主导结果——必须在多路检索中都排名靠前才能获得高分。

3.3 边界案例分析

案例 1:文档只在一路中出现

文档 A:BM25 排名 #1,向量未召回
文档 B:BM25 排名 #5,向量排名 #3

RRF(A) = 0.3/(60+1) + 0 = 0.00492
RRF(B) = 0.3/(60+5) + 0.7/(60+3) = 0.00462 + 0.01111 = 0.01573

文档 B 在两路中都有排名,RRF 分数远高于只在一路排第 1 的文档 A。这是 RRF “共识优先”设计哲学的体现——多路检索的”共识”比单路的极端排名更可靠。

但这也带来一个问题:如果文档 A 确实是唯一相关的文档(BM25 精确匹配),但向量检索因为语义偏差没有召回它,RRF 会把它排到后面。解决方案:在 RRF 之后加 Rerank 做精排,让 Rerank 模型有机会”纠正”RRF 的遗漏。

案例 2:三路排名完全一致

文档 C:BM25 #1,向量 #1,图谱 #1
文档 D:BM25 #2,向量 #2,图谱 #2

RRF(C) = 0.3/61 + 0.7/61 + w_g/61 = (1.0+w_g)/61
RRF(D) = 0.3/62 + 0.7/62 + w_g/62 = (1.0+w_g)/62

三路完全一致时,RRF 的排序结果和单路排序完全一致——这正是我们期望的。RRF 不会”破坏”共识。

案例 3:极端权重失衡

假设 w_向量 = 0.99,w_BM25 = 0.01

文档 E:BM25 #1,向量 #20
文档 F:BM25 #20,向量 #1

RRF(E) = 0.01/(60+1) + 0.99/(60+20) = 0.000164 + 0.01238 = 0.01254
RRF(F) = 0.01/(60+20) + 0.99/(60+1) = 0.000125 + 0.01623 = 0.01635

极端权重下,RRF 退化为单路排序——向量排名几乎完全决定结果。这说明 RRF 不能解决”应该给哪路更高权重”的问题,它只解决了”量纲不一致”的问题。权重选择仍然需要根据场景调优。

3.4 RRF vs 其他融合方法的系统对比

对比维度 RRF (WeKnora) 分数加权 (Dify/RAGFlow) CombMNZ CombSUM
输入 只需排名 需要分数 需要分数+排名 需要分数
归一化 不需要 必须 必须 必须
对异常值鲁棒性
参数量 1 (k) + 权重 1 (alpha) + 归一化方式 0 0
多路扩展性 天然支持 每加一路需重新归一化 支持 支持
实现复杂度
推荐场景 多路异构检索 同构双路检索 学术实验 学术实验

CombMNZ 和 CombSUM 是信息检索领域的经典融合方法。CombSUM 将各路归一化分数直接相加;CombMNZ 在 CombSUM 的基础上乘以文档出现在几路检索中。两者都对归一化质量敏感,实际应用不如 RRF 广泛。

3.5 参数敏感性实验设计

WeKnora 当前使用 k=60 作为固定值,但不同场景下最优 k 值可能不同。推荐的参数敏感性实验:

k 值 预期 Context Precision 预期 Context Recall 适合场景
10 低(排名差异大,单路主导) 高(单路极端排名被放大) 确信某路远优于其他路
30 中高 标准双路场景
60 高(共识优先,多路一致排名才高) 通用三路混合
100 高(差异被进一步压缩) 低(无法区分细微排名差异) 检索结果质量均匀时

详见 精读: WeKnora 中 RRF 融合器的实现细节


四、Rerank 策略对比

4.1 Rerank 在 RAG 管线中的位置

Rerank 是检索管线中”粗排 → 精排”的精排步骤。类比:粗排像海选——从 1000 个候选人中选出 50 个;精排像面试——对 50 个候选人逐一深入评估,选出最合适的 5 个。

粗排(向量/BM25)的特点是速度快但精度有限——Bi-Encoder 把 query 和 doc 分别编码成向量,用余弦相似度衡量相关性,但无法建模 query-doc 之间的交互关系。精排(Rerank)使用 Cross-Encoder,把 query 和 doc 拼在一起送入模型,让模型看到两者的交互细节,精度显著提升但速度慢(每个 query-doc 对需要一次模型前向传播)。

Bi-Encoder(粗排):
  Embed(query) → q_vec
  Embed(doc)   → d_vec
  score = cosine(q_vec, d_vec)  # 快:向量距离一次计算

Cross-Encoder(精排):
  score = CrossEncoder([query; doc])  # 慢但准:query-doc 交互建模

4.2 各项目 Rerank 策略全景

项目 Rerank 方式 信号数 Rerank 模型 权重配置 鲁棒性
WeKnora 三信号复合 3 bge-reranker 等 0.6 model + 0.3 base + 0.1 source
Dify 单模型 Rerank 1 Cohere/bge-reranker/自定义 无(完全依赖模型)
RAGFlow 单模型 Rerank 1 bge-reranker/自定义
FastGPT 单参数加权 1 本质不是 Rerank 模型 rerankWeight
AnythingLLM 0 - - 最低

4.3 Cross-Encoder Rerank(Dify / RAGFlow)

Dify 和 RAGFlow 使用标准的 Cross-Encoder Rerank:把 query 和每个 candidate doc 拼成 [CLS] query [SEP] doc [SEP],送入 Cross-Encoder 模型(如 bge-reranker-v2-m3、Cohere Rerank),模型输出一个相关性分数。

优点

缺点

4.4 LLM-as-Reranker

一些实验性方案直接用 LLM(如 GPT-4)做 Rerank——给 LLM 看 query 和 candidate docs,让它排序或打分。

Prompt 示例:
  给定查询: "{query}"
  以下哪个文档与查询最相关?请按相关性从高到低排序。

  文档 1: {doc_1}
  文档 2: {doc_2}
  ...
  文档 N: {doc_N}

  输出格式: [文档编号排序,如 2, 5, 1, 3, 4]

优点

缺点

目前五个项目中没有一个采用 LLM-as-Reranker 作为默认策略,但 Dify 的 Code 节点 + 自定义工作流可以实现类似效果。

4.5 复合 Rerank(WeKnora)

WeKnora 的复合 Rerank 是所有项目中最精细的设计:

final_score(d) = 0.6 × rerank_model_score(q, d)
              + 0.3 × base_relevance_score(d)
              + 0.1 × source_credibility(d)

三个信号的作用

  1. rerank_model_score(0.6):Cross-Encoder 对 (query, doc) 对的深度语义评估。权重最高,因为是”最聪明”的信号。

  2. base_relevance_score(0.3):RRF 融合后的基础排名分,代表多路检索的”共识”。这个信号的作用是兜底——即使 Rerank 模型在专业术语上判断失误,多路检索的共识排名还在。

  3. source_credibility(0.1):来源可信度。不是从文本内容推断的,而是在文档摄入时根据元数据预先标注的:

来源类型         可信度分数
──────────────────────
官方文档          1.0
产品文档          0.9
技术博客(官方)    0.8
社区文档          0.6
论坛帖子          0.4
用户笔记          0.3

为什么三个信号比一个好?

假设一个医疗知识库中,用户问”阿司匹林的禁忌症”。两篇文档:

单模型 Rerank 可能给 B 打高分(因为”不能”和”禁忌”语义上更直接),但复合 Rerank 会考虑来源可信度(A 是 1.0,B 是 0.4),最终 A 排在前面。这在企业场景中价值巨大——回答基于官方文档而非社区猜测。

4.6 Rerank 的性能开销对比

Rerank 的主要开销是模型调用。假设 top-N=20 个 candidate docs:

Rerank 方式 每次调用延迟 每次调用成本 总开销 (N=20)
无 Rerank 0 0 0
FastGPT 线性合并 <1ms 0 <1ms
Dify/RAGFlow Cross-Encoder ~500ms ~$0.001 ~10s / $0.02
WeKnora 复合 Rerank ~600ms (Cross-Encoder + 两个计算) ~$0.001 + 计算 ~12s / $0.02
LLM-as-Reranker ~3-5s ~$0.03-0.10 ~3-5s / $0.03-0.10

注:LLM-as-Reranker 的延迟看起来比 Cross-Encoder 低,是因为它一次调用处理所有 docs(而非 N 次),但单次调用成本远高于 Cross-Encoder。

详见 精读: WeKnora 复合 Rerank 深度解析


五、分块策略跨项目对比

5.1 分块对 RAG 质量的根本影响

分块(Chunking)是 RAG 系统中”最不起眼但影响最大”的环节。类比:分块像把一块大蛋糕切成小份——切太大,一个人吃不完(LLM context 被大 chunk 占满);切太小,每个人只尝到一口就没了(失去上下文);切得不均匀,有的有奶油有的只有蛋糕坯(信息不完整)。

更具体地说,分块质量直接影响三个下游环节:

  1. 向量表示质量:一个 768 维向量要承载 chunk 的全部语义信息。chunk 太大(如整篇文章),向量被”稀释”——搜索时不够精确;chunk 太小(如单句),向量缺少上下文——”它使用了 RRF 算法”这句话脱离上下文后,”它”指谁?

  2. 检索精度:分块边界如果切在语义中间(如把”营收 23.5 亿”切成”营收”和”23.5 亿”两个 chunk),检索时可能只召回了半句话,LLM 无法给出准确回答。

  3. LLM 生成质量:送给 LLM 的 context 如果缺少必要上下文,LLM 只能”猜”——这就是幻觉的根源之一。

5.2 五种分块策略全景

项目 分块策略 核心思想 优势 劣势
AnythingLLM 固定大小 按字符数/token 数硬切 简单、可预测 语义边界被切断
FastGPT 固定大小 + QA 对拆分 基础分块 + LLM 改写为问答对 QA 对检索精度高 LLM 调用成本高
Dify 自动/自定义/父子分块 按文档类型自适应 + 父子分块 覆盖多场景 语义级分块缺失
RAGFlow 模板驱动 不同文档类型用不同分块模板 领域精准(法律/论文/FAQ) 需要选择/创建模板
WeKnora 4 级自适应降级链 auto → heading → heuristic → recursive → legacy 全自动、适应不同文档质量 降级链可能选错策略

5.3 固定大小分块(AnythingLLM / FastGPT 基础模式)

最简单的分块策略:按固定 token 数切割,相邻 chunk 之间有 overlap。

chunk_size = 500 tokens
chunk_overlap = 50 tokens

文档: [token_0 ... token_499] [token_450 ... token_949] [token_900 ... token_1399] ...
        chunk_1                 chunk_2                  chunk_3

问题示例

原文:"2024 年公司总营收为 23.5 亿元,同比增长 15.3%。其中,云计算业务贡献了 8.2 亿元,占比 34.9%。"

固定 500 token 切分后:
  chunk_47: "...2024 年公司总营收为"
  chunk_48: "23.5 亿元,同比增长 15.3%..."

“23.5 亿”和”营收”被分到了两个 chunk,检索”2024 年营收”可能只召回 chunk_47,缺少具体数字。

5.4 QA 对拆分(FastGPT 特色)

FastGPT 的 QA 对拆分是五个项目中最独特的分块策略。核心思想:先让 LLM 把文档内容改写成”问题-答案”对,再对 Q 和 A 分别向量化。

原文:"FastGPT 的工作流引擎支持条件分支、循环和变量传递。"

           │
           ▼ LLM 调用

QA 对:
  Q: FastGPT 工作流引擎支持哪些控制结构?
  A: 支持条件分支、循环和变量传递。

为什么 QA 对检索精度高? 因为 Q 已经预判了用户可能的提问方式。用户问”工作流引擎支持什么”,向量检索可以直接匹配到 Q 字段——这比在原文中搜索”支持”更精确。

代价:每段文本都需要调用 LLM 生成 QA 对,大规模文档库的摄入成本显著高于传统分块。一篇 10,000 字的文档可能拆分出 50-100 个 QA 对,每个需要一次 LLM 调用。

局限:不适合叙述性文档(故事、论文、报告),因为叙述性信息是线性递进的,不是可以独立提取的知识点。

详见 精读: FastGPT QA 对拆分策略详解

5.5 模板驱动分块(RAGFlow 特色)

RAGFlow 为不同文档类型预置了 9 种分块模板:

模板 分块逻辑 核心规则
通用 (General) 按段落 + 语义边界 无特殊处理
问答 (Q&A) 每个问答对为一个 chunk Q 和 A 绑定,不拆分
手册 (Manual) 按章节层级 保留操作步骤完整性
论文 (Paper) 按 Abstract/Intro/Method/Exp/Conclusion 公式保留 LaTeX
法律 (Law) 按条款切分 条款编号与正文绑定
书籍 (Book) 按章节 + 小节 章节摘要自动生成
演示 (Presentation) 每页幻灯片为一个 chunk OCR + 演讲者备注
表格 (Table) 每行/每条记录为一个 chunk 列名作为上下文保留
图片 (Picture) 每张图片 OCR 作为一个 chunk 图片描述生成

法律模板的精妙之处

输入:
  第三十二条  有下列情形之一的,用人单位可以解除劳动合同:
    (一)在试用期间被证明不符合录用条件的;
    ...

法律模板分块:
  Chunk: {
    "article": "第三十二条",
    "content": "有下列情形之一的,用人单位可以解除劳动合同:\n(一)在试用期间被证明不符合录用条件的;\n...",
    "references": ["第十五条"]  // 自动识别的引用关系
  }

条款编号与正文绑定——检索”第三十二条”时,整条法规完整出现。引用关系被提取出来,可用于后续知识图谱构建。

详见 精读: RAGFlow 模板驱动分块深度解析

5.6 4 级自适应降级链(WeKnora 特色)

WeKnora 的分块策略最灵活——不是固定用某一种策略,而是根据文档质量自动选择:

auto(自动检测文档结构)
  │ 如果有明确的标题层次结构
  ▼
heading(按标题分块)
  │ 如果标题结构不清晰或不均匀
  ▼
heuristic(启发式——段落间距 / 空行 / 缩进模式)
  │ 如果启发式失败
  ▼
recursive(递归字符分割——按 chunk_size / chunk_overlap 硬切)
  │ 如果 recursive 也出问题
  ▼
legacy(最原始的固定长度切割)

为什么需要降级链? 因为文档输入的质量不可控。一篇结构良好的 Markdown 走 heading 就够了——标题层级是天然的语义边界。一篇 OCR 过来的扫描 PDF 可能只有纯文本没有结构,就降级到 recursive 或 legacy。

语义级分块(WeKnora 的第 4 级可选策略)

1. 把文档分成句子序列: [s1, s2, s3, ..., sn]
2. 对每个句子做 embedding: [e1, e2, e3, ..., en]
3. 计算相邻句子的余弦相似度: sim(ei, ei+1)
4. 当 sim(ei, ei+1) < 阈值 → 在 si 和 si+1 之间切分
5. 阈值通常设为 0.5-0.7(可配置)

日常类比:连续几页都在讲同一个主题,突然下一页话题急转——语义相似度在切分点出现”断崖”。语义级分块就是自动检测这种断崖。

详见 精读: WeKnora 4 级自适应分块策略

5.7 父子分块(Dify 特色)

Dify 的父子分块是另一种解决”检索粒度 vs 上下文完整性”矛盾的设计:

父 chunk(大,如 1000 tokens)
  ├─ 子 chunk 1(小,如 200 tokens)
  ├─ 子 chunk 2(小,如 200 tokens)
  └─ 子 chunk 3(小,如 200 tokens)

检索时:
  1. 用子 chunk 做检索(粒度细,精度高)
  2. 找到匹配的子 chunk 后
  3. 返回其父 chunk 的完整内容给 LLM(保留上下文)

这和 RAGFlow 的模板驱动分块是不同维度的设计——父子分块不关心文档类型,只关心粒度层次;模板驱动分块关心文档类型,但粒度由模板决定。两者可以组合使用:先用模板确定分块边界,再在模板边界内做父子分层。

详见 精读: Dify 分块策略详解


六、文档解析能力对比

6.1 解析质量决定 RAG 天花板

RAGFlow 的核心洞察值得反复强调:RAG 系统的瓶颈往往不在检索算法,而在文档解析质量。再好的向量检索,如果把表格数据切碎了、把图片里的文字丢了,召回的就是残缺信息。这就是”GIGO”(Garbage In, Garbage Out)原则在 RAG 中的体现。

6.2 解析能力梯度

项目 解析引擎 PDF 表格 扫描件 OCR 版面分析 公式提取 支持格式
AnythingLLM 基础文本提取 不支持 不支持 不支持 不支持 8+
FastGPT 第三方服务 基础 基础 不支持 不支持 10+
Dify PyMuPDF / pdfplumber 基础 插件式 不支持 不支持 10+
WeKnora IMA 引擎 + docreader 深度 深度 部分 15+
RAGFlow DeepDoc 引擎 极深 极深 深度学习模型 LaTeX 20+

6.3 简单文本提取 vs DeepDoc

用一份含表格的年报 PDF 来对比:

简单文本提取(AnythingLLM / FastGPT / Dify)

PDF 内嵌文本层提取结果:
  "指标 2024年 2023年 上半年 下半年 营收 100亿 40亿 60亿 净利润 20亿 8亿 12亿"

所有文字混在一起,行列关系完全丢失。按 500 字切分后:
  chunk_A: "指标 2024年 2023年 上半年 下半年 营收"
  chunk_B: "100亿 40亿 60亿 净利润 20亿 8亿 12亿"

检索"2024 年营收" → 召回 chunk_A → 只有"营收"没有数字
                     或召回 chunk_B → 只有数字没有"营收"标签

DeepDoc 解析(RAGFlow)

版面分析 → 识别出表格区域
表格结构恢复 → HTML table:
  <table>
    <tr><td>指标</td><td>2024 年</td><td colspan="2">2023 年</td></tr>
    <tr><td></td><td></td><td>上半年</td><td>下半年</td></tr>
    <tr><td>营收</td><td>100 亿</td><td>40 亿</td><td>60 亿</td></tr>
    <tr><td>净利润</td><td>20 亿</td><td>8 亿</td><td>12 亿</td></tr>
  </table>

整个表格作为一个 chunk → 检索"2024 年营收" → 召回完整表格 → LLM 精确回答"100 亿"

6.4 DeepDoc 的四步处理管线

Step 1: 版面分析(Layout Analysis)
  输入: PDF 页面图像
  输出: 每个区域的类型标注(文本/表格/图片/标题/页眉页脚)
  模型: 基于深度学习的目标检测模型(类似 YOLO/Mask R-CNN)

Step 2: 文本提取(Text Extraction)
  对文本区域: 直接提取 PDF 内嵌文本
  对图片/扫描区域: 调用 OCR 引擎

Step 3: 表格结构恢复(Table Structure Recognition)
  输入: 表格区域图像
  输出: 行列关系 + 跨行跨列信息(HTML table 或 JSON)

Step 4: 结构化内容组装
  按版面顺序组装各区域内容
  保留区域间的层级关系(标题→段落→子段落)

处理速度代价

文档类型 页数 DeepDoc 处理时间 简单提取时间
纯文本 PDF 10 ~5 秒 <1 秒
含表格 PDF 10 ~30 秒 <1 秒
扫描件 PDF 10 ~60 秒 N/A
复杂年报 PDF 50 ~5 分钟 <5 秒

DeepDoc 的深度解析带来处理速度的代价。对于需要实时索引更新的场景是瓶颈,但 RAGFlow 的应对策略是异步处理——文档上传后放入任务队列,后台解析完成后通知用户。

详见 精读: RAGFlow DeepDoc 引擎深度解析


七、向量数据库选型对比

7.1 向量数据库的角色

向量数据库是 RAG 系统的”记忆存储”——所有文档 chunk 经过 Embedding 后变成高维向量,存在向量数据库中。检索时,查询也被 Embedding 成向量,在向量数据库中做 ANN(近似最近邻)搜索,找到语义最相似的 top-K 个 chunk。

7.2 各项目支持的向量库后端

向量库 WeKnora Dify RAGFlow FastGPT AnythingLLM 特点
Milvus 分布式、大规模生产首选
Qdrant - Rust 写的,性能好
Weaviate - - 内建 BM25 混合搜索
Pinecone - - - 全托管云服务
Chroma - 轻量、适合原型
pgvector - 已有 PG 的团队免运维
Elasticsearch - BM25 + 向量双支持
FAISS - - - - 纯内存、研究用
LanceDB - - - 嵌入式、零运维
总计 10 6+ 4+ 1-2 11  

7.3 选型决策树

你的场景是什么?
  ├─ 个人/小团队原型 → Chroma 或 LanceDB(零运维)
  ├─ 已有 PostgreSQL → pgvector(无需新服务)
  ├─ 已有 Elasticsearch → ES 向量搜索(BM25 + 向量一体化)
  ├─ 中大规模生产 → Qdrant 或 Milvus
  │    ├─ 需要 BM25 混合 → Weaviate 或 Qdrant
  │    └─ 纯向量大规模 → Milvus(分布式扩展性好)
  ├─ 不想运维 → Pinecone(全托管云)
  └─ 研究/实验 → FAISS(纯内存、极致速度)

7.4 向量库支持数量 vs 项目定位

一个有趣的观察:向量库支持数量最多的不是检索深度最强的 WeKnora,而是 AnythingLLM(11 个)。原因在于设计目标不同:


八、Embedding 模型选择

8.1 Embedding 模型对检索质量的影响

Embedding 模型是把文本转换为向量的核心组件。不同的 Embedding 模型在以下维度上差异巨大:

8.2 各项目 Embedding 支持对比

项目 默认模型 可选模型 本地模型支持 中文优化
WeKnora bge-large-zh 多种 ✓ (Ollama)
Dify text-embedding-3-small 7+ 种 ✓ (Ollama) ✓ (bge-large-zh)
RAGFlow bge-large-zh 多种
FastGPT text-embedding-ada-002 3-4 种 部分
AnythingLLM text-embedding-3-small 30+ 适配器 ✓ (Ollama/LMStudio) 部分

8.3 Embedding 维度与检索质量的非线性关系

直觉上,维度越高(3072 > 1536 > 768),向量承载的信息越多,检索应该越精确。但实际并非如此简单:

8.4 Embedding 一致性原则

一个常被忽视但至关重要的原则:同一个知识库必须始终使用同一个 Embedding 模型。如果中途换了模型,已有向量的维度和语义空间与新模型不兼容,检索结果会完全错误。

正确做法:
  知识库创建时选择模型 → 所有文档用同一模型 embedding → 检索时用同一模型 embed query

错误做法:
  用 OpenAI 模型 embedding 了 1000 个文档
  → 改用 bge-large-zh 模型 embed 新查询
  → 两个模型的向量空间不兼容
  → 余弦相似度无意义
  → 检索结果随机

如果需要换模型,必须对整个知识库重新 embedding。这是一项昂贵的操作——10 万个 chunk,每个 1536 维向量需要一次 API 调用,成本可达数十美元。


九、Agent/Workflow 集成对比

9.1 RAG 不是终点,而是 Agent 的工具

RAG 系统的最终价值不在于”检索+生成”本身,而在于能否被 Agent 调用、被 Workflow 编排、被其他系统集成。五个项目在”RAG 与 Agent/Workflow 的集成”上走了完全不同的路线。

9.2 集成模式梯度

模式 代表项目 特点 灵活性 可预测性
纯 RAG(无 Agent) AnythingLLM 检索+生成就完事 最低 最高
简单 Agent FastGPT 工作流中嵌入检索节点
可视化 Workflow Dify 拖拽编排复杂管线
Graph Agent RAGFlow 图定义 RAG 专用推理流程 中高
EventManager + Plugin + MCP WeKnora 事件驱动 + 插件管线 + MCP 被外部调用 最高

9.3 Dify 的可视化 Workflow

Dify 的工作流引擎是五个项目中表达力最强的。它用 JSON DSL 存储 DAG(有向无环图),支持 30+ 种节点类型:

关键节点类型:
  ├─ Start/End: 流程入口/出口
  ├─ LLM: 大模型调用(意图识别/文本生成/摘要)
  ├─ Knowledge Retrieval: RAG 检索
  ├─ Code: 执行 Python/JS(沙箱内)
  ├─ HTTP Request: 调用外部 API
  ├─ IF-ELSE: 条件分支
  ├─ Iteration: 迭代循环
  ├─ Tool: 调用内置/自定义工具
  └─ Template Transform: Jinja2 模板渲染

Agent 与 Workflow 的组合模式

Chatbot 类型(纯对话):
  用户 → LLM → 回复

Agent 类型(ReAct / Function Calling):
  用户 → LLM → [思考 → 工具调用 → 观察] × N → 回复
  (循环执行,LLM 自主决策)

Workflow 类型(可视化编排):
  用户 → Start → Node1 → Node2 → ... → End → 回复
  (DAG 执行,人工预定义流程)

组合模式(Workflow 中嵌入 Agent):
  用户 → Start → Knowledge Retrieval → IF-ELSE
                                           ├─ 高相关 → LLM 生成回答 → End
                                           └─ 低相关 → Agent 节点(自主决策)→ End

详见 精读: Dify Workflow Engine 深度解析

9.4 WeKnora 的 EventManager + Plugin + MCP

WeKnora 的集成方式与 Dify 完全不同——它不是”自己编排 Agent”,而是”被其他 Agent 调用”。

EventManager + Plugin 管线

// 伪代码,基于 WeKnora 源码结构
type EventManager struct {
    subscribers map[EventType][]Plugin
    eventChan   chan Event
}

// 查询到来时,三路 Plugin 并行执行
func (em *EventManager) Emit(event Event) {
    for _, plugin := range em.subscribers[event.Type] {
        go plugin.Handle(event)  // goroutine 并发
    }
}

Go 的 goroutine 让 BM25、向量、知识图谱三路检索并行执行,总延迟取决于最慢的那一路。这是 Go 语言在并发场景下的天然优势。

MCP Server(WeKnora 新增)

WeKnora 新增了 mcp-server/ 模块,实现了 MCP(Model Context Protocol)Server。这意味着 Claude Code / CatDesk 等支持 MCP 的 Agent 框架可以直接连接 WeKnora 的检索能力,不需要写自定义集成代码。

Agent (Claude Code / CatDesk)
  │ MCP 协议
  ▼
WeKnora MCP Server
  │
  ├─ knowledge_search 工具
  ├─ knowledge_list 工具
  └─ ...

这种”RAG 即服务”的集成模式是 WeKnora 在 Agent 生态中的正确定位——不做编排(让 Dify/LangGraph 做),只做检索后端。

详见 精读: WeKnora EventManager 深度解析

9.5 FastGPT 的可视化工作流

FastGPT 的工作流引擎与 Dify 类似(可视化 DAG 编排),但更聚焦于知识库场景:

FastGPT 特有节点:
  ├─ datasetNode: 知识库检索(双路召回)
  ├─ answerNode: 中间回复(流式推送中间状态)
  └─ pluginNode: 插件调用(工作流子图封装)

FastGPT 的工作流和 Dify 的关键区别在于插件系统:FastGPT 的插件本质上是”封装好的工作流子图”——用户把一段常用的工作流片段保存为插件,在其他工作流中通过 pluginNode 调用。Dify 的插件是”独立 Python/Node 模块”——需要写代码开发。FastGPT 的插件门槛更低但灵活性不如 Dify。

详见 精读: FastGPT 工作流引擎深度解析


十、知识图谱能力对比

10.1 知识图谱在 RAG 中的独特价值

知识图谱是 WeKnora 区别于其他四个项目的核心差异化。它的价值在于解决一类特殊问题——多跳推理

“多跳推理”的例子:用户问”ERR_OOM_KILL_001 的发明者还写过哪些论文”。这个问题需要两步推理:(1) 找到 ERR_OOM_KILL_001 是谁发明的;(2) 找到这个人还写过什么。向量检索和 BM25 都无法一步完成——因为第二步需要的文档可能根本不包含”ERR_OOM_KILL_001”这个关键词。

知识图谱通过实体关系链来支持多跳推理:”ERR_OOM_KILL_001” → [发明者是] → “张三” → [写过] → “论文 A, 论文 B, 论文 C”。

10.2 三种知识图谱构建策略

策略 代表 构建方式 实体质量 关系质量 构建成本 构建速度
PMI 统计 WeKnora 点互信息共现统计 低(只知道”有关联”)
LLM 驱动 RAGFlow GPT-4/Claude 抽取实体关系 高(理解语义关系类型)
Dify/AnythingLLM/FastGPT - - - - -

10.3 PMI 知识图谱深度剖析(WeKnora)

PMI(Pointwise Mutual Information,点互信息)是一种统计方法,用于衡量两个实体的共现是否超出随机预期:

\[PMI(x, y) = \log_2\left(\frac{P(x,y)}{P(x) \cdot P(y)}\right)\]

其中 $P(x)$、$P(y)$ 分别为实体 $x$、$y$ 在语料中出现的概率,$P(x,y)$ 为两者在同一文档/段落中共同出现的概率。

PMI 的直觉理解

翻看一年的微信聊天记录,”报销”和”发票”总是一起出现(高 PMI),说明它们有强关联。而”报销”和”天气”偶尔同时出现纯属巧合(低 PMI),不建立关系边。

WeKnora PMI 图谱的构建步骤

1. 实体抽取
   从文档中提取候选实体(名词短语/专业术语)
   → 使用中文分词 + 词性标注过滤

2. 共现统计
   扫描所有文档,统计每对实体的共现频率
   → 窗口大小通常为段落级别(一个 chunk 内)

3. PMI 计算
   对每对实体计算 PMI 值
   → 过滤掉低频对(出现 < N 次的不可靠)

4. 图谱构建
   PMI > 阈值的实体对 → 在图中建立边
   边的权重 = PMI 值
   → 形成加权无向图

5. 图谱索引
   对图做预处理(BFS/DFS 可达性索引)
   → 支持快速图遍历查询

PMI 图谱的优势和局限

优势:

局限:

详见 精读: WeKnora PMI 知识图谱深度解析

10.4 LLM 驱动知识图谱(RAGFlow)

RAGFlow 的 Graph RAG 使用 LLM 从文档中抽取实体和关系:

Prompt 示例:
  从以下文本中提取所有命名实体和它们之间的关系。
  文本:{chunk_text}
  请以 JSON 格式输出:
  {
    "entities": [{"name": "实体名", "type": "人物/组织/概念/..."}],
    "relations": [{"source": "实体A", "relation": "关系类型", "target": "实体B"}]
  }

与 PMI 的对比

维度 PMI (WeKnora) LLM 驱动 (RAGFlow)
关系类型 只有”有关联” 有具体语义(属于/创建/影响…)
实体质量 依赖分词质量 高(LLM 理解语义)
构建成本 极低 高(每次 LLM 调用 $0.01-0.05)
一致性 高(统计确定性) 低(LLM 输出不稳定)
增量维护 简单(更新 PMI 值) 困难(实体消歧问题)

潜在融合方案:先 PMI 预筛选(低成本找到高共现实体对),再 LLM 标注关系类型(高精度确定关系语义)。这样既保留 PMI 的成本优势,又获得 LLM 的语义质量。

详见 精读: RAGFlow Graph RAG 实现详解


十一、生产部署对比

11.1 部署复杂度梯度

项目 最低配置 必需组件 部署方式 启动时间
AnythingLLM 1C2G 单可执行文件 docker run <1 分钟
FastGPT 2C4G MongoDB + PostgreSQL + Redis Docker Compose / Sealos 3-5 分钟
Dify 2C4G PostgreSQL + Redis + Celery + API + Web + Nginx Docker Compose / K8s 5-10 分钟
RAGFlow 4C8G Milvus + Redis + Elasticsearch + API + Web Docker Compose 10-15 分钟
WeKnora 2C4G 向量DB + Redis + Go 后端 + React 前端 + docreader Docker Compose 5-10 分钟

11.2 资源需求分析

AnythingLLM 最低:单可执行文件 + 内建 LanceDB,1C2G 即可运行。因为不做 BM25、不做 Rerank、不做知识图谱,计算量最小。

RAGFlow 最高:DeepDoc 的深度解析需要 GPU 或大量 CPU(版面分析、表格识别、OCR 都是深度学习推理),4C8G 是最低门槛,生产环境建议 8C16G+。

WeKnora 中高:三路检索本身计算量不大(BM25 和向量检索都是毫秒级),但 docreader(Python 文档解析微服务)需要额外资源。如果文档量大,docreader 可能成为瓶颈。

11.3 可扩展性对比

项目 水平扩展 瓶颈 适合规模
AnythingLLM 不支持 单机内存限制 个人/小团队
FastGPT Sealos K8s 自动扩缩容 MongoDB 写入瓶颈 中型企业
Dify API Server 无状态可水平扩展 Celery Worker 任务积压 大型企业
RAGFlow Worker 可水平扩展 Milvus 索引更新延迟 中大型企业
WeKnora Go 后端天然高并发 知识图谱增量维护 大规模

11.4 运维复杂度

项目 监控 备份 升级 故障排查
AnythingLLM 基础日志 复制数据目录 替换可执行文件 简单(单进程)
FastGPT MongoDB + PostgreSQL 监控 标准 DB 备份 Docker 镜像更新 中等(3-4 个服务)
Dify 需监控 6 个服务 PG dump + Redis save docker compose pull + restart 复杂(6 个服务级联)
RAGFlow 需监控 Milvus + ES + Redis 多个 DB 备份 docker compose pull + 索引重建 复杂(组件多)
WeKnora 需监控向量DB + docreader 向量DB 快照 + 元数据备份 docker compose pull 中高(Go + Python 微服务)

十二、评估框架整合

12.1 RAGAS 四维评估

RAGAS(Retrieval Augmented Generation Assessment)是当前最主流的 RAG 评估框架,四个核心指标分别评估不同环节:

指标 评什么 为什么重要 满分条件
Faithfulness(忠实度) 答案中每个声明是否在 context 中有支撑 检测幻觉 答案每句话都能指回检索到的 chunk
Answer Relevancy(答案相关性) 答案是否真正回答了用户问题 检测答非所问 答案高度聚焦用户意图
Context Precision(上下文精确度) 检索到的 chunk 中有多少是相关的 检测检索噪声 所有检索到的 chunk 都与问题直接相关
Context Recall(上下文召回率) 回答所需的信息是否都被检索到了 检测检索遗漏 ground truth 每个要点都在检索结果中

12.2 各平台 RAGAS 评估的适用性差异

RAGAS 四个指标是通用的,但不同平台因为架构差异,评估时需要关注的重点不同:

平台 最可能低分的指标 根因 改进方向
AnythingLLM Context Recall 单路向量检索召回面窄 加 BM25、加 Rerank
FastGPT Context Precision MongoDB $text 噪声大 换专业 BM25 引擎
Dify Context Precision 简单分数加权归一化不稳定 引入 RRF
RAGFlow Context Recall(扫描件场景除外) 文档解析质量已保证,问题主要在检索路数少 加知识图谱第三路
WeKnora Answer Relevancy 三路检索可能召回过多信息,LLM 被 noise 干扰 调 Rerank 权重、降 top-K

12.3 消融实验设计

评估 WeKnora 各组件贡献度时,推荐以下消融实验:

检索路数消融

实验组 开启路数 预期 Context Recall 预期 Context Precision
基线 BM25 + 向量 + 图谱(三路全开) 最高
-图谱 BM25 + 向量 多跳问题下降 不变或微升(噪声减少)
-BM25 向量 + 图谱 精确匹配问题下降 不变
仅向量 向量 最低 取决于向量模型质量

Rerank 消融

实验组 Rerank 配置 预期 Context Precision 预期 Faithfulness
基线 0.6 模型 + 0.3 基础 + 0.1 来源 最高 最高
仅模型 1.0 模型 中高(领域偏差时下降) 中高
无 Rerank 跳过 Rerank 低(噪声 chunk 多) 中(LLM 可能被噪声误导)

分块大小消融

chunk 大小 预期 Context Precision 预期 Context Recall 预期 Faithfulness
128 tokens 高(chunk 信息集中) 低(上下文碎片化) 低(LLM 看到不完整信息)
512 tokens 中高 中高 中高
1024 tokens 低(噪声多) 高(信息完整) 中(噪声可能误导 LLM)

12.4 三分法归因:检索失败 vs 生成幻觉 vs 答非所问

当 RAG 输出错误答案时,根因可能来自三个不同环节:

失败类型 表现 哪个指标低 对策
检索失败 关键文档没被检索到 Context Recall 低 改分块/改检索策略/加图谱路
检索噪声 检索到了但噪声太多 Context Precision 低 加 Rerank / 调 top-K
生成幻觉 检索正确但答案编造 Faithfulness 低 换模型/加引用约束/降温度
答非所问 检索和生成都对但偏题 Answer Relevancy 低 改 prompt/query 改写

归因顺序(debug 时从底向上):先看 Context Recall(有没有找到),再看 Context Precision(噪声大不大),再看 Faithfulness(有没有编),最后看 Answer Relevancy(答没答对题)。

详见 RAG 评估方法论 RAGAS 四指标详解与消融实验设计


十三、逐项目深度分析

13.1 WeKnora(腾讯,~14.3K star,Go,犀牛鸟候选项目)

设计哲学:把”检索质量”做到极致——不止有向量语义搜索,还叠加 BM25 关键词精确匹配和知识图谱推理,三路结果通过 RRF 融合出最优排序,最后再用复合 Rerank 做精排。知识库不只是被动被查询,还能主动发现知识冲突和过期内容。

核心架构

用户查询
  │
  ├─ BM25 关键词检索 ──────────────────────────────┐
  │                                                 │
  ├─ 向量语义检索(10 种向量库后端)────────────────│── RRF 融合 ─→ 复合 Rerank ─→ LLM 生成
  │                                                 │   (k=60)     (0.6 model +
  ├─ 知识图谱推理(PMI 加权实体关系)──────────────┘              0.3 base +
  │                                                                0.1 source)
  └─ [自维护 Wiki] ─→ 知识巡检(冲突检测 / 过期发现 / lint 检查)

关键源码实体

模块 核心机制 作用
EventManager 事件驱动管线 所有 RAG 操作统一走事件总线,Plugin 可在任意环节插入
Plugin Pipeline 插件管道 文档解析、分块、向量化、检索、Rerank 每个环节可独立替换
RRF 融合器 Reciprocal Rank Fusion k=60,向量权重 0.7、关键词权重 0.3,合并三路检索结果
复合 Rerank 三信号加权 0.6 × 模型打分 + 0.3 × 基础相关度 + 0.1 × 来源可信度
PMI 知识图谱 点互信息加权 从文档中自动抽取实体关系,用 PMI 衡量关系强度
自适应分块 4 级降级链 auto → heading → heuristic → recursive → legacy
自维护 Wiki 知识巡检 lint 检查——发现过期知识、实体矛盾、引用断裂

犀牛鸟洞察

详见 精读: WeKnora 竞赛贡献指南

13.2 FastGPT(~28K star,TypeScript)

设计哲学:面向企业的”知识库 + 工作流”平台。检索管线相对简洁,把更多精力放在权限管理、多租户和企业级工作流编排上。

核心架构

用户查询
  │
  ├─ 多查询扩展(query rewrite)
  │     └─ 将一个模糊问题拆成多个精确子问题
  │
  ├─ 双路召回
  │     ├─ Embedding 向量检索(1-2 个向量库后端)
  │     └─ MongoDB $text 全文检索(依赖 jieba 中文分词)
  │
  └─ 简单 Rerank(单 rerankWeight 参数加权融合)
       └─ 送入 LLM 生成答案

关键特色

模块 机制 特点
多查询扩展 query rewrite LLM 改写查询,生成多个变体分别检索,扩大召回面
jieba 分词 中文 tokenization MongoDB $text 索引依赖分词质量,jieba 对中文效果显著
QA 对拆分 LLM 改写为问答对 五个项目中最独特的分块策略,检索精度显著提升
多租户架构 MongoDB 文档级隔离 RBAC 权限 + API Key 管理 + 用量配额

局限

详见 精读: FastGPT


13.3 AnythingLLM(~61K star,JavaScript)

设计哲学:极致简化——一个可执行文件搞定所有事情。不追求检索的”最优”,追求使用的”最简”。

核心架构

用户查询
  │
  └─ 纯向量检索(无 BM25,无 Rerank)
       │
       ├─ 11 个向量库后端(LanceDB / Chroma / Pinecone / Qdrant / Milvus / Weaviate
       │                     / pgvector / Elasticsearch / Zilliz / AstraDB / hnswlib)
       │
       ├─ Memory 系统(按相关度过滤历史对话)
       │
       └─ 30+ LLM 适配器(OpenAI / Anthropic / Ollama / LMStudio / LocalAI...)

为什么没有 BM25 和 Rerank

AnythingLLM 的目标是”在本地跑一个 AI 助手”的个人用户,不是企业级知识库。纯向量检索在 80% 的日常场景下”够用”——你问”项目进展怎么样”,向量检索能召回包含”进度”“状态”“更新”等语义相似的文档。BM25 的优势在精确关键词匹配(如型号名、错误码),个人场景下需求不大。

Memory 系统

AnythingLLM 有一个独特的 Memory 机制——不只是把最近 N 条对话塞进 context,而是根据当前 query 和历史消息的语义相关度做过滤。类比:你和朋友聊天提到”上次吃饭”,大脑自动跳到那次吃饭的记忆,而不是按时间顺序回忆所有对话。

详见 精读: AnythingLLM


13.4 Dify(~144K star,TypeScript/Python)

设计哲学:全栈 LLM 应用平台,RAG 是众多能力之一。核心价值在于”拖拽搭建 LLM 应用”——可视化工作流 + 模型管理 + Prompt IDE + 数据集管理 + Agent 编排。

RAG 模块架构

用户查询
  │
  ├─ BM25 关键词检索
  ├─ 向量语义检索
  └─ 混合融合(加权)─→ Rerank(可选)─→ LLM 生成

关键特点

竞争格局中的位置

Dify 是赛道事实标准(144K star)。RAG 实现属于”工程化水平高但检索深度一般”——BM25+向量双路混合覆盖大多数场景,但没有 WeKnora 的知识图谱第三路,Rerank 也没有三信号复合设计。核心竞争力在平台生态而非检索深度。

详见 精读: Dify


13.5 RAGFlow(~83K star,Python/TypeScript)

设计哲学:检索之前先把文档”吃透”。DeepDoc 引擎对 PDF 表格、扫描件、图片中的文字都做了专门处理,支持 20+ 文件格式。

核心架构

文档输入
  │
  └─ DeepDoc 引擎
       ├─ PDF 深度解析(版面分析 / 表格识别 / 图文分离)
       ├─ 扫描件 OCR(基于深度学习的文字识别)
       ├─ 嵌套表格处理(跨行跨列的复杂表格)
       ├─ Word / Excel / PPT / Markdown / HTML / 邮件...
       └─ 20+ 格式统一输出结构化内容
            │
            ├─ BM25 + 向量混合检索
            └─ 支持自定义权重

DeepDoc 引擎的独特价值

类比:其他 RAG 系统处理文档像”用吸管喝珍珠奶茶”——把所有内容当成一股液体吸进来,珍珠(表格数据)、茶(正文)、奶泡(图片说明)全混在一起。RAGFlow 的 DeepDoc 像”先用筛子把珍珠、茶、奶泡分开”,每种成分用不同方式处理——表格保留行列结构,正文按语义分段,图片先 OCR 再提取文字。

企业文档场景中价值极大。一份年报 PDF 里的表格如果被当成纯文本切分,数字和列名就错位了——”营收 23.5 亿”可能被切成”营收”在一个 chunk、”23.5 亿”在另一个 chunk。DeepDoc 保留表格结构后,检索质量显著提升。

详见 精读: RAGFlow


十四、全景透视

14.1 检索管线深度梯度

AnythingLLM:   查询 ─→ 向量检索 ─→ 结果
                       (最简)

FastGPT:       查询 ─→ 多查询扩展 ─→ 双路召回(embedding + $text) ─→ 简单 Rerank ─→ 结果

Dify/RAGFlow:  查询 ─→ BM25 + 向量混合 ─→ Rerank(可选) ─→ 结果
                       (标准做法)

WeKnora:       查询 ─→ BM25 + 向量 + 知识图谱三路 ─→ RRF 融合 ─→ 复合 Rerank ─→ 结果
                       (最深)                           (k=60)    (三信号加权)

14.2 检索策略深度矩阵

维度 WeKnora Dify RAGFlow FastGPT AnythingLLM
向量检索
BM25 关键词 ✓($text) -
知识图谱 ✓(PMI) - ✓(实验性LLM驱动) - -
RRF 融合 ✓(k=60) 加权 加权 加权 -
复合 Rerank ✓(三信号) 可选 可选 单参数 -
多查询扩展 - - -
自适应分块 ✓(4级) 固定+父子 模板驱动 固定+QA对 固定
知识巡检 ✓(Wiki) - - - -
检索深度评级 ★★★★★ ★★★ ★★★★ ★★★ ★★

14.3 架构模式对比

维度 WeKnora Dify RAGFlow FastGPT AnythingLLM
主语言 Go TS/Python Python/TS TypeScript JavaScript
代码量 ~800 files ~5000+ ~2000+ ~2500+ ~1500+
架构模式 EventManager+Plugin 平台化+微服务 DeepDoc引擎+Web Monorepo+工作流 单体全栈
单文件信息密度 极高(Go) 中等 中等 中等
通读成本 最低 最高 中等 中等 较低

14.4 向量数据库支持对比

向量库 WeKnora Dify RAGFlow FastGPT AnythingLLM
Milvus
Qdrant -
Weaviate - -
Pinecone - - -
Chroma -
pgvector -
Elasticsearch -
FAISS - - - -
LanceDB - - -
总计 10 6+ 4+ 1-2 11

14.5 技术路线对比矩阵

维度 WeKnora Dify RAGFlow FastGPT AnythingLLM
检索质量 ★★★★★ ★★★ ★★★★ ★★★ ★★
文档解析 ★★★★(IMA) ★★★ ★★★★★ ★★★ ★★
部署便利 ★★★ ★★★★ ★★★ ★★★ ★★★★★
生态规模 ★★ ★★★★★ ★★★★ ★★★ ★★★★
代码精简 ★★★★★ ★★ ★★★ ★★★ ★★★
企业特性 ★★★ ★★★★ ★★★ ★★★★ ★★
学术深度 ★★★★★ ★★ ★★★★ ★★

十五、关键设计决策对比

15.1 检索融合策略:RRF vs 加权混合

RRF(WeKnora):基于排名的融合——不关心每路检索的分数绝对值,只关心排名。这解决了一个根本问题:BM25 分数和向量余弦相似度不在同一个量纲上,直接加权没有意义。

RRF 的核心优势:
  - 归一化天然内建——排名本身就是归一化的
  - 对异常值不敏感——某路检索分数爆炸不会主导结果
  - 参数简单——只有一个 k 值

加权混合的问题:
  - 需要手动归一化各路分数(min-max / z-score / percentile)
  - 归一化方式的选择本身引入新的超参数
  - 不同 query 的最优权重可能不同

15.2 Rerank 策略:单信号 vs 多信号

项目 Rerank 方式 信号数 鲁棒性
WeKnora 0.6 model + 0.3 base + 0.1 source 3 高——模型失准时有兜底
Dify 可选 rerank 模型 1 中——完全依赖模型质量
RAGFlow 可选 rerank 模型 1
FastGPT 单 rerankWeight 参数 1 低——本质是向量和全文分数的线性插值
AnythingLLM 0 最低——纯向量相似度

15.3 分块策略:固定 vs 自适应 vs 模板驱动

WeKnora 的 4 级自适应分块是五个项目中最灵活的。其他项目基本采用固定分块策略(按字符数 / token 数切割,配合 overlap),对文档质量有较高要求——如果文档结构混乱,固定分块会产生大量跨语义边界的 chunk,严重影响检索质量。

RAGFlow 的 DeepDoc 在分块之前先做了文档结构理解,本质上把”分块”问题转化为”文档解析”问题——先把表格、段落、标题识别出来,再按识别结果分块。这是另一种”自适应”思路,但和 WeKnora 的降级链是不同维度的设计。

FastGPT 的 QA 对拆分是第三种思路——把”分块”问题转化为”问答生成”问题。不关心原文怎么切,而是让 LLM 把原文改写成问答对,用 Q 做检索、用 A 做生成。这种方式在 FAQ 类文档中效果极好,但在叙述性文档中效果差。


十六、端到端检索流程对比

16.1 WeKnora(最深管线)

用户输入 "WeKnora 的知识图谱用了什么算法?"
  │
  ├─ ① BM25 检索:精确匹配 "WeKnora" "知识图谱" "算法"
  │     → 命中文档 A(包含 "WeKnora" 关键词)
  │     → 命中文档 B(包含 "知识图谱算法" 关键词)
  │
  ├─ ② 向量检索:语义相似度
  │     → 命中文档 C(讨论 "实体关系抽取" 但没提 "知识图谱")
  │     → 命中文档 D(讨论 "PMI 共现分析")
  │
  ├─ ③ 知识图谱检索:实体推理
  │     → "WeKnora" → "知识图谱" → "PMI" 三跳关联
  │     → 命中文档 E(PMI 的数学定义,普通检索可能遗漏)
  │
  ├─ ④ RRF 融合:按排名合并 A/B/C/D/E
  │     → 文档 A 在 BM25 排第 1、向量排第 3 → 高 RRF 分
  │     → 文档 E 只在知识图谱排第 1 → 中等 RRF 分(但提供了独特信息)
  │
  └─ ⑤ 复合 Rerank:三信号精排
       → 文档 A: 0.6×0.9 + 0.3×0.8 + 0.1×0.7 = 0.85(最终第 1)
       → 文档 E: 0.6×0.7 + 0.3×0.6 + 0.1×0.9 = 0.69(独特来源加分)

16.2 AnythingLLM(最简管线)

用户输入 "WeKnora 的知识图谱用了什么算法?"
  │
  └─ ① 向量检索:语义相似度
       → 命中文档 C(语义最近的前 K 个文档)
       → 送入 LLM 生成答案
       → 如果文档 C 没提到具体算法名 → 回答可能不完整

差距一目了然:WeKnora 通过三路检索 + 知识图谱推理能找到 AnythingLLM 找不到的信息(如文档 E),通过复合 Rerank 能更精确地排序结果。

16.3 Dify(标准双路管线)

用户输入 "WeKnora 的知识图谱用了什么算法?"
  │
  ├─ ① BM25 检索:精确匹配
  │     → 命中文档 A、B
  │
  ├─ ② 向量检索:语义相似度
  │     → 命中文档 C、D
  │
  ├─ ③ 分数加权融合(min-max 归一化后 α=0.7 加权)
  │     → 合并排序 A/B/C/D
  │
  ├─ ④ 可选 Rerank:Cross-Encoder 精排
  │
  └─ ⑤ LLM 生成
       → 文档 E(PMI 数学定义)可能被遗漏——没有知识图谱路去发现它

Dify 的双路管线覆盖了大部分场景,但面对多跳推理问题时缺少知识图谱的支持。


十七、代码质量评估

17.1 代码组织与可读性

维度 WeKnora Dify RAGFlow FastGPT AnythingLLM
文件组织 模块清晰,Go 包结构标准 微服务分层清晰 引擎+Web 分离 Monorepo 结构 单体平铺
命名规范 Go 惯例,简洁 Python/TS 混合风格 Python 惯例 TS 惯例 JS 惯例
注释密度 高(核心算法有详细注释) 中等 中等 中等
测试覆盖 核心模块有单测 CI 覆盖较全 中等 中等 基础

17.2 通读路径推荐

WeKnora(推荐 2-3 天):

1. 入口:EventManager 事件总线 → 理解所有操作的统一入口
2. 检索管线:BM25 → 向量检索 → 知识图谱 → RRF 融合器 → 复合 Rerank
3. 分块管线:自适应分块降级链(auto → heading → heuristic → recursive → legacy)
4. 知识巡检:自维护 Wiki 的 lint 检查逻辑

RAGFlow(推荐 3-4 天):

1. 入口:DeepDoc 引擎 → 理解文档解析的完整流程
2. 版面分析:PDF 的页面布局检测(文本区域 / 表格区域 / 图片区域)
3. 表格识别:行列结构恢复、跨行跨列处理
4. 检索模块:BM25 + 向量混合

Dify(推荐 5-7 天):

1. 入口:docker-compose.yaml → 理解 6 个服务的角色和依赖
2. 工作流引擎:api/core/workflow/ → DAG 表示和拓扑排序
3. RAG 管线:api/core/rag/ → 检索/分块/Rerank 实现
4. 模型抽象层:api/core/model_runtime/ → 100+ 模型统一接口
5. Agent 框架:api/core/agent/ → ReAct 和 Function Calling

十八、总结与建议

如果目标是理解 RAG 系统设计:先读 WeKnora(检索管线最深,Go 代码精简)→ 对比 RAGFlow(文档解析最强)→ 对比 Dify(平台化工程最成熟)

如果目标是犀牛鸟贡献:WeKnora 代码量小、概念密度高、三路检索设计独特、与腾讯犀牛鸟项目对齐。主要贡献方向:RRF 参数自适应、知识图谱质量评估、分块策略自动选择、检索效果 benchmark。

如果目标是快速搭建 RAG 应用:AnythingLLM 门槛最低(下载即用),Dify 适合团队协作(可视化编排),FastGPT 适合企业场景(权限管理)。

学习价值排序(从”理解 RAG 系统设计”角度):

  1. WeKnora — 检索管线最深,代码最精简,概念密度最高
  2. RAGFlow — 文档解析赛道最深,理解”为什么好的解析是 RAG 的前提”
  3. Dify — 赛道标杆,理解”全栈 LLM 平台如何集成 RAG”
  4. AnythingLLM — 理解”本地优先 RAG”的取舍
  5. FastGPT — 企业级知识库的权限和多租户设计有参考价值

交叉引用

相关页面 关系 本篇覆盖维度
精读: WeKnora WeKnora 架构详解 二~五节 RRF/Rerank/分块摘要,完整细节见精读
精读: Dify Dify 架构详解 Workflow Engine / Model Runtime / Agent 模式对比
精读: RAGFlow RAGFlow 架构详解 DeepDoc / 模板分块 / Graph RAG 对比
精读: FastGPT FastGPT 架构详解 QA 对拆分 / 多查询扩展 / 多租户对比
精读: AnythingLLM AnythingLLM 架构详解 Memory 系统 / 向量库支持对比
WeKnora 竞赛贡献指南 犀牛鸟贡献路径 评估框架 → 消融实验 → Rerank 权重调优
RAG 评估方法论 RAGAS 四维评估 十二节评估框架整合
Agentic RAG 模式 6 种 RAG-Agent 结合模式 九节 Agent/Workflow 集成对比
RAG Agent 集成 Agent 与 RAG 平台集成 MCP Server / RAG 即服务
RAG 挑战总览 通用 RAG 难题 分块困境 / 检索最后一公里 / 知识腐化
选型决策树 什么场景选什么 7.3 向量库选型 + 11 部署对比
生产级 RAG 全景 全景关系图 14 节全景透视