Langchain-Chatchat的markdownHeaderTextSplitter使用

文章目录

    • 背景
    • 排查步骤
      • 官方issue排查
      • 测试正常对话
      • 测试官方默认知识库
      • Debug排查
        • vscode配置launch.json
        • 命令行自动启动conda
        • debug知识库搜索
        • 测试更换ChineseRecursiveTextSplitter分词器
      • 结论
    • 关于markdownHeaderTextSplitter的探索
      • 标准的markdown测试集
      • Langchain区分head1和head2
      • Langchain区分head1,head2,head3
      • Langchain-Chatchat测试结果
      • 分析Langchain-Chatchat的markdown文件加载
      • 为什么Langchain-Chatchat会丢失标题
    • 后记

背景

接上篇Langchain-Chatchat之pdf转markdown格式,pdf转markdown之后,使用官方的markdownHeaderTextSplitter分词器,创建完知识库之后进行问答,结果发现大模型无法正常返回,且日志报错如下:

  File "/home/jfli/anaconda3/envs/py3.11/lib/python3.11/site-packages/langchain_community/chat_models/openai.py", line 493, in _astreamif len(chunk["choices"]) == 0:^^^^^^^^^^^^^^^^^^^^^
TypeError: Caught exception: object of type 'NoneType' has no len()

markdownHeaderTextSplitter这个分词器和markdown格式不是天生一对吗?为什么会出现这种报错?

排查步骤

官方issue排查

  1. https://github.com/chatchat-space/Langchain-Chatchat/issues/2062
    1. 重新install dashscope 无效
    2. 升级fschat 无效
  2. https://github.com/chatchat-space/Langchain-Chatchat/issues/3727
    1. 官方回答说这种类型的回答都代表大模型输出内容不对导致的。
    2. 所以就是要确认大模型是可用的,确认知识库的搜索结果是否符合预期。

测试正常对话

正常对话没问题,且大模型回复自己是千问,说明大模型也正常加载使用。

测试官方默认知识库

测试sample知识库的问题,结果是可以正常回复。说明大模型对于知识库的问答是生效的状态。

Debug排查

vscode配置launch.json
{// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387"version": "0.2.0","configurations": [{"name": "Langchain-Chatchat","type": "debugpy","request": "launch","program": "${workspaceFolder}/startup.py","args": ["-a"],"console": "integratedTerminal","python": "/home/xxx/anaconda3/envs/py3.11/bin/python"}]
}

命令行自动启动conda

因为环境依赖都在conda下,如果不配置自动开启conda的话,服务会因为缺少依赖起不来。

配置launch.json的参数中没办法设置conda环境。有一种使用方法是先定义个task.json,在launch.json中定义preLaunchTask制定先运行task.json,在task.json中启动conda环境。
参考:利用launch.json和tasks.json 文件进行vscode 调试以及自动编译_tasks.json make编译-CSDN博客
经验证,没有成功。
第二种方法是直接修改zshrc文件,在文件下面新增:

conda activate py3.11

这样每次打开新的终端都会自动启动conda环境,缺点就是每次启动py3.11环境,如果需要切换环境的话需要自己手动切换。

debug知识库搜索
  1. 初始化模型
    1. 实例化模型的时候,api地址对应的端口是20000image.png
  2. 查看知识库搜索结果
    1. 可以看到在向量库已经拿到数据了,根据向量返回的内容组装context,请求大模型出错。image.png
    2. 查看启动配置,发现model_worker已经正常启动了
2024-05-11 17:52:50 | INFO | model_worker | Register to controller
INFO:     Started server process [3818873]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:7861 (Press CTRL+C to quit)
  1. 为什么请求大模型是走的20000这个端口呢?而不是配置中的21012端口?
    1. langchain-chatchat中默认的openai 端口是20000,这个配置会作为api_base传递给ChatOpenAI类,最后组装langchain的LLMChain,发起大模型请求。
    2. 目前发现请求大模型的地址
http://127.0.0.1:20000/v1/chat/completions# 这个地址是初始化openai的时候,使用fastchat提供的fastapi路由,
# 文件在fastchat.serve.openai_api_server# qianwen 大模型实际部署的端口是21012,对不上,是否会是这个问题呢?
  1. 参考fastchat的文档:https://github.com/lm-sys/FastChat/blob/main/docs/openai_api.md
    1. http://127.0.0.1:20000是fastchat启动的restful的api地址,同时也要启动模型工作线程 fastchat.serve.model_worker
    2. 测试fastchat中是否可以调用本地的qianwen-14B的模型
