【LangChain】langchain_community.vectorstores.docarray.DocArrayInMemorySearch 类:基于 DocArray 库实现的内存向量存储

langchain_community.vectorstores.docarray.in_memory.DocArrayInMemorySearch(以下简称 DocArrayInMemorySearch)是 LangChain 框架中基于 DocArray 库实现的内存向量存储类,专为小型数据集和快速原型开发设计。它支持将文本文档转换为嵌入向量并存储在内存中,提供高效的相似性搜索功能,广泛应用于语义搜索、检索增强生成(RAG)和对话系统等场景。本文将从定义、核心功能、创建方法、应用场景、示例代码和注意事项等方面,系统讲解 DocArrayInMemorySearch 的功能与使用方法。


一、定义与作用

1. 什么是 DocArrayInMemorySearch

DocArrayInMemorySearch 是 LangChain 社区模块中的一个向量存储实现,基于 DocArray 库的内存索引功能。它通过在 RAM 中存储嵌入向量,支持快速的精确最近邻搜索(exact nearest-neighbor search)。与需要数据库服务器的持久化向量存储(如 Chroma、Pinecone)不同,DocArrayInMemorySearch 完全运行在内存中,适合临时或小型数据处理。

  • 核心功能

    • 在内存中存储文档的嵌入向量,支持快速相似性搜索。
    • 兼容多种嵌入模型(如 OpenAIEmbeddings、HuggingFaceEmbeddings)。
    • 支持文档和文本的动态添加、搜索和删除操作。
    • 提供最大边际相关性(MMR)搜索,优化结果的相关性和多样性。
    • 作为 LangChain VectorStore 接口的实现,与框架的其他组件无缝集成。
  • 设计目标

    • 提供轻量级、易于使用的向量存储解决方案,降低开发门槛。
    • 适合快速原型开发、测试和学习场景,无需复杂配置。
    • 支持小型数据集的语义搜索和上下文检索。
2. 为什么需要 DocArrayInMemorySearch

在 LLM 应用中,向量存储用于将文本转换为嵌入向量并进行相似性搜索,以支持语义检索和上下文增强。DocArrayInMemorySearch 的优势在于:

  • 简单性:无需设置外部数据库,适合快速上手。
  • 速度:内存操作提供低延迟的搜索性能。
  • 灵活性:支持动态更新和多种搜索方式,适应多种实验场景。

从官方文档来看,它特别适合处理数百到数千条记录的小型数据集,例如在开发初期测试 RAG 系统或语义搜索功能。


二、核心功能与特性

DocArrayInMemorySearch 提供了一系列功能,使其成为小型向量存储的理想选择。以下是其核心特性和方法的详细说明:

1. 内存存储
  • 特性:所有数据(文档、嵌入向量、元数据)存储在 RAM 中,提供快速访问。
  • 限制:受内存容量限制,不适合大规模数据集;程序终止后数据丢失(非持久化)。
2. 嵌入支持
  • 特性:支持任何符合 LangChain Embeddings 接口的嵌入模型,用于将文本转换为向量。
  • 常见嵌入模型
    • OpenAIEmbeddings:基于 OpenAI 的文本嵌入模型。
    • HuggingFaceEmbeddings:基于 Hugging Face 的开源模型。
    • SentenceTransformerEmbeddings:用于生成高质量句子嵌入。
3. 搜索功能
  • 精确最近邻搜索:遍历所有向量,找到与查询最相似的文档,适合小型数据集。
  • 最大边际相关性(MMR)搜索:平衡搜索结果的相关性和多样性,减少冗余。
  • 带分数的搜索:返回文档及其相似性分数,便于排序和过滤。
4. 文档与文本管理
  • 文档支持:处理 langchain_core.documents.Document 对象,包含文本内容(page_content)和元数据(metadata)。
  • 文本支持:直接处理字符串列表,适合快速测试。
  • 动态更新:支持添加或删除文档/文本,灵活管理存储内容。
5. 异步支持
  • 提供同步方法(如 similarity_search)和异步方法(如 asimilarity_search),支持并发操作。
6. 检索器集成
  • 可以通过 as_retriever() 方法转换为 LangChain 的 VectorStoreRetriever,用于链式操作或代理系统。
关键方法

以下是 DocArrayInMemorySearch 的主要方法及其功能:

