Langchain-Chatchat之pdf转markdown格式

文章目录

背景

在使用Langchain-Chatchat做RAG的时候,发现导入的pdf文件中的表格关系无法保存,导致LLM的回答不符合预期。例如我想问的内容在表格中,但LLM的回答并不是对表格的总结。

那么想要解决这个问题,就需要找到一种合适的文本格式来保留表格间的关系,然后修改Langchain-Chatchat的文本加载源码,使pdf文本转换成目标的文本格式,也就是本篇的markdown格式。

开发环境

  • RAG框架: Langchain-Chatchat
  • 大模型: Qwen1.5-14B-Chat
  • 资源要求: GPU显存
    • 14B双精度约等于14*2,加上embeding模型,大约30G的显存
    • CPU>8核即可
  • Prompt: 使用Langchain-Chatchat为知识库配置的默认Prompt。

loader文本解析步骤

Langchain-Chatchat默认对pdf文件使用的loader是mypdfloader.py,解析文档的流程如下:

  1. 调用server/api.py中的/knowledge_base/upload_docs 上传文档
  2. 通过KnowledgeFile这个类来实现文档解析,文档分词等功能
  3. 调用mypdfloader.py加载pdf文件,使用pyMuPDF包的fitz解析pdf文档
  4. 获取pdf中的text内容
  5. 针对图片使用ocr模块进行解析,获取图片中的文本
  6. text和图片文本连接到一起,作为文档的内容
  7. 调用unstructured.partition.text import partition_text 进行文本段落划分
  8. 使用默认的ChineseRecursiveTextSplitter进行分词,存储到向量库

出问题的地方就在于加载pdf文件的部分,把表格作为普通的文本加载,自然就保存不了表格的关系了。

markdown格式的文本

Blog - Artifex
RAG分块策略的五个级别

为什么选择markdown格式

  1. markdown可以支持"基于文档的分块"
  2. 提取出markdown格式,支持保留表格的行,列关系
  3. 结构化的内容更有利于LLM大模型理解和上下文保存

在 LLM 和 RAG 环境中使用 Markdown 文本格式可确保更准确和相关的结果,因为它为 LLM 提供了更丰富的数据结构和更相关的数据块加载。

测试markdown格式提取表格

相比于text格式的分词来说,markdown格式的分词可以保留表格的数据和关系

,例如下面的表格。

原pdf表格
markdown格式的表格

可以看到表格关系都保留下来了。

测试markdown格式的知识库

运行项目

参考官方的开发环境搭建 即可。因为使用的是大模型是Qwen1.5-14B-Chat,因此需要更改模型配置文件的路径,读取Qwen1.5-14B-Chat。

markdown 复制代码
# model_config.py
MODEL_ROOT_PATH = "你的本地模型地址path"
LLM_MODELS = ["Qwen1.5-14B-Chat"]
MODEL_PATH = {
  "llm_model":{
    "Qwen1.5-14B-Chat": "modelPath/Qwen1.5-14B-Chat",
  }
}

# server_config.py
FSCHAT_MODEL_WORKERS = {
  # 给Qwen-14b不同的启动端口,不然会默认使用default
    "Qwen1.5-14B-Chat": {
        "host": DEFAULT_BIND_HOST,
        "port": 21012,
        "device": LLM_DEVICE,
        "infer_turbo": False,
        # model_worker多卡加载需要配置的参数
        "gpus": "0,1,2,3", # 使用的GPU,以str的格式指定,如"0,1",如失效请使用CUDA_VISIBLE_DEVICES="0,1"等形式指定
        "num_gpus": 4, # 使用GPU的数量
    },
}

修改文件加载器loader

  1. 使用pdf4llm读取文件: https://pymupdf.readthedocs.io/en/latest/rag.html
    1. 安装 https://github.com/pymupdf/RAG/
  2. 修改document_loaders/mypdfloader.py
markdown 复制代码
import pdf4llm
def pdf2markdown_text(filepath):
    doc = pdf4llm.to_markdown(filepath, pages=None)
    return doc

# pdf转markdown
from unstructured.partition.md import partition_md
text = pdf2markdown_text(self.file_path)
# 这里使用partition_md的分段
return partition_md(text=text, **self.unstructured_kwargs)
  1. 使用默认的ChineseRecursiveTextSplitter分词器
  2. web端页面新建知识库,导入pdf文件即可
  3. 测试表格问答效果
    1. 脚手架的搭设高度以及对应的安全等级
    2. pdf文档
    3. 大模型回答
    4. 可以看到保留了表格的关系,大模型做的总结是正确的。