# 查看当前启动的模型
curl "http://127.0.0.1:20000/v1/models"# 返回了qianwen-14B
{"object":"list","data":[
{"id":"Qwen1.5-14B-Chat","object":"model","created":1715421368,
"owned_by":"fastchat","root":"Qwen1.5-14B-Chat","parent":null,
"permission":[{"id":"modelperm-4dMH93oGAz7eFLMoAdKegr","object":"model_permission","created":1715421368,"allow_create_engine":false,"allow_sampling":true,"allow_logprobs":true,"allow_search_indices":true,"allow_view":true,"allow_fine_tuning":false,"organization":"*","group":null,"is_blocking":false}
]}]}# 查看启动的模型
curl -X POST "http://127.0.0.1:20001/list_models"
{"models":["Qwen1.5-14B-Chat"]}# 和模型交流
curl http://localhost:20000/v1/chat/completions \-H "Content-Type: application/json" \-d '{"model": "Qwen1.5-14B-Chat","messages": [{"role": "user", "content": "Hello! What is your name?"}]}'# 模型回答{"id":"chatcmpl-3ySLAgNaGJUqXcbu39cAmf","object":"chat.completion","created":1715421533,"model":"Qwen1.5-14B-Chat","choices":[{"index":0,"message":{"role":"assistant","content":"Hello! My name is Assistant. I'm here to help you with any questions or tasks you need assistance with. How can I help you today?"},"finish_reason":"stop"}],"usage":{"prompt_tokens":25,"total_tokens":55,"completion_tokens":30}}
  3. 结论是访问20000端口请求大模型没问题,fastchat可以找到启动的大模型实例。20000端口是fastchat的controller地址,实际的大模型由model_worker启动。
  1. 错误堆栈追踪
    1. 追踪堆栈发现是调用langchain的langchain_core/language_models/chat_models.py,调用了_agenerate_with_cache函数,但并没有命中cache,走了617行
    2. 命中langchain_community/chat_models/openai.py的_agenerate函数
    3. 最终报错是在langchain_community/chat_models/openai.py的_astream函数,代码如下:
        async for chunk in await acompletion_with_retry(self, messages=message_dicts, run_manager=run_manager, **params):if not isinstance(chunk, dict):chunk = chunk.dict()if len(chunk["choices"]) == 0:continuechoice = chunk["choices"][0]# 错误代码
if len(chunk["choices"]) == 0:
  1. 拿到知识库返回的context,手动调用大模型查询试试?
    1. 知识库返回5w多个字符,不符合预期。
    2. 从返回内容上来看,充斥着大量的"##############" ,不符合我们的预期。使用MarkdownHeaderTextSplitter只是想保留标题,按照标题来分块,而不是污染原来的文档。
  2. 更改markdownHeaderTextSplitter的配置
    1. 默认的配置如下image.png
    2. 更改为只保留head1和head2看看
      1. 结果依然不行,文档含有大量的"##############",且分块只有2个。如果是textSplitter的话,分块有165个,比较正常。
      2. 猜测是markdownHeaderTextSplitter适合标准格式的markdown文件,我们这里把pdf转换成markdown并不标准,格式不统一。此时通过markdownHeaderTextSplitter分词识别到的head1和head2比较少,导致分块只有2个。
      3. langchain-chatchat中分词配置中的chunkSize和overlapSize对markdownHeaderTextSplitter不生效。如果markdown文件不标准的话,可能一个块有几w个字,会影响大模型的输出。
    3. 更改markdownHeaderTextSplitter的配置到head6
      1. 知识库分块明显多了,从2个块变成了35个块。
      2. 部分问答可以出来,部分问答依然返回错误

测试更换ChineseRecursiveTextSplitter分词器
  1. 可以正常被搜索到,返回1216个字符
  2. 返回的内容依然是带有markdown格式的内容,保留了表格的关系
  3. 知识库查看数据可以正常分块,一共165个块。image.png

结论

pdf转markdown之后生成的markdown格式不够标准,这种情况下使用markdownHeadertextSplitter进行分词的效果不符合预期。
且因为配置文件中的chunkSize和overlapSize对markdownHeaderTextSplitter不生效,导致分块结果很差,一个块几万个字。
大模型是拿到知识库查询的结果,作为"context"传过去的,几万个字传给大模型,直接导致大模型推理时间过久且没有返回结果。

