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 UnauthorizedInvalidApiKey

解决方案

  • 检查 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 匹配
});

结语

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

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

相关推荐
铁皮饭盒16 分钟前
26年bunjs, elysia+pg一把梭, redis都省了
前端·javascript·后端
AlbertZein9 小时前
Agent 场景下,谁才是真正好用的 Flash 模型
aigc·ai编程
uccs10 小时前
流式响应的三次进化:EventSource → ReadableStream → TransformStream
openai·ai编程·claude
lichenyang45313 小时前
Docker 学习笔记(一):为什么需要镜像、容器和仓库?
前端
kyriewen13 小时前
别再对着 TypeScript 报错发呆了:我把 10 个最常见的红色波浪线翻译成了人话
前端·javascript·typescript
IT_陈寒13 小时前
SpringBoot自动配置的坑,我的API突然就404了
前端·人工智能·后端
不丿二14 小时前
AI 时代下的个人工作台沉淀——一个越用越懂你的本地 AI 助手
ai编程
奇奇怪怪的14 小时前
Embedding 模型 10+ 横向评测
前端
陈广亮14 小时前
Monorepo 从 0 到 1 实操指南 2026 版:pnpm catalogs + Turborepo 2.x + changesets 全链路
前端