方法 描述 参数示例 返回值 备注
from_documents(documents, embeddings) 从文档和嵌入模型初始化向量存储 documents: List[Document], embeddings: Embeddings DocArrayInMemorySearch 实例 常用于初始化文档集合
from_texts(texts, embeddings, metadatas) 从文本列表和嵌入模型初始化向量存储 texts: List[str], embeddings: Embeddings, metadatas: List[dict] DocArrayInMemorySearch 实例 适合快速测试文本数据
add_documents(documents) 添加新文档到存储 documents: List[Document] List[str](文档 ID) 支持动态扩展存储
add_texts(texts, metadatas) 添加新文本到存储 texts: List[str], metadatas: List[dict] List[str](文本 ID) -
similarity_search(query, k=4) 根据查询字符串搜索最相似的 k 个文档 query: str, k: int List[Document] 默认返回 4 个结果
similarity_search_with_score(query, k=4) 搜索并返回文档及相似性分数 query: str, k: int List[Tuple[Document, float]] 分数范围通常为 0-1(余弦相似性)
max_marginal_relevance_search(query, k=4, lambda_mult=0.5) MMR 搜索,优化相关性和多样性 query: str, k: int, lambda_mult: float List[Document] lambda_mult 控制相关性与多样性平衡
get_by_ids(ids) 根据 ID 获取文档 ids: List[str] List[Document] 从版本 0.2.11 起支持,ID 不存在时不抛异常
delete(ids) 根据 ID 删除文档 ids: List[str] bool/None 删除后内存可能需要手动释放
as_retriever() 将向量存储转换为检索器 - VectorStoreRetriever 实例 用于链式操作或代理系统

三、创建与使用方法

创建和使用 DocArrayInMemorySearch 的典型流程包括以下步骤:

  1. 准备数据

    • 使用 LangChain 的文档加载器(如 TextLoader)加载原始数据。
    • 使用文本分割器(如 CharacterTextSplitter)将长文档分割为小块,生成 Document 对象列表。
  2. 选择嵌入模型

    • 初始化一个嵌入模型(如 OpenAIEmbeddings),用于将文本转换为向量。
  3. 初始化向量存储

    • 使用 from_documentsfrom_texts 方法创建 DocArrayInMemorySearch 实例。
  4. 执行搜索

    • 使用 similarity_searchmax_marginal_relevance_search 方法检索相关文档。
示例代码:基本使用

以下是一个完整的示例,展示如何加载文档、初始化向量存储并进行相似性搜索:

from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import CharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import DocArrayInMemorySearch
from langchain_core.documents import Document

# 1. 准备文档(示例使用手动创建的 Document)
documents = [
    Document(page_content="巴黎是法国的首都,位于塞纳河畔。", metadata={"source": "wiki_paris"}),
    Document(page_content="伦敦是英国的首都,以大本钟闻名。", metadata={"source": "wiki_london"}),
    Document(page_content="东京是日本的首都,人口众多。", metadata={"source": "wiki_tokyo"})
]

# 2. 初始化嵌入模型
embeddings = OpenAIEmbeddings()

# 3. 创建向量存储
db = DocArrayInMemorySearch.from_documents(documents, embeddings)

# 4. 执行相似性搜索
query = "法国的首都是哪里?"
results = db.similarity_search(query, k=2)

# 5. 输出结果
for doc in results:
    print(f"内容: {doc.page_content}")
    print(f"元数据: {doc.metadata}")

输出示例

内容: 巴黎是法国的首都,位于塞纳河畔。
元数据: {'source': 'wiki_paris'}
内容: 伦敦是英国的首都,以大本钟闻名。
元数据: {'source': 'wiki_london'}
示例代码:从文本初始化

如果没有 Document 对象,可以直接使用文本列表:

texts = [
    "Python 是一种简单易学的编程语言。",
    "LangChain 是一个用于构建 LLM 应用的框架。",
    "DocArray 是一个多模态数据处理库。"
]
metadatas = [
    {"category": "programming"},
    {"category": "AI"},
    {"category": "library"}
]

db = DocArrayInMemorySearch.from_texts(texts, embeddings, metadatas=metadatas)
results = db.similarity_search("LLM 框架是什么?", k=1)
print(results[0].page_content)

输出

LangChain 是一个用于构建 LLM 应用的框架。

四、常见用途与应用场景

DocArrayInMemorySearch 在 LangChain 的多种场景中表现出色,以下是其主要应用场景:

1. 快速原型开发
  • 场景:在开发初期,快速测试 RAG 系统或语义搜索功能,无需设置复杂数据库。
  • 示例:测试文档检索效果,验证嵌入模型的性能。
  • 优势:无需外部依赖,代码简单,适合实验。
2. 小型数据集处理
  • 场景:处理数百到数千条记录的文本数据,例如公司内部文档、FAQ 列表。
  • 示例:为小型知识库构建语义搜索功能。
  • 优势:内存存储提供低延迟,适合小规模应用。
