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 _astream
    if 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:
                continue
            choice = 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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Notes for video: EDC-Con 2022/01 - EDC Conceptual Overview and Architecture

Eclipse Dataspace Connector 中文概念 Eclipse Dataspace Connector (EDC) 是一个开源项目,旨在提供一种标准化的方法来连接和共享数据空间中的数据。它是 Eclipse Foundation 下的一个项目,目标是促进数据共享和数据交换的互操作性。以下是 EDC 的一些…

【前端学习——react坑】useState使用

问题 使用useState 时,例如 const [selectedId, setSelectedId] useState([false,true,false]);这样直接利用,无法引发使用selectedId状态的组件的变化,但是selectedId是修改了的 let tempselectedId;temp[toggledId]selectedId[toggledId…

MySQL数据库的数据文件保存在哪?MySQL数据存在哪里

在安装好MySQL数据库使用一段时间后,会产生许多的数据库和数据。那这些数据库的数据文件存放在本地文件夹的什么位置呢 一、默认位置 一般来说MySQL数据库的数据文件都是存放在data文件夹之中,但是根据使用的存储引擎不同,产生的一些文件也…

C++初阶之模板进阶

个人主页:点我进入主页 专栏分类:C语言初阶 C语言进阶 数据结构初阶 Linux C初阶 算法 欢迎大家点赞,评论,收藏。 一起努力,一起奔赴大厂 目录 一.非类型模板参数 二.模板的特化 2.1引入 2.2全特化 2.3…

关于pytest中用例名称使用中文乱码的解决

场景:使用pytest.mark.parametrize装饰器为用例自定义名称时,运行显示乱码。如下图所示: 解决方案: 1.在根目录 pytest.ini中增加一行代码 [pytest] disable_test_id_escaping_and_forfeit_all_rights_to_community_supportTrue…

Point-Nerf 理论笔记和理解

文章目录 什么是point nerf 和Nerf 有什么区别Point Nerf 核心结构有哪些?什么是point-based radiance field? 点云位置以及置信度是怎么来Point pruning 和 Point Growing 什么是point nerf 和Nerf 有什么区别 基本的nerf 是通过过拟合MLP来完成任意视角场景的重…

【CTF Web】CTFShow web6 Writeup(SQL注入+PHP+位运算)

web6 1 阿呆一口老血差点噎死自己&#xff0c;决定杠上了 解法 注意到&#xff1a; <!-- flag in id 1000 -->拦截很多种字符&#xff0c;连 select 也不给用了。 if(preg_match("/\|\"|or|\||\-|\\\|\/|\\*|\<|\>|\^|\!|x|hex|\(|\)|\|select/i"…

IOS开发者证书快捷申请

App Uploader 在进行iOS应用开发中,可以借助appuploader辅助工具进行证书制作、上传和安装测试等操作。首先,您需要访问官方网站获取最新版本的appuploader。最新版本已经优化了与Apple账号的登录流程,无需支付688元,并提供了Windows版和Mac版供用户选择。下载完成后,解压…

地质考察AR远程交互展示系统辅助老师日常授课

广东这片充满活力的土地&#xff0c;孕育了一家引领ARVR科技潮流的杰出企业——深圳华锐视点&#xff0c;作为一家专注于VR/AR技术研究与业务开发的先锋公司。多年来&#xff0c;我们不断突破技术壁垒&#xff0c;将AR增强现实技术与各行各业的实际需求完美结合&#xff0c;助力…

【lambdastreammaven】

lambda 匿名函数 为了简化java中的匿名内部类 事件监听 写一个类 实现 ActionListener 接口 (外部类) | | 内部类 类在其他地方用不到, 索性就把这个类定义在类的内部使用 好处: 1.内部可以使用外部类的成员 …

都2024年了!是谁还不会优化 Hive 的小文件啊!!!速看!

文章目录 小文件产生的原因1.查询建表或者插入2.装载数据3.动态分区小文件影响解决方法针对已经存在的小文件进行优化1.小文件归档2.getmerge3.concatenate4.重写针对写入数据时的优化1.调参优化2.动态分区优化3.使用 Spark 算子控制小文件数量查看 HDFS 上的文件时,无意间点进…

已有yarn集群部署spark

已有yarn集群的情况下&#xff0c;部署spark只需要部署客户端。 一、前提条件 已部署yarn集群&#xff0c;部署方式参考&#xff1a;https://blog.csdn.net/weixin_39750084/article/details/136750613?spm1001.2014.3001.5502&#xff0c;我部署的hadoop版本是3.3.6已安装j…

Java的结构与运行机制

1. JDK JRE JVM三者的区别 JDK(Java Development Kit)&#xff1a;Java开发工具包 JDK包含JRE&#xff0c;还包括其他例如&#xff1a;编译器(javac)、javadoc、jar等&#xff0c;JDK是能够创建和编译程序的。 JRE(Java runtime environment)&#xff1a;Java运行环境 JRE是运…

逻辑分析仪 - 采样率/采样深度

采样深度&#xff08;Sampling Depth&#xff09; 采样深度指的是逻辑分析仪在一次捕获过程中可以记录的最大样本数量。简单来说&#xff0c;采样深度越大&#xff0c;逻辑分析仪可以记录的数据量就越多。这对于分析长时间的信号变化或复杂的信号序列非常重要。 采样率&#…

java面试(JVM)

JVM是什么 Java Virtual Machine Java程序的运行环境&#xff08;java二进制字节码的运行环境&#xff09; 好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收机制 JVM由哪些部分组成&#xff0c;运行流程是什么 什么是程序计数器 程序计数器…

uniapp微信小程序解决type=“nickname“获取昵称,v-model绑定值为空问题!

解决获取 type"nickname"值为空问题 文章目录 解决获取 type"nickname"值为空问题效果图Demo解决方式通过表单收集内容通过 uni.createSelectorQuery 效果图 开发工具效果图&#xff0c;真机上还会显示键盘输入框 Demo 如果通过 v-model 结合 blur 获取不…

Python数据分析实验四:数据分析综合应用开发

目录 一、实验目的与要求二、主要实验过程1、加载数据集2、数据预处理3、划分数据集4、创建模型估计器5、模型拟合6、模型性能评估 三、主要程序清单和运行结果四、实验体会 一、实验目的与要求 1、目的&#xff1a; 综合运用所学知识&#xff0c;选取有实际背景的应用问题进行…

YOLOv8_pose训练流程-原理解析[关键点检测理论篇]

本篇将介绍一下YOLOv8关键点检测网络的训练流程,同样在看此篇文章之前先去看一下预测流程[YOLOv8_pose预测流程-原理解析[关键点检测理论篇],还有目标检测任务的训练流程YOLOv8训练流程-原理解析[目标检测理论篇] ,这两篇都是前置课程,下图是YOLOv8实例分割的网络结构图。 …

C语言笔记22 •结构体•

C语言结构体 1.结构体类型的声明 struct Stu { char name[ 20 ]; // 名字 int age; // 年龄 char sex[ 5 ]; // 性别 char id[ 20 ]; // 学号 }; 2.结构体变量的创建和初始化 #include <stdio.h>// 定义一个结构体类型 Point struct Point {int x;int y; };i…

pikachu-Unsafe Filedownload

任意点击一个图片进行下载&#xff0c;发现下载的url。 http://127.0.0.1/pikachu/vul/unsafedownload/execdownload.php?filenamekb.png 构造payload&#xff1a; 即可下载 当前页面的源码&#xff0c;可以进行路径穿越来下载一些重要的配置文件来获取信息。 http://127.0.…