关于markdownHeaderTextSplitter的探索

标准的markdown测试集

# 查特查特团队
荣获AGI Playground Hackathon黑客松“生产力工具的新想象”赛道季军。
## 报道简介
2023年10月16日, Founder Park在近日结束的AGI Playground Hackathon黑客松比赛中,查特查特团队展现出色的实力,荣获了“生产力工具的新想象”赛道季军。本次比赛由Founder Park主办,并由智谱、Dify、Zilliz、声网、AWS云服务等企业协办。
## 获奖队员简介
+ 小明,A大学+ 负责Agent旅游助手的开发、场地协调以及团队住宿和行程的安排+ 在保证团队完赛上做出了主要贡献。作为队长,栋宇坚持自信,创新,沉着的精神,不断提出改进方案并抓紧落实,遇到相关问题积极请教老师,提高了团队开发效率。
# 你好啊
## 世界你好
比赛吸引了120多支参赛团队,最终有36支队伍进入决赛,其中34支队伍成功完成了路演。
## 中国你好
比赛吸引了120多支参赛团队,最终有36支队伍进入决赛,其中34支队伍成功完成了路演。
# 中午吃什么
## 世纪难题
比赛吸引了120多支参赛团队,最终有36支队伍进入决赛,其中34支队伍成功完成了路演。
## 为什么选择吃什么这么难
比赛吸引了120多支参赛团队,最终有36支队伍进入决赛,其中34支队伍成功完成了路演。
## 现在的年轻人到底需要什么?
比赛吸引了120多支参赛团队,最终有36支队伍进入决赛,其中34支队伍成功完成了路演。
# 早睡早起
## 为什么晚睡
比赛吸引了120多支参赛团队,最终有36支队伍进入决赛,其中34支队伍成功完成了路演。
## 晚睡的危害是什么
比赛吸引了120多支参赛团队,最终有36支队伍进入决赛,其中34支队伍成功完成了路演。

Langchain区分head1和head2

image.png

Langchain区分head1,head2,head3

image.png
可以看到文档划分还是符合预期的。Langchain官方给出的测试demo没问题。

Langchain-Chatchat测试结果

更改markdown文件及分词器配置

  1. markdown文件包含一级,二级,三级标题
  2. 分词器只包含head1和head2

测试结果

  1. 依然只有一个文档
  2. 删除了md的分割标识符
  3. 保留了标题和内容的关系
  4. 没有保留标题的meta信息,不符合预期。
查特查特团队  
荣获AGI Playground Hackathon黑客松“生产力工具的新想象”赛道季军。  
报道简介  
2023年10月16日, Founder Park在近日结束的AGI Playground Hackathon黑客松比赛中,查特查特团队展现出色的实力,荣获了“生产力工具的新想象”赛道季军。本次比赛由Founder Park主办,并由智谱、Dify、Zilliz、声网、AWS云服务等企业协办。  
获奖队员简介  
小明,A大学  
负责Agent旅游助手的开发、场地协调以及团队住宿和行程的安排  
在保证团队完赛上做出了主要贡献。作为队长,栋宇坚持自信,创新,沉着的精神,不断提出改进方案并抓紧落实,遇到相关问题积极请教老师,提高了团队开发效率。  
你好啊  
世界你好  
比赛吸引了120多支参赛团队,最终有36支队伍进入决赛,其中34支队伍成功完成了路演。  
中国你好  
比赛吸引了120多支参赛团队,最终有36支队伍进入决赛,其中34支队伍成功完成了路演。  
杭州你好啊  
比赛吸引了120多支参赛团队,最终有36支队伍进入决赛,其中34支队伍成功完成了路演。  
中午吃什么  
世纪难题  
比赛吸引了120多支参赛团队,最终有36支队伍进入决赛,其中34支队伍成功完成了路演。  
为什么选择吃什么这么难  
比赛吸引了120多支参赛团队,最终有36支队伍进入决赛,其中34支队伍成功完成了路演。    
年轻人要什么?  
比赛吸引了120多支参赛团队,最终有36支队伍进入决赛,其中34支队伍成功完成了路演。  
早睡早起  
为什么晚睡  
比赛吸引了120多支参赛团队,最终有36支队伍进入决赛,其中34支队伍成功完成了路演。  
为什么不早睡  
比赛吸引了120多支参赛团队,最终有36支队伍进入决赛,其中34支队伍成功完成了路演。

