今天不聊概念定义直接聊怎么在落地场景里把这套系统调好知识库处理、高级召回、排序优化再加一嘴 GraphRAG。坚实地基——知识库处理RAG 的上限不取决于你用什么大模型而取决于你的知识库管理得怎么样。下面四个场景建议按序号一个一个过。场景 1知识库问题生成与检索优化先看一个典型问题。你有一个知识库里存了关于上海迪士尼的各种信息其中一篇写到上海迪士尼乐园位于上海市浦东新区2016年6月16日开园乐园占地面积390公顷包含七大主题园区。用户问了一个问题“如果我想体验最刺激的过山车应该去哪个区域”你的知识库里相关的片段写的是探险岛有XX过山车项目但过山车和最刺激这两个词在向量空间里其实隔了十万八千里——纯语义匹配的话根本对不上。这就是 RAG 召回最头疼的问题用户表达方式和知识表述方式之间的鸿沟。怎么解决我一般从两个方向入手我管它叫双向奔赴。正向Doc-to-Query——给每个知识切片生成可能的问题思路很简单你的知识库里有一段文本它的特征是一堆向量。用户问问题时也是把问题变成一堆向量。两边向量长得像就觉得这个相关。但问题是——你的知识切片可能写的是上海迪士尼乐园位于上海市浦东新区是中国大陆首座迪士尼主题乐园于2016年6月16日开园用户的提问可能是中国大陆的第一座迪士尼在哪这两句话在语义上有重叠但关键词的重叠度非常低。所以一种很直接的优化思路是提前为每个知识切片生成可能被问到的各种问题然后把这些问题也一并做向量化。检索的时候用户的问题跟这些生成的问题去匹配而不是直接跟原文匹配。具体怎么做上代码。def generate_questions_for_chunk(knowledge_chunk, num_questions5): 为单个知识切片生成多样化问题 instruction 你是一个专业的问答系统专家。给定的知识内容能回答哪些多样化的问题 这些问题可以 1. 使用不同的问法直接问、间接问、对比问等 2. 避免重复和相似的问题 3. 确保问题不超出知识内容范围 请返回JSON格式 { questions: [ { question: 问题内容, question_type: 问题类型直接问/间接问/对比问/条件问等, difficulty: 难度等级简单/中等/困难 } ] } prompt f### 指令###\n{instruction}\n### 知识内容###\n{knowledge_chunk}\n### 生成问题数量###\n{num_questions} response get_completion(prompt, model) return parse_json_response(response)比如我们拿一段迪士尼的文本跑一下知识内容: 上海迪士尼乐园位于上海市浦东新区是中国大陆首座迪士尼主题乐园于2016年6月16日开园。乐园占地面积390公顷包含七大主题园区米奇大街、奇想花园、探险岛、宝藏湾、明日世界、梦幻世界和迪士尼小镇。生成的 5 个问题问题类型难度1上海迪士尼乐园是什么时候开园的直接问简单2中国大陆第一座迪士尼乐园在哪里间接问简单3与美国、日本等地的迪士尼相比上海迪士尼有什么特别之处对比问中等4如果想游览上海迪士尼的所有主题园区需要了解哪些区域条件问中等5上海迪士尼乐园占地多少公顷直接问简单看到没同样一段原文生成了五种不同类型的问法。有直接问时间的、有间接问地点的、有对比类的问题、有条件类的问题。如果想让问题更丰富可以用generate_diverse_questions()生成 8 个更精细的问题——要求问题带提问角度和是否可回答的标注def generate_diverse_questions(self, knowledge_chunk, num_questions8): 生成更多样化的问题更丰富 instruction 你是一个专业的问答系统专家。请为给定的知识内容生成高度多样化的问题 1. 问题类型多样化直接问、间接问、对比问、条件问、假设问、推理问等 2. 表达方式多样化使用不同的句式、词汇、语气 3. 难度层次多样化简单、中等、困难的问题都要有 4. 角度多样化从不同角度和维度提问 5. 确保问题不超出知识内容范围 请返回JSON格式额外包含perspective和is_answerable字段 同样的迪士尼文本用这个版本跑出来前几个问题就是这样的“上海迪士尼乐园是在哪一年开园的”直接问简单时间信息角度可回答“如果一个人想在上海体验迪士尼主题乐园他应该去哪里”间接问简单地理位置角度可回答“上海迪士尼和香港迪士尼相比哪个是中国大陆首座迪士尼主题乐园”对比问中等地域比较角度可回答“假如你计划去上海迪士尼游玩你会选择哪个主题园区来体验探险氛围”假设问中等游客体验角度可回答这里有一个关键细节生成的问题不能超出原文的内容范围。你看第 3 问跟香港迪士尼相比——这段原文其实并没有香港迪士尼的信息但问题问的是哪个是中国大陆首座原文确实说了是中国大陆首座迪士尼主题乐园所以这个问题的答案就在原文里。这是可回答的。如果你让 LLM 生成了 5 个问法基本一样的问题“迪士尼什么时候开的”、“迪士尼哪年开的”、“迪士尼开园时间是几几年”说明 prompt 里对多样性的约束不够。一定要要求不同类型的问法。问题的去向跟原文一起做 embedding生成的问题是放在哪里的很多人以为问题是单独存一个字段或者放到元数据里。其实不是。我把问题和原文拼在一起形成一个新的 chunk再对这个 chunk 做 embedding 存到向量库里。# 原始 chunkoriginal 上海迪士尼乐园位于上海市浦东新区...# 生成的 5 个问题questions [ 上海迪士尼乐园是什么时候开园的, 中国大陆第一座迪士尼乐园在哪里, ...]# 拼接后augmented_chunk original \n \n.join(questions)# → 上海迪士尼乐园位于上海市浦东新区...上海迪士尼乐园是什么时候开园的...# 对这个 augmented_chunk 做 embedding1024维embedding embedding_model.encode(augmented_chunk)# 存入向量库这样做的逻辑是你存的不是原文的特征而是原文 它可能被怎么问的特征。用户的问题来的时候它的特征跟这个丰富过的特征去匹配匹配精度就会更高。提取时的逻辑是这样的——不管你是匹配到原文还是匹配到生成的问题最终返回的永远是原始的知识内容。因为 embedding 只是一个帮你做特征提取和计算的工具它帮你找谁跟谁更像但最终要送到大模型里的、要展示给用户的是那个原始的文本。embedding 只是替你做筛选的。反向Query-to-Doc——改写用户的提问双向奔赴的另一端是改用户的问题。用户问如何提高深度学习模型的训练效率这个提问本身可能跟你的知识库里的分布式训练、混合精度训练这些知识对不上——因为用户没提到这些具体术语。这时候可以让大模型帮你做一次意图扩展用户问如何提高深度学习模型的训练效率大模型扩展后可以从以下几个角度回答1. 优化算法2. 混合精度训练3. 分布式训练4. 数据增强...把扩展后的内容也拿去检索。实际上这就是很多大模型的深度思考模式在做的事——先想一下我这个提问可以拆成哪些方面再针对每个方面去检索。不过我个人的经验是一般我不会单独写一个 prompt 来做 query 改写。现在的大模型基本都支持深度思考模式开启这个模式它天然就会帮你做意图扩展不需要你额外写逻辑。评估两种检索方式的差异到底多大光说理论不行我们直接看数据。我拿一个迪士尼问答场景做了三组测试查询分别跑 BM25 原文检索和 BM25 问题检索对生成的问题建索引测试查询原文检索分数原文是否命中问题检索分数问题是否命中如果我想体验最刺激的过山车应该去哪个区域0.155✗1.000✓可以带食物进去吗0.153✓0.556✓什么时间去人比较少0.168✓0.279✓**原文检索准确率66.7%3中2**问题检索准确率100.0%3中3从三分之二到全对——区别就只是你花那十几分钟去生成了一批问题。不过你也看到了问题检索虽然全中了但第二题的分数差异很大0.556 vs 1.000第三题的分数增量也不明显。所以我的建议是两个索引都建结果做融合。后面讲到高级召回的时候我会细说 RRF 和加权混合的方法。还有一个重要的细节你一定要注意确保生成的问题足够多样化。如果你生成的 5 个问题都是迪士尼开园时间、“迪士尼哪年开的”、迪士尼什么时候开的这种同一个角度的变体——那它们测的是同一个维度约等于只做了一次检索。问题的多样性 召回的覆盖面。关键是要覆盖直接问、间接问、条件问、假设问、推理问。每个问题要有不同的提问角度。再说个实用的策略Small-to-Big上面说的是给原文生成问题来丰富特征。还有一个我特别喜欢用的策略叫Small-to-Big。简单说就是如果你的文档特别长、特别碎不要直接拿原文去做检索。先把原文生成一个摘要small放到一个向量库。用户来提问时先用 small 做一轮粗筛。如果 small 表明这篇文档跟用户问题相关再把完整的原文big取出来拼到 prompt 里。用户提问 ↓Step 1: 检索 small摘要/标题——快速过一遍 ↓Step 2: 如果 small 匹配 → 找到对应的 big原文 ↓Step 3: 把 big 放入 prompt → LLM 生成回答这个跟直接检索的差别在哪直接检索是在细节的海洋里找准确的信息Small-to-Big 是先定位到正确的岛屿再在岛上找细节。你看 NotebookLM 这个工具。它在检索之前帮你做了大量的预处理每段原文都生成了摘要。你去提一个问题它先匹配摘要再用摘要定位到具体的原文段落。它做得很自然你甚至感觉不到这个环节的存在但这个预处理就是它效果好最核心的原因之一。场景 2对话知识沉淀产品上线后每天产生大量对话。这些对话里埋着金子。但大部分团队的做法是什么都不做。对话就躺在数据库里直到被清理。核心流程def extract_knowledge_from_conversation(conversation): 从单次对话中提取结构化知识 instruction 你是一个专业的知识提取专家。请从给定的对话中提取有价值的知识点 1. 事实性信息地点、时间、价格、规则等 2. 用户需求和偏好 3. 常见问题和解答 4. 操作流程和步骤 5. 注意事项和提醒 请返回JSON格式 { extracted_knowledge: [ { knowledge_type: 事实/需求/问题/流程/注意, content: 知识内容, confidence: 置信度(0-1), source: 来源用户/AI/对话, keywords: [关键词1, 关键词2], category: 分类 } ], conversation_summary: 对话摘要, user_intent: 用户意图 } response get_completion(prompt, model) return parse_json_response(response)提取出五类知识事实价格、规则、参数等稳定信息需求用户当下想要什么临时性需过滤问题用户怎么问的临时性需过滤流程操作步骤、方法论注意提醒、风险、边界条件关键过滤需求和问题类型是临时性、个性化的不应入库。只保留事实、流程、注意三类。# 过滤掉临时性的知识和问题filtered_knowledge [ k for k in knowledge_list if k.get(knowledge_type) not in [需求, 问题]]智能合并一次性可能从多条对话中提取相似知识。用 LLM 做合并比用规则好得多def merge_knowledge_with_llm(knowledge_group, knowledge_type): prompt f 你是一个专业的知识整理专家。请将以下{knowledge_type}类型的知识点进行智能合并 合并要求 1. 保留所有重要信息避免信息丢失 2. 消除重复内容整合相似表述 3. 提高内容的准确性和完整性 4. 合并后的置信度取所有知识点中的最高值 ### 待合并的知识点 {chr(10).join(knowledge_contents)} return get_completion(prompt, model)一个真实运行的例子——3 条对话提取了 22 个知识点过滤后剩 17 个合并后压缩到3 个综合知识点。合并率 86%信息完整度接近 100%。在实操中这个 pipeline 应该跑在定时任务里——每天凌晨处理前一天的对话把新知识增量写入。不是想起来跑一次是基础设施级别的运维操作。场景 3知识库健康度检查你的知识库三个月前建的现在还好吗答案通常是不好。健康度检查从三个维度切入完整性、时效性、一致性。完整性检查查缺失用测试查询去问知识库看它能不能答上来。具体做法准备一批30 条典型的用户问题逐一检索知识库让 LLM 判断库里是否有匹配的知识。def check_completeness(knowledge_text, test_queries): instruction 你是一个知识库完整性检查专家。请分析给定的测试查询和知识库内容 判断知识库中是否缺少相关的知识。 检查标准 1. 查询是否能在知识库中找到相关答案 2. 知识是否完整、准确 3. 是否存在知识空白 返回JSON格式包含missing_knowledge列表和coverage_score(0-1) # 输出示例 # coverage_score: 0.75 # missing_knowledge: [{query: ..., missing_aspect: ..., importance: 高}]时效性检查查过期价格信息、政策规则、技术版本——这三种知识过期速度惊人。用 LLM 逐项扫描时间相关信息是否过期年份、日期、时间范围价格信息是否最新价格、费用、票价政策规则是否更新技术信息是否过时版本、技术标准def check_freshness(knowledge_text, current_time): instruction 你是一个知识时效性检查专家。 检查标准 1. 时间相关信息是否过期 2. 价格信息是否最新 3. 政策规则是否更新 4. 技术信息是否过时 prompt f### 当前时间###\n{current_time}\n### 分析结果###过期的知识比没有知识更可怕——它让你误以为系统是对的。一致性检查查冲突同一份产品参数A 文档写 100 元B 文档写 120 元。两个都在库里。用户问价钱模型随机选一个回答——选对的概率是 50%。def check_consistency(knowledge_text): 检查同一主题的多篇文档是否存在矛盾信息。 检查标准 1. 价格信息的差异 2. 规则政策的冲突 3. 时间信息的不一致 4. 操作流程的差异 健康度检测不是一次性的。查一次没意义关键是建立巡检节奏——每周跑一次结果挂看板。最好有个自动化 Pipeline检测到异常 → 自动生成问题清单 → 通知运营人员处理。场景 4知识库版本管理与性能比较你的知识库改了一版你怎么知道改了是好是坏没法回滚的 RAG就像没有 Git 的代码库。版本管理应该包含什么class KnowledgeBaseVersionManager: def__init__(self): self.versions {} # version_name - {metadata, chunks, index} defcreate_version(self, name, description, chunks): 保存知识库快照构建向量索引 pass defdetect_changes(self, kb1, kb2): 版本差异检测——基于集合论 kb1_dict {chunk[id]: chunk for chunk in kb1} kb2_dict {chunk[id]: chunk for chunk in kb2} added_ids set(kb2_dict.keys()) - set(kb1_dict.keys()) # 新增 removed_ids set(kb1_dict.keys()) - set(kb2_dict.keys()) # 删除 common_ids set(kb1_dict.keys()) set(kb2_dict.keys()) # 共有 # 检测内容修改 modified_ids [ cid for cid in common_ids if kb1_dict[cid][content] ! kb2_dict[cid][content] ] return {added: added_ids, removed: removed_ids, modified: modified_ids} defevaluate_performance(self, version_name, test_queries): 用标准测试集评估版本性能 correct 0 total_time 0 for query_info in test_queries: start datetime.now() results self.retrieve(version_name, query_info[query], k3) elapsed (datetime.now() - start).total_seconds() total_time elapsed # 简单字符串匹配评估 if query_info[expected_answer] in results: correct 1 return { accuracy: correct / len(test_queries), avg_response_time: total_time / len(test_queries) } defcompare_versions(self, v1_name, v2_name, test_queries): A/B 对比两个版本 perf1 self.evaluate_performance(v1_name, test_queries) perf2 self.evaluate_performance(v2_name, test_queries) return { accuracy_improvement: perf2[accuracy] - perf1[accuracy], time_delta: perf2[avg_response_time] - perf1[avg_response_time], recommendation: 推荐使用版本2if perf2[accuracy] perf1[accuracy] else维持版本1 } defregression_test(self, version_name, test_cases): 回归测试——确保版本更新不破坏原有功能 passed sum( 1for tc in test_cases ifself.evaluate_retrieval_quality(version_name, tc[query], tc[expected]) ) return {pass_rate: passed / len(test_cases)}一个实际跑过的对比结果指标版本1v1.03个chunk版本2v2.05个chunk变化知识切片数352平均切片长度36字符54字符50%检索准确率60.0%100.0%40%平均响应时间115.8ms120.2ms4.4ms回归测试通过率—100.0%—版本 2 准确率提升 40%响应时间几乎不变回归测试全过。这种情况下推荐使用版本 2是明确的。版本之间怎么检索FAISS embeddingdef build_vector_index(chunks): vectors [get_text_embedding(c[content]) for c in chunks] vectors np.array(vectors).astype(float32) ids np.array([c[id] for c in chunks]).astype(int64) dim vectors.shape[1] text_index faiss.IndexFlatL2(dim) # L2距离 text_index.add_with_ids(vectors, ids) return text_indexdefretrieve(query, index, metadata_store, k3): query_vec get_text_embedding(query).astype(float32) distances, indices index.search(query_vec.reshape(1, -1), k) results [] for i, doc_id inenumerate(indices[0]): results.append({ id: doc_id, content: metadata_store[doc_id], similarity_score: 1.0 / (1.0 distances[0][i]) # 距离转分数 }) return results但说实话版本管理这件事实际项目中很少有人做。为什么成本太高。你要保存快照、建索引、跑测试题、产报告。一次可能要几小时。但生产环境到了规模——当你的知识库从几百篇膨胀到几万篇每天有新增和修改没有版本管理你连哪里出了问题都定位不出来。一句话建议至少做到两点——每次改知识前打个 snapshot每次上线前跑一轮回归测试。就这两条已经能挡住 80% 的翻车。精准雷达——高级召回知识库做好了下一步就是怎么从里面找到最相关的知识。从纯向量到混合检索重排序下面三个技术依次递进。查询优化MultiQuery 与改写传统 RAG 的召回链路用户提问 → 向量化 → 跟所有知识算相似度 → 取 top-K。这个链路有一个根本问题用户的提问方式跟你知识库里的表述方式可能完全不一样。“怎么退款和退货后的资金流向处理”——在向量空间里可能是两个方向。但它们是同一个意思。MultiQuery 的思想极其简单别拿用户原话去检索。先让 LLM 把问题改写/扩展成多个版本分别检索合并去重。def multi_query_retrieve(query, kb_index, k5, n_queries4): # Step 1: 改写 expansion_prompt f 用户的问题是{query} 请从不同角度生成{n_queries}个改写版本的问题让它们覆盖 不同的表述方式和提问角度。直接返回改写后的问题列表。 rewritten_queries get_completion(expansion_prompt, modelqwen) # 通常会返回类似 # 1. 客户经理投诉处罚细则 # 2. 一次投诉扣几分 # 3. 投诉处罚的量化标准是什么 # 4. 扣分规则是什么 # Step 2: 并行检索 all_results [] for q in rewritten_queries [query]: results vector_retrieve(q, kb_index, kn_queries*2) all_results.extend(results) # Step 3: 去重合并打分 merged {} for doc in all_results: if doc[id] notin merged or doc[score] merged[doc[id]][score]: merged[doc[id]] doc returnsorted(merged.values(), keylambda x: x[score], reverseTrue)[:k]LangChain 之前内置了MultiQueryRetriever新版本做了简化去掉了但逻辑是一样的。自己写一个 prompt 就能搞定——关键是改写时要多样化不同句式、不同关键词、不同颗粒度不是简单的同义替换。代价是什么一次改写 N 次检索接口调用翻了 N 倍。不过并发检索可以优化延时收益召回率提升 20-30%通常远超成本。混合检索BM25 Vector这是大厂 RAG 项目的事实标配。不是 embedding 不好——但纯 embedding 有三个硬伤精确匹配不敏感——搜第3条 第2款向量检索大概率匹配到跟3和2相关的无关内容低频术语衰竭——稀有术语的语义表征不够容易被淹没缺乏字面信号——某些场景下用户就是要精确关键词命中BM25 恰好擅长这些。它不关心语义只关心关键词在文档里出现的频率 × 关键词在整个语料里的稀有度 ÷ 文档长度的归一化。# BM25 的核心逻辑简化# score(D, Q) Σ IDF(qi) × TF(qi, D) × (k1 1) / (TF(qi, D) k1 × (1 - b b × |D| / avgdl))# # 其中# TF(qi, D) 词qi在文档D中的出现频率# IDF(qi) log((N - n(qi) 0.5) / (n(qi) 0.5)) —— 词越稀有IDF越高# k1 1.2 ~ 2.0 —— 词频饱和参数# b 0.75 —— 文档长度归一化参数# |D| 文档长度# avgdl 语料库平均文档长度所以 BM25 打分规律关键词越稀有、出现频率越高、文档越短 → 分数越高。BM25 Vector 混合——怎么混最常见的是RRFReciprocal Rank Fusion。def rrf_merge(vector_scores, bm25_scores, k_rrf60): RRF: 两个排序列表融合成一个。 k_rrf 控制平滑度——越大排名靠后的文档越难逆袭。 标准值60 doc_scores {} for rank, (doc_id, _) in enumerate(vector_scores): doc_scores[doc_id] doc_scores.get(doc_id, 0) 1.0 / (k_rrf rank 1) for rank, (doc_id, _) in enumerate(bm25_scores): doc_scores[doc_id] doc_scores.get(doc_id, 0) 1.0 / (k_rrf rank 1) return sorted(doc_scores.items(), keylambda x: -x[1])RRF 的优势是不需要分数归一化——直接拿排名算分两个模型各自输出 top-K谁排得高谁权重大。另一种更常见的做法是用权重混合def hybrid_weighted(query, vector_index, bm25_index, alpha0.5, top_k30): alpha 1.0 → 纯向量 alpha 0.0 → 纯 BM25 alpha 0.5 → 等权混合 vector_results vector_index.search(query, top_k) bm25_results bm25_index.search(query, top_k) # 分数归一化 vector_scores normalize(vector_results.scores) bm25_scores normalize(bm25_results.scores) combined {} for i, doc inenumerate(vector_results): combined[doc.id] combined.get(doc.id, 0) alpha * vector_scores[i] for i, doc inenumerate(bm25_results): combined[doc.id] combined.get(doc.id, 0) (1 - alpha) * bm25_scores[i] returnsorted(combined.items(), keylambda x: -x[1])[:top_k]调参建议alpha 从 0.5 开始。如果你的领域偏精确检索法律条文、政策条款alpha 降到 0.3。如果偏语义相似智能客服问答alpha 升到 0.7。初召的 K 设定也很关键——不要设太小。一般 30-50给后面的 Rerank 留足候选。精细排序Rerank 模型召回管饱了但你从 30 个候选里怎么挑 top-3用向量相似度排但向量的相似跟用户的相关很多时候不是一回事。向量相似度高 ≠ 对你的问题有用。Rerank 模型也叫 Cross-Encoder跟向量检索Bi-Encoder的核心区别维度Bi-Encoder向量检索Cross-EncoderRerank计算方式问题和文档各自算 embedding问题和文档拼接过编码器交互粒度粗一次推理可对比百万级细一次推理只算一对速度快毫秒级慢几十毫秒级精度中等高适用阶段初召海选精排top-N里排Rerank 把 query 和每个候选文档拼成一个序列穿进模型做全连接交互计算——它能捕捉这个文档对这个问题有多具体地有用。def rerank(query, candidate_docs, rerank_model, top_k3): 对初召结果进行重排序。 候选通常 30-50 个排到 top-3 到 top-5。 scores [] for doc in candidate_docs: # 拼接 query 和文档内容 pair_text f[CLS] {query} [SEP] {doc[content]} [SEP] score rerank_model.predict(pair_text) # 相关性分数 scores.append((doc, score)) # 按分数降序 return sorted(scores, keylambda x: x[1], reverseTrue)[:top_k]完整的召回链路应该是这样用户问题 ↓Step 1: BM25 Vector 混合初召召 30-50 个 ↓Step 2: Rerank 精排排到 top-3 到 top-5 ↓Step 3: 拼入 prompt → LLM 生成回答前沿探索——GraphRAG以上所有技术都建立在向量 关键词的检索框架上。但如果你遇到的问题是多跳推理比如迪士尼的票价体系为什么有淡旺季差异本质上是需要理解知识之间的逻辑关系。这时候就是 GraphRAG 的舞台了简单说两句。GraphRAG 做的不是检索是关系理解。它先把文档里的实体和关系抽出来构建知识图谱再按关联密度聚成社区、生成摘要。查询时它不只是在找跟问题相似的段落而是在图里走关系链路。但需要说明的是大部分场景不需要 GraphRAG。Native RAG BM25 Rerank 的组合能解决 95% 的检索问题。GraphRAG 适合的是高决策场景——需要综合多个维度的信息才能回答、需要逻辑推理的复杂问题。考虑到接入成本和维护成本建议先把你的一二篇做好再说。总结从知识库的加工处理到召回再到排序这一步一步都是工程活没有太多花活。几个教训收尾测试才是大头。“测试肯定是大头就是工程没有太多难的环节。就是要仔细不断地反复去盯盯得眼睛累。” 这就是真实的 RAG 工作场景。你不可能一次查全。一千个 chunk 里的冲突检测每次都要跑多次 LLM 判断。你只能做分类在每个类别里单独查。一开始别想太多先跑起来。纯向量就能用。等到用户说找不到了加 BM25。还不够上 MultiQuery。Rerank 在第三顺位——收益最大但成本也最高。这大概就是 RAG 调优的真相——技术选型不是问题工程落地才是。所有人在 PPT 上都做得很好真正拉开差距的是进了生产环境之后那些没人管的知识库和没人跑的回归测试。能把一个系统的各个环节都看住的人比做新模型的人值钱得多。后面我们会聊聊某些传统RAG无法满足的应用场景我们应该用什么技术替代为大家介绍两个比较新的方向 Agentic Retrieval 和 LLM Wiki学AI大模型的正确顺序千万不要搞错了2026年AI风口已来各行各业的AI渗透肉眼可见超多公司要么转型做AI相关产品要么高薪挖AI技术人才机遇直接摆在眼前有往AI方向发展或者本身有后端编程基础的朋友直接冲AI大模型应用开发转岗超合适就算暂时不打算转岗了解大模型、RAG、Prompt、Agent这些热门概念能上手做简单项目也绝对是求职加分王给大家整理了超全最新的AI大模型应用开发学习清单和资料手把手帮你快速入门学习路线:✅大模型基础认知—大模型核心原理、发展历程、主流模型GPT、文心一言等特点解析✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑✅开发基础能力—Python进阶、API接口调用、大模型开发框架LangChain等实操✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经以上6大模块看似清晰好上手实则每个部分都有扎实的核心内容需要吃透我把大模型的学习全流程已经整理好了抓住AI时代风口轻松解锁职业新可能希望大家都能把握机遇实现薪资/职业跃迁这份完整版的大模型 AI 学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】