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

结语

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

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

相关推荐
冷小鱼1 小时前
LangChain 系统性科普:从入门到架构设计
langchain
kisshyshy1 小时前
告别 Node 噩梦?用 Bun + TypeScript 像写诗一样调用大模型
前端·typescript
wuhen_n1 小时前
RAG 关键环节:文本分块策略与最优参数配置
前端·langchain·ai编程
Nile1 小时前
Claude Code-Dynamic Workflows:1.为什么用工作流?
人工智能·ai·ai编程·ai-native
狂炫冰美式1 小时前
AI 生成 Draw.io,导入飞书/Lark 画板后可编辑
前端·人工智能·后端
Moment2 小时前
我做了一套前端也能学懂的 AI Agent 系列,从 Prompt 一路讲到多 Agent 😍😍😍
前端·后端·面试
yaoxiaoganggang2 小时前
克隆 Superpowers 的规则库到你的本地(或者直接作为 Git Submodule)
人工智能·经验分享·git·ai编程
dy17172 小时前
二维码打印
前端·javascript·vue.js
智商不够_熬夜来凑2 小时前
【Radio & Checkbox】
前端·javascript·vue.js