以编程方式使用文档

Redis 是一个快速的开源内存数据存储。作为 Redis Stack, 的一部分, 是启用向量相似性语义搜索以及许多其他类型搜索的模块。

本指南提供了快速入门 Redis 向量存储的快速概述。若要获取所有 RedisVectorStore 功能和配置的详细文档,请前往 API 参考.

概述

集成详情

ClassPackagePY 支持DownloadsVersion
RedisVectorStore@langchain/redis!NPM - Downloads!NPM - Version

设置

要使用 Redis 向量存储,请设置一个启用 RediSearch 的 Redis Stack 实例,并安装 @langchain/redis@langchain/core。安装 redis 在传递您自己的实例时使用 Node.js 客户端 createClient 实例到 RedisVectorStore.

本指南使用 OpenAI 嵌入 作为示例。您可以使用 其他支持的嵌入模型 instead.

npm install @langchain/redis @langchain/core redis @langchain/openai
yarn add @langchain/redis @langchain/core redis @langchain/openai
pnpm add @langchain/redis @langchain/core redis @langchain/openai

您可以通过以下方式使用 Docker 在本地设置 Redis 实例 这些说明.

凭据

设置 REDIS_URL 环境变量:

process.env.REDIS_URL = "your-redis-url";

如果您在本指南中使用 OpenAI 嵌入,也请设置您的 OpenAI 密钥:

process.env.OPENAI_API_KEY = "YOUR_API_KEY";

如果您想获取模型调用的自动追踪,您还可以设置您的 LangSmith API 密钥,方法是在下方取消注释:

// process.env.LANGSMITH_TRACING="true"
// process.env.LANGSMITH_API_KEY="your-api-key"

实例化

const embeddings = new OpenAIEmbeddings({
  model: "text-embedding-3-small",
});

const client = createClient({
  url: process.env.REDIS_URL ?? "redis://localhost:6379",
});
await client.connect();

const vectorStore = new RedisVectorStore(embeddings, {
  redisClient: client,
  indexName: "langchainjs-testing",
});

管理向量存储

向向量存储添加项目

const document1: Document = {
  pageContent: "The powerhouse of the cell is the mitochondria",
  metadata: { type: "example" },
};

const document2: Document = {
  pageContent: "Buildings are made out of brick",
  metadata: { type: "example" },
};

const document3: Document = {
  pageContent: "Mitochondria are made out of lipids",
  metadata: { type: "example" },
};

const document4: Document = {
  pageContent: "The 2024 Olympics are in Paris",
  metadata: { type: "example" },
};

const documents = [document1, document2, document3, document4];

await vectorStore.addDocuments(documents);

顶级文档 ID 当前不受支持,但您可以通过直接向向量存储提供其 ID 来删除文档。

查询向量存储

一旦您的向量存储已创建并且相关文档已添加,您很可能希望在链或代理运行期间对其进行查询。

直接查询

执行简单的相似性搜索可以按如下方式进行:

const similaritySearchResults = await vectorStore.similaritySearch(
  "biology",
  2
);

for (const doc of similaritySearchResults) {
  console.log(`* ${doc.pageContent} [${JSON.stringify(doc.metadata, null)}]`);
}

过滤当前会查找包含所提供字符串的任何元数据键。

如果您想执行相似性搜索并接收相应的分数,您可以运行:

const similaritySearchWithScoreResults =
  await vectorStore.similaritySearchWithScore("biology", 2);

for (const [doc, score] of similaritySearchWithScoreResults) {
  console.log(
    `* [SIM=${score.toFixed(3)}] ${doc.pageContent} [${JSON.stringify(
      doc.metadata
    )}]`
  );
}
* [SIM=0.835] The powerhouse of the cell is the mitochondria [{"type":"example"}]
* [SIM=0.852] Mitochondria are made out of lipids [{"type":"example"}]

通过转换为检索器进行查询

您还可以将向量存储转换为 检索器 以便在链中更方便地使用。