其他问题

运行项目报错

raise OSError(errno.ENOSPC, "inotify watch limit reached")
OSError: [Errno 28] inotify watch limit reached

streamlit可能需要开启大量的inotify实例来监视文件系统的改动,因此可以手动增加max_user_watches的值来解决。

一般程序监视某个或某些目录的文件是否被创建、修改、删除等等就需要启动inotify实例,但是每一个inotify实例都需要消耗一定量的内存。

查看系统当前的max_user_watches
# 查看当前系统中的max_user_instances数量
cat /proc/sys/fs/inotify/max_user_instances
max_user_instances 控制着一个单一用户(或者用户ID,UID)可以创建的 inotify 实例的最大数量。

# 查看当前系统中的max_user_watches数量
cat /proc/sys/fs/inotify/max_user_watches
max_user_watches 控制着一个用户可以添加到所有 inotify 实例中的监视项(watches)的总数。

# 增大max_user_instances的值 (修改成10240还是启动不了,得修改成102400)
sudo sysctl -w fs.inotify.max_user_watches=102400
修改sysctl.conf配置
# 目前把这一行配置给加到/etc/sysctl.conf中去了,设置成102400
fs.inotify.max_user_watches=102400
# 执行一次sysctl.conf配置
sudo sysctl -p /etc/sysctl.conf
# 这样的好处是不需要重新启动系统即可应用更改,并且在每次系统启动时会自动将此值设置为 102400。

图片提取问题

经过测试,有的图片内容能提取出来,有的提取不出来 -- 建议还是加一个图片提取函数

  1. 图片中的逻辑关系会丢失,例如:
  2. 因为ppt排版中有文字和图片,会丢失一些逻辑关系,例如:文字1 图片1 ,在解析的时候会分别加载,失去了文字1 和图片1的逻辑关系
怎么提取图片内容
  1. 目前pdf4llm不支持图片的读取
  2. 可以看到在langchain中的使用,是文字提取+图片提取
    1. 参考:https://github.com/langchain-ai/langchain/blob/master/libs/community/langchain_community/document_loaders/parsers/pdf.py#L218
    2. _extract_images_from_page 函数
      1. 也是使用的OCR模块
    3. 不同的地方在于,langchain的pdfloader是text+img的方式。不是我们想要的markdown的方式,可以再添加一个提取图片的函数来完善markdown文件。

使用Milvus向量库报错

markdown 复制代码
AssertionError: A list of valid ids are required when auto_id is False.
或
milvus error: KeyError: 'pk'

参考:https://github.com/langchain-ai/langchain/issues/17172

原因是Langchain-Chatchat中milvus的默认配置是auto_id=False,也就是说需要自己提供主键。但是在代码中没有发现有添加主键的部分,因此导入到milvus会报错。

修复方法也比较简单,直接在初始化Milvus的时候设置auto_id=True即可,如下:

markdown 复制代码
    def _load_milvus(self):
        self.milvus = Milvus(embedding_function=EmbeddingsFunAdapter(self.embed_model),
         collection_name=self.kb_name,
         connection_args=kbs_config.get("milvus"),
         auto_id=True,
         index_params=kbs_config.get("milvus_kwargs")["index_params"],
         search_params=kbs_config.get("milvus_kwargs")["search_params"]
         )

end

相关推荐
Langchain3 分钟前
不可错过!CMU最新《生成式人工智能大模型》课程:从文本、图像到多模态大模型
人工智能·自然语言处理·langchain·大模型·llm·大语言模型·多模态大模型
墨染辉7 小时前
10.2 如何解决从复杂 PDF 文件中提取数据的问题?
pdf
shandianchengzi11 小时前
【记录】Excel|Excel 打印成 PDF 页数太多怎么办
pdf·excel
bianshaopeng20 小时前
android 原生加载pdf
android·pdf
卢卡斯23320 小时前
在线PDF怎么转换成JPG图片?分享14种转换操作!
pdf
J不A秃V头A1 天前
iTextPDF中,要实现表格中的内容在数据长度超过边框时自动换行
java·pdf
我爱学Python!1 天前
基于 LangChain 的自动化测试用例的生成与执行
人工智能·自然语言处理·langchain·自动化·llm·测试用例·大语言模型
嘻嘻仙人2 天前
【杂谈一之概率论】CDF、PDF、PMF和PPF概念解释与分析
pdf·概率论·pmf·cdf
资深前端之路2 天前
vue2 将页面生成pdf下载
前端·vue.js·pdf
Eiceblue2 天前
Python 复制PDF中的页面
vscode·python·pdf