【LangChain.js学习】 向量数据库(内存/持久化)

核心说明

向量数据库是 LangChain 构建知识库问答的核心组件,用于存储文档文本的向量嵌入(Embedding),并支持相似性检索(根据查询语句的向量匹配最相关的文本块)。分为「内存向量数据库」(MemoryVectorStore,临时存储)和「持久化向量数据库」(Chroma,永久存储),前者适合测试/临时场景,后者适合生产环境。

一、核心概念

1. 向量嵌入(Embedding)

将文本转换为数值向量(如1536维数组),使计算机能通过「向量距离」衡量文本语义相似度,本文使用阿里通义千问的 text-embedding-v2 模型生成嵌入。

2. 相似性检索

输入查询语句→生成查询向量→计算与库中所有文本向量的距离(如余弦相似度)→返回最相似的N个文本块,是知识库问答的核心逻辑。

二、内存向量数据库(MemoryVectorStore)

核心特点

  • 数据存储在内存中,程序重启后丢失;
  • 无需额外部署服务,开箱即用;
  • 适合快速测试、临时知识库场景。

完整实现代码

typescript 复制代码
import { TextLoader } from "@langchain/classic/document_loaders/fs/text";
import { RecursiveCharacterTextSplitter } from "@langchain/classic/text_splitter";
import { MemoryVectorStore } from "@langchain/classic/vectorstores/memory";
import { OpenAIEmbeddings } from "@langchain/openai";

// 1. 初始化嵌入模型(阿里通义千问)
const embeddingsModel = new OpenAIEmbeddings({
    model: "text-embedding-v2", // 通义千问嵌入模型
    configuration: {
        baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1", // 阿里百炼兼容接口
        apiKey: "[你的阿里百炼API Key]", // 替换为有效Key
    },
});

// 2. 初始化内存向量数据库
const vectorStore = new MemoryVectorStore(embeddingsModel);

// 3. 加载并分割文档(复用文本加载逻辑)
const loader = new TextLoader("./data/data.txt");
const documents = await loader.load();

// 文本分割器(适配中文语义)
const splitter = new RecursiveCharacterTextSplitter({
    chunkSize: 25, // 每个文本块最大字符数
    chunkOverlap: 5, // 块间重叠字符数(保证上下文连贯)
    separators: [",", "。"], // 中文优先分割符
});
const splitDocs = await splitter.splitDocuments(documents);

// 4. 将分割后的文本块存入向量库(自动生成嵌入向量)
await vectorStore.addDocuments(splitDocs);

// 5. 相似性检索(查询+返回Top2最相关文本)
const results = await vectorStore.similaritySearch("李娟的出生于哪里?", 2);

// 输出检索结果
console.log("内存向量库检索结果:");
results.forEach((doc, index) => {
    console.log(`第${index+1}条:`, doc.pageContent);
});

/** 输出示例:
内存向量库检索结果:
第1条: 李娟,1979年7月出生于新疆生产建设兵团
第2条: 兵团,籍贯四川乐至,当代女作家
*/

三、持久化向量数据库(Chroma)

核心特点

  • 数据持久化存储(磁盘/数据库),程序重启后不丢失;
  • 支持独立部署服务,多进程/多实例共享数据;
  • 适合生产环境、长期维护的知识库场景。

1. 环境准备

安装Chroma(Python)

bash 复制代码
# 安装Chroma依赖
pip install chromadb

# 启动Chroma服务(后台运行,端口8000)
chroma run --host 0.0.0.0 --port 8000

安装LangChain-Chroma依赖(Node.js)

bash 复制代码
pnpm add @langchain/community

2. 完整实现代码

typescript 复制代码
import { TextLoader } from "@langchain/classic/document_loaders/fs/text";
import { RecursiveCharacterTextSplitter } from "@langchain/classic/text_splitter";
import { Chroma } from "@langchain/community/vectorstores/chroma";
import { OpenAIEmbeddings } from "@langchain/openai";

// 1. 初始化嵌入模型(与内存库一致)
const embeddingsModel = new OpenAIEmbeddings({
    model: "text-embedding-v2",
    configuration: {
        baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
        apiKey: "[你的阿里百炼API Key]",
    },
});

