智谱GLM-5.2与万亿港元市值:国产大模型首个破万亿港元的资本市场里程碑
2026/6/25 15:39:45
RAG(Retrieval-Augmented Generation,检索增强生成)是当前大模型应用中最主流的架构之一。它通过结合外部知识库与大语言模型(LLM),有效缓解了模型幻觉、知识滞后和领域专业性不足等问题。本文将带你从零开始,完整实现一个生产级 RAG 系统。
一个典型的 RAG 系统包含以下核心模块:
用户提问 → 查询理解 → 向量检索 → 文档重排 → 提示工程 → LLM 生成 → 输出 ↑ ↑ (可选) (可选) 查询改写 重排序模型我们将逐步实现每个环节。
pipinstalllangchain==0.2.0\langchain-community\langchain-core\langchain-text-splitters\sentence-transformers\chromadb\rank_bm25\transformers\torch\openai\python-dotenv建议使用 Python 3.9+,并设置虚拟环境。
支持 PDF、Word、TXT、HTML 等格式:
fromlangchain_community.document_loadersimportPyPDFLoader,DirectoryLoader loader=DirectoryLoader("./docs",glob="*.pdf",loader_cls=PyPDFLoader)documents=loader.load()合理切分对检索质量至关重要。推荐使用语义感知切分:
fromlangchain_text_splittersimportRecursiveCharacterTextSplitter text_splitter=RecursiveCharacterTextSplitter(chunk_size=512,chunk_overlap=50,separators=["\n\n","\n","。","!","?",";"," ",""])chunks=text_splitter.split_documents(documents)技巧:
chunk_overlap可避免语义割裂;separators按优先级断句。
BAAI/bge-large-zh-v1.5(中文强)、text-embedding-ada-002(OpenAI)sentence-transformers:fromlangchain_community.embeddingsimportHuggingFaceBgeEmbeddings embeddings=HuggingFaceBgeEmbeddings(model_name="BAAI/bge-large-zh-v1.5",model_kwargs={"device":"cuda"},encode_kwargs={"normalize_embeddings":True})使用 Chroma(轻量级)或 Milvus(生产级):
importchromadbfromlangchain_chromaimportChroma vectorstore=Chroma.from_documents(documents=chunks,embedding=embeddings,persist_directory="./chroma_db")retriever=vectorstore.as_retriever(search_kwargs={"k":5})
k=5表示检索 Top-5 相关片段。
原始向量检索可能召回不相关结果,需优化:
使用 LLM 对用户问题进行澄清或扩展:
fromlangchain_core.promptsimportPromptTemplatefromlangchain_openaiimportChatOpenAI rewrite_prompt=PromptTemplate.from_template("你是一个查询优化器。请将以下用户问题改写为更清晰、更适合检索的形式:{question}")llm=ChatOpenAI(model="gpt-4o")rewriter=rewrite_prompt|llm rewritten_query=rewriter.invoke({"question":"怎么重启服务?"}).content结合关键词(BM25) + 向量检索:
fromrank_bm25importBM25Okapiimportjieba# 构建 BM25 索引(中文需分词)corpus=[doc.page_contentfordocinchunks]tokenized_corpus=[list(jieba.cut(text))fortextincorpus]bm25=BM25Okapi(tokenized_corpus)defhybrid_search(query,k=5):# 向量检索vec_results=retriever.invoke(query)vec_ids={doc.metadata["id"]fordocinvec_results}# BM25 检索tokenized_query=list(jieba.cut(query))bm25_scores=bm25.get_scores(tokenized_query)top_bm25=sorted(range(len(bm25_scores)),key=lambdai:bm25_scores[i],reverse=True)[:k]# 融合(取并集去重)all_docs=vec_results+[chunks[i]foriintop_bm25ifinotinvec_ids]returnall_docs[:k]使用 Cross-Encoder 模型对 Top-K 结果重新打分:
fromsentence_transformersimportCrossEncoder reranker=CrossEncoder("BAAI/bge-reranker-large")pairs=[(query,doc.page_content)fordocinretrieved_docs]scores=reranker.predict(pairs)reranked=[docfor_,docinsorted(zip(scores,retrieved_docs),reverse=True)]template=""" 你是一个专业客服助手,请根据以下上下文回答用户问题。 - 如果答案不在上下文中,请回答“根据现有资料无法回答”。 - 保持回答简洁、准确。 上下文: {context} 问题:{question} 回答: """prompt=ChatPromptTemplate.from_template(template)fromlangchain_core.runnablesimportRunnablePassthroughfromlangchain_core.output_parsersimportStrOutputParser rag_chain=({"context":retriever,"question":RunnablePassthrough()}|prompt|llm|StrOutputParser())answer=rag_chain.invoke("如何配置 API 密钥?")RAG 系统需持续评估:
# 示例:用 RAGAS 评估fromragasimportevaluatefromragas.metricsimportfaithfulness,answer_relevancy result=evaluate(dataset=your_test_set,metrics=[faithfulness,answer_relevancy],llm=llm,embeddings=embeddings)一个健壮的 RAG 系统 ≠ 简单拼接“检索 + LLM”。关键在于: