范围:检索增强生成(Retrieval-Augmented Generation)的完整技术体系——架构演进、文档分块、Embedding 选型、向量库选型、混合检索与重排、查询增强、开发框架、评估方法、生产最佳实践与反模式。
1. 总体结论
- RAG = 参数化记忆 + 非参数化证据:在推理时让 LLM 去外部语料库检索,解决幻觉、知识过时、领域专有知识三大问题。核心是"检索质量决定生成质量",但检索阶段的提升并不总是等价于答案变好——必须做端到端联合评估(见 §9)。
- 当前生产事实标准栈(2025–2026 已收敛):
查询重写 → 混合检索(BM25 + 稠密向量,RRF 融合)→ Cross-Encoder 重排 → 生成器(可选 agentic 回路)。纯向量检索几乎从不单独用于生产。 - 最常被低估的两点:① 分块/解析往往比换检索器更能拉动指标(解析烂的 PDF/表格,换再好的 reranker 也救不回来);② 评估先行——先用 RAGAS 等框架量化,再动手调组件。
- 选型一句话:质量优先用商业 rerank + 强 embedding;预算/隐私优先用BGE-M3(MIT,自托管成本之王,同时出 dense+sparse+ColBERT)+ bge-reranker-v2-m3(Apache 2.0);向量库默认OpenSearch(你已在用)或 Qdrant,超大规模(100M+ 向量)上 Milvus。
- 架构不是越复杂越好:Naive RAG 加一个 reranker 能覆盖大部分"答案在单个 chunk 里"的场景;Agentic/GraphRAG 只在多跳推理、跨文档关系合成时才值得其成本。
2. 技术体系全景
一次完整 RAG 调用链(离线建库 + 在线检索两段):
【离线 · 索引】 文档 → 解析/OCR/版面还原 → 分块(chunk) → [可选]上下文增强 → Embedding → 入库(向量+倒排) └ 元数据(来源/时间/权限/实体) 【在线 · 检索】 用户 Query → 查询重写/扩展/HyDE/拆解 → 混合检索(BM25 + kNN/ANN) → 元数据 pre-filter → RRF 融合排序 → Cross-Encoder 重排 (top-100 → top-3~5) → 上下文组装(去重/裁剪/排序) → LLM 生成 → [Agentic] 自评检索质量 → 不达标则重新检索 / 换源 / 停止 → 答案 + 引用溯源各阶段的"杠杆点"排序(经验值,按性价比从高到低):
解析/分块 > 混合检索 > 重排 > 查询变换 > 更复杂的架构。多数团队的瓶颈在前两项,而不是 LLM 本身。
3. 架构演进:从 Naive 到 Agentic
| 架构 | 核心机制 | 延迟量级 | 单位成本 | 适用 |
|---|---|---|---|---|
| Naive RAG | 单段向量检索 + 直接生成 | ~100-300ms | 最低 | 答案在单个 chunk 内;加 reranker 后精度大增 |
| Advanced RAG | 混合检索 + 重排 + 查询变换 | 500ms-2s | $0.005-0.03 | 需要 2-3 个文档事实拼接;生产主力 |
| Agentic RAG | Agent 决定何时/检索什么/重查几轮/停 | 2-10s+ | $0.01-0.10 | 多跳推理、跨库交叉验证、需要"检查-重查"回路 |
| GraphRAG | 建实体-关系图,检索时图遍历组装上下文 | 1-5s | $0.02-0.15 | 跨文档关系、全局归纳、可解释性 |
| Adaptive RAG | 复杂度分类器 → 分流到上面各档 | 按档 | 按档 | 混合负载,按问题难度省成本 |
决策树(生产选型常用):
答案在单个文档 chunk 里? ├─ 是 → Naive RAG(+reranker) └─ 否 → 需要 2-3 个文档事实? ├─ 是 → Advanced RAG(混合 + 重排 + 查询变换) └─ 否 → 需要跨大量文档推理? ├─ 关系型 → GraphRAG ├─ 多步推理 → Agentic RAG └─ 混合负载 → Adaptive RAG关键判断:
- Agentic RAG 的本质是把"检索"变成 Agent 可调用的工具,加入自评与重查回路。代价是每查询 2-10x token(Iterative Retrieval 2-3x、Query Decomposition 3-5x、Cross-Corpus 三角验证 5-10x),且编排复杂。仅在问题天然多步时才划算。
- GraphRAG 的瓶颈是子图选择与计算开销,且评估仍以 QA 风格为主,尚不成熟。适合"跨文档合成"类问题;结构化/实体关系查询强,但别指望它替代普通检索。
- 多数场景 Naive+重排 或 Advanced 就够。上 Agentic/Graph 前先证明 Advanced 打不满指标。
4. 文档处理与分块(Chunking)
分块是"被系统性低估"的环节。结论先行(来自 2025 多篇论文的系统评测):
| 分块策略 | 机制 | 评测结论 |
|---|---|---|
| 固定大小(Fixed-size) | 按 token/字符/句数切,带 overlap | 最可靠、最省算力。真实文档上常优于语义分块 |
| 语义分块(Semantic) | 相邻句 embedding 相似度低于阈值处断点 | 收益高度依赖任务,计算成本高,不总是划算(NAACL 2025 结论:不足以 justify 成本) |
| Late Chunking | 先把整篇文档喂进长上下文 embedding,出 token 级向量后再分块 + mean-pooling | 比 naive 分块平均提升 ~1.5-1.9%(相对 ~3%),无需训练,依赖长上下文模型 |
| Contextual Retrieval(Anthropic) | 用 LLM 给每个 chunk 前置补充上下文再 embedding | 保留语义连贯性更好,但算力成本高(依赖 LLM 调用) |
| PIC(ACL 2025) | 用文档摘要作"伪指令"引导按主题分句 | 无训练提升 Hits@k 与 EM |
| Recursive Semantic(RSC) | 递归切大块 + 合并小块 + 尺寸归一 | 在 4 数据集上优于传统语义分块,兼顾粒度与连贯 |
工程建议:
- 默认用固定大小 + 递归字符切分(按 markdown 标题层级优先),chunk 512 token、overlap 50-100 token。简单且稳。
- 语义分块只在"高主题多样性"语料上可能有优势;普通企业文档别盲目上。
- 长上下文模型普及后,Late Chunking 值得评估——它让 chunk embedding 带上全文语境,且免训练。
- 真正的杀手锏不是分块算法,而是"解析质量":PDF/表格/扫描件解析错了,分块和检索都白搭(RAGFlow 的定位就是打这一点)。
- 经验法则:chunk 太大→引入噪声、稀释关键信息;太小→丢上下文。512 token 是甜点,配合 reranker 容错。
- 保留元数据(来源、章节标题、时间戳、权限、实体)用于 pre-filter 与溯源。
5. Embedding 模型选型
核心认知:text-embedding-3-large是教程默认,但 2025-2026 的 MTEB 上已掉到中下游(retrieval 子集约第 5)——多数 RAG 默认它是生态惯性,不是质量最优。开源自托管在成本上碾压(BGE-M3 自托管 $5-20/M 文档 vs OpenAI 3-large ~$1,300/M,65-260x 差距)。
5.1 主力模型对比(2026)
| 模型 | 方/性质 | 维度 | MTEB(参考) | 上下文 | 语言 | 许可 | 定位 |
|---|---|---|---|---|---|---|---|
| Qwen3-Embedding-8B | 开源 | up to 4096 | ~70.6 | 32K | 100+ | Apache 2.0 | 开源多语言 SOTA 档 |
| GTE-Qwen2-7B-instruct | 开源 | 3584 | ~70.2 | 32K | CJK 强 | Apache 2.0 | 亚洲语言首选 |
| NV-Embed-v2 | 开源 | 4096 | ~72.3(MTEB 榜首) | 32K | 英文为主 | CC-BY-NC(非商用) | 质量天花板但商用受限 |
| BGE-M3 | 开源 | 1024 | ~63-64 | 8K | 100+ | MIT | 自托管成本之王,dense+sparse+ColBERT 三合一 |
| Jina v5/v4 | 开源 | 1024/2044 | ~71.7(v5-small) | 8K+ | 119+ | Apache 2.0 | 质量/体积比优秀 |
| Cohere embed-v4 | API | 1536 | ~65.2 | 128K | 100+ | 商业 | 超长上下文企业档 |
| text-embedding-3-large | API | 3072 | ~64.6 | 8K | 多语言 | 商业 | 通用,生态默认 |
| Nomic-embed-v1.5/v2 | 开源 | 768 | ~59-65 | 8K/512 | 多语言 | Apache 2.0 | 轻量/CPU 友好 |
5.2 选型建议
- 预算/隐私优先(自托管):BGE-M3(1.1GB 显存即可,MIT,同时产出稠密向量 + 学习稀疏词权重 + ColBERT 多向量,一套模型做三路混合检索,省掉独立 BM25/ES 集群)或Qwen3-Embedding-8B / GTE-Qwen2(有 16GB 显存时,质量更高,中文强)。
- 多语言/CJK:GTE-Qwen2 或 Qwen3-Embedding;BGE-M3 也覆盖 100+ 语言。
- 代码检索:专用 code embedding(voyage-code-3 等)通常更准。
- 维度不是质量旋钮,是成本旋钮:高维 ≠ 更好。256 维 int8 的 Voyage 可胜 3072 维 float 的 OpenAI。选模型看质量、看维度看成本。
- 长文档:选长上下文模型(8K-32K)+ Late Chunking,减少分块数。
- 注意:MTEB 分数是横向参考,不一定预测你语料上的真实表现,务必用自己的评测集(见 §9)实测。
6. 向量数据库选型
6.1 选型总表(2026)
| 库 | 语言/架构 | 许可证 | 索引 | 混合检索 | 定位 |
|---|---|---|---|---|---|
| OpenSearch 2.x | Java/Lucene | Apache-2.0 | Lucene HNSW + Faiss | 原生 RRF | ES 开源后继,全文+向量一体(你已在用) |
| Qdrant | Rust | Apache-2.0 | HNSW(filtrable) | 原生 hybrid | 过滤强、延迟低、性价比好的默认选择 |
| Milvus 2.x | C++/Go | Apache-2.0 | HNSW/IVF/DiskANN | 2.6 内置 BM25 | 纯向量标杆,十亿级 |
| Weaviate | Go | BSD-3 | HNSW | 原生 hybrid(alpha) | 向量优先,内置 vectorizer,多模态好 |
| Vespa | C++ | Apache-2.0 | HNSW | 内置多阶段 ranking+ML | 千亿级混合检索/推荐 |
| pgvector (+pgvectorscale) | Postgres 扩展 | PostgreSQL | IVFFlat/HNSW | SQL 融合 | 已有 PG 时的务实选择,预过滤/JOIN 强 |
| Chroma | Python | Apache-2.0 | HNSW | 弱 | 原型/本地开发 |
| FAISS | C++ 库 | MIT | IVF/PQ/HNSW | 无(纯库) | 算法控制/离线批处理 |
| Pinecone | SaaS | 商业 | 专有 | sparse-dense | 零运维全托管 |
6.2 关键判断
- “向量只是搜索引擎该有的一项能力”(HN 共识)。如果你已有 OpenSearch/ES/PG,优先在其上加向量,而不是引入独立向量库——预过滤、JOIN、事务、HA 这些"基础功"通用库更成熟。
- 向量质量主要由 embedding 决定,不是数据库决定(多篇基准结论一致)。数据库的职责是"可靠地取回对的向量"。
- 混合检索(BM25 + 稠密)在三种系统上都优于任一方单独(Weaviate/OpenSearch/pgvector 实测:混合 hit@10 0.725/0.685/0.665 > 单向量)。
- 规模阈值:
- < 100 万向量:任意皆可,pgvector/Chroma 足够。
- 100 万-1000 万:Qdrant/OpenSearch 甜蜜点。
- 千万-亿级:Milvus(或 Vespa/Vespa 多阶段排序)。
1 亿:考虑 int8/PQ 量化 + 冷热分层 + 分片。
- 对你的场景(运维平台多模态检索,OpenSearch 已落地):延续 OpenSearch(k-NN + BM25 + RRF + 多阶段),千万级再上 Faiss SQ 量化与 ILM 冷热分层——见关联阅读那篇。若未来检索压力转向纯向量超大规模,再评估 Milvus/Vespa 替换/并行。
- **过滤(pre-filter vs in-filter)**是实际选型关键:业务常带
tenant_id/time_range/permission过滤,Qdrant 的 filtrable-HNSW、Weaviate 的倒排+HNSW、OpenSearch 的 k-NN filter 表现不一,务必用你自己的过滤选择率实测 recall。
7. 检索策略:混合检索 + RRF + 重排
这是"召回 → 精度"的两段式,当前生产黄金组合。
7.1 为什么必须混合
- BM25(稀疏/词法):擅长精确词、型号、专有名词、错误拼写;kNN/稠密:擅长语义相似、同义、跨语言。二者互补——技术文档、产品目录、带标识符的场景,混合一致性地胜过纯语义。
- 微软 Azure AI Search 基准:hybrid 比纯向量+10% NDCG,hybrid + reranker 再+37%。
7.2 RRF(Reciprocal Rank Fusion)
- 不用对齐 BM25 分数和余弦分数量纲,只按各自排名融合:
score = Σ 1/(k + rank_i),k 常取 60。 - OpenSearch 2.19 原生支持
rank: rrf;Weaviate 用alpha参数(0=纯关键词,1=纯向量);pgvector 需在 SQL 里手写 RRF 表达式。
7.3 Cross-Encoder 重排(把召回变精度)
- Bi-encoder(embedding 模型):query 和 doc 各自编码再比余弦,快但"从不同时看到两者",用于召回。
- Cross-encoder(reranker):把 (query, doc) 拼接一起过 attention,能推理细粒度相关性,精度高但慢(O(n) per pair)→只能对 top-100 候选做,不能扫全库。
- 经典流水线:召回 top-100 → 重排 → 取 top-3~5 给 LLM。重排加 200-600ms,top-100 时仍在毫秒级可接受。
- 重排器选型:
| Reranker | 托管 | 参数 | 上下文 | 许可 | 备注 |
|---|---|---|---|---|---|
| bge-reranker-v2-m3 | 自托管 | 568M | 8K | Apache 2.0 | 自托管默认起点 |
| bge-reranker-v2-gemma | 自托管 | gemma-2b | — | Apache 2.0 | 更高精度、更高成本 |
| Cohere Rerank 3.5/4 | API | 未公开 | 4K/32K | 商业 | 生产基线,Notion 在用 |
| Voyage rerank-2.5 | API | 未公开 | 32K | 商业 | 首个支持指令跟随(“偏好含合规信息的”),32K 上下文 |
| Jina Reranker v2 | API/自托管 | 278M | 1024 | CC-BY-NC(商用需协议) | 吞吐高,多语言/代码 |
| ColBERT late-interaction | 自托管 | — | — | 各版本 | 介于两者之间,索引更大(token 级) |
- 重排何时没用:当初始召回就差(recall@20 < 0.70)时——reranker 只能给已找到的排序,造不出没召回的东西。先修分块/embedding/混合。
- 给你的建议:OpenSearch + bge-reranker-v2-m3(Apache 2.0 自托管)做二阶段,成本与精度平衡好;要"按指令调相关性"再上 Voyage/Cohere API。
8. 查询增强(Query Transformation)
让"用户的口语"变成"检索友好的输入":
| 技术 | 机制 | 何时用 |
|---|---|---|
| Query Rewriting | LLM 改写/规范化口语查询 | 通用,几乎总有益 |
| Query Expansion | 扩展同义词/相关词 | 提升召回 |
| Multi-Query / RAG-Fusion | 生成多个查询变体,各检索后融合 | 长尾/歧义查询 |
| HyDE(Hypothetical Document Embeddings) | 先让 LLM 生成"假想答案文档",用它 embedding 去检索 | 语义检索强时;查询短而意图模糊 |
| Step-back Prompting | 先生成更抽象的上位问题再检索 | 需要通用原理支撑的问题 |
| Query Decomposition | 复杂问题拆成子问题分别检索 | 多跳(Agentic 里常见) |
| Self-Query / Metadata 抽取 | 从查询里抽出结构化过滤条件(时间/类型) | 需要 pre-filter 时 |
注意:这些都是token 成本 + 延迟的投入,按问题复杂度选——Adaptive RAG 就是为"别对所有问题都上全套"而生。
9. 评估体系(最重要也最被忽视)
核心原则:检索指标提升 ≠ 答案变好,必须端到端 + 分阶段联合评估。
9.1 RAGAS 指标体系(无参考答案即可评,LLM-as-judge)
| 指标 | 评什么 | 阶段 |
|---|---|---|
| Faithfulness(忠实度) | 答案的每条 claim 能否由检索上下文支撑(抗幻觉主指标)= 支撑claim数/总claim数 | 生成 |
| Answer Relevance(答案相关性) | 答案是否真的回答了问题(生成反向问题算余弦) | 生成 |
| Context Precision(上下文精确率) | 检索上下文里相关排得靠前程度 | 检索 |
| Context Recall(上下文召回) | 参考答案所需信息是否都召回了 | 检索 |
| Context Entities Recall | 实体是否召回 | 检索 |
| Answer Correctness / Factual Correctness | 答案 vs 参考答案事实一致(需参考答案) | 生成 |
| Noise Sensitivity | 对上下文里无关信息的敏感度 | 综合 |
| Response Groundedness | 回答是否扎根上下文(faithfulness 的替代实现) | 生成 |
- 无参考答案时用:Faithfulness + Answer Relevance + Context Precision/Recall(默认四指标)。
- 有参考答案时:加 Factual Correctness(
ragas_rag_full)。 - Faithfulness 可换轻量分类器:Vectara HHEM-2.1-Open(小、免费、开源)替代 LLM 判 claim,生产更省。
- 学术警示(多篇评测):Faithfulness 和 Factual Correctness 与人评一致性最好;Answer Relevance / Context Relevance 基于余弦,可解释性差、阈值难定,别单独拿来下结论。
9.2 其他评估手段
- 检索层:Recall@k、MRR@k、nDCG(经典 IR 指标)。
- LLM-as-judge:通用协议,注意 judge 模型偏差。
- 成本/延迟/安全:系统综述(QUB 128 篇 PRISMA 综述)强调——质量要和**成本、延迟、安全(投毒/泄漏/越狱/提示注入)**一起评,而不是只看准确率。
- 建自己的评测集:从真实业务问题抽样(几十到几百条),标注参考答案,跑 CI 回归——这是"改动到底有没有用"的唯一可靠依据。
10. 开发框架选型
| 框架 | 定位 | 许可 | 何时选 |
|---|---|---|---|
| LlamaIndex | 检索优先,索引/连接器/解析强(LlamaParse) | MIT | 数据密集、文档多、纯检索质量瓶颈 |
| LangChain / LangGraph | 编排 + Agent 强,集成面最广 | MIT | 多步 Agent、RAG 只是工具之一 |
| Haystack | 显式 typed pipeline,可审计、可序列化 | Apache 2.0 | 企业/受监管、要"向审计解释流水线" |
| RAGFlow | 深度文档解析(扫描件/表格/版面) | Apache 2.0 | 语料是 PDF/合同/财报/扫描件 |
| Dify | 可视化低代码,内置知识库+Chat UI | 改 Apache 2.0 | 非工程师也要参与、快速内网应用 |
| LightRAG | 图 + 向量混合检索 | MIT | 跨文档关系问题 |
| RAGAS | 评估(配合上面任一个用) | Apache 2.0 | 质量评分 / CI 门槛 |
| txtai | 单包极简 | Apache 2.0 | 嵌入式/边缘 |
决策要点:
- 瓶颈是解析(烂 PDF/表格/扫描件)→ LlamaIndex(LlamaParse) 或 RAGFlow。
- 瓶颈是检索(embedding/混合/重排)→ LangChain RAG 或 Haystack(LightRAG 加知识图)。
- 瓶颈是评估(不知道有没有变好)→ 先挂 RAGAS 进 CI,再改别的。
- 团队已有 LangGraph 投资 → 别为检索再引入 LlamaIndex,用 LlamaIndex 查询引擎当一个 tool 更划算。
- 框架变动快(LangChain 2025-2026 有大版本重构),锁定 minor 版本,预算迁移成本;star 数 ≠ 生产质量(Dify star 高但生产部署占比低)。
11. 生产最佳实践 + 反模式
最佳实践
- 混合检索 + reranker作为默认起点(纯向量几乎不上生产)。
- 解析/分块质量优先,保留元数据用于过滤与溯源。
- 先建评测集 + 挂 RAGAS CI,任何组件改动都量化验证。
- pre-filter 用元数据(租户/时间/权限)缩小召回集,别全库扫。
- 答案带引用溯源(哪段、哪个文档、哪页),既抗幻觉又可信。
- 处理"检索不到"的路径:明确拒答 / 转人工 / 换源,而非硬答(Faithfulness 低时应触发 fallback)。
- 规模上量:int8/PQ 量化 + 冷热分层(OpenSearch ILM / Faiss SQ)。
- 安全:防提示注入(检索内容可能含恶意指令)、防知识库投毒、权限贯穿检索层。
反模式
- ❌ 默认
text-embedding-ada-002/ 盲目默认text-embedding-3-large(质量已非最优,且 ada 该退役)。 - ❌ 只看检索指标(Recall@k)就宣布成功,不做端到端答案评估。
- ❌ 召回很差时先加 reranker(先修检索)。
- ❌ 盲目上 Agentic/GraphRAG(成本 2-10x,多数问题 Naive+重排 就够)。
- ❌ 把高维当高质量(维度是成本旋钮)。
- ❌ 忽略许可:NV-Embed-v2 / Jina 是 CC-BY-NC,商用自托管受限;Elasticsearch 是 AGPL/SSPL/ELv2,嵌入/分发有法务风险(你选 OpenSearch 正好避开)。
- ❌ 用余弦相似度阈值做硬判断(可解释性差、各模型量纲不一致)。
12. 风险
- 评估陷阱:LLM-as-judge 有偏差,余弦类指标不可解释——单指标下结论会误导,需多指标 + 人评抽检。
- 许可合规:多个 SOTA embedding/reranker(NV-Embed-v2、Jina)非商用许可;商用前必查 license。
- 架构过度:Agentic/GraphRAG 复杂度高、token 成本 2-10x、可维护性差,且评估体系仍不成熟(GraphRAG 子图选择是公认瓶颈)。
- 安全:RAG 引入检索内容作为不可信输入,提示注入 / 知识库投毒 / 敏感信息泄漏是新增攻击面,需专门的鲁棒性与隐私基准。
- 框架漂移:LangChain/LlamaIndex 大版本重构频繁,锁版本 + 预算迁移。
- 成本失控:embedding 全量重建、reranker 对过大候选集、agentic 多轮检索都会推高成本,需 token/延迟预算感知。
13. 下一步
- 明确一个目标 RAG 场景(如运维知识库问答 / 文档问答),用其真实问题抽 50-100 条建评测集。
- 用 OpenSearch(现有)搭最小闭环:BM25 + BGE-M3 稠密 + RRF + bge-reranker-v2-m3,跑 RAGAS 四指标基线。
- 对比测试:纯向量 vs 混合 vs 混合+重排,量化各档增量,决定是否值得上 reranker。
- 验证分块策略(固定 512 vs late chunking)在你语料上的差异。
- 评估是否需 Agentic/Graph(仅当 Advanced 打不满且问题是多跳/关系型)。
- 安全评估:检索内容提示注入防御 + 权限贯穿检索层。
参考来源(检索于 2026-10)
- Agentic RAG 综述:arxiv.org/abs/2501.09136
- RAG 架构对比/决策树:blog.starmorph.com(RAG Techniques Compared)、futureagi.com(RAG Architecture 2026)
- Embedding 选型:ailog.fr(MTEB 榜单)、tensakulabs.com(自托管基准)、llms.blog(BGE-M3/NV-Embed/GTE 生产对比)、rulesell.com/embeddings
- 向量库对比:db-engines.com(Vector DBMS 排名)、centron.de(Weaviate vs OpenSearch vs pgvector 实测)、tigerdata.com(pgvector vs Qdrant)、dev.to(Pinecone/Weaviate/Milvus/Qdrant 2026)
- 分块:NAACL 2025《Is Semantic Chunking Worth the Cost》、arxiv 2409.04701(Late Chunking)、arxiv 2504.19754(Late Chunking vs Contextual Retrieval)、ACL 2025《Document Segmentation Matters (PIC)》
- 重排:ianas.fr(Reranker 对比)、bigdataboutique.com(Cross-Encoder 原理)、digitalapplied.com(Hybrid/Rerank 2026)
- 评估:arxiv 2309.15217(RAGAS 论文)、docs.ragas.io(指标列表)、arxiv 2407.12873(RAG 指标可靠性评测)、QUB 系统综述(RAG SLR, PRISMA)
- 框架:nutrient.io / markaicode.com / ayautomate.com / dupple.com / rulesell.com(LangChain vs LlamaIndex vs Haystack vs RAGFlow)