// 2. 初始化Chroma向量数据库(连接远程服务)
const vectorStore = new Chroma(embeddingsModel, {
    url: "http://localhost:8000", // Chroma服务地址
    collectionName: "langchain_nodejs_demo", // 集合名称(类似数据库表)
});

// 3. 加载并分割文档(与内存库一致)
const loader = new TextLoader("./data/data.txt");
const documents = await loader.load();

const splitter = new RecursiveCharacterTextSplitter({
    chunkSize: 25,
    chunkOverlap: 5,
    separators: [",", "。"],
});
const splitDocs = await splitter.splitDocuments(documents);

// 4. 将文本块存入Chroma(自动创建集合+生成嵌入)
await vectorStore.addDocuments(splitDocs);

// 5. 相似性检索
const results = await vectorStore.similaritySearch("李娟的出生于哪里?", 2);

// 输出检索结果
console.log("Chroma向量库检索结果:");
results.forEach((doc, index) => {
    console.log(`第${index+1}条:`, doc.pageContent);
});

/** 输出示例:
Chroma向量库检索结果:
第1条: 李娟,1979年7月出生于新疆生产建设兵团
第2条: 兵团,籍贯四川乐至,当代女作家
*/

3. 关键扩展操作

typescript 复制代码
// 1. 清空集合(删除所有数据)
await vectorStore.delete({ collectionName: "langchain_nodejs_demo" });

// 2. 带分数的相似性检索(返回相似度得分,0-1,越高越相似)
const resultsWithScore = await vectorStore.similaritySearchWithScore("李娟的作品有哪些?", 2);
console.log("带分数的检索结果:");
resultsWithScore.forEach(([doc, score], index) => {
    console.log(`第${index+1}条:`, doc.pageContent, `相似度:${score.toFixed(4)}`);
});

// 3. 自定义检索参数(如过滤元数据)
const filteredResults = await vectorStore.similaritySearch(
    "李娟的职务",
    1,
    { source: "./data/data.txt" } // 仅检索指定来源的文本
);

四、内存/持久化向量库对比

维度 内存向量库(MemoryVectorStore) 持久化向量库(Chroma)
数据存储 内存 磁盘/数据库
持久化 程序重启丢失 永久保留
部署成本 无(无需额外服务) 需部署Chroma服务
性能 读写速度快(无网络IO) 有网络IO,速度略慢
多实例共享 不支持 支持(多进程连接同一服务)
适用场景 测试、临时知识库 生产环境、长期知识库

五、核心原理与关键注意事项

1. 核心流程

flowchart TD A[加载文档] --> B[文本分割为小文本块] B --> C[嵌入模型生成文本向量] C --> D[存入向量数据库] E[用户查询] --> F[生成查询向量] F --> G[向量库相似性检索] G --> H[返回最相关文本块]

2. 关键注意事项

  1. Chroma服务启动 :确保Chroma服务正常运行(chroma run),否则会报连接错误;
  2. 文本分割参数chunkSize 不宜过大(超过嵌入模型上下文)或过小(语义不完整),中文建议20-50字符;
  3. 集合名称管理 :Chroma的 collectionName 建议按业务分类(如 product_docuser_manual),避免数据混乱。
相关推荐
simon_luv_pho2 小时前
一行代码把网页变成 AI Agent?
前端
兆子龙2 小时前
模块联邦(Module Federation)详解:从概念到手把手 Demo
前端·架构
ZFSS2 小时前
Kimi Chat Completion API 申请及使用
前端·人工智能
没想好d2 小时前
通用管理后台组件库-8-表格组件
前端
前端Hardy2 小时前
HTML&CSS&JS:打造丝滑的3D彩纸飘落特效
前端·javascript·css
布列瑟农的星空3 小时前
rsbuild mock 插件开发指南
前端
用泥种荷花3 小时前
【LangChain.js学习】 文档加载(Loader)与文本分割全解析
前端
cxxcode4 小时前
Vite 热更新(HMR)原理详解
前端
HelloReader4 小时前
Tauri 架构从“WebView + Rust”到完整工具链与生态
前端