const retriever = vectorStore.asRetriever({
  k: 2,
});
await retriever.invoke("biology");
[
  Document {
    pageContent: 'The powerhouse of the cell is the mitochondria',
    metadata: { type: 'example' },
    id: undefined
  },
  Document {
    pageContent: 'Mitochondria are made out of lipids',
    metadata: { type: 'example' },
    id: undefined
  }
]

用于检索增强生成

有关如何使用此向量存储进行检索增强生成 (RAG) 的指南,请参阅以下部分:

删除文档

您可以通过两种方式从向量存储中删除文档:

删除所有文档

您可以使用以下命令删除整个索引及其所有文档:

await vectorStore.delete({ deleteAll: true });

按 ID 删除特定文档

您还可以通过提供文档 ID 来删除特定文档。请注意,配置的键前缀将自动添加到您提供的 ID 中:

// The key prefix will be automatically added to each ID
await vectorStore.delete({ ids: ["doc1", "doc2", "doc3"] });

关闭连接

完成操作后请确保关闭客户端连接,以避免过多的资源消耗:

await client.disconnect();

高级功能

自定义架构和元数据过滤

Redis 向量存储支持元数据字段的自定义架构定义,从而实现更高效的过滤和搜索。此功能允许您为元数据定义特定的字段类型和验证规则。

定义自定义架构

创建向量存储时可以定义自定义架构,以指定字段类型、验证规则和索引选项:

const embeddings = new OpenAIEmbeddings({
  model: "text-embedding-3-small",
});

const client = createClient({
  url: process.env.REDIS_URL ?? "redis://localhost:6379",
});
await client.connect();

// Define custom schema for metadata fields
const customSchema:RedisVectorStoreConfig["customSchema"] = {
  userId: {
    type: SchemaFieldTypes.TEXT,
    required: true,
    SORTABLE: true,
  },
  category: {
    type: SchemaFieldTypes.TAG,
    SORTABLE: true,
    SEPARATOR: ",",
  },
  score: {
    type: SchemaFieldTypes.NUMERIC,
    SORTABLE: true,
  },
  tags: {
    type: SchemaFieldTypes.TAG,
    SEPARATOR: ",",
    CASESENSITIVE: true,
  },
  description: {
    type: SchemaFieldTypes.TEXT,
    NOSTEM: true,
    WEIGHT: 2.0,
  },
};

const vectorStoreWithSchema = new RedisVectorStore(embeddings, {
  redisClient: client,
  indexName: "langchainjs-custom-schema",
  customSchema,
});

架构字段类型

自定义架构支持三种主要字段类型:

  • TEXT:支持全文搜索的字段,可选配词干提取、加权和排序
  • TAG:用于精确匹配的分类字段,支持多个值和自定义分隔符
  • NUMERIC:支持范围查询和排序的数值字段

字段配置选项

每个字段都可以通过各种选项进行配置:

  • - required:该字段是否必须在元数据中存在(默认值:false)
  • - SORTABLE:启用该字段的排序功能(默认值:undefined)
  • - SEPARATOR:对于 TAG 字段,指定多个值的分隔符(默认值:",")
  • - CASESENSITIVE:对于 TAG 字段,启用大小写敏感匹配(Redis 期望 true,而非布尔值)
  • - NOSTEM:对于 TEXT 字段,禁用词干提取(Redis 期望 true,而非布尔值)
  • - WEIGHT:对于 TEXT 字段,指定搜索权重(默认值:1.0)

使用架构验证添加文档

使用自定义架构时,文档会自动根据定义的架构进行验证:

const documentsWithMetadata: Document[] = [
  {
    pageContent: "Advanced JavaScript techniques for modern web development",
    metadata: {
      userId: "user123",
      category: "programming",
      score: 95,
      tags: ["javascript", "web-development", "frontend"],
      description: "Comprehensive guide to JavaScript best practices",
    },
  },
  {
    pageContent: "Machine learning fundamentals and applications",
    metadata: {
      userId: "user456",
      category: "ai",
      score: 88,
      tags: ["machine-learning", "python", "data-science"],
      description: "Introduction to ML concepts and practical applications",
    },
  },
  {
    pageContent: "Database optimization strategies for high performance",
    metadata: {
      userId: "user789",
      category: "database",
      score: 92,
      tags: ["database", "optimization", "performance"],
      description: "Advanced techniques for database performance tuning",
    },
  },
];

