说说RAG
RAGRetrieval-Augmented Generation检索增强生成是当前大语言模型LLM应用中最火热的架构也是解决大模型知识截止、幻觉、数据安全等核心问题的关键技术。面试官问这个问题通常是想考察你对大模型落地实践的理解深度以及是否真的做过相关项目。一、什么是RAG核心概念1.1 为什么需要RAG大模型如 GPT-4虽然强大但有三个致命缺陷问题说明RAG如何解决知识截止模型训练后新知识不知道实时检索最新文档幻觉模型会编造答案用检索到的真实内容约束生成数据安全企业私域数据不能用于训练只在问答时检索数据不外传1.2 RAG的定义RAG 检索Retrieval 生成Generation简单说在让大模型回答问题前先从知识库中检索相关文档然后把文档作为上下文一起给大模型让它基于这些材料生成答案。二、RAG的完整工作流程[用户问题] ↓ 1. 问题理解 向量化 ↓ 2. 向量检索 (从知识库找相似文档) ↓ 3. 检索结果排序 过滤 ↓ 4. 构建Prompt (问题 检索到的文档) ↓ 5. LLM生成答案 ↓ [最终答案]2.1 详细拆解第一步知识库准备离线阶段# 1. 文档切分documentsload_documents()chunkssplit_documents(documents,chunk_size500,# 每块大小chunk_overlap50# 重叠避免切断语义)# 2. 向量化fromsentence_transformersimportSentenceTransformer modelSentenceTransformer(BAAI/bge-large-zh)# 国产开源embedding模型vectors[]forchunkinchunks:vectormodel.encode(chunk)# 转为向量 (768/1024维)vectors.append(vector)# 3. 存入向量数据库# 如FAISS, Milvus, PGVector, Chroma, Elasticsearchvector_store.add_vectors(vectors,chunks)第二步在线检索# 用户提问question公司今年的营收目标是少# 1. 问题向量化question_vectormodel.encode(question)# 2. 向量检索相似度搜索top_k5resultsvector_store.search(question_vector,top_ktop_k,similarity_threshold0.7# 相似度阈值)# 3. 检索结果retrieved_docs[result.textforresultinresults]第三步增强生成# 构建Promptpromptf 请基于以下材料回答问题。如果材料中没有相关信息请说根据提供的资料无法回答。 材料{.join(retrieved_docs)}问题{question}答案 # 调用LLManswerllm.generate(prompt)三、RAG的核心技术点面试重点3.1 文档切分策略# 不好的切分按固定长度硬切chunks[text[i:i500]foriinrange(0,len(text),500)]# ❌ 可能切断句子破坏语义# 好的切分按语义边界fromlangchain.text_splitterimportRecursiveCharacterTextSplitter splitterRecursiveCharacterTextSplitter(chunk_size500,chunk_overlap50,separators[\n\n,\n,。,,,,, ,])chunkssplitter.split_text(text)# ✅ 尽量在句子边界切分3.2 向量化模型选择模型特点适用场景BGE系列国产开源中英文好通用场景OpenAI Embedding英文强中文一般国际化业务M3E轻量级中文优化资源受限场景E5多语言效果好学术场景3.3 向量数据库选型数据库特点适用场景FAISS内存索引速度快小规模单机Milvus分布式云原生大规模生产PGVectorPostgreSQL插件已有PostgreSQLElasticsearch全文检索向量混合搜索Chroma轻量Python原生快速原型3.4 检索优化RAG的关键# 1. 混合检索向量 关键词# 向量检索语义相似vector_resultsvector_search(query)# 关键词检索精确匹配bm25_resultsbm25_search(query)# 融合排序RRF算法final_resultsreciprocal_rank_fusion(vector_results,bm25_results)# 2. 重排序Rerankfromsentence_transformersimportCrossEncoder rerankerCrossEncoder(BAAI/bge-reranker-large)pairs[(query,doc)fordocincandidate_docs]scoresreranker.predict(pairs)# 更精确的语义打分# 3. 元数据过滤resultsvector_store.search(query,filter{date:{$gte:2024-01-01},department:销售部})四、RAG的进阶优化面试加分项4.1 Query改写解决检索词与文档不匹配# 原始问题今年赚了多少钱# 文档中可能只有营收、利润没有赚了多少钱# Query改写策略defrewrite_query(question):# 1. 同义词扩展expandedexpand_synonyms(question)# 2. 假设性问题hypotheticalgenerate_hypothetical_doc(question)# 3. 多角度查询sub_queriesdecompose_query(question)return[question]expanded[hypothetical]sub_queries4.2 多路召回defmulti_recall(query):results[]# 路1向量检索语义results.extend(vector_search(query))# 路2关键词检索精确results.extend(keyword_search(query))# 路3知识图谱检索实体关系results.extend(graph_search(query))# 路4SQL查询结构化数据results.extend(sql_search(query))# 统一去重、排序returndedup_and_rerank(results)4.3 上下文管理defbuild_context(retrieved_docs,max_tokens4000):# 1. 按相关性排序docssorted(retrieved_docs,keylambdax:x.score,reverseTrue)# 2. 动态截断context[]total_tokens0fordocindocs:doc_tokenscount_tokens(doc.text)iftotal_tokensdoc_tokensmax_tokens:breakcontext.append(doc.text)total_tokensdoc_tokens# 3. 关键信息前置防止长上下文丢失注意力return\n\n.join(context)五、RAG vs Fine-tuning选型决策维度RAGFine-tuning知识更新实时更新改文档即可需重新训练周期长幻觉控制强基于检索内容弱依赖记忆数据安全数据不离线安全数据需用于训练推理成本低仅检索调用同普通模型复杂推理较弱强模型能力适用场景FAQ、知识库问答特定风格、复杂任务最佳实践RAG Fine-tuning 结合Fine-tuning让模型学会怎么回答风格、格式RAG给模型最新知识回答什么六、RAG系统的评估指标# 检索阶段recallk检索到的相关文档数/总相关文档数 precisionk检索到的相关文档数/检索总数 mrr第一个相关文档的排名倒数# 生成阶段answer_relevance答案是否回答了问题 factual_consistency答案是否基于检索文档 faithfulness答案是否与检索文档一致# 整体end_to_end_latency检索时间生成时间 user_satisfaction用户反馈评分七、生产级RAG架构完整示例# 完整的RAG服务classRAGService:def__init__(self):self.embedding_modelSentenceTransformer(BAAI/bge-large-zh)self.vector_storeMilvusClient(hostlocalhost,port19530)self.rerankerCrossEncoder(BAAI/bge-reranker-large)self.llmOpenAIClient()# 或本地LLMself.cacheRedisCache()# 缓存常见问题asyncdefanswer(self,question:str,user_id:str)-str:# 1. 检查缓存cachedself.cache.get(question)ifcached:returncached# 2. 检索docsawaitself.retrieve(question)# 3. 生成answerawaitself.generate(question,docs)# 4. 缓存带过期时间self.cache.set(question,answer,ttl3600)# 5. 异步记录日志用于后续分析asyncio.create_task(self.log_interaction(question,docs,answer,user_id))returnanswerasyncdefretrieve(self,question:str)-List[str]:# 多路召回candidates[]# 向量检索q_vecself.embedding_model.encode(question)vector_resultsself.vector_store.search(q_vec,top_k20)candidates.extend(vector_results)# 关键词检索可选ifself.need_keyword_search(question):keyword_resultsself.keyword_search(question)candidates.extend(keyword_results)# 去重candidatesdedup(candidates)# 重排序pairs[(question,doc.text)fordocincandidates]scoresself.reranker.predict(pairs)# 按重排序得分取top_ktop_docs[docfor_,docinsorted(zip(scores,candidates),reverseTrue)[:5]]return[doc.textfordocintop_docs]

相关新闻