分析Langchain-Chatchat的markdown文件加载

  1. 测试发现langchain-chatchat加载markdown文件使用的是langchain的markdown document loader
  2. 测试结果如下image.png
  3. 也就是document loader的结果文件是没有markdown标识的,因此会导致进行markdownHeaderTextSplitter的时候,无法正确的按照标题来分割数据。
  4. document loader加上mode=“elements” 参数,发现可以区分标题了image.png
  5. 测试markdownHeaderTextSplitter的效果
    1. 如果加上mode=“elements” 参数的话,markdown_splitter.split_text(markdown_document[0].page_content)的返回image.png
    2. 如果不加 mode=“elements” 参数的话,结果是一整块image.png
    3. 添加mode="elements"并且使用循环去进行split_text :
      1. image.png
      2. 这个结果也不是符合预期的,只有文档内容page_content,没有meta信息,也没有标题信息。

为什么Langchain-Chatchat会丢失标题

正如这篇文章所说: https://community.deeplearning.ai/t/loading-markdown-from-file-for-splitting/575875 langChain 中的 Markdown 加载器(UnstructedMarkdownLoader)删除了示例中分割文本所需的 Markdown 字符(例如:#、##、###)。所以按照标题分块是行不通的。

  1. 但是可以使用TextLoader来原样加载markdown文件,如下:image.png
  2. 结合markdownHeaderTextSplitter
    1. image.png
    2. 成功记录了标题信息,分块很成功!

后记

开源项目开箱即用是好事,但是直接拿来做产品还是欠佳的,怪不得大家最终都会走到自定义分词器的步骤,业务的需求千变万化,代码都掌握在自己手里才能以不变应万变啊。
就这样吧,还是挺有意思的。

end

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/840803.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux驱动(2)---Linux内核的组成

1.Linux内核源码目录 arch包含和硬件体系相关结构相关源码,每个平台占用一个目录 block:块设备驱动程序I/O调度 crypto:常用加密和三列算法,还有一些压缩和CRC校验算法。 documentation:内核个部分的通用解释和注释.。 drive…

01_尚硅谷JavaWeb最新版笔记

尚硅谷JAVAWEB概述 课程概述 计划学习时间:1周以内

【2024软考】史上最全!软考刷题+解析大合集(9万字全手工打,货真价实)

计算机基础知识 1.中断向量表用来保存各个中断源的中断服务程序的入口地址。当外设发出中断请求信号(INTR)以后,由中断控制器(INTC)确定其中断号,并根据中断号查找中断向量表来取得其中断服务程序的入口地…

第86天:代码审计-PHP项目TP框架安全写法1day利用0day分析

案例一: 利用框架漏洞-TP3框架-SQL注入&Demo&YxtCMF 首先先查询thinkphp的版本 去寻找版本漏洞: Thinkphp3.2.3及以下版本漏洞整理_thinkphp3.2.3漏洞-CSDN博客 去查这个exp注入 这里的利用条件是必须有find方法,并且where后面的参数是数组 …

java基础-JVM日志、参数、内存结构、垃圾回收器

一、基础基础 1.1 数据类型 Java的数据类型分为原始数据类型和引用数据类型。 原始数据类型又分为数字型和布尔型。 数字型又有byte、short、int、long、char、float、double。注意,在这里char被定义为整数型,并且在规范中明确定义:byte、…

电赛一等奖!基于TMS320F2812的简易数字频率计

电赛一等奖!简易数字频率计设计(原理图、PCB、源码、分析报告) 这份文件是关于合肥工业大学电气与自动化工程学院的一个项目报告,题目为“基于TMS320F2812的简易数字频率计”。项目由方敏、侯其立、李苗、张巧云四位本科生完成&am…

Redis 哨兵机制的工作原理——Java全栈知识(22)

Redis 哨兵机制的工作原理 在之前的文章我们讲到了 Redis 的三种集群架构:跳转文章:Redis集群模式 接下来我们详细讲哨兵机制的作用以及实现原理 以下是 Redis 哨兵的结构图 1、Redis 哨兵的作用 哨兵的作用如下: 1、监控,2、…

【ArcGIS微课1000例】0111:谷歌地球Google Earth下载安装与使用教程

一、谷歌地球安装 双击安装包,默认点击完成即可。 二、谷歌地球使用 打开快捷方式,开始使用谷歌地球。欢迎界面: 软件主界面: 三、谷歌地球下载 软件安装包位于《ArcGIS微课实验1000例(附数据)专栏配套完数据包中的0111.rar中…

