06_Doris + LangChain构建RAG知识库实战
第六篇Doris LangChain构建 RAG 知识库实战关键字Apache Doris、LangChain、RAG、检索增强生成、向量数据库、Embedding、向量化、知识库、Retrieval-Augmented Generation标签RAG | LangChain | 向量数据库 | 知识库 | 大语言模型 | 检索系统 | Python | 智能问答一、引言为什么 RAG 是大模型落地的必经之路在 2023 年的大模型浪潮中有一个现象值得关注很多企业在花费巨资部署大模型后发现模型幻觉严重、专业知识匮乏、企业数据无法利用。而 RAGRetrieval-Augmented Generation检索增强生成正是解决这些问题的关键技术。作为一名深度参与过多个 RAG 项目的架构师我见过太多团队在向量数据库选型上踩坑有的选择了专用向量数据库却发现运维复杂、成本高昂有的选择了 pgvector却发现性能瓶颈明显有的选择了 Elasticsearch却发现向量检索能力不够原生。Apache Doris 4.0 的出现给这个领域带来了新的选择。它将向量检索、文本搜索和结构化查询统一在同一个引擎中让 RAG 知识库的构建变得前所未有的简单。今天我将从架构设计、向量存储、检索优化到端到端实战为大家系统性地解析如何用 Doris LangChain 构建生产级的 RAG 知识库。二、RAG 架构设计2.1 什么是 RAGRAG 的核心理念可以用一句话概括不让 LLM 胡编乱造用真实的检索结果引导它生成准确的答案。┌─────────────────────────────────────────────────────────────────┐ │ RAG 工作流程 │ │ │ │ 用户问题 │ │ Apache Doris 4.0 的 AI 函数有哪些 │ │ │ │ │ │ │ ▼ │ │ ┌─────────────┐ │ │ │ 检索阶段 │ ← 根据用户问题检索相关文档 │ │ │ (Retrieval) │ │ │ └──────┬──────┘ │ │ │ │ │ │ 找到相关文档 │ │ │ 1. Doris AI 函数包括 AI_SENTIMENT、 │ │ │ AI_CLASSIFY、AI_SIMILARITY 等... │ │ │ 2. AI 函数支持 OpenAI、DeepSeek 等模型... │ │ │ │ │ ▼ │ │ ┌─────────────┐ │ │ │ 生成阶段 │ ← 用检索结果作为上下文生成答案 │ │ │(Generation) │ │ │ └──────┬──────┘ │ │ │ │ │ ▼ │ │ 回答 │ │ Apache Doris 4.0 提供了丰富的 AI 函数包括 │ │ • AI_SENTIMENT情感分析 │ │ • AI_CLASSIFY文本分类 │ │ • AI_SIMILARITY语义相似度计算 │ │ • AI_SUMMARIZE文本摘要 │ │ • 以及其他 7 个函数... │ └─────────────────────────────────────────────────────────────────┘2.2 RAG vs 微调 vs 长上下文很多团队在用 RAG 还是微调之间纠结。让我用一个对比表格来说明它们的适用场景┌─────────────────────────────────────────────────────────────────┐ │ RAG vs 微调 vs 长上下文 对比 │ ├─────────────────┬─────────────┬─────────────┬────────────────────┤ │ 维度 │ RAG │ 微调 │ 长上下文 │ ├─────────────────┼─────────────┼─────────────┼────────────────────┤ │ 知识更新频率 │ 高实时 │ 低需训练│ 低需预处理 │ │ 知识准确性 │ 高可溯源 │ 中幻觉风险│ 高可溯源 │ │ 部署成本 │ 低 │ 高 │ 中 │ │ 响应延迟 │ 中 │ 低 │ 高 │ │ 适用场景 │ 知识库问答 │ 风格适配 │ 单文档分析 │ │ 维护难度 │ 低 │ 高 │ 中 │ └─────────────────┴─────────────┴─────────────┴────────────────────┘结论知识库类场景RAG 是首选。2.3 基于 Doris 的 RAG 架构┌─────────────────────────────────────────────────────────────────────────┐ │ Doris RAG 知识库架构 │ │ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ 文档处理层 │ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ │ │ PDF解析 │ │ Web抓取 │ │ 数据库 │ │ API接入 │ │ │ │ │ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │ │ │ │ │ │ │ │ │ │ │ │ └────────────┴────────────┴────────────┘ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ ┌─────────────────┐ │ │ │ │ │ 文档切分器 │ │ │ │ │ │ (Chunking) │ │ │ │ │ └────────┬────────┘ │ │ │ └────────────────────────┼───────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ 向量生成层 │ │ │ │ │ │ │ │ ┌─────────────────┐ ┌─────────────────┐ │ │ │ │ │ OpenAI Embedding │ │ Ollama 本地模型 │ │ │ │ │ │ (text-embedding-3)│ │ (BGE-large) │ │ │ │ │ └────────┬─────────┘ └────────┬─────────┘ │ │ │ │ │ │ │ │ │ │ └───────────┬───────────┘ │ │ │ │ ▼ │ │ │ │ ┌─────────────────┐ │ │ │ │ │ Embedding 生成 │ │ │ │ │ │ (768/1024/1536维)│ │ │ │ │ └────────┬─────────┘ │ │ │ └───────────────────────┼─────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ Doris 存储层 │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ HNSW向量索引 │ │ 倒排索引 │ │ 列式存储 │ │ │ │ │ │ (语义相似) │ │ (关键词匹配) │ │ (元数据) │ │ │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ LangChain 应用层 │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ 检索链(Retrieval) │ │ 生成链(Generation) │ │ 对话链(Chain) │ │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────┘三、Doris Vector Store 集成3.1 LangChain Doris IntegrationDoris 提供了官方的 LangChain 集成包可以通过 pip 安装pipinstalllangchain langchain-community apache-doris-vector3.2 连接配置fromlangchain_community.vectorstoresimportApacheDorisfromlangchain_community.embeddingsimportOpenAIEmbeddings# 配置连接参数vectorstoreApacheDoris(embeddingOpenAIEmbeddings(),hostdoris.example.com,port9030,userlangchain_user,passwordyour_password,databaserag_knowledge,table_namedocument_vectors,# 自动创建此表embedding_columnembedding,# 向量列名text_columntext,# 文本列名metadata_columnmetadata,# 元数据列可选)3.3 自动建表机制Doris Vector Store 会在首次调用时自动创建表结构-- 自动创建的表结构CREATETABLEdocument_vectors(idBIGINTAUTO_INCREMENT,textTEXTNOTNULLCOMMENT文档片段内容,embedding ARRAYFLOATNOTNULLCOMMENT向量嵌入结果,metadata JSONCOMMENT元数据来源、时间等,INDEXidx_vec(embedding)USINGANN PROPERTIES(index_typehnsw,metric_typel2_distance,dim1536-- 根据 embedding 模型维度自动设置))ENGINEOLAPDUPLICATEKEY(id)DISTRIBUTEDBYHASH(id)BUCKETS16;四、文档加载与切分策略4.1 文档加载器LangChain 提供了丰富的文档加载器fromlangchain_community.document_loadersimport(PyPDFLoader,# PDF 文件WebBaseLoader,# 网页UnstructuredMarkdownLoader,# MarkdownCSVLoader,# CSV 文件Docx2txtLoader,# Word 文档UnstructuredHTMLLoader,# HTML)# PDF 加载pdf_loaderPyPDFLoader(document.pdf)# 网页加载web_loaderWebBaseLoader([https://doris.apache.org/docs/get-starting,https://doris.apache.org/docs/query-data,])# 批量加载documentsweb_loader.load()4.2 文档切分策略文档切分Chunking是 RAG 系统的关键环节切分策略直接影响检索效果┌─────────────────────────────────────────────────────────────────┐ │ 文档切分策略对比 │ ├─────────────────┬─────────────┬─────────────────────────────────────┤ │ 策略 │ 块大小 │ 适用场景 │ ├─────────────────┼─────────────┼─────────────────────────────────────┤ │ 固定长度切分 │ 500-1000字符 │ 通用场景快速实现 │ │ 句子级别切分 │ 完整句子 │ 对语义完整性要求高 │ │ 段落级别切分 │ 段落边界 │ 文档结构清晰时效果最好 │ │ 递归字符切分 │ 可配置 │ 通用场景推荐使用 │ │ Markdown/HTML切分 │ 结构感知 │ 技术文档、网页 │ └─────────────────┴─────────────┴─────────────────────────────────────┘推荐配置fromlangchain.text_splitterimportRecursiveCharacterTextSplitter# 递归字符切分推荐text_splitterRecursiveCharacterTextSplitter(chunk_size1000,# 每块的目标大小chunk_overlap200,# 块之间的重叠保持上下文连贯length_functionlen,# 长度计算函数add_start_indexTrue,# 添加起始位置索引separators[\n\n,\n,。,,, ,]# 切分符优先级)# 文档切分chunkstext_splitter.split_documents(documents)语义切分高级fromlangchain_experimental.text_splitterimportSemanticChunkerfromlangchain_openaiimportOpenAIEmbeddings# 基于语义的切分使用 LLM 判断切分点semantic_splitterSemanticChunker(embeddingsOpenAIEmbeddings(),breakpoint_threshold_typepercentile,# 基于百分位breakpoint_threshold_amount95,# 95 百分位作为切分点)chunkssemantic_splitter.split_documents(documents)五、向量生成与存储闭环5.1 应用层生成向量最常见的方案是在应用层生成向量然后存入 Dorisfromlangchain_openaiimportOpenAIEmbeddingsfromlangchain_community.vectorstoresimportApacheDoris# 初始化 Embedding 模型embeddingsOpenAIEmbeddings(modeltext-embedding-3-small,# 1536 维dimensions1536)# 生成向量并存储vectorstoreApacheDoris.from_documents(documentschunks,# 切分后的文档块embeddingembeddings,# 向量化模型hostdoris.example.com,port9030,userlangchain_user,passwordyour_password,databaserag_knowledge,table_namedoris_docs)5.2 Doris 内置 TEXT_EMBEDDING 函数Doris 4.0 提供了内置的 TEXT_EMBEDDING 函数可以在数据库内部直接生成向量# 应用层只需要传入文本 Doris 内部完成向量化# 这减少了网络开销和序列化成本vectorstoreApacheDoris.from_documents(documentschunks,embeddingNone,# 使用 Doris 内置向量化hostdoris.example.com,port9030,userlangchain_user,passwordyour_password,databaserag_knowledge,table_namedoris_docs,use_doris_embeddingTrue,# 启用 Doris 内置向量化embedding_resourceopenai_embedding# 引用 Doris 中的 embedding 资源)性能对比┌─────────────────────────────────────────────────────────────────┐ │ 向量生成方式性能对比 │ │ │ │ 方案 │ 网络开销 │ 序列化开销 │ 优化器支持 │ │ ──────────────┼───────────┼────────────┼──────────────── │ │ 应用层生成 │ 高 │ 高 │ 否 │ │ Doris 内置 │ 低 │ 低 │ 是 │ │ │ │ 延迟改善应用层生成 ~50ms → Doris 内置 ~10ms │ └─────────────────────────────────────────────────────────────────┘5.3 增量数据处理importscheduleimporttimedefprocess_new_documents():定时处理新增文档# 1. 加载新增文档new_docsload_new_documents()# 2. 切分new_chunkstext_splitter.split_documents(new_docs)# 3. 增量添加到向量库vectorstore.add_documents(new_chunks)print(f已添加{len(new_chunks)}个文档块)# 定时任务每小时执行一次schedule.every().hour.do(process_new_documents)whileTrue:schedule.run_pending()time.sleep(1)六、混合检索实现6.1 向量相似度搜索# 基础向量检索resultsvectorstore.similarity_search(queryDoris 的 AI 函数有哪些,k5# 返回 Top 5 结果)# 带分数的检索results_with_scoresvectorstore.similarity_search_with_score(queryDoris 的 AI 函数有哪些,k5)# 使用余弦相似度resultsvectorstore.similarity_search_with_relevance_scores(queryDoris 的 AI 函数有哪些,k5)6.2 倒排索引加速过滤结合 Doris 的倒排索引实现更精确的过滤# 支持元数据过滤的检索resultsvectorstore.similarity_search(query向量检索性能优化,k10,filter{source:doris_docs,# 文档来源date:{$gte:2024-01-01},# 时间范围category:performance# 分类})6.3 多路召回融合fromlangchain.retrieversimportEnsembleRetriever# 定义多路检索器vector_retrievervectorstore.as_retriever(search_kwargs{k:10})keyword_retrievervectorstore.as_retriever(search_typemmr,# 最大边际相关性search_kwargs{k:5,fetch_k:20})# 融合检索ensemble_retrieverEnsembleRetriever(retrievers[vector_retriever,keyword_retriever],weights[0.6,0.4]# 向量检索权重 60%关键词检索权重 40%)# 执行融合检索resultsensemble_retriever.get_relevant_documents(queryDoris 性能优化)七、端到端问答系统构建7.1 QA Chain 构建fromlangchain_openaiimportChatOpenAIfromlangchain.chainsimportRetrievalQA# 初始化 LLMllmChatOpenAI(modelgpt-4o,temperature0,max_tokens1000)# 创建 QA 链qa_chainRetrievalQA.from_chain_type(llmllm,chain_typestuff,# 将检索结果拼接到 promptretrievervectorstore.as_retriever(search_kwargs{k:5}),return_source_documentsTrue,# 返回源文档verboseTrue)# 执行问答resultqa_chain.invoke({query:Apache Doris 4.0 的 AI 函数有哪些})print(result[result])print(\n参考来源)fordocinresult[source_documents]:print(f-{doc.metadata[source]})7.2 Prompt 工程fromlangchain.promptsimportPromptTemplate# 自定义 Prompttemplate你是一个技术文档问答助手。请根据以下参考文档回答用户的问题。 参考文档 {context} 用户问题{question} 回答要求 1. 如果参考文档中有相关信息请基于文档回答 2. 如果文档中没有相关信息请明确说明我无法从提供的文档中找到答案 3. 回答要简洁明了突出关键信息 4. 如果涉及代码请提供完整的代码示例 回答promptPromptTemplate(templatetemplate,input_variables[context,question])# 使用自定义 Promptqa_chainRetrievalQA.from_chain_type(llmllm,chain_typestuff,retrievervectorstore.as_retriever(search_kwargs{k:5}),promptprompt,return_source_documentsTrue)7.3 对话历史管理fromlangchain.chainsimportConversationalRetrievalChainfromlangchain.memoryimportConversationBufferMemory# 对话记忆memoryConversationBufferMemory(memory_keychat_history,return_messagesTrue,output_keyanswer)# 对话检索链convo_chainConversationalRetrievalChain.from_llm(llmChatOpenAI(modelgpt-4o,temperature0),retrievervectorstore.as_retriever(search_kwargs{k:3}),memorymemory,combine_docs_chain_kwargs{prompt:prompt})# 多轮对话resultconvo_chain.invoke({question:Doris 4.0 是什么时候发布的})print(result[answer])resultconvo_chain.invoke({question:新版本有哪些主要特性})print(result[answer])# LLM 会理解新版本指的是上面的Doris 4.0八、性能调优与成本控制8.1 检索质量优化TopK 调优# 检索更多候选retrievervectorstore.as_retriever(search_kwargs{k:10,# 最终返回数量fetch_k:50,# 初始候选数量lambda_mult:0.5# MMR 参数})重排序Rerankingfromlangchain_community.cross_encodersimportHuggingFaceCrossEncoder# 使用 Cross-Encoder 进行重排序cross_encoderHuggingFaceCrossEncoder(model_namecross-encoder/ms-marco-MiniLM-L-6-v2)defrerank_documents(query,documents,top_n3):对检索结果进行重排序doc_texts[doc.page_contentfordocindocuments]# 计算相关性分数scorescross_encoder.predict([(query,doc)fordocindoc_texts])# 按分数排序rankedsorted(zip(documents,scores),keylambdax:x[1],reverseTrue)return[docfordoc,scoreinranked[:top_n]]# 使用重排序initial_resultsvectorstore.similarity_search(query,k20)final_resultsrerank_documents(query,initial_results,top_n3)8.2 成本优化策略Embedding 模型选择┌─────────────────────────────────────────────────────────────────┐ │ Embedding 模型对比 │ ├───────────────┬─────────────┬─────────────┬─────────────────────┤ │ 模型 │ 维度 │ MTEB 得分 │ 成本 │ ├───────────────┼─────────────┼─────────────┼─────────────────────┤ │ text-embedding-3-large│ 3072 │ 高 │ 高 │ │ text-embedding-3-small│ 1536 │ 中高 │ 中 │ │ text-embedding-ada-002 │ 1536 │ 中 │ 低 │ │ BGE-large-zh │ 1024 │ 高中文│ 本地免费 │ │ m3e-large │ 1024 │ 高中文│ 本地免费 │ └───────────────┴─────────────┴─────────────┴─────────────────────┘本地部署 Embeddingfromlangchain_community.embeddingsimportOllamaEmbeddings# 使用 Ollama 本地部署的模型embeddingsOllamaEmbeddings(modelnomic-embed-text,# 支持中英文的高质量模型base_urlhttp://localhost:11434)# 构建向量库vectorstoreApacheDoris.from_documents(documentschunks,embeddingembeddings,# ... 其他配置)8.3 缓存策略fromfunctoolsimportlru_cachelru_cache(maxsize10000)defcached_embedding(text:str)-list:缓存 Embedding 结果returnembeddings.embed_query(text)# 批量嵌入时使用defbatch_embed_with_cache(texts:list)-list:批量嵌入支持缓存return[cached_embedding(text)fortextintexts]九、生产环境部署9.1 Docker Compose 部署# docker-compose.ymlversion:3.8services:doris:image:apache/doris:2.0.0-feports:-9030:9030-8030:8030environment:-FE_SERVERSfe1:127.0.0.1:9010doris-be:image:apache/doris:2.0.0-bedepends_on:-dorisenvironment:-POD_TYPEbe-FE_HOSTS127.0.0.1:9010rag-api:build:./rag-serviceports:-8000:8000environment:-DORIS_HOSTdoris-DORIS_PORT9030-OPENAI_API_KEY${OPENAI_API_KEY}depends_on:-dorisnetworks:default:name:rag-network9.2 FastAPI 服务封装fromfastapiimportFastAPI,HTTPExceptionfrompydanticimportBaseModelfromlangchain.chainsimportRetrievalQA appFastAPI(titleDoris RAG API)# 全局变量qa_chainNoneapp.on_event(startup)asyncdefload_chain():globalqa_chain vectorstoreApacheDoris.from_existing(hostdoris.example.com,databaserag_knowledge,embeddingOpenAIEmbeddings())qa_chainRetrievalQA.from_chain_type(llmChatOpenAI(temperature0),chain_typestuff,retrievervectorstore.as_retriever())classQueryRequest(BaseModel):question:strchat_history:list[]classQueryResponse(BaseModel):answer:strsources:listapp.post(/query,response_modelQueryResponse)asyncdefquery(request:QueryRequest):ifnotqa_chain:raiseHTTPException(status_code500,detailQA chain not initialized)resultqa_chain.invoke({query:request.question,chat_history:request.chat_history})returnQueryResponse(answerresult[result],sources[{content:doc.page_content[:200],source:doc.metadata.get(source)}fordocinresult.get(source_documents,[])])if__name____main__:importuvicorn uvicorn.run(app,host0.0.0.0,port8000)十、总结与展望Doris LangChain 的组合为 RAG 知识库提供了优雅而强大的解决方案。Doris 的 HNSW 向量索引提供了毫秒级的语义检索能力倒排索引支持精准的关键词过滤而统一的 SQL 接口大大简化了系统的复杂度。在实际项目中我总结了以下最佳实践文档切分是关键好的切分策略能让检索效果提升 30% 以上混合检索优于单一检索向量关键词的双路召回是业界主流方案重排序提升质量Cross-Encoder 重排序是性价比极高的优化手段本地 Embedding 降低成本对于中文场景BGE-large 是很好的选择展望未来GraphRAG基于知识图谱的 RAG和 Agentic RAG带自主决策的 RAG将是重要的演进方向。Doris 的图引擎和 MCP Server 能力为这些高级场景提供了基础设施支持。