RAG 核心:向量嵌入与本地向量数据库实战

为什么需要向量嵌入?

计算机的"语言困境"

作为人类,我们天然理解文字的含义:

  • "猫" → 毛茸茸的、会喵喵叫、养来抓老鼠...
  • "狗" → 忠诚的、会看家、是人类的好朋友...

但对计算机来说,"猫"和"狗"只是两个字符串,它不知道它们有什么关系。

Embedding 的核心思想

Embedding(向量化) 的核心思想是:把文字转换成一串数字(向量)。

scss 复制代码
"猫"  →  [0.12, -0.34, 0.56, 0.78, ...]  (1024维向量)
"狗"  →  [0.15, -0.31, 0.53, 0.80, ...]  (1024维向量)
"汽车"→  [0.89, 0.12, -0.34, 0.21, ...]  (1024维向量)

关键规律:如果两个向量的距离很近,说明对应的文本在语义上也相似。

向量距离的计算

衡量两个向量"远近"的常用方法:

| 方法 | 公式 | 说明 |
|:----------|:-------------------|:--------------|---|---|-----|---------------|
| 余弦相似度 | `cos(θ) = (A·B)/( | A | | B | )` | 关注方向,值越接近1越相似 |
| 欧氏距离 | d = √Σ(ai - bi)² | 关注绝对距离,值越小越相似 |
| 点积 | A·B = Σai×bi | 结合方向和长度 |

Embedding 的应用场景

应用场景 说明 前端示例
语义搜索 搜"手机"也能找到"智能手机" 站内搜索、文档检索
相似推荐 找到和当前内容最相似的内容 相关文章推荐
分类聚类 把相似的内容自动归类 新闻自动分类
去重判断 判断两段文字是否重复 内容查重

向量嵌入原理深入

从文本到向量的转换流程

flowchart LR subgraph 文本向量化流程 direction LR A[原始文本<br/><br/>我爱编程] B[分词<br/><br/>我,爱,编程] C[Token ID<br/><br/>101,234,567,...] D[Embedding模型<br/><br/>Transformer编码器] E[向量数组<br/><br/>0.12, -0.34, 0.56,...] A --> B B --> C C --> D D --> E end

传统数据库 vs 向量数据库

传统数据库存储的是精确值:

sql 复制代码
SELECT * FROM products WHERE name = '手机';  -- 只能精确匹配

但如果你搜"手机",就搜不到"智能手机"。

向量数据库的优势:即使搜索词不完全一样,也能找到语义上相关的内容!

对比维度 传统数据库 向量数据库
查询方式 精确匹配 相似度匹配
返回结果 满足条件的记录 语义最相似的 Top-K
对模糊输入的容忍度 低 高
典型场景 用户登录、订单查询 语义搜索、推荐系统

本地轻量向量数据库部署

Chroma 简介

Chroma 是一款以 AI 为原生、开源的向量数据库,专注于开发者生产力和幸福感。它采用 Apache 2.0 许可,非常适合前端开发者快速上手。

Chroma 的核心优势:

特性 说明
零配置启动 无需复杂部署,开箱即用
轻量级 内存存储,适合开发测试
LangChain 原生支持 官方提供完整集成
元数据过滤 支持结构化条件查询

Docker 部署(推荐)

bash 复制代码
# 拉取 Chroma 镜像
docker pull chromadb/chroma

# 运行容器
docker run -d -p 8000:8000 chromadb/chroma

启动成功后,服务运行在 http://localhost:8000。

npm 安装与配置

bash 复制代码
# 安装 LangChain Chroma 集成包
npm install @langchain/community chromadb @langchain/openai

# 如果使用阿里云百炼 Embedding,还需安装
npm install @langchain/openai

本地连接配置

typescript 复制代码
// 本地 Chroma 连接配置
import { Chroma } from "@langchain/community/vectorstores/chroma";
import { OpenAIEmbeddings } from "@langchain/openai";

const embeddings = new OpenAIEmbeddings({
  model: "text-embedding-v3",
  apiKey: process.env.BAILIAN_API_KEY,
  configuration: {
    baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
  },
});

const vectorStore = new Chroma(embeddings, {
  collectionName: "my_knowledge_base",
  url: "http://localhost:8000",  // Docker 服务地址
});