3. 学习与教学
  • 场景:学习 LangChain 或向量存储的工作原理,理解嵌入和相似性搜索。
  • 示例:在教程或课程中演示向量存储的基本操作。
  • 优势:易于配置,适合初学者。
4. 临时任务
  • 场景:需要临时存储和检索数据,例如分析一次性数据集或调试模型输出。
  • 示例:分析用户反馈的语义相似性。
  • 优势:无需持久化,数据随程序生命周期结束而清除。
5. 对话系统支持
  • 场景:在对话系统中存储对话历史或相关文档,供模型检索上下文。
  • 示例:为聊天机器人提供背景知识检索。
  • 优势:动态添加文档,支持实时更新。

五、示例代码:RAG 工作流

以下是一个结合 RAG 的完整示例,展示 DocArrayInMemorySearch 在问答系统中的应用:

from langchain_core.documents import Document
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import DocArrayInMemorySearch
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough

# 1. 准备文档
documents = [
    Document(page_content="巴黎是法国的首都,人口约220万,位于塞纳河畔。", metadata={"source": "wiki"}),
    Document(page_content="伦敦是英国的首都,拥有大本钟和伦敦眼。", metadata={"source": "wiki"}),
]

# 2. 初始化嵌入和向量存储
embeddings = OpenAIEmbeddings()
db = DocArrayInMemorySearch.from_documents(documents, embeddings)

# 3. 创建检索器
retriever = db.as_retriever(search_kwargs={"k": 1})

# 4. 定义提示模板
template = ChatPromptTemplate.from_messages([
    ("system", "根据以下上下文回答问题:\n{context}"),
    ("human", "{question}")
])

# 5. 创建 RAG 链
model = ChatOpenAI(model="gpt-4o")
chain = (
    {"context": retriever, "question": RunnablePassthrough()}
    | template
    | model
)

# 6. 执行查询
response = chain.invoke("巴黎有多少人口?")
print(response.content)

输出示例

巴黎的人口大约为220万。

六、注意事项与最佳实践

  1. 数据规模

    • 仅适合小型数据集(数百到数千条记录)。对于大规模数据,考虑使用持久化向量存储(如 Chroma、Pinecone)。
    • 监控内存使用情况,避免因数据量过大导致溢出。
  2. 嵌入模型选择

    • 选择合适的嵌入模型,确保向量质量。例如,OpenAIEmbeddings 适合高质量嵌入,但需 API 密钥;HuggingFaceEmbeddings 适合开源场景。
    • 确保嵌入模型与数据语言和任务匹配。
  3. 搜索优化

    • 使用 max_marginal_relevance_search 提高结果多样性,适合需要多角度信息的场景。
    • 调整 k 参数,控制返回结果数量,避免过多无关文档。
  4. 元数据管理

    • 为文档设置有意义的元数据(如 sourcecategory),便于后续过滤和分析。
    • 保持元数据结构一致,避免键值类型不统一。
  5. 持久化需求

    • 如果需要数据持久化,考虑其他向量存储(如 Chroma 或 FAISS),或在程序结束后手动保存数据。
  6. 版本兼容性

    • 确保使用最新版本的 LangChain(如 0.2.x),因为社区模块的 API 在早期版本可能不同。
    • 安装 DocArray 依赖:pip install docarray
  7. 错误处理

    • 检查嵌入模型是否正确配置(如 API 密钥是否有效)。
    • 确保输入文档或文本不为空,否则可能抛出异常。

七、总结

langchain_community.vectorstores.docarray.in_memory.DocArrayInMemorySearch 是 LangChain 框架中一个轻量级的内存向量存储实现,基于 DocArray 库,提供快速的嵌入存储和相似性搜索功能。它适合小型数据集、快速原型开发和学习场景,通过简单的 API 支持文档管理、动态更新和多种搜索方式。尽管受内存限制和非持久化的约束,它在开发初期或临时任务中表现出色,与 LangChain 的链、代理和检索器无缝集成。

通过理解其功能、创建方法和应用场景,开发者可以高效利用 DocArrayInMemorySearch 构建语义搜索、RAG 系统和对话应用。对于需要扩展到大规模数据的场景,建议迁移到持久化向量存储。

参考资源

  • LangChain 官方文档:DocArrayInMemorySearch
  • LangChain API 参考:DocArrayInMemorySearch
  • DocArray 官方文档

你可能感兴趣的:(LangChain,langchain,DocArrayInMemor,DocArray,向量存储,相似性搜索)