langchain知识库分割、加载、检索

本文介绍了如何使用LangChain库进行Markdown文本分割、嵌入、向量存储和检索,包括OpenAIEmbeddings、HuggingFaceBGE模型、Chroma向量数据库以及上下文压缩检索技术。作者展示了如何加载数据、创建向量数据库并执行文档查询以获取相关信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先看完整初级代码,再看我一块一块说明,每一块都可以扩展

import os

import torch
from langchain.text_splitter import MarkdownTextSplitter
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.embeddings import HuggingFaceBgeEmbeddings
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMChainExtractor
from modelscope import AutoModelForCausalLM, AutoTokenizer
def pretty_print_docs(docs):
    print(f"\n{'-' * 100}\n".join([f"Document {i+1}:\n\n" + d.page_content for i, d in enumerate(docs)]))

def load_data(path):
    '''
    加载数据
    :param path: md文件路径
    :return:
    '''
    with open(path,'r',encoding='utf-8') as files:
        markdown_text = files.read()
    markdown_splitter = MarkdownTextSplitter(chunk_size=500, chunk_overlap=50)
    docs = markdown_splitter.create_documents([markdown_text])  # 分割
    for i,m in enumerate(docs):
        print(i,m)
    '''
    embedding 数据    无openai key
    
    embeddings = OpenAIEmbeddings()
    docsearch = Chroma.from_texts(docs,embeddings)
    query = "什么是肤质?"
    doc = docsearch.similarity_search(query)
    print(doc[0].page_content)
    '''
    model_name = r"bge-large-zh"
    model_kwargs = {'device': 'cpu'}
    encode_kwargs = {'normalize_embeddings': True}
    model = HuggingFaceBgeEmbeddings(
        model_name=model_name,
        model_kwargs=model_kwargs,
        encode_kwargs=encode_kwargs
    )


    '''
    向量数据库,使用chroma
    '''
    # 向量数据库保存位置
    persist_directory = 'chroma/'

    # 检查持久化目录是否存在
    if os.path.exists(persist_directory) and len(os.listdir(persist_directory)) > 0:  # 检查目录是否为空
        print("Chroma数据库已存在,无需重复创建.")
        vectordb = Chroma(persist_directory=persist_directory, embedding_function=model)
    else:
        # 创建向量数据库
        vectordb = Chroma.from_documents(
            documents=docs,
            embedding=model,
            persist_directory=persist_directory
        )
        vectordb.persist()  # 向量数据库的持久化

    # 查看向量数据库中的文档数量
    print("向量数据库中的文档数量",vectordb._collection.count())

    '''
    向原有数据库添加内容
    #docsearch.add_texts(["Ankush went to Princeton"]) # 添加文本

    #docsearch = Chroma.from_texts(docs, model)
    '''

    '''
    从向量数据库中检索与问题相关的数据
    '''
    query = "什么是肤质?"
    # doc = vectordb.similarity_search(query,k=3)  # 寻常检索
    doc = vectordb.max_marginal_relevance_search(query, k=3)  # 使用mmr检索,可过滤相似度高的文档

    # 上下文压缩检索
    compressor = LLMChainExtractor.from_llm(llm)

    compression_retriever = ContextualCompressionRetriever(
        base_compressor=compressor,
        base_retriever=vectordb.as_retriever()
    )
    question = "什么是肤质?"
    compressed_docs = compression_retriever.get_relevant_documents(question)
    pretty_print_docs(compressed_docs)
    # 打印文档数量
    print("文档数量 ",len(doc))
    print("第一个文档 ",doc[0].page_content)


if __name__ == '__main__':
    load_data('beautiful bible.md')

def pretty_print_docs(docs):
    print(f"\n{'-' * 100}\n".join([f"Document {i+1}:\n\n" + d.page_content for i, d in enumerate(docs)]))

这个代码用来打印检索出的文档信息,类型基本是列表

接下来是load data用来加载、分割、检索数据

    with open(path,'r',encoding='utf-8') as files:
        markdown_text = files.read()
    markdown_splitter = MarkdownTextSplitter(chunk_size=500, chunk_overlap=50)
    docs = markdown_splitter.create_documents([markdown_text])  # 分割

这个代码是open我的markdown文档,然后根据500大小,50重复分割,具体见langchain技术文档Markdown文本分割器# – LangChain中文网

    model_name = r"bge-large-zh"
    model_kwargs = {'device': 'cpu'}
    encode_kwargs = {'normalize_embeddings': True}
    model = HuggingFaceBgeEmbeddings(
        model_name=model_name,
        model_kwargs=model_kwargs,
        encode_kwargs=encode_kwargs
    )

这个代码是加载embedding模型bge-large-zh,如果有网络困难,可以手动去bge-large-zh · 模型库 (modelscope.cn)这里下载后放在代码同级,里面也有很多方式加载模型,我选择langchain方法。解释一下为什么要在"bge-large-zh"前面加r,因为这个模型文件与代码同级,但是我不想用绝对路径,用相对路径的话又会自动去huggingface下载模型,所以我加r就可以识别到本地的模型了

# 向量数据库保存位置
    persist_directory = 'chroma/'

    # 检查持久化目录是否存在
    if os.path.exists(persist_directory) and len(os.listdir(persist_directory)) > 0:  # 检查目录是否为空
        print("Chroma数据库已存在,无需重复创建.")
        vectordb = Chroma(persist_directory=persist_directory, embedding_function=model)
    else:
        # 创建向量数据库
        vectordb = Chroma.from_documents(
            documents=docs,
            embedding=model,
            persist_directory=persist_directory
        )
        vectordb.persist()  # 向量数据库的持久化

    # 查看向量数据库中的文档数量
    print("向量数据库中的文档数量",vectordb._collection.count())