文本向量化存储代码实战

完整 TS 实现

typescript 复制代码
// src/vector-store-demo.ts
import { OpenAIEmbeddings } from "@langchain/openai";
import { Chroma } from "@langchain/community/vectorstores/chroma";
import { Document } from "@langchain/core/documents";
import dotenv from "dotenv";

dotenv.config();

// 1. 初始化 Embedding 模型(阿里云百炼)
const embeddings = new OpenAIEmbeddings({
  apiKey: process.env.BAILIAN_API_KEY,
  configuration: {
    baseURL: process.env.BAILIAN_BASE_URL,
  },
  model: "text-embedding-v3",  // 阿里云百炼模型
});

// 2. 准备文档数据
const documents: Document[] = [
  {
    pageContent: "RAG(检索增强生成)是一种结合检索和生成的技术方案,可以有效解决大模型幻觉问题。",
    metadata: { source: "rag_intro.md", topic: "RAG基础" },
  },
  {
    pageContent: "向量数据库专门用于存储和检索高维向量数据,支持相似度搜索而非传统的关系型精确匹配。",
    metadata: { source: "vector_db.md", topic: "向量数据库" },
  },
  {
    pageContent: "Embedding 模型将文本转换为数值向量,使得语义相似的文本在向量空间中距离更近。",
    metadata: { source: "embedding.md", topic: "嵌入模型" },
  },
];

// 3. 创建向量存储并添加文档
async function createVectorStore() {
  console.log("🔄 正在创建向量数据库...");
  
  const vectorStore = await Chroma.fromDocuments(
    documents,
    embeddings,
    {
      collectionName: "rag_knowledge_base",
      url: "http://localhost:8000",  // Chroma 服务地址
    }
  );
  
  console.log("✅ 向量数据库创建成功!");
  console.log(`📊 已存储 ${documents.length} 个文档块\n`);
  
  return vectorStore;
}

// 4. 执行相似度检索
async function searchSimilar(vectorStore: Chroma, query: string) {
  console.log(`🔍 查询: "${query}"\n`);
  
  const results = await vectorStore.similaritySearch(query, 2);
  
  console.log("📋 检索结果(按相似度排序):");
  results.forEach((doc, idx) => {
    console.log(`\n  ${idx + 1}. [相似度排名${idx + 1}]`);
    console.log(`     内容: ${doc.pageContent.slice(0, 100)}...`);
    console.log(`     来源: ${doc.metadata.source}`);
  });
  
  return results;
}

// 5. 带分数返回的检索
async function searchWithScore(vectorStore: Chroma, query: string) {
  const resultsWithScore = await vectorStore.similaritySearchWithScore(query, 2);
  
  console.log("\n📊 检索结果(含相似度分数):");
  resultsWithScore.forEach(([doc, score], idx) => {
    console.log(`\n  ${idx + 1}. 相似度: ${score.toFixed(4)}`);
    console.log(`     内容: ${doc.pageContent.slice(0, 80)}...`);
  });
  
  return resultsWithScore;
}

// 主函数
async function main() {
  try {
    // 创建向量存储
    const vectorStore = await createVectorStore();
    
    // 测试检索
    await searchSimilar(vectorStore, "什么是RAG技术?");
    await searchWithScore(vectorStore, "如何解决大模型幻觉");
    
  } catch (error) {
    console.error("❌ 错误:", error);
  }
}

main();

使用过滤器的高级检索

typescript 复制代码
// 带元数据过滤的检索
async function searchWithFilter(vectorStore: Chroma) {
  const filter = { topic: "向量数据库" };
  
  const results = await vectorStore.similaritySearch(
    "向量存储",
    2,
    filter  // 只检索 topic 为"向量数据库"的文档
  );
  
  console.log("🔍 带过滤条件的检索结果:");
  results.forEach((doc, idx) => {
    console.log(`  ${idx + 1}. ${doc.pageContent.slice(0, 80)}...`);
  });
}

批量添加文档

