LangChain + Qdrant 向量数据库实战:从 Docker 安装到 RAG 问答全链路

适合人群:LangChain 开发者、RAG 应用工程师、AI 工程落地、知识库开发人员

摘要

本文完整记录了在 Windows 环境下使用 LangChain + Qdrant 搭建企业知识库问答系统的全流程。从 Docker 安装 Qdrant、Python 依赖配置、环境变量管理,到 QdrantDB 封装、文档建库、向量检索、LCEL 链式 RAG 问答,覆盖全链路实战。对比 Milvus 与 Qdrant 的选型差异,附带完整可运行代码和高频踩坑排查方案。


一、为什么选 Qdrant?Milvus vs Qdrant 选型对比

在本地开发和中小规模知识库场景中,向量数据库的选型直接影响开发体验。以下是 Milvus 与 Qdrant 的核心对比:

对比项Milvus (v2.6)Qdrant (v1.12)
内存占用启动需 4-8 GB仅需 512 MB - 1 GB
依赖复杂度需 etcd、MinIO、Pulsar 等 5+ 组件单容器,零依赖
部署难度多容器编排,启动慢docker run 一行启动
Windows 兼容性偶发连接问题原生 HTTP/gRPC,稳定
适用场景大规模生产集群本地开发、中小项目、原型验证
性能亿级向量,分布式扩展百万级向量,毫秒响应

选型结论:本地开发、学习项目、中小规模知识库,Qdrant 是更轻、更快、更稳的选择。


二、项目目录结构总览

F:\LangChain\
├── env\.env                    # 环境变量配置文件
├── data\
│   ├── raw\XX销售有限公司员工守则.pdf   # 原始知识库素材
│   └── readable\               # 预处理后的可读文本
├── DB\
│   ├── __init__.py              # 使 DB 成为 Python 包
│   ├── MilvusDB.py              # Milvus 适配器(保留原实现)
│   └── QdrantDB.py              # Qdrant 适配器(新增)
├── providers\
│   └── models.py                # 模型封装(Embedding + LLM)
└── Practice\07\0727_qdrant\      # Qdrant 版本练习脚本
    ├── 01_基础完整版.py          # 单 PDF 全内联(保留 Milvus)
    ├── 02_基础封装版.py          # 调用封装(保留 Milvus)
    ├── 03_升级封装版.py          # 多目录递归加载(保留 Milvus)
    ├── 04_Retriever 基础检索.py  # 检索程序(已适配 Qdrant)
    ├── 05_手动 RAG.py           # 手动组装 RAG(已适配 Qdrant)
    ├── 06_LCEL RAG.py           # LCEL 链式 RAG(已适配 Qdrant)
    ├── 07_建库程序.py           # 文档入库(已适配 Qdrant)
    ├── 08_rag_service.py        # RAG 服务类(已适配 Qdrant)
    └── 09_问答入口.py            # 交互式终端(已适配 Qdrant)

三、Docker 安装 Qdrant

3.1 前置条件

  • Windows 10/11 专业版(已启用 WSL2)
  • Docker Desktop 已安装并运行
  • 至少 2GB 可用内存

3.2 创建数据持久化目录

mkdir "F:\LangChain\qdrant_data"

3.3 拉取镜像并启动容器

docker run -d --name qdrant \
  -p 6333:6333 -p 6334:6334 \
  -v "F:/LangChain/qdrant_data:/qdrant/storage" \
  qdrant/qdrant:v1.12.0

参数详解

参数说明
-d后台运行
--name qdrant容器名称
-p 6333:6333HTTP REST API 端口
-p 6334:6334gRPC 端口(LangChain 使用此端口)
-v ...数据持久化到本地目录,容器重启不丢数据

3.4 验证容器运行状态

docker ps --filter name=qdrant

应显示 STATUS: UpPORTS: 0.0.0.0:6333-6334

3.5 Web UI 可视化管理(可选)

浏览器访问 http://localhost:6333/dashboard,可图形化管理集合、查看向量数据。


四、Python 依赖安装

在虚拟环境中安装 Qdrant 相关依赖:

"F:\LangChain\.venv\Scripts\pip.exe" install qdrant-client langchain-qdrant

国内网络可加清华镜像加速:

pip install qdrant-client langchain-qdrant -i https://pypi.tuna.tsinghua.edu.cn/simple

依赖说明

包名作用
qdrant-clientQdrant 原生客户端,用于创建集合、统计信息
langchain-qdrantLangChain 适配器,提供 QdrantVectorStore

五、.env 环境变量配置

编辑 F:\LangChain\env\.env,添加 Qdrant 及模型配置:

# DashScope 向量模型 API Key
DASHSCOPE_API_KEY=sk-your-key-here

# 本机 Docker Qdrant 服务地址
QDRANT_URL=http://localhost:6333

# 中文文本向量模型
EMBEDDING_MODEL=text-embedding-v4

# 大模型 API(OpenAI 兼容格式)
DEEPSEEK_BASE_URL=https://api.siliconflow.cn/v1
DEEPSEEK_API_KEY=sk-your-key-here

配置注意事项

  • QDRANT_URL 不要带端口号后面的路径,纯 http://localhost:6333 即可
  • 如使用 LongCat-2.0 等第三方模型,复用 DEEPSEEK_BASE_URLDEEPSEEK_API_KEY,只需改 model 参数

六、QdrantDB 适配器封装详解

文件位置:F:\LangChain\DB\QdrantDB.py

这一层封装是整个项目的核心,它屏蔽了 Qdrant 底层 API 的复杂性,上层代码只需调用 get_qdrant_client() 即可获得 LangChain 适配的向量库实例。

6.1 完整代码

import os
from dotenv import load_dotenv
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams
from langchain_qdrant import QdrantVectorStore
from providers.models import get_embedding_model


def get_qdrant_client(collection_name, is_delete=False, url="http://localhost:6333"):
    """
    获取 Qdrant 向量库实例,可选择是否删除旧集合

    参数:
    - collection_name: 集合名称(必传)
    - is_delete: 是否删除旧集合
    - url: Qdrant 服务地址

    内部逻辑:
    1. 读取 Qdrant 服务地址
    2. 创建 Qdrant 原生客户端(跳过版本兼容性检查)
    3. 根据 is_delete 决定是否删除旧 collection
    4. 如 collection 不存在,自动创建(指定 vector_size=1024, Distance.COSINE)
    5. 构造并返回 QdrantVectorStore 实例
    """
    load_dotenv()
    url = os.getenv("QDRANT_URL", url)

    # 创建原生客户端,跳过兼容性检查(避免版本警告)
    client = QdrantClient(url=url, grpc_port=6334, check_compatibility=False)

    # 检测集合是否存在
    collection_exists = False
    try:
        client.get_collection(collection_name)
        collection_exists = True
    except Exception:
        pass

    # 删除旧集合
    if is_delete and collection_exists:
        client.delete_collection(collection_name)
        print(f"已删除旧 collection: {collection_name}")
        collection_exists = False

    # 自动创建新集合
    if not collection_exists:
        vector_size = 1024  # DashScope text-embedding-v4 维度
        client.create_collection(
            collection_name=collection_name,
            vectors_config=VectorParams(
                size=vector_size,
                distance=Distance.COSINE,
            ),
            timeout=30,  # 创建耗时较长,需显式设置超时
        )
        print(f"已创建新 collection: {collection_name} (dim={vector_size})")

    # 创建 LangChain 适配的向量库实例
    vector_store = QdrantVectorStore(
        client=client,
        collection_name=collection_name,
        embedding=get_embedding_model(),  # DashScope 嵌入模型(单例)
    )

    return vector_store

6.2 关键设计要点

设计点说明
check_compatibility=False跳过客户端与服务端的版本兼容性检查,避免误报
timeout=30创建集合约需 10-15 秒,默认 5 秒会超时
vector_size=1024DashScope text-embedding-v4 的固定维度,勿改
Distance.COSINE余弦距离,适合语义相似度计算
单例 embeddingget_embedding_model() 内部缓存,避免重复初始化

七、建库程序:文档入库全流程

7.1 核心流程

PDF 文件
  |
  v
PyPDFLoader(按页加载)
  |
  v
RecursiveCharacterTextSplitter(chunk_size=300, overlap=50)
  |
  v
get_qdrant_client(is_delete=True,强制重建集合)
  |
  v
