基于LangChain的本地知识库问答机器人

介绍

众所周知 OpenAI 的 API 无法联网的,所以如果只使用自己的功能实现联网搜索并给出回答、总结 PDF 文档、基于某个 Youtube 视频进行问答等等的功能肯定是无法实现的。所以,我们来介绍一个非常强大的第三方开源库:LangChain 。
文档地址:https://python.langchain.com/en/latest/
这个库目前非常活跃,每天都在迭代,已经有 22k 的 star,更新速度飞快。
LangChain 是一个用于开发由语言模型驱动的应用程序的框架。他主要拥有 2 个能力:

  • 可以将 LLM 模型与外部数据源进行连接
  • 允许与 LLM 模型进行交互

LLM 模型:Large Language Model,大型语言模型

基础功能

LLM 调用

  • 支持多种模型接口,比如 OpenAI、Hugging Face、AzureOpenAI …
  • Fake LLM,用于测试
  • 缓存的支持,比如 in-mem(内存)、SQLite、Redis、SQL
  • 用量记录
  • 支持流模式(就是一个字一个字的返回,类似打字效果)

Prompt管理,支持各种自定义模板
拥有大量的文档加载器,比如 Email、Markdown、PDF、Youtube …
对索引的支持

  • 文档分割器
  • 向量化
  • 对接向量存储与搜索,比如 Chroma、Pinecone、Qdrand

Chains

  • LLMChain
  • 各种工具Chain
  • LangChainHub

必知概念

Loader 加载器

顾名思义,这个就是从指定源进行加载数据的。比如:文件夹 DirectoryLoader、Azure 存储 AzureBlobStorageContainerLoader、CSV文件 CSVLoader、印象笔记 EverNoteLoader、Google网盘 GoogleDriveLoader、任意的网页 UnstructuredHTMLLoader、PDF PyPDFLoader、S3 S3DirectoryLoader/S3FileLoader、

Document 文档

当使用loader加载器读取到数据源后,数据源需要转换成 Document 对象后,后续才能进行使用。

Text Spltters 文本分割

顾名思义,文本分割就是用来分割文本的。为什么需要分割文本?因为我们每次不管是做把文本当作 prompt 发给 openai api ,还是还是使用 openai api embedding 功能都是有字符限制的。

比如我们将一份300页的 pdf 发给 openai api,让他进行总结,他肯定会报超过最大 Token 错。所以这里就需要使用文本分割器去分割我们 loader 进来的 Document。

Vectorstores 向量数据库

因为数据相关性搜索其实是向量运算。所以,不管我们是使用 openai api embedding 功能还是直接通过向量数据库直接查询,都需要将我们的加载进来的数据 Document 进行向量化,才能进行向量运算搜索。转换成向量也很简单,只需要我们把数据存储到对应的向量数据库中即可完成向量的转换。

Chain 链

我们可以把 Chain 理解为任务。一个 Chain 就是一个任务,当然也可以像链条一样,一个一个的执行多个链。

Agent 代理

我们可以简单的理解为他可以动态的帮我们选择和调用chain或者已有的工具。
执行过程可以参考下面这张图:
在这里插入图片描述

Embedding

用于衡量文本的相关性。这个也是 OpenAI API 能实现构建自己知识库的关键所在。
他相比 fine-tuning 最大的优势就是,不用进行训练,并且可以实时添加新的内容,而不用加一次新的内容就训练一次,并且各方面成本要比 fine-tuning 低很多。

实战

DeepSeek API-key

DeepSeek API 使用与 OpenAI 兼容的 API 格式,通过修改配置,可以使用 OpenAI SDK 来访问 DeepSeek API,或使用与 OpenAI API 兼容的软件。
DeepSeek开放平台:https://platform.deepseek.com(在此申请API-KEY)
API文档:https://api-docs.deepseek.com/zh-cn/

本地知识库问答

import os
# from langchain.document_loaders import UnstructuredFileLoader
from langchain.chains.summarize import load_summarize_chain
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai.chat_models.base import BaseChatOpenAI
from langchain.prompts import PromptTemplate
from langchain.chains.question_answering import load_qa_chain
# from langchain_community.document_loaders import UnstructuredFileLoader
from langchain_unstructured import UnstructuredLoader

# 配置管理
API_KEY = os.getenv('DEEPSEEK_API_KEY', 'api-key')
API_BASE = os.getenv('DEEPSEEK_API_BASE', 'https://api.deepseek.com')

try:
    # 导入文本
    loader = UnstructuredLoader("测试.txt")  #切换为本地知识库路径
    document = loader.load()
    print(f'documents:{len(document)}')

    # 初始化文本分割器
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=500,
        chunk_overlap=0
    )

    # 切分文本
    split_documents = text_splitter.split_documents(document)
    print(f'documents:{len(split_documents)}')

    # 加载 llm 模型
    llm = BaseChatOpenAI(
        model='deepseek-chat',
        openai_api_key=API_KEY,
        openai_api_base=API_BASE,
        max_tokens=1024
    )

    # 定义问答提示模板
    qa_template = """你是一个专家,根据用户提问给出精准的回答,精简内容,避免冗余:{context}
    问题:{question}"""
    QA_PROMPT = PromptTemplate(template=qa_template, input_variables=["context", "question"])

    # 创建问答链
    qa_chain = load_qa_chain(llm, chain_type="stuff", prompt=QA_PROMPT)

    print("进入连续问答模式,输入 '退出' 结束问答。")
    while True:
        question = input("请输入问题:")
        if question == "退出":
            break
        answer = qa_chain.invoke({"input_documents": split_documents, "question": question})["output_text"]
        print("答案:", answer)

except Exception as e:
    print(f"An error occurred: {e}")

参考文档

https://liaokong.gitbook.io/llm-kai-fa-jiao-cheng#gou-jian-ben-di-zhi-shi-ku-wen-da-ji-qi-ren

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值