typescript 复制代码
// 批量添加文档(支持自定义 ID)
async function batchAddDocuments(vectorStore: Chroma) {
  const newDocs: Document[] = [
    { pageContent: "Chroma 是一款开源的向量数据库...", metadata: { type: "intro" } },
    { pageContent: "LangChain 提供了丰富的向量存储集成...", metadata: { type: "tutorial" } },
  ];
  
  const ids = await vectorStore.addDocuments(newDocs, { ids: ["doc_001", "doc_002"] });
  console.log(`✅ 已添加 ${ids.length} 个文档,ID: ${ids.join(", ")}`);
}

删除文档

typescript 复制代码
// 按 ID 删除文档
async function deleteDocument(vectorStore: Chroma) {
  await vectorStore.delete({ ids: ["doc_001"] });
  console.log("✅ 已删除指定文档");
}

向量数据库选型建议

选型决策框架

根据数据规模和场景需求选择合适的向量数据库:

text 复制代码
开始
  │
  ├─ 数据规模 < 10万条?
  │   ├─ 是 → Chroma(轻量级嵌入式)
  │   └─ 否 ↓
  │
  ├─ 数据规模 10万-500万条?
  │   ├─ 是 → Qdrant(高性能独立部署)
  │   └─ 否 ↓
  │
  ├─ 数据规模 > 500万条?
  │   ├─ 是 → Milvus(分布式集群)
  │   └─ 否 ↓
  │
  └─ 已有 PostgreSQL 基础设施?
      └─ 是 → pgvector(数据库插件)

主流方案对比

数据库 架构模式 性能 混合搜索 分布式 适用场景
Chroma 轻量级嵌入式 ★★☆ ✗ ✗ 本地开发测试、POC验证
Qdrant 高性能独立 ★★★★ ✓ ✓ 实时推荐、复杂查询
Milvus 分布式集群 ★★★★★ ✓ ✓ 千万级生产环境
pgvector PostgreSQL扩展 ★★★ 有限 ✗ 已有PG基础设施

场景选型建议

使用场景 推荐方案 理由
本地开发/学习 Chroma 零配置、开箱即用
前端 Demo 项目 Chroma 轻量、集成简单
中小企业生产 Qdrant 性能好、运维成本适中
大规模生产环境 Milvus 分布式、高可用
已有 PostgreSQL pgvector 复用现有基础设施

常见问题与解决方案

问题 1:Embedding 模型调用失败

现象 :401 Unauthorized 或 InvalidApiKey

解决方案:

  • 检查 API Key 是否正确
  • 确认 Base URL 是 https://dashscope.aliyuncs.com/compatible-mode/v1
  • 确认模型名称正确(text-embedding-v3)

问题 2:Chroma 连接失败

现象 :ECONNREFUSED 连接错误

解决方案:

bash 复制代码
# 检查 Chroma 服务是否运行
curl http://localhost:8000/api/v1/heartbeat

# 如果未运行,启动 Docker 容器
docker run -d -p 8000:8000 chromadb/chroma

问题 3:向量检索结果不相关

现象:检索到的内容与查询语义不匹配

解决方案:

  • 检查 Embedding 模型是否与检索时一致
  • 增加文档块的重叠度
  • 调整检索的 k 值(返回数量)
  • 使用 similaritySearchWithScore 查看相似度分数,评估检索质量

问题 4:添加文档时向量维度不匹配

现象 :dimension mismatch 错误

解决方案:

  • 确保所有文档使用相同的 Embedding 模型
  • 检查是否在创建 Collection 时指定了正确的维度
typescript 复制代码
// 创建时明确指定维度
const vectorStore = new Chroma(embeddings, {
  collectionName: "my_collection",
  numDimensions: 1024,  // 与 text-embedding-v3 匹配
});

结语

通过这篇教程,我们深入学习了向量嵌入的原理和向量数据库的实践用法。

对于文章中错误的地方或有任何疑问,欢迎在评论区留言讨论!

相关推荐
子兮曰4 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰4 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万4 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝4 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋4 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
1点东西4 天前
做了近两年的Agent开发,其实真正要学的就是这五件事
llm·agent·ai编程
七牛云行业应用4 天前
Qwen-Image-2.1 开源部署完整指南:Diffusers、ComfyUI 与推理服务
ai编程
卡布鲁4 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
染指11104 天前
122.Agent-LangChain核心组件-中间件-动态提示词(dynamic_promapt)
人工智能·langchain·agent·agents
福如意如我心意4 天前
TencentDB Agent Memory和其他开源memory
ai编程