RAG + Agent + Prompt工程中

RAG + Agent + Prompt 工程中:搭建本地向量数据库Qdrant、文档处理与多语言支持国际化

本文是 RAG 系统实战系列 的中间篇。在前一篇文章中,我们介绍了 RAG 的基本原理和 LangChain 的核心概念。今天,我们将深入实战环节------手把手教你如何搭建本地向量数据库(Qdrant),并重点讲解 文档预处理流程多语言国际化支持 的完整实现方案。

附上项目源代码:lhlhlhlhl/assessment-rag


前言:为什么向量数据库如此重要?

在 RAG(检索增强生成)系统中,向量数据库 是连接"用户问题"与"知识库内容"的桥梁。它的作用是:

  • 将你的文档内容转换为高维向量(即"嵌入")
  • 快速找出与用户提问语义最相近的几段文本
  • 为大模型提供精准的上下文,从而生成高质量回答

没有高效的向量存储和检索机制,RAG 就失去了"增强"的意义。

在本项目中,我们选择 Qdrant 作为本地向量数据库,并围绕它构建了一套完整的文档处理 + 多语言支持体系。


一、向量数据库选型:为什么是 Qdrant?

市面上有 Pinecone、Weaviate、Milvus、FAISS 等多种向量数据库,我们最终选择了 Qdrant,原因如下:

特性 说明
🚀 高性能 用 Rust 编写,内存效率高,单机每秒可处理数千次查询
📦 轻量易部署 支持 Docker 一键启动,也支持二进制直接运行
🔍 支持元数据过滤 不仅能按向量相似度搜索,还能结合标签、来源等条件筛选
🌐 双协议支持 同时提供 RESTful API 和 gRPC 接口,适配不同场景
🆓 开源免费 社区活跃,文档完善,适合本地开发和中小规模生产

二、两种部署方式:Docker vs 直接安装

方案一:推荐!使用 Docker Compose 一键部署(开发首选)

1. 创建 docker-compose.yml
yaml 复制代码
version: '3.8'

services:
  qdrant:
    image: qdrant/qdrant:latest
    container_name: smart_assessment_qdrant
    ports:
      - "6333:6333"  # REST API 端口
      - "6334:6334"  # gRPC 端口(可选)
    volumes:
      - ./qdrant_storage:/qdrant/storage  # 持久化数据
    environment:
      - QDRANT__SERVICE__GRPC_PORT=6334
    restart: unless-stopped
    networks:
      - rag_network

networks:
  rag_network:
    driver: bridge

💡 关键解释

  • volumes 将本地 qdrant_storage/ 目录挂载到容器内,即使删除容器,数据也不会丢失
  • restart: unless-stopped 保证服务崩溃后自动重启
  • 自定义网络 rag_network 便于未来扩展(如加入 LLM 服务)
2. 启动服务
复制代码
docker-compose up -d
3. 验证是否成功
bash 复制代码
curl http://localhost:6333/collections

如果返回 {"result":{"collections":[]},"status":"ok"},说明 Qdrant 已正常运行!


方案二:非 Docker 安装(适合无 Docker 环境)

Windows 用户:
  1. GitHub Releases 下载 qdrant-windows-x86_64.zip

  2. 解压后运行:

    复制代码
    .\qdrant.exe
Linux/macOS 用户:
bash 复制代码
# 方法1:APT 安装(Ubuntu/Debian)
echo "deb [trusted=yes] https://apt.qdrant.io stable main" | sudo tee /etc/apt/sources.list.d/qdrant.list
sudo apt update && sudo apt install qdrant

# 方法2:直接下载二进制
wget https://github.com/qdrant/qdrant/releases/latest/download/qdrant-linux-x86_64.tar.gz
tar xzf qdrant-linux-x86_64.tar.gz
./qdrant

⚠️ 注意:非 Docker 方式需要手动管理配置、日志和数据目录,强烈建议开发阶段使用 Docker


✅ 为什么我们推荐 Docker?

对比项 直接安装 Docker
安装复杂度 高(需处理依赖、路径、权限) 极低(一条命令)
跨平台一致性 差(Windows/Linux 行为可能不同) 完美一致
数据隔离 无(文件散落在系统各处) 完全隔离
版本切换 困难 修改镜像标签即可
卸载清理 容易残留 docker-compose down -v 一键清空

🧩 打个比方

直接安装就像在客厅里搭帐篷------占地方、难收拾;

Docker 就像买了一个带轮子的集装箱------随时移动、干净整洁。


