摘要 :本文基于FastAPI项目,手把手完成 Qdrant向量数据库部署 、OpenAI兼容阿里云Embedding接口配置、全局客户端工具封装、向量入库与语义检索全流程开发。解决传统每次请求重复创建连接、配置散乱、维度不匹配、接口鉴权失败等常见问题,封装可直接复用的工具类,适配生产级项目使用。
适用场景:RAG知识库、语义检索、文本相似度匹配、智能问答系统开发
技术栈:FastAPI + Python + Qdrant + 阿里云Embedding(OpenAI兼容)
一、前言
在RAG智能检索项目中,向量数据库与文本向量化是核心基础能力。Qdrant作为Rust开发的高性能向量数据库,凭借优秀的过滤查询性能、支持本地轻量化部署、gRPC异步高性能交互等优势,成为主流选型。
很多开发者在集成时会遇到几个典型问题:
-
每次接口请求重复创建Embedding和Qdrant客户端,造成资源浪费、请求卡顿
-
Embedding向量维度与Qdrant集合维度不匹配,检索报错
-
多环境配置散乱,鉴权失败、接口地址不统一
-
没有统一的工具封装,业务代码冗余、复用性差
本文将从零完成环境部署→依赖安装→全局配置→客户端工具封装→业务 CRUD 实操,实现延迟加载客户端、全局复用连接、项目优雅集成。
二、环境准备与依赖安装
2.1 安装项目依赖
在项目 backend/pyproject.toml 中添加Qdrant客户端与OpenAI兼容请求依赖,仅需新增两行配置:
python
[dependencies]
# 新增 Qdrant向量数据库客户端
qdrant-client = "^1.10.0"
# 新增 OpenAI兼容接口请求客户端(适配阿里云Embedding)
openai = "^1.0.0"
依赖配置完成后,重新安装项目依赖,确保环境生效:
bash
# 根据项目包管理工具执行
poetry install
# 或 pip安装
pip install -r requirements.txt
注意 :本文使用OpenAI兼容客户端调用阿里云Embedding接口,仅为协议兼容,不依赖OpenAI模型,可适配任意支持OpenAI协议的向量模型服务商。
2.2 Qdrant服务部署(Docker一键部署)
推荐Docker部署Qdrant,支持数据持久化,适配本地开发与服务器部署:
bash
# Linux/Mac 启动命令
docker run -p 6333:6333 -p 6334:6334 \ -v "$(pwd)/qdrant_storage:/qdrant/storage" \ qdrant/qdrant:latest
# Windows 启动命令
docker run -p 6333:6333 -p 6334:6334 ^ -v "%cd%/qdrant_storage:/qdrant/storage" ^ qdrant/qdrant:latest
启动成功后,默认访问地址:http://localhost:6333,6333为HTTP端口,6334为gRPC端口。
三、全局环境变量配置(核心)
在项目根目录 .env 文件中统一配置Embedding与Qdrant参数,统一管理多环境配置,避免硬编码。
3.1 完整.env配置
python
# Embedding 向量模型配置(阿里云OpenAI兼容接口)
EMBEDDING_API_KEY=你的阿里云百炼API密钥 EMBEDDING_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
EMBEDDING_MODEL=text-embedding-v3
EMBEDDING_DIM=1536
# Qdrant 向量数据库配置
QDRANT_URL=http://localhost:6333
QDRANT_API_KEY= # 本地开发环境无需密钥,留空即可
QDRANT_COLLECTION=async_demo_collection
3.2 配置项详细说明
| 配置项 | 作用说明 |
|---|---|
| EMBEDDING_API_KEY | Embedding接口鉴权密钥,阿里云百炼平台获取 |
| EMBEDDING_BASE_URL | OpenAI兼容接口地址,阿里云固定兼容地址 |
| EMBEDDING_MODEL | 向量模型名称,与服务商接口对应 |
| EMBEDDING_DIM | 向量维度,当前统一使用1536维,必须与Qdrant集合维度一致 |
| QDRANT_URL | Qdrant服务部署地址,本地默认localhost:6333 |
| QDRANT_API_KEY | Qdrant鉴权密钥,本地开发为空,线上服务按需配置 |
| QDRANT_COLLECTION | 向量数据存储集合名称,类比数据库表名 |
3.3 常见报错解决方案
报错场景:Embedding接口401鉴权失败
排查方案:
-
校验
EMBEDDING_API_KEY是否为有效、未过期的密钥 -
确认
EMBEDDING_BASE_URL、EMBEDDING_MODEL属于同一服务商接口 -
检查网络是否可正常访问向量接口地址
✅ 配置修改完成后,必须重启后端服务,环境变量方可生效。
四、全局配置类改造
修改 backend/app/core/config.py,读取.env环境变量,统一全局配置,项目全局可调用。
python
from pydantic_settings import BaseSettings
from typing import Optional
class Settings(BaseSettings):
# Embedding配置
EMBEDDING_API_KEY: str
EMBEDDING_BASE_URL: str
EMBEDDING_MODEL: str
EMBEDDING_DIM: int = 1536
# Qdrant配置
QDRANT_URL: str
QDRANT_API_KEY: Optional[str] = ""
QDRANT_COLLECTION: str
class Config:
env_file = ".env"
env_file_encoding = "utf-8"
# 全局单例配置
settings = Settings()
五、核心客户端工具封装(重点)
新建 backend/app/core/clients.py,实现延迟创建客户端、全局连接复用、异步向量转换、服务关闭释放连接核心能力,避免每次请求重复创建连接,提升接口性能。
5.1 完整工具封装代码
python
from typing import List, Optional
from openai import AsyncOpenAI
from qdrant_client import AsyncQdrantClient
from app.core.config import settings
# 模块级全局变量,全局复用连接
_embedding_client: Optional[AsyncOpenAI] = None
_qdrant_client: Optional[AsyncQdrantClient] = None
def get_embedding_client() -> AsyncOpenAI:
"""延迟初始化Embedding异步客户端,全局单例复用"""
global _embedding_client
if _embedding_client is None:
_embedding_client = AsyncOpenAI( api_key=settings.EMBEDDING_API_KEY, base_url=settings.EMBEDDING_BASE_URL )
return _embedding_client
def get_qdrant() -> AsyncQdrantClient:
"""延迟初始化Qdrant异步客户端,全局单例复用"""
global _qdrant_client
if _qdrant_client is None: _qdrant_client = AsyncQdrantClient(
url=settings.QDRANT_URL,
api_key=settings.QDRANT_API_KEY
if settings.QDRANT_API_KEY else None )
return _qdrant_client
async def embed_texts(text_list: List[str]) -> List[List[float]]:
""" 批量文本向量化 :param text_list: 文本列表 :return: 向量列表 """
client = get_embedding_client()
resp = await client.embeddings.create( input=text_list, model=settings.EMBEDDING_MODEL ) return [d.embedding for d in resp.data]
async def close_clients():
"""FastAPI服务停止时关闭所有客户端连接,释放资源"""
global _embedding_client, _qdrant_client
if _embedding_client:
await _embedding_client.close()
if _qdrant_client:
await _qdrant_client.close()
_embedding_client = None _qdrant_client = None
5.2 核心设计亮点
-
延迟加载:首次调用才创建客户端,服务启动轻量化
-
全局单例:模块级变量保存客户端,避免重复创建网络连接
-
异步适配:完全基于异步客户端,适配FastAPI异步架构,性能更高
-
资源释放:提供关闭方法,服务停止自动释放连接,避免内存泄漏
-
批量向量化:支持批量文本转向量,减少接口请求次数
六、完整业务操作实战(建表+入库+检索)
基于封装好的工具类,实现Qdrant核心业务:集合创建、文本向量入库、语义相似度检索,可直接运行测试。
七、代码运行效果
执行脚本后,控制台输出如下,代表集成成功:
python
import asyncio
from typing import List
from qdrant_client import models
from app.core.clients import get_qdrant, embed_texts
from app.core.config import settings
# 集合名称统一读取全局配置
COLLECTION_NAME = settings.QDRANT_COLLECTION
async def init_collection():
"""初始化向量集合(类比数据库建表)"""
qdrant = get_qdrant()
# 存在则删除旧集合,避免维度冲突
exists = await qdrant.collection_exists(COLLECTION_NAME)
if exists:
await qdrant.delete_collection(COLLECTION_NAME)
# 创建新集合,向量维度与Embedding模型严格对齐
await qdrant.create_collection(
collection_name=COLLECTION_NAME,
vectors_config=models.VectorParams(
size=settings.EMBEDDING_DIM,
distance=models.Distance.COSINE # 余弦相似度匹配
)
)
print(f"✅ 成功创建向量集合:{COLLECTION_NAME},向量维度:{settings.EMBEDDING_DIM}")
async def insert_docs(text_list: List[str]):
"""
文本批量向量化并写入Qdrant
携带自定义payload元数据,方便后续过滤检索
"""
qdrant = get_qdrant()
# 文本转向量
embeddings = await embed_texts(text_list)
# 组装向量数据与元数据
points = []
for index, (text, vec) in enumerate(zip(text_list, embeddings)):
point = models.PointStruct(
id=index,
vector=vec,
payload={
"content": text,
"source": "project_demo"
}
)
points.append(point)
# 批量写入向量数据库
await qdrant.upsert(COLLECTION_NAME, points=points)
print(f"✅ 成功写入 {len(points)} 条向量数据")
async def search_docs(query_text: str, top_k: int = 2):
"""语义相似度检索,返回匹配结果"""
qdrant = get_qdrant()
# 查询文本向量化
query_embedding = (await embed_texts([query_text]))[0]
# 向量相似度检索
hits = await qdrant.query_points(
collection_name=COLLECTION_NAME,
query=query_embedding,
limit=top_k
)
return hits.points
if __name__ == '__main__':
# 1. 初始化集合
asyncio.run(init_collection())
# 2. 测试入库文本
docs = [
"Milvus 是Go语言开发开源向量数据库,国内项目使用广泛",
"Qdrant 使用Rust开发,过滤查询性能优秀,支持qdrant‑lite本地模式",
"Pinecone 云托管向量数据库,无需运维,按用量计费",
"Chroma 轻量级向量库,适合本地原型与学习测试"
]
asyncio.run(insert_docs(docs))
# 3. 语义检索测试
hits = asyncio.run(search_docs("Rust开发的向量数据库有哪些", 4))
print("\n🔍 语义检索结果:")
for hit in hits:
print(f"相似度得分:{hit.score:.4f} | 文本内容:{hit.payload.get('content')}")
✅ 成功创建向量集合:async_demo_collection,向量维度:1536 ✅ 成功写入 4 条向量数据 🔍 语义检索结果: 相似度得分:0.8923 | 文本内容:Qdrant 使用Rust开发,过滤查询性能优秀,支持qdrant‑lite本地模式 相似度得分:0.7125 | 文本内容:Milvus 是Go语言开发开源向量数据库,国内项目使用广泛 ......
八、项目核心规范与避坑总结
-
维度强制统一:Qdrant集合向量维度必须和Embedding模型输出维度完全一致,否则检索报错
-
客户端复用:禁止在接口函数内重复创建客户端,必须全局单例延迟加载,优化并发性能
-
配置统一管理:所有密钥、地址、维度参数写入.env,禁止代码硬编码
-
鉴权排查优先级:401报错优先校验密钥有效性,再核对接口地址与模型匹配性
-
异步适配:FastAPI项目必须使用异步Qdrant客户端,同步客户端会阻塞事件循环
九、总结
本文完成了 Qdrant部署→依赖安装→环境配置→全局工具封装→向量入库+语义检索 全流程开发,封装的客户端工具具备延迟加载、全局复用、资源自动释放的生产级能力。
整套方案完全适配FastAPI异步项目,兼容阿里云、OpenAI等所有OpenAI协议的Embedding模型,可直接接入RAG知识库、智能问答、文本相似度检索等业务场景,开箱即用、易于扩展维护。
往期推荐:FastAPI+RAG知识库搭建、大模型接口统一封装、向量检索优化实战