Langchain-Chatchat的markdownHeaderTextSplitter使用

news2025/3/1 0:59:12

文章目录

    • 背景
    • 排查步骤
      • 官方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

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

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

相关文章

小白跟做江科大32单片机之学习准备

1.安装好51MDK之后,出现不能正常安装支持包的情况 在线安装支持包——>在keil5软件下点击这个,即可进入更新支持包界面 进去之后找这个 国产的可以找和这个 最后有这个就可以了

【人工智能项目】小车障碍物识别与模型训练(完整工程资料源码)

实物演示效果: 一、绪论: 1.1 设计背景 小车障碍物识别与模型训练的设计背景通常涉及以下几个方面: 随着自动驾驶技术的发展,小车(如无人驾驶汽车、机器人等)需要能够在复杂的环境中自主导航。障碍物识别是实现这一目标的关键技术之一,它允许小车检测并避开路上的障碍物…

JavaScript 动态网页实例 —— 表格处理

表格是网页设计中必不可少的内容之一。本章首先介绍HTML中普通表格的组成结构,然后,在此基础上,介绍如何使用JavaScript设置表格的属性。随后,更具体地介绍操作表格元素的一般方法,主要是对表格行、列的动态增删操作。有了这些基础,在本章的最后介绍对表元的操作,即如何…

C语言 | Leetcode C语言题解之第108题将有序数组转换为二叉搜索树

题目: 题解: struct TreeNode* helper(int* nums, int left, int right) {if (left > right) {return NULL;}// 选择任意一个中间位置数字作为根节点int mid (left right rand() % 2) / 2;struct TreeNode* root (struct TreeNode*)malloc(sizeo…

生产制造边角料核算说明及ODOO演示

今天群里有伙伴提到边角料的处理问题,我们梳理了一下,在生产过程中,如果产生了边角料,核算产成品的投料成本时需要考虑边角料的价值,以确保成本核算的准确性。以下是注意的几点: 一、边角料的入账价值 在生…

poi操作word模板,对原有的word修改

/*** 化工园区调查表** param templatePath* param outPath* param parkInterview*/public static String getDocx(String templatePath, String outPath, ParkInterview parkInterview){File file new File(templatePath);File file1 new File(outPath);if(!file1.exists()…

初识C语言——第二十五天

函数的嵌套调用和链式访问 函数不可以嵌套定义&#xff0c;但可以嵌套调用 链式访问&#xff1a;把一个函数的返回值作为另外一个函数的参数 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h>//写一个函数&#xff0c;每调用一次这个函数&#xff0c;就会 将num…

ArcGIS批量更改所有符号的格式

这期谈一下&#xff0c;如何修改所有符号的样式。 比如&#xff0c;我们需要更改下图的面符号位无轮廓的 该如何批量修改的呢&#xff1f; 视频教学吧&#xff1a; ArcGIS批量更改所有符号的格式 ArcGIS全系列实战视频教程——9个单一课程组合系列直播回放-CSDN博客文章浏览阅…

OracleDG原理

一、DataGuard架构介绍 1、基本介绍 在DG环境中&#xff0c;至少会有两个数据库&#xff0c;一个数据库处于Open状态&#xff0c;对外提供服务&#xff0c;这个数据库叫做primary Database。第二个数据库处于恢复状态&#xff0c;叫做Standby Database。运行时Primay Databas…

C# 正则表达式使用小计

此文档用于记录平时使用正则表达式的心得&#xff0c;不定期更新 基础 实例 替换实例一 //这里匹配以 “( 开头,以 )” 结尾的字符串 private static Regex REGEX_ARG_CONTENT new Regex("""(.*?)""");//此方法用于在匹配到的结果前添加字符…

TG5032CGN TCXO 超高稳定10pin端子型适用于汽车动力转向控制器

TG5032CGN TCXO / VC-TCXO是一款应用广泛的晶振&#xff0c;具有超高稳定性&#xff0c;CMOS输出和使用晶体基振的削波正弦波输出形式。且有低相位噪声优势&#xff0c;是温补晶体振荡器(TCXO)和压控晶体振荡器(VCXO)结合的产物&#xff0c;具有TCXO和VCXO的共同优点&#xff0…

微网群如何协调控制?基于目标级联法的微网群多主体分布式优化调度程序代码!

前言 微电网将分布式电源(distributed generation&#xff0c;DG)与负荷组成有机整体&#xff0c;通过控制策略降低了分布式电源直接并网对大电网的影响&#xff0c;是分布式电源友好并网的有效手段。随着微电网的不断发展&#xff0c;局部范围内的多个微电网互相联结形成微网…

学习记录16-反电动势

一、反电动势公式 在负载下反电势和端电压的关系式为&#xff1a;&#x1d448;&#x1d43c;&#x1d445;&#x1d43f;*&#xff08;&#x1d451;&#x1d456; / &#x1d451;&#x1d461;&#xff09;&#x1d438; E为线圈电动势、 &#x1d713; 为磁链、f为频率、N…

大语言模型预训练新前沿:「最佳适配打包」重塑文档处理标准

源自&#xff1a;机器之心 “人工智能技术与咨询” 发布 声明:公众号转载的文章及图片出于非商业性的教育和科研目的供大家参考和探讨&#xff0c;并不意味着支持其观点或证实其内容的真实性。版权归原作者所有&#xff0c;如转载稿涉及版权等问题&#xff0c;请立即联系我们…

颠覆传统编码,零基础也能飞的工具!

YDUIbuilder以其低代码的设计理念&#xff0c;通过简单的拖拽操作&#xff0c;即使是编程新手也能快速构建出专业的用户界面。这不再是一个遥不可及的梦想&#xff0c;而是一个触手可及的现实。 组件化世界&#xff0c;创意无限&#xff1a;构建梦想中的界面 在YDUIbuilder的组…

java项目之人事系统源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的人事系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 基于vue的人事系统的主要使用者…

软件无线电学习-第二代移动通信系统过程理解

本文知识内容摘自《软件无线电原理和应用》 无线通信领域让大家感受最深的是民用移动通信的快速发展。民用移动通信在短短的二十年时间里已发展了三代&#xff1a;20世纪80年代的模拟体制(TACS/AMPS)为第一代移动通信(简称1G)&#xff1b;20世纪90年代的数字体制(GSMCDMATDMA)…

.NET快速实现网页数据抓取

网页数据抓取需求 本文我们以抓取博客园10天推荐排行榜第一页的文章标题、文章简介和文章地址为示例&#xff0c;并把抓取下来的数据保存到对应的txt文本中。 请求地址&#xff1a;https://www.cnblogs.com/aggsite/topdiggs 创建控制台应用 创建名为DotnetSpiderExercise的控…

呆马科技----构建智能可信的踏勘云平台

近年来&#xff0c;随着信息技术的快速发展&#xff0c;各个行业都在积极探索信息化的路径&#xff0c;以提升工作效率和服务质量。智慧踏勘云平台是基于区块链和大数据技术构建的全流程智慧可信踏勘解决平台。平台集远程视频、数据显示、工作调度、过程记录为一体&#xff0c;…

5.23 Linux中超时检测方式+模拟面试

1.IO多路复用的原理&#xff1f; IO多路复用使得一个或少量线程资源处理多个连接的IO事件的技术。对于要处理的多个阻塞的IO操作&#xff0c;建立集合并存储它们的文件描述符&#xff0c;利用单个阻塞函数去监控集合中文件描述符事件到达的情况&#xff0c;&#xff08;如果到…