三、连接 Qdrant:代码实现详解

无论采用哪种部署方式,我们的 JavaScript 代码连接逻辑完全一致。以下是核心类 QdrantVectorStoreManager 的精要解读:

arduino 复制代码
// 初始化客户端
this.client = new QdrantClient({
  url: `http://${config.QDRANT_HOST}:${config.QDRANT_PORT}`,
  timeout: 30000,
});

// 使用 Qwen 兼容 OpenAI 的 Embedding 模型
this.embeddings = new OpenAIEmbeddings({
  openAIApiKey: config.QWEN_API_KEY,
  modelName: config.EMBEDDING_MODEL,
  configuration: { baseURL: config.QWEN_API_BASE }
});

🔑 关键点 :虽然用了 OpenAIEmbeddings,但通过 baseURL 指向 Qwen 的 API,实现了"用 OpenAI 接口调 Qwen 模型"。

后续的 initCollection()addDocuments()search() 等方法封装了集合创建、文档插入和相似检索,完全兼容 LangChain 生态,可直接用于 RAG 链。

效果展示:


四、文档处理:从原始文件到向量存储

这是 RAG 效果好坏的关键!很多初学者直接把整篇文档丢进去,结果检索效果很差。正确的做法是 "分块 + 嵌入 + 存储"

步骤 1️⃣:加载文档(支持 Markdown)

我们设计了一个 DocumentLoader 类,专门用于递归扫描 docs/ 目录下的所有 .md 文件:

scss 复制代码
// 递归查找所有 .md 文件
findMarkdownFiles(dirPath) {
  const files = [];
  const items = fs.readdirSync(dirPath);
  for (const item of items) {
    const itemPath = path.join(dirPath, item);
    if (fs.statSync(itemPath).isDirectory()) {
      files.push(...this.findMarkdownFiles(itemPath)); // 递归
    } else if (path.extname(item) === '.md') {
      files.push(itemPath);
    }
  }
  return files;
}

每个文档被封装为一个 Document 对象,包含:

  • content:文件全文
  • metadata:来源路径、文件名、加载时间等

步骤 2️⃣:智能文本分割(重中之重!)

为什么不能整篇存?

因为大模型有上下文长度限制(如 8192 tokens),而且长文本嵌入会丢失局部语义。

我们使用 LangChain 的 RecursiveCharacterTextSplitter,并针对中文做了优化

csharp 复制代码
new RecursiveCharacterTextSplitter({
  chunkSize: 500,        // 每块约 500 字符
  chunkOverlap: 50,      // 相邻块重叠 50 字,避免断句
  separators: [
    '\n\n',   // 优先按段落切
    '\n',
    '。', '!', '?',  // 中文句号、感叹号、问号
    ';', ',',         // 分号、逗号
    ' ',                // 英文空格
    ''                  // 最后按字符切
  ]
})

🌟 效果示例

原文:"Qwen 是阿里巴巴推出的 AI 模型。它支持多语言。"

→ 切分为两块:

块1:"Qwen 是阿里巴巴推出的 AI 模型。"

块2:"它支持多语言。"

这样既能保持语义完整,又避免跨句切割。


步骤 3️⃣:向量化 & 存入 Qdrant

这一步由 QdrantVectorStore.addDocuments() 自动完成:

  1. 调用 embeddings.embedDocuments() 生成向量
  2. [向量, 文本, 元数据] 作为"点(Point)"存入 Qdrant

整个过程对开发者透明,你只需传入 Document[] 即可。


五、国际化(i18n):让系统支持中英文切换

为了让项目更专业、更易用,我们加入了完整的多语言支持。

1. 技术选型:i18next + JSON 资源文件

  • i18next:业界标准的 JS 国际化库
  • JSON 文件:按语言分类存储翻译文本,结构清晰

目录结构:

bash 复制代码
src/i18n/
├── index.js              # 国际化管理器
└── locales/
    ├── en/translation.json
    └── zh-CN/translation.json

2. 核心:I18nManager 单例类

javascript 复制代码
class I18nManager {
  async init(language = 'en') {
    await i18next.use(Backend).init({
      lng: language,
      fallbackLng: 'en',
      backend: {
        loadPath: './locales/{{lng}}/translation.json'
      }
    });
  }

  t(key, options = {}) {
    return i18next.t(key, options); // 如 t('messages.loading_docs', { count: 5 })
  }

  getPreferredLanguage() {
    // 1. 读取系统环境变量 LANG
    // 2. 自动匹配支持的语言(如 zh_CN → zh-CN)
    // 3. 默认回退到英文
  }
}