vector_store.add_documents(写入向量)
  |
  v
校验 points_count 与文档块数量一致

7.2 关键代码(Qdrant vs Milvus 差异)

# Qdrant 版本
from DB.QdrantDB import get_qdrant_client

# 建库
vector_store = get_qdrant_client(COLLECTION_NAME, is_delete=True)
ids = vector_store.add_documents(chunks)

# 统计方式不同:Qdrant 用 points_count
from qdrant_client import QdrantClient
client = QdrantClient(url=os.getenv("QDRANT_URL"))
collection_info = client.get_collection(COLLECTION_NAME)
row_count = collection_info.points_count

7.3 运行验证

cd "F:\LangChain\Practice\07\0727_qdrant"
"F:\LangChain\.venv\Scripts\python.exe" "07_建库程序.py"

预期输出

PDF 加载完成,共 3 页
文档切分完成,共 10 个文档块
已删除旧 collection: employee_handbook
已创建新 collection: employee_handbook (dim=1024)
写入返回 ID 数量:10
Collection 实际行数:10
建库成功:employee_handbook

八、检索程序:向量相似度检索

8.1 核心流程

  1. 获取 Qdrant 向量库实例(is_delete=False,不删除已有数据)
  2. 构建 Retriever(search_kwargs={'k': 3}
  3. 检索与问题最相关的 3 个文档块

8.2 关键代码

from DB.QdrantDB import get_qdrant_client

vector_store = get_qdrant_client(COLLECTION_NAME, is_delete=False)
retriever = vector_store.as_retriever(search_kwargs={'k': 3})
documents = retriever.invoke(QUESTION)

8.3 运行验证

"F:\LangChain\.venv\Scripts\python.exe" "04_Retriever 基础检索.py"

预期输出

问题:今天生病了,请了一天假,扣多少钱?
共检索到 3 个文档块

--- 查询结果 1 ---
来源:XX销售有限公司员工守则.pdf,第 1 页
业贿赂。
5. 维护公司利益...

--- 查询结果 2 ---
来源:XX销售有限公司员工守则.pdf,第 2 页
件。
2. 合同审批:...

--- 查询结果 3 ---
来源:XX销售有限公司员工守则.pdf,第 2 页
体现 professionalism 和敬业精神。
第二章 员工权利与义务...

九、RAG 完整服务架构

9.1 架构概览

用户提问
  ↓
Retriever(Qdrant 检索 top-3 文档块)
  ↓
format_documents(格式化为 [资料1]\n来源...\n内容...)
  ↓
PromptTemplate(System Prompt + 参考资料 + 用户问题)
  ↓
LLM(LongCat-2.0 / DeepSeek)
  ↓
StrOutputParser(解析为纯文本)
  ↓
返回 {answer, sources}

9.2 关键配置

COLLECTION_NAME = 'employee_handbook'

# 检索器配置
self.retriever = self.vector_store.as_retriever(search_kwargs={'k': 3})

# 大模型温度(temperature=0 保证回答稳定、不发散)
model = get_longcat_model(temperature=0)

# Prompt 核心规则
# 1. 不要编造参考资料中不存在的制度、时间、数字
# 2. 资料不足时回答"根据现有资料无法确定"
# 3. 简洁、清楚、分点

9.3 运行验证

from rag_service import RAGService

service = RAGService()
result = service.ask('病假扣多少钱')
print(result['answer'])
# 输出:根据现有资料无法确定。参考资料中仅提到...

十、交互式问答入口

"F:\LangChain\.venv\Scripts\python.exe" "09_问答入口.py"

交互示例

企业知识库助手已启动,输入 exit 退出。

请输入问题:病假扣多少钱

回答:根据现有资料无法确定。参考资料中仅提到员工依法享有病假权利...

资料来源
1. XX销售有限公司员工守则.pdf,1页
2. XX销售有限公司员工守则.pdf,2页

请输入问题:exit
程序已退出

十一、常见问题排查

11.1 创建集合超时 TimeoutError

现象07_建库程序.pyTimeoutError: Operation timed out

原因create_collection 默认超时 5 秒,实际需 10-15 秒

解决:显式设置 timeout=30

client.create_collection(..., timeout=30)

11.2 集合不存在 404

现象RuntimeError: Collection employee_handbook does not exist

原因:直接初始化 QdrantVectorStore 时集合不存在

解决:先用原生客户端 create_collection 创建,再初始化 QdrantVectorStore,或使用封装好的 get_qdrant_client(内部已处理自动创建逻辑)

11.3 DeepSeek 503/429 限流

现象:模型调用报 503 Service Unavailable429 Too Many Requests

原因:DeepSeek 服务端高峰期过载

解决方案

  1. 等 5-10 分钟重试
  2. 换非高峰时段(晚上/凌晨)测试
  3. 切换备用模型(如 LongCat-2.0,复用同一 API 平台密钥)

11.4 维度不匹配错误

现象Vector dimension mismatch: expected 1024, got 1536

原因:建库和查询使用了不同的 embedding 模型

解决:确保所有代码调用同一个 get_embedding_model()(单例模式),模型固定为 text-embedding-v4


十二、快速命令速查表

操作命令
启动 Qdrantdocker run -d --name qdrant -p 6333:6333 -p 6334:6334 -v "F:/LangChain/qdrant_data:/qdrant/storage" qdrant/qdrant:v1.12.0
查看容器docker ps --filter name=qdrant
停止容器docker stop qdrant
删除容器docker rm -f qdrant
安装依赖pip install qdrant-client langchain-qdrant
建库python "07_建库程序.py"
检索python "04_Retriever 基础检索.py"
完整 RAGpython "09_问答入口.py"

十三、核心知识点总结

知识点说明
Qdrant 定位轻量级向量数据库,单容器启动,适合本地开发和中小项目
QdrantDB 封装层屏蔽底层 API 差异,上层代码改 import 即可切换向量库
集合自动创建get_qdrant_client() 内部自动检测并创建集合,无需手动管理
vector_size=1024DashScope text-embedding-v4 固定维度,建库和查询必须一致
Distance.COSINE余弦距离,适合语义相似度计算
timeout=30创建集合耗时较长,必须显式设置超时
is_delete 参数建库时设 True 强制重建,检索时设 False 保留数据

完整数据流

PDF 文件
  -> PyPDFLoader
  -> RecursiveCharacterTextSplitter
  -> Document 文档块
  -> Embedding 向量化
  -> Qdrant 向量数据库
  -> Retriever 检索
  -> LLM 生成回答

Milvus 与 Qdrant 共存策略

  • Milvus 版本保留在 0727/ 目录
  • Qdrant 版本在 0727_qdrant/ 目录
  • 两者互不干扰,通过 DB/MilvusDB.pyDB/QdrantDB.py 分别封装

高频踩坑清单

  • create_collection 必须设置 timeout=30,默认 5 秒会超时
  • QDRANT_URL 不要带尾部路径,纯 http://localhost:6333
  • 建库和查询必须使用同一个 embedding 模型,否则维度不匹配
  • is_delete=True 会清空集合数据,检索时务必设为 False
  • Docker Desktop 未运行时,所有 Qdrant 操作会报连接拒绝
  • DeepSeek 503/429 是模型服务端限流,与向量库无关,换模型或错峰即可
  • check_compatibility=False 可跳过版本警告,不影响功能

问题排查顺序

容器状态 → 端口连通 → 集合存在 → embedding 维度 → 模型调用

配套 CSDN 封面图提示词

16:9,CSDN技术博客封面,极简科技蓝风格,扁平化UI,LangChain + Qdrant向量数据库,RAG知识库问答系统架构图,Docker容器,向量检索,代码元素,干净渐变背景,上方留白放标题,高清科技风

文末互动

本文完整覆盖了 Qdrant 在 Windows 环境下的 Docker 安装、Python 依赖配置、环境变量管理、QdrantDB 适配器封装、文档建库、向量检索、LCEL 链式 RAG 问答全链路,附带完整可运行代码和高频踩坑排查方案。

大家在搭建 RAG 知识库时,用的是 Milvus、Qdrant 还是其他向量数据库?遇到过哪些部署或检索效果的问题?欢迎评论区交流!

后续持续更新:Embedding 模型对比选型、RAG 检索效果优化、多轮对话记忆持久化、Agent 智能体开发。

点赞 + 收藏,持续更新大模型工程化干货!

更多推荐