企业如何防止数据泄密?大型企业必备的文件加密软件

随着信息化建设的大步推进,越来越多的企业资料以电子文件的形式保存,企业内部和企业之间的信息交流也主要依靠电子文件。近年来的泄密事件层出不穷,比如东软泄密案、HTC窃密案、力拓案等,给企业带来灾难性的经济损失及信誉重创。如…

出题123

题目时限空间说明 无特殊均默认 1 s , 256 M B 1s,256MB 1s,256MB Problem a 最大化 在最大化目标值的基础上选择的操作越多越好,且输出操作应当按照顺序执行,即你的输出顺序就是你的执行顺序,当有多个执行顺序可以最大化目标值时&#xff0…

python中的条件语句

python中语句的执行顺序 默认情况下,python代码的执行顺序,是从上到下依次执行的,这个顺序是不会变的, python中的条件语句 电脑的CPU芯片是能够进行算术运算也能进行逻辑判断的。 条件语句能够表达“如果...否则...” 这样的语…

基于51单片机的数字频率计(电路图+pcb+论文+仿真+源码)

于51单片机的数字频率计 设计的频率计范围能够达到1HZ-1MHZ(实际上51单片机达不到这个范围,不要在实验环境下进行),这个是课设来着,用Proteus仿真实现的,给有需要的同学参考一下 仿真原理图如下(proteus仿真工程文件可…

面试八股之JVM篇3.6——垃圾回收——强引用、弱引用、虚引用、软引用

🌈hello,你好鸭,我是Ethan,一名不断学习的码农,很高兴你能来阅读。 ✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。 🏃人生之义,在于追求,不在成败,勤通…

Javascript特效之鼠标悬停特效【css】

先看一看效果&#xff0c;是不是很炫酷啊&#xff1f;&#xff1f; HTML代码&#xff1a; <!DOCTYPE html> <html><head><meta charset""UTF-8"" /><title>CSS特效&#xff1a;鼠标悬停效果</title><link rel&q…

SQL分类——DDL(数据定义语言)

一、DDL&#xff08;数据定义语言&#xff09; &#xff08;1&#xff09;DDL——数据库——操作的相关语法&#xff1a; 查询 可以一次性查询当前数据库服务器中所有的数据库&#xff1a; SHOW DATABASES; 查询当前所处的数据库&#xff1a; SELECT DATABASE(); 创建 一般最简…

Python | Leetcode Python题解之第101题对称二叉树

题目&#xff1a; 题解&#xff1a; class Solution:# 在【100. 相同的树】的基础上稍加改动def isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool:if p is None or q is None:return p is qreturn p.val q.val and self.isSameTree(p.left, q.ri…

Transformer详解(1)-结构解读

Transormer块主要由四个部分组成&#xff0c;注意力层、位置感知前馈神经网络、残差连接和层归一化。 1、注意力层(Multi-Head Attention) 使用多头注意力机制整合上下文语义&#xff0c;它使得序列中任意两个单词之间的依赖关系可以直接被建模而不基于传统的循环结构&#…

基于.net开发的博客系统

基于.net开发可以批量上传md文件生成文章的博客系统 .NET 个人博客 基于.net开发的博客系统 个人博客系统&#xff0c;采用.net core微服务技术搭建&#xff0c;采用传统的MVC模式&#xff0c;使用EF core来对mysql数据库(sqlite数据库)进行CRUD操作项目 为什么要自己开发博客…

clion读取文件设置为读取当前目录下的文件

1.问题 使用vs读取文件时一切正常 但是同样的代码在clion中无法正常执行 原因 原因&#xff1a;clion的源文件找不到input.txt文件的位置 需要设置工作目录&#xff0c;例如此时input.txt在当前目录下&#xff0c;那么就设置 设置当前文件的工作目录为$FileDir$即可&am…

Ubuntu 如何根据NVIDIA显卡型号确定对应的显卡驱动版本并安装

目录 一、查询推荐安装的驱动版本 二、安装推荐版本的驱动 1. 通过终端安装&#xff0c;只安装 nvidia 驱动&#xff08;亲测可用&#xff01;&#xff09; 2. 通过 software & Updates 安装&#xff0c;安装 nvidia 驱动。 三、查询能安装的最新的显卡驱动版本 1. 方…