优势

  • 支持插值(如 {{count}}
  • 自动语言检测
  • 未翻译时回退到英文

3. 翻译文件示例(zh-CN/translation.json)

json 复制代码
{
  "document_loader": {
    "loading_all_docs": "正在加载所有文档...",
    "loaded_doc": "已加载文档: {{path}}",
    "error_loading_doc": "加载文档失败 {{path}}: {{error}}"
  },
  "text_splitter": {
    "splitting_docs": "正在分割文档...",
    "split_doc": "文档 {{path}} 已分割为 {{count}} 个块"
  },
  "vector_store": {
    "creating_collection": "正在创建集合: {{name}}",
    "collection_exists": "集合 {{name}} 已存在",
    "adding_batch": "正在添加 {{count}} 个文档块..."
  }
}

4. 在代码中使用

less 复制代码
// 初始化(自动检测系统语言)
await i18nManager.init(i18nManager.getPreferredLanguage());

// 打印日志
console.log(i18nManager.t('vector_store.adding_batch', { count: docs.length }));

5. 命令行支持语言切换

sql 复制代码
# 默认根据系统语言自动选择
npm run start

# 强制使用中文
npm run start -- -l zh-CN

# 强制使用英文
npm run start -- -l en

效果展示:

🌍 用户体验提升:非英语用户不再面对满屏英文报错,大大降低使用门槛。


六、完整流程:从零初始化到交互问答

整个系统启动流程如下:

  1. 验证配置 → 2. 加载文档 → 3. 智能分块 → 4. 连接 Qdrant → 5. 批量向量化存储
css 复制代码
graph LR
A[验证配置] --> B[加载 docs/ 下所有 .md 文件]
B --> C[按语义分割为小块]
C --> D[连接 Qdrant]
D --> E[生成向量并存入]
E --> F[启动交互式问答]

在问答阶段,用户输入问题后:

  • 系统将问题向量化
  • 在 Qdrant 中检索 Top-K 相似块
  • 将结果 + 原始问题交给 LLM 生成答案
  • 返回答案 + 来源引用(含相似度分数)

总结

本文我们完成了 RAG 系统的三大核心模块:

向量数据库搭建 :通过 Docker 快速部署 Qdrant,兼顾性能与便捷性

文档智能处理 :从加载、中文友好分块到向量化,确保检索质量

多语言支持:基于 i18next 实现中英文无缝切换,提升可用性

这些工作为后续的 Agent 决策、Prompt 优化、评估指标 等高级功能打下了坚实基础。(如果想看完整代码可到开头展示的代码仓库中查看,里面包含rag调用的完整代码)

📌 下期预告:我们将使用rag去做一个法律检索的专业ai问答助手,使用爬虫技术去完善我们的数据库,采用流式输出去展示我们的代码,将后端rag技术与前端页面结合起来。


附:常见问题

Q:为什么不用 FAISS?

→ FAISS 是纯向量库,无持久化、无过滤、无 API,适合实验;Qdrant 是完整数据库,适合产品。

Q:分块大小怎么选?

→ 中文建议 300--800 字符,英文 200--500 tokens。可通过 CHUNK_SIZE 配置调整。

Q:Qwen 的 embedding 维度是多少?

text-embedding-v2 输出 1536 维 ,务必在 config.EMBEDDING_DIMENSION 中正确设置!


希望这篇文章能帮你少走弯路,快速搭建出自己的 RAG 系统!欢迎点赞、收藏、评论交流 👇 ```

相关推荐
天命码喽c1 小时前
Docker-compose部署GraphRAG-2.7.0
运维·docker·容器
南天一梦N2 小时前
新的软件研发范式即将到来!
驱动开发·架构·系统架构·aigc·ai编程
WebCandy2 小时前
【开源】一个丝滑的 Claude Code 环境变量快速切换工具
人工智能·aigc·ai编程
智泊AI3 小时前
何恺明新作:扩散模型+Transformer才是王炸!
llm
你的坚持终将美好,3 小时前
Docker 中一起启动多个容器脚本
docker·容器
像风一样自由20203 小时前
Docker 与 Docker Compose:从零开始的容器化之旅
运维·docker·容器
血小溅3 小时前
Springboot项目Docker 多平台构建指南
后端·docker
家家小迷弟3 小时前
docker容器内部安装python和numpy的方法
python·docker·numpy
北珣.3 小时前
docker镜像操作
运维·docker·容器·镜像