这次我们来看一个 LangChain 与 Milvus 向量数据库结合并应用 DML数据操作语言进行实战的项目。对于想要构建本地知识库、实现智能问答或文档检索的开发者来说这个组合是当前非常热门且实用的技术栈。它解决了如何将海量非结构化文本如PDF、Word、网页转化为可被大语言模型LLM高效理解和检索的向量知识库的核心问题。简单来说这个实战项目的核心流程是用 LangChain 处理文档、切分文本、调用 Embedding 模型生成向量然后将这些向量存储到 Milvus 中。当用户提问时将问题也转化为向量在 Milvus 中进行相似性搜索找到最相关的文档片段最后将这些片段作为上下文喂给 LLM生成精准的答案。整个过程实现了从原始文档到智能问答的自动化流水线。本文将带你从零开始完成一个完整的 LangChain Milvus DML 实战项目。我们会重点关注环境搭建、数据导入、向量检索以及通过 DML 进行数据管理的全流程。无论你是想构建一个企业内部的文档助手还是为自己的项目添加智能检索能力这篇文章都能提供一套可直接落地的方案。1. 核心能力速览在深入细节之前我们先通过一个表格快速了解这个技术栈的核心能力和门槛。能力项说明项目类型基于 LangChain 框架与 Milvus 向量数据库的 RAG检索增强生成应用实战核心功能文档加载与解析、文本分割、向量化嵌入、向量存储与相似性检索、上下文增强的问答生成数据处理支持 PDF、TXT、Markdown、Word、网页等多种格式文档的批量处理向量引擎使用 Milvus 进行高性能向量相似度搜索支持亿级向量毫秒级检索DML 操作实战演示如何使用 DMLINSERT, DELETE, UPDATE, QUERY管理 Milvus 中的向量数据硬件门槛CPU 即可运行。Milvus 支持 Standalone单机模式对 GPU 无硬性要求。Embedding 模型若使用本地模型如 BGE可能需要 GPU 加速但也可使用 OpenAI、智谱等在线 API。显存占用取决于 Embedding 模型。若使用text2vec等较小模型CPU 推理即可若使用大型模型且启用 GPU则需按模型规格预留显存通常 2G-8G。Milvus 本身内存占用与数据量相关。启动方式Docker 启动 Milvus 服务 Python 脚本启动 LangChain 应用或使用docker-compose一键编排。接口能力LangChain 应用可封装为 FastAPI/Flask 服务提供文档上传、知识库构建、问答查询等 RESTful API。批量任务天然支持。LangChain 的文档加载器Document Loader和文本分割器Text Splitter专为批量文档处理设计。适合场景企业知识库问答、个人文档智能管理、法律/金融文档检索、客服机器人知识增强、代码库检索等。2. 适用场景与使用边界这个技术栈并非万能明确其适用边界能帮助你更好地决策。它非常适合以下场景私有化知识问答你有大量内部文档产品手册、会议纪要、技术文档希望构建一个能准确回答其中问题的聊天机器人。精准信息检索传统关键词搜索如CtrlF在语义模糊时失效你需要“根据意思找文档”例如搜索“如何申请休假”而非“休假制度 PDF”。降低 LLM 幻觉直接向 LLM 提问专业问题它可能胡编乱造。通过 RAG 提供确切的文档片段作为依据能极大提升回答的准确性和可信度。低成本更新知识大模型训练成本高、周期长。通过更新 Milvus 中的向量知识库即可让应用获得最新知识无需重新训练模型。它可能不适用于极度简单的问答如果问题答案只是固定的几句话直接写规则或查表更高效。强推理与计算任务例如复杂的数学计算、代码执行、逻辑推演RAG 主要提供信息检索复杂推理仍需依赖 LLM 本身的能力。对延迟极其敏感的场景从文档处理、向量化到检索、生成链路较长端到端延迟通常在数秒级别不适合实时性要求极高的交互。未经授权的版权内容必须强调处理的文档应确保拥有合法版权或使用授权。切勿将受版权保护的书籍、论文、商业数据等未经许可纳入系统以免引发法律风险。3. 环境准备与前置条件开始实战前请确保你的开发环境满足以下要求。我们将以Linux/macOS或WSL2 (Windows)环境为例进行说明。基础环境清单操作系统: Ubuntu 20.04/22.04, CentOS 7, macOS, 或 Windows 10/11 with WSL2。Docker Docker Compose: Milvus 推荐使用 Docker 部署这是最简便的方式。# 检查 Docker 是否安装 docker --version # 检查 Docker Compose 是否安装 docker-compose --versionPython: 版本 3.8 - 3.11。推荐使用 3.9 或 3.10。python --versionCUDA (可选): 如果你计划在本地运行需要 GPU 的 Embedding 模型如bge-large-zh则需要安装对应版本的 CUDA 和 cuDNN。如果使用 CPU 或在线 API则跳过。软件安装安装 Docker请参考 Docker 官方文档安装适合你系统的版本。安装 Python 依赖管理工具推荐使用conda或venv创建虚拟环境。# 使用 conda 创建环境 conda create -n langchain-milvus python3.10 conda activate langchain-milvus # 或使用 venv python -m venv venv source venv/bin/activate # Linux/macOS # venv\Scripts\activate # Windows4. 安装部署与启动方式我们将分两步走先启动 Milvus 向量数据库服务再搭建 LangChain 应用环境。4.1 启动 Milvus 服务Docker Compose 方式这是最推荐的方式它能一键启动 Milvus 及其依赖如 MinIO 用于对象存储etcd 用于元数据管理。下载配置文件# 创建项目目录并进入 mkdir langchain-milvus-demo cd langchain-milvus-demo # 下载最新的 docker-compose.yml 文件 wget https://github.com/milvus-io/milvus/releases/download/v2.4.0/milvus-standalone-docker-compose.yml -O docker-compose.yml注意版本号v2.4.0可能更新请查阅 Milvus 官方 Release 获取最新版本。启动服务sudo docker-compose up -d这个命令会在后台启动所有容器。使用docker-compose ps检查服务状态当所有容器状态均为Healthy或Up时表示启动成功。验证连接 安装pymilvus客户端并运行一个简单的连接测试。pip install pymilvus# test_connection.py from pymilvus import connections, utility # 连接到本地 Milvus 服务 connections.connect(hostlocalhost, port19530) # 检查连接是否成功 print(utility.get_server_version())运行脚本python test_connection.py如果输出版本号如2.4.0则连接成功。4.2 搭建 LangChain 应用环境在同一个项目目录下创建 LangChain 应用所需的环境。安装核心 Python 包pip install langchain langchain-community langchain-core pymilvuslangchain-community包含了许多社区维护的文档加载器和工具。安装文档处理依赖按需安装# 用于处理 PDF pip install pypdf # 或功能更强大的 pymupdf # pip install pymupdf # 用于处理 Word 文档 pip install python-docx # 用于处理 Markdown pip install markdown # 用于网页抓取如果需要 pip install beautifulsoup4 html2text选择 Embedding 模型在线 API推荐入门简单无需本地算力。pip install openai # 使用 OpenAI # 或 pip install zhipuai # 使用智谱AI本地模型数据隐私性高离线可用。pip install sentence-transformers # 使用 Sentence Transformers 模型如 BGE5. 功能测试与效果验证构建你的第一个知识库现在我们来完成一个完整的流程加载本地 PDF 文档切分文本生成向量存入 Milvus并进行语义检索问答。5.1 文档加载与处理假设我们有一个knowledge.pdf文件放在./docs目录下。# document_processor.py import os from langchain_community.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter # 1. 加载文档 pdf_path ./docs/knowledge.pdf loader PyPDFLoader(pdf_path) documents loader.load() print(f加载了 {len(documents)} 页文档。) # 2. 分割文本 text_splitter RecursiveCharacterTextSplitter( chunk_size500, # 每个文本块的最大字符数 chunk_overlap50, # 块之间的重叠字符数保持上下文连贯 separators[\n\n, \n, 。, , , , , , ] # 中文优先的分隔符 ) split_docs text_splitter.split_documents(documents) print(f分割为 {len(split_docs)} 个文本块。) # 查看第一个块的内容和元数据 print(f示例块内容: {split_docs[0].page_content[:200]}...) print(f示例块元数据: {split_docs[0].metadata})5.2 向量化与存储到 Milvus这里我们以使用本地BGE模型和在线OpenAIAPI 两种方式为例。方案一使用本地 BGE 模型数据隐私性好# vector_store_local.py from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.vectorstores import Milvus # 1. 初始化本地 Embedding 模型 model_name BAAI/bge-small-zh-v1.5 # 中文小模型也可用 bge-large-zh-v1.5 model_kwargs {device: cpu} # 使用 CPU如果有 GPU 可改为 cuda:0 encode_kwargs {normalize_embeddings: True} # 归一化有利于相似度计算 embeddings HuggingFaceEmbeddings( model_namemodel_name, model_kwargsmodel_kwargs, encode_kwargsencode_kwargs ) # 2. 连接到 Milvus 并创建向量库 # 如果集合collection不存在会自动创建 vector_store Milvus.from_documents( documentssplit_docs, embeddingembeddings, connection_args{host: localhost, port: 19530}, collection_namelangchain_demo, # Milvus 集合名 drop_oldTrue # 如果集合已存在则删除重建。生产环境慎用 ) print(文档向量已成功存储到 Milvus 集合 ‘langchain_demo‘ 中。)方案二使用 OpenAI API简单快捷# vector_store_openai.py from langchain_openai import OpenAIEmbeddings from langchain_community.vectorstores import Milvus import os os.environ[OPENAI_API_KEY] 你的-OpenAI-API-KEY # 1. 初始化 OpenAI Embedding embeddings OpenAIEmbeddings(modeltext-embedding-3-small) # 2. 存储到 Milvus vector_store Milvus.from_documents( documentssplit_docs, embeddingembeddings, connection_args{host: localhost, port: 19530}, collection_namelangchain_demo_openai, drop_oldTrue ) print(使用 OpenAI Embedding 存储完成。)5.3 语义检索测试存储完成后我们可以进行相似性搜索这是 RAG 的核心。# retrieval_test.py from langchain_community.vectorstores import Milvus from langchain_community.embeddings import HuggingFaceEmbeddings # 或 OpenAIEmbeddings # 1. 加载已存在的向量库使用与存储时相同的 Embedding 模型 embeddings HuggingFaceEmbeddings(model_nameBAAI/bge-small-zh-v1.5) vector_store Milvus( embedding_functionembeddings, connection_args{host: localhost, port: 19530}, collection_namelangchain_demo # 集合名必须一致 ) # 2. 进行相似性搜索 query 本文档中提到的核心架构是什么 docs vector_store.similarity_search(query, k3) # k 表示返回最相关的几个文档块 print(f针对问题 ‘{query}‘检索到 {len(docs)} 个相关片段\n) for i, doc in enumerate(docs): print(f--- 片段 {i1} ---) print(f内容: {doc.page_content[:300]}...) # 预览前300字符 print(f来源: {doc.metadata.get(source, N/A)}, 页码: {doc.metadata.get(page, N/A)}\n)运行此脚本你将看到系统从你上传的 PDF 中找到了与问题最相关的文本片段。这证明了向量检索是有效的。6. DML 实战管理你的向量数据DMLData Manipulation Language是操作数据库中数据的语言。在 Milvus 的语境下我们通过 PyMilvus 来执行这些操作LangChain 的Milvus向量库封装了部分操作。下面我们实战 CRUD。6.1 插入INSERT新数据除了初始的from_documents我们也可以后续插入单条或批量数据。# dml_insert.py from langchain_community.vectorstores import Milvus from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_core.documents import Document embeddings HuggingFaceEmbeddings(model_nameBAAI/bge-small-zh-v1.5) vector_store Milvus( embedding_functionembeddings, connection_args{host: localhost, port: 19530}, collection_namelangchain_demo ) # 创建新的 Document 对象 new_doc Document( page_content这是后续新增的一条重要知识项目将于下个季度启动敏捷开发模式。, metadata{source: manual_insert, date: 2024-09-24} ) # 插入新数据 vector_store.add_documents([new_doc]) print(新文档已插入。)6.2 查询QUERY与搜索我们已经用过similarity_search。Milvus 还支持带过滤条件的搜索这是 DML 中 QUERY 的体现。# dml_query_with_filter.py from pymilvus import connections, Collection from langchain_community.embeddings import HuggingFaceEmbeddings import numpy as np # 直接使用 PyMilvus 进行更精细的查询 connections.connect(hostlocalhost, port19530) collection Collection(langchain_demo) # 加载集合 collection.load() # 将集合加载到内存 # 假设我们想搜索但只针对 source 为 “knowledge.pdf” 的文档 query_embedding HuggingFaceEmbeddings(model_nameBAAI/bge-small-zh-v1.5).embed_query(敏捷开发) search_params {metric_type: IP, params: {}} # IP 表示内积相似度计算方式 # 构建过滤表达式 (DML 中的 WHERE 子句) filter_expr source knowledge.pdf results collection.search( data[query_embedding], anns_fieldembedding, # 向量字段名 paramsearch_params, limit3, exprfilter_expr, # 应用过滤条件 output_fields[content, source, page] # 指定返回的标量字段 ) for hits in results: for hit in hits: print(fID: {hit.id}, 距离: {hit.distance:.4f}) print(f内容: {hit.entity.get(content)[:200]}...) print(f元数据: source{hit.entity.get(source)}, page{hit.entity.get(page)}\n)6.3 更新UPDATE数据Milvus 不支持直接更新已插入向量的值。通常的“更新”操作是先删除DELETE旧的向量实体再插入INSERT新的向量实体。但可以更新标量字段非向量字段不过这需要知道实体 ID。# dml_update_scalar.py from pymilvus import connections, Collection connections.connect(hostlocalhost, port19530) collection Collection(langchain_demo) collection.load() # 假设我们知道要更新的实体 ID 是 12345 entity_id 12345 # 这个 ID 需要从之前的插入或搜索操作中获取 # 更新其 metadata 中的一个标量字段 collection.delete(fid {entity_id}) # 先删除 # 然后重新插入带有新内容和元数据的新实体这里省略插入代码需重新生成向量 print(f实体 {entity_id} 已标记为删除需重新插入更新后的数据。)注意对于频繁更新的场景这种“删-插”模式效率较低需考虑数据版本管理策略。6.4 删除DELETE数据可以根据条件删除数据例如删除来源为某个文件的所有数据。# dml_delete.py from pymilvus import connections, Collection connections.connect(hostlocalhost, port19530) collection Collection(langchain_demo) collection.load() # 删除所有 source 为 “temporary.md” 的实体 delete_expr source temporary.md result collection.delete(delete_expr) print(f删除表达式 ‘{delete_expr}‘ 执行完成。) print(f删除的实体数量: {result.delete_count if hasattr(result, delete_count) else 未知})7. 资源占用与性能观察了解系统资源消耗对于部署和优化至关重要。1. Milvus 服务资源占用启动后使用docker stats命令观察容器资源使用情况。docker stats你会看到milvus-standalone、etcd、minio等容器的 CPU、内存占用。对于小型知识库万级文档块内存占用通常在 1GB 以内。数据量增大时主要关注milvus-standalone容器的内存增长。2. Embedding 模型推理资源CPU 推理速度较慢但通用性强。处理一个包含 1000 个文本块每个500字的文档集可能需要几分钟到十几分钟。使用top或htop观察 Python 进程的 CPU 使用率。GPU 推理速度大幅提升。使用nvidia-smi观察显存占用和 GPU 利用率。以bge-large-zh为例单个批次推理可能占用 1-2GB 显存。3. 检索性能Milvus 的检索速度极快对于百万级向量的集合毫秒级返回结果。性能主要受以下因素影响索引类型创建集合时选择的索引如IVF_FLAT,HNSW影响搜索速度和精度。HNSW通常更快但更耗内存。搜索参数nprobe搜索的聚类中心数等参数越大精度越高速度越慢。硬件数据加载到内存后搜索速度主要取决于 CPU 和内存带宽。优化建议对于生产环境根据数据规模选择合适的 Milvus 集群部署方案而非 Standalone。Embedding 阶段是瓶颈考虑使用更高效的模型如bge-small或异步批处理。合理设置文本块大小chunk_size和重叠chunk_overlap在信息完整性和检索效率间取得平衡。8. 常见问题与排查方法在搭建和运行过程中你可能会遇到以下问题问题现象可能原因排查方式解决方案连接 Milvus 失败1. Milvus 服务未启动。2. 端口被占用或防火墙阻止。3. 主机地址错误。1.docker-compose ps检查容器状态。2.telnet localhost 19530测试端口连通性。3. 检查连接代码中的host和port。1. 运行docker-compose up -d启动。2. 确保端口19530开放。3. 在 Docker 容器内运行时host 应为milvus-standalone。pymilvus版本不兼容安装的pymilvus版本与 Milvus 服务端版本不匹配。运行pip show pymilvus和查看 Milvus 服务端版本。安装匹配的版本例如 Milvus 2.4.x 对应pymilvus2.4.0,2.5.0。文档加载器报错1. 文件路径错误。2. 缺少对应的解析库如pypdf。3. 文件格式损坏或加密。1. 检查文件路径是否存在。2. 查看错误信息确认缺失的包。3. 尝试用其他软件打开文件。1. 使用绝对路径或检查相对路径。2.pip install安装缺失的包。3. 确保文档可正常打开。Embedding 过程慢或卡住1. 使用 CPU 推理大型模型。2. 网络问题使用在线 API 时。3. 文本块过大或过多。1. 观察 CPU 使用率是否 100%。2. 检查网络连接和 API 密钥。3. 打印处理进度观察卡在哪一步。1. 考虑换用更小的模型或启用 GPU。2. 检查代理或防火墙设置。3. 调整chunk_size或分批次处理。相似性搜索返回无关结果1. Embedding 模型不匹配存储和检索时用了不同模型。2. 文本分割不合理上下文丢失。3. 搜索参数k或search_params设置不当。1. 确认存储和检索代码中model_name一致。2. 检查分割后的文本块是否完整表达了语义。3. 尝试调整k值或search_params。1. 确保使用相同的 Embedding 模型实例。2. 调整chunk_size和chunk_overlap。3. 对于 Milvus尝试使用HNSW索引并调整ef参数。内存或显存不足OOM1. 一次性加载所有文档并生成向量数据量太大。2. Milvus 集合数据量超出内存。3. GPU 显存不足以加载 Embedding 模型。1. 监控系统内存/显存使用情况。2. 观察docker stats中 Milvus 容器内存。3. 使用nvidia-smi观察显存。1. 分批处理文档例如每次处理 100 个文本块。2. 为 Milvus 配置更大的cache_size或使用磁盘索引。3. 换用更小的模型或在 CPU 上推理。DML 删除/更新操作无效1. 过滤表达式语法错误。2. 集合未加载load()。3. 实体 ID 不正确或条件不匹配。1. 检查表达式字符串是否符合 Milvus 语法。2. 在执行操作前调用collection.load()。3. 先执行一个查询确认目标数据存在。1. 使用简单的表达式测试如id in [1,2,3]。2. 确保在执行 DML 前已加载集合。3. 通过搜索获取准确的实体 ID 再操作。9. 最佳实践与使用建议为了让你的项目更健壮、易维护遵循以下建议环境隔离与配置管理始终使用 Python 虚拟环境venv或conda。将 Milvus 的连接参数、Embedding 模型名称、API Keys 等配置信息放入环境变量或配置文件如.env、config.yaml不要硬编码在脚本中。数据预处理流程标准化为不同格式的文档编写统一的预处理管道Pipeline包括格式校验、字符编码处理、无关内容页眉页脚清洗等。文本分割是 RAG 效果的关键。针对你的文档类型技术文档、对话记录、法律条文调整chunk_size和chunk_overlap并进行效果测试。向量存储策略为不同的知识库或文档类型创建不同的 Milvus 集合Collection便于管理和隔离。在插入数据时在元数据metadata中记录丰富的来源信息如source文件路径、page页码、timestamp入库时间、doc_id文档唯一ID等为后续的过滤和追溯提供便利。应用层设计将 LangChain 链Chain封装成独立的服务如使用 FastAPI提供upload、search、ask等端点。在问答链RetrievalQA中考虑设置score_threshold只返回相似度高于阈值的文档片段避免无关信息干扰 LLM。实现简单的缓存机制对相同或相似的问题直接返回缓存答案提升响应速度。监控与维护记录关键操作的日志如文档处理数量、向量化耗时、检索耗时、问答请求等。定期检查 Milvus 集合的健康状态和内存使用情况。建立知识库更新机制当源文档变更时能够增量更新或全量重建向量库。安全与合规重中之重确保你拥有处理文档内容的合法权利。对于企业数据遵守内部数据安全政策。如果使用在线 Embedding API如 OpenAI需评估数据出境风险。对敏感数据务必使用本地 Embedding 模型。对外的问答 API 应实施身份认证和速率限制防止滥用。10. 总结与下一步通过本文的实战你已经掌握了使用 LangChain 和 Milvus 构建本地知识库问答系统的核心流程从环境搭建、文档处理、向量化存储到 DML 数据管理和语义检索。这个组合的强大之处在于它将 LLM 的生成能力与向量数据库的精准检索能力结合让大模型能够“引经据典”给出有据可依的回答。最值得尝试的下一步接入真正的 LLM 完成问答链本文重点在“检索”R下一步是实现“增强生成”AG。使用 LangChain 的RetrievalQA链将检索到的文档片段作为上下文发送给 OpenAI GPT、智谱 GLM 或本地部署的 Llama 等 LLM生成最终答案。尝试不同的 Embedding 模型对比OpenAI text-embedding-3-small、BGE、M3E等模型在你的业务数据上的效果选择最适合的一个。探索 Milvus 高级特性如混合搜索同时使用向量和标量过滤、多向量检索、索引类型调优等以进一步提升检索精度和速度。构建一个简单的 Web UI使用 Gradio 或 Streamlit 快速搭建一个前端界面上传文档和提问让整个流程对非技术人员也更友好。最容易踩的坑环境不一致开发、测试、生产环境的 Python 包版本、Milvus 版本不一致导致奇怪错误。务必使用requirements.txt或Dockerfile锁定环境。文本分割不当这是影响效果的最大因素之一。分割过细会丢失上下文过粗则检索不精准。务必针对你的文档内容进行测试和调整。忘记加载集合在使用 PyMilvus 直接操作集合进行搜索或 DML 前必须调用collection.load()否则操作会失败或无效。建议将本文的代码作为基础模板收藏在构建你自己的智能文档应用时根据实际需求进行扩展和优化。这套技术栈正在快速发展保持对 LangChain 和 Milvus 官方文档的关注能让你及时获取最新的功能和最佳实践。