具体实现见Chroma# – LangChain中文网,需要判断persist_directory文件是否存在,不要重复加载了,用Chroma.from_documents()创建向量数据库,docs是文档,且要persist向量持久化。如果存在了,则可以直接用Chroma()加载存在的数据库

query = "什么是肤质?"
    # doc = vectordb.similarity_search(query,k=3)  # 寻常检索
    doc = vectordb.max_marginal_relevance_search(query, k=3)  # 使用mmr检索,可过滤相似度高的文档

正常检索和用mmr检索,mmr检索可以少点重复内容,返回k个答案。以上代码连起来可以运行,不需要加上下文压缩检索。

# 上下文压缩检索
    compressor = LLMChainExtractor.from_llm(llm)

    compression_retriever = ContextualCompressionRetriever(
        base_compressor=compressor,
        base_retriever=vectordb.as_retriever()
    )
    question = "什么是肤质?"
    compressed_docs = compression_retriever.get_relevant_documents(question)
    pretty_print_docs(compressed_docs)

检索方法使用上下文压缩检索,具体见将字符串压缩器和文档转换器连在一起# – LangChain中文网

大致有原始的压缩和llm的压缩,这样输出可以少点字数,否则只会输出原文。

其中本代码中compressor = LLMChainExtractor.from_llm(llm)是可以选择llm=openai(),但是作者想要用本地自定义模型的api,但是作者目前没写出来,所以就搁置一下。先用ollama的见Llama-cpp# – LangChain中文网

    llm = Ollama(base_url="",
                 model="ggml-model-q4_0.gguf",
                 callback_manager=CallbackManager([StreamingStdOutCallbackHandler()]))

使用ollama的gguf的模型,由于官网没有qwen的gguf,具体量化看我下一篇文章。但是在windows跑不起来,base_url也需要一个代码,后续补充。

以上所有内容都可以在界面中选择不同的类型,如知识库增加删除、模型选择等。后续再搞

### 使用 LangChain 构建知识库 #### 安装必要的依赖项 为了使用 LangChain 构建知识库,首先需要安装一些基础的 Python 库。这些库包括但不限于 `langchain` 和其他辅助工具。 ```bash pip install langchain transformers torch faiss-cpu neo4j ``` #### 初始化项目并加载预训练模型 初始化一个新的 Python 文件作为项目的入口点,并导入所需的模块: ```python from langchain import KnowledgeBase, VectorStore, LLM import torch from transformers import AutoTokenizer, AutoModelForSeq2SeqLM ``` 创建一个函数来加载预先训练好的语言模型 (LLM),这一步骤对于后续的数据处理至关重要[^1]。 #### 数据准备与预处理 收集待加入知识库中的文档资料,并对其进行清洗和分词等预处理工作。可以利用正则表达式去除无关字符或将长篇文章分割成较短片段以便更好地被索引。 #### 向量化文本内容 将经过清理后的纯文本转化为数值型特征向量表示形式,便于之后存入矢量数据库中进行高效查询匹配。这里推荐采用 FAISS 或者其他的相似度搜索引擎实现快速检索功能。 ```python vector_store = VectorStore() for doc in processed_documents: vector_representation = convert_to_vector(doc.text) vector_store.add(vector_representation, metadata=doc.metadata) def convert_to_vector(text): tokenizer = AutoTokenizer.from_pretrained('model-name') model = AutoModelForSeq2SeqLM.from_pretrained('model-name') inputs = tokenizer.encode_plus( text, max_length=512, padding='max_length', truncation=True, return_tensors="pt" ) with torch.no_grad(): outputs = model.generate(inputs['input_ids']) embeddings = outputs.last_hidden_state.mean(dim=1).squeeze().numpy() return embeddings.tolist() ``` #### 集成 LLM 提升问答质量 通过集成大型语言模型(LLM),可以在用户提问时不仅限于返回最接近的问题答案对,而是能够理解上下文背景给出更贴切的回答建议。当接收到一个问题请求时,先从向量空间里找到最近邻的文章段落,再传递给 LLM 进行最终润色加工。 ```python llm_model = LLM.load("path/to/your/model") def get_answer(question): nearest_doc_id = find_nearest_document(question) context = fetch_context(nearest_doc_id) prompt = f"Given the following context:\n{context}\nAnswer this question: {question}" response = llm_model(prompt=prompt) return response.generated_text ``` #### 存储结构化信息至图数据库 除了传统的键值对或关系型表格外,还可以考虑把实体间的关系以图形的方式保存下来形成所谓的“知识图谱”。借助 Neo4j 等专用软件可以方便地管理和可视化复杂网络结构内的节点及其相互作用情况[^2]。 ```python graph_db.connect(url="bolt://localhost", username="neo4j", password="password") entities = extract_entities_from_texts(processed_documents) relationships = infer_relationships_between(entities) for entity in entities: graph_db.create_node(label=entity.type, properties={"name": entity.name}) for rel in relationships: start_node = find_entity_by_name(rel.source) end_node = find_entity_by_name(rel.target) graph_db.create_relationship(start=start_node, type=rel.label, end=end_node) ``` 以上就是使用 LangChain 搭建本地知识库系统的概览过程,具体细节可能因实际应用场景而有所不同,请根据需求调整相应参数设置和技术选型[^1]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值