// This will validate each document's metadata against the custom schema
await vectorStoreWithSchema.addDocuments(documentsWithMetadata);

带元数据过滤的高级相似性搜索

自定义架构使用 similaritySearchVectorWithScoreAndMetadata method:

// Search with TAG filtering
const tagFilterResults =
  await vectorStoreWithSchema.similaritySearchVectorWithScoreAndMetadata(
    await embeddings.embedQuery("programming tutorial"),
    3,
    {
      category: "programming", // Exact tag match
      tags: ["javascript", "frontend"], // Multiple tag OR search
    }
  );

console.log("Tag filter results:");
for (const [doc, score] of tagFilterResults) {
  console.log(`* [SIM=${score.toFixed(3)}] ${doc.pageContent}`);
  console.log(`  Metadata: ${JSON.stringify(doc.metadata)}`);
}
// Search with NUMERIC range filtering
const numericFilterResults =
  await vectorStoreWithSchema.similaritySearchVectorWithScoreAndMetadata(
    await embeddings.embedQuery("high quality content"),
    5,
    {
      score: { min: 90, max: 100 }, // Score between 90 and 100
      category: ["programming", "ai"], // Multiple categories
    }
  );

console.log("Numeric filter results:");
for (const [doc, score] of numericFilterResults) {
  console.log(`* [SIM=${score.toFixed(3)}] ${doc.pageContent}`);
  console.log(
    `  Score: ${doc.metadata.score}, Category: ${doc.metadata.category}`
  );
}
// Search with TEXT field filtering
const textFilterResults =
  await vectorStoreWithSchema.similaritySearchVectorWithScoreAndMetadata(
    await embeddings.embedQuery("development guide"),
    3,
    {
      description: "comprehensive guide", // Text search in description field
      score: { min: 85 }, // Minimum score of 85
    }
  );

console.log("Text filter results:");
for (const [doc, score] of textFilterResults) {
  console.log(`* [SIM=${score.toFixed(3)}] ${doc.pageContent}`);
  console.log(`  Description: ${doc.metadata.description}`);
}

数值范围查询选项

对于数值字段,您可以指定各种范围查询:

// Exact value match
{ score: 95 }

// Range with both min and max
{ score: { min: 80, max: 100 } }

// Only minimum value
{ score: { min: 90 } }

// Only maximum value
{ score: { max: 95 } }

错误处理和验证

自定义架构提供带有有用错误消息的自动验证:

try {
  // This will fail validation - missing required userId field
  const invalidDoc: Document = {
    pageContent: "Some content without required metadata",
    metadata: {
      category: "test",
      // Missing required userId field
    },
  };

  await vectorStoreWithSchema.addDocuments([invalidDoc]);
} catch (error) {
  console.log("Validation error:", error.message);
  // Output: "Required metadata field 'userId' is missing"
}

try {
  // This will fail validation - wrong type for score field
  const wrongTypeDoc: Document = {
    pageContent: "Content with wrong metadata type",
    metadata: {
      userId: "user123",
      score: "not-a-number", // Should be number, not string
    },
  };

  await vectorStoreWithSchema.addDocuments([wrongTypeDoc]);
} catch (error) {
  console.log("Type validation error:", error.message);
  // Output: "Metadata field 'score' must be a number, got string"
}

性能优势

使用自定义 schema 有几个性能优势:

  1. **索引元数据字段**:单独的元数据字段分别建立索引,支持快速过滤
  2. **类型优化查询**:数字和标签字段使用优化的查询结构
  3. **减少数据传输**:搜索结果中仅返回相关字段
  4. **更好的查询规划**:Redis 可以根据字段类型和索引优化查询

向后兼容性

自定义 schema 功能完全向后兼容。没有自定义 schema 的现有 Redis 向量存储将完全按照以前的方式继续工作。您可以逐步迁移到新索引或重建现有索引时的自定义 schema。

API 参考

有关所有 RedisVectorStore 功能和配置的详细文档,请访问 API 参考.