LangChain教程 | langchain 文本拆分器 | Text Splitters全集

news2024/12/21 20:29:14

        在阅读本文前,建议先看下langchain的基础,最主要的是先看下langchain 文档加载器使用教程有关的内容,会更容易把知识串联起来。

概述

        一旦加载了文档,您通常会想要转换它们以更好地适应您的应用程序。最简单的例子是,您可能希望将一个长文档分割成更小的块,以便适合模型的上下文窗口。LangChain有许多内置的文档转换器,可以轻松地拆分、组合、过滤和操作文档。

        当你想处理很长的文本时,有必要将文本分割成块。虽然这听起来很简单,但这里有很多潜在的复杂性。理想情况下,您希望将语义相关的文本片段放在一起。“语义相关”的含义可能取决于文本的类型。示例展示了几个方法来做到这一点。

概括地说,文本拆分器的工作方式如下:

  1. 将文本分成语义上有意义的小块(通常是句子)。
  2. 开始将这些小块组合成一个更大的块,直到达到一定的大小(通过某些函数来测量)。
  3. 一旦达到该大小,将该文本块作为自己的文本块,然后开始创建一个有一些重叠的新文本块(以保持文本块之间的上下文)。

这意味着您可以沿着两个不同的轴自定义文本拆分器:

  1. 文本的拆分方式
  2. 如何测量区块大小

①、文本拆分器的类型

        LangChain提供了许多不同类型的文本拆分器。这些都存在langchain-text-splitters包里。下表列出了所有的因素以及一些特征:

Name:文本拆分器的名称

Splits on:此文本拆分器如何拆分文本

Adds Metadata:此文本拆分器是否添加关于每个块来源的元数据。

Description:拆分器的描述,包括何时使用它的建议。

NameSplits OnAdds MetadataDescription
RecursiveA list of user defined characters递归拆分文本。递归分割文本的目的是试图将相关的文本片段保持在一起。这是开始拆分文本的推荐方式。
HTMLHTML specific characters基于特定于HTML的字符拆分文本。值得注意的是,这添加了关于该块来自何处的相关信息(基于HTML)
MarkdownMarkdown specific characters基于特定于Markdown的字符拆分文本。值得注意的是,这增加了关于该块来自哪里的相关信息(基于降价)
CodeCode (Python, JS) specific characters基于特定于编码语言的字符拆分文本。有15种不同的语言可供选择。
TokenTokens拆分令牌上的文本。有几种不同的方法来衡量token。
CharacterA user defined character基于用户定义的字符拆分文本。一种更简单的方法。
[Experimental] Semantic ChunkerSentences首先对句子进行拆分。然后,如果它们在语义上足够相似,就将它们组合在一起。取自Greg Kamradt

②、评估文本拆分器

        您可以使用Chunkviz实用程序由Greg Kamradt创造.,Chunkviz是一个很好的工具,可视化你的文本拆分器是如何工作的。它将向您展示文本是如何拆分的,并帮助调整拆分参数。(这里不展开说,本文主要还是讲拆分器有关内容。)

一、按字符拆分 Split by character

        这是最简单的方法。这将基于字符进行拆分(默认情况下为 ““),并根据字符数测量块长度。

  1. 文本如何拆分:按单个字符拆分。
  2. 如何测量块大小:通过字符数。
pip install -qU langchain-text-splitters

在网上找一篇长文章,然后复制到spilitters_text.txt文本中,用于测试用例 

例如:人民财评:花香阵阵游人醉,“春日经济”热力足

# This is a long document we can split up.
with open("../../splitters_test.txt") as f:
    state_of_the_union = f.read()
- separators - 分隔符字符串数组
- chunk_size - 每个文档的字符数量限制
- chunk_overlap - 两份文档重叠区域的长度
- length_function - 长度计算函数
- is_separator_regex - 如果为真:应当被解释为正则表达式,因此不需要转义。如果为假:应当被当作普通字符串分隔符,并转义任何特殊字符。
from langchain_text_splitters import CharacterTextSplitter

text_splitter = CharacterTextSplitter(
    separator="\n\n",
    chunk_size=1000,
    chunk_overlap=200,
    length_function=len,
    is_separator_regex=False,
)

texts = text_splitter.create_documents([state_of_the_union])
print(texts[0])

打印结果:只打印了第一段文字

这是一个将元数据与文档一起传递的示例,请注意它是与文档一起分割的。

meta_datas = [{"document": 1}, {"document": 2}]
documents = text_splitter.create_documents(
    [state_of_the_union, state_of_the_union], metadatas=meta_datas
)
print(len(documents))
print(documents[0])
print(documents[3])

 这里清晰看到分成了2个文档数据。 

上面返回的都是以文档格式获取到数据,另外还有一种是直接得到字符串数据。

text_splitter.split_text(state_of_the_union)[0]

开头不再是page_content,而是双引号,这就是字符串格式。

二、按字符递归拆分 Recursively split by character

        对于通用文本,建议使用此文本拆分器。它由字符列表参数化。它试图按顺序分割它们,直到这些块足够小。默认列表是["\n\n", "\n", " ", ""]。这样做的效果是尽量将所有段落(然后是句子,然后是单词)保持在一起,因为这些段落一般看起来是语义最相关的文本片段。

  1. 文本如何拆分:按字符列表。
  2. 如何测量块大小:通过字符数。
pip install -qU langchain-text-splitters
from langchain_text_splitters import RecursiveCharacterTextSplitter

# This is a long document we can split up.
with open("./demo_static/splitters_test.txt") as f:
    state_of_the_union = f.read()
text_splitter = RecursiveCharacterTextSplitter(
    # Set a really small chunk size, just to show.
    chunk_size=100,
    chunk_overlap=20,
    length_function=len,
    is_separator_regex=False,
)

texts = text_splitter.create_documents([state_of_the_union])
print(texts[0])
print(texts[1])

【敲重点啊!】

 从没有单词边界的语言中拆分文本

一些书写系统没有单词边界,例如 中文 、日文和泰文。使用默认分隔符列表拆分文本["\n\n", "\n", " ", ""]会导致单词在单词块之间拆分。要将单词放在一起,您可以覆盖分隔符列表以包括附加标点符号:

  • 添加ASCII句号“.”, Unicode句号““(用于中文文本),以及象形字句号 ““(用于日语和汉语)
  • 增加 zero-width space 用于泰语、缅甸语、缅甸语和日语。
  • 添加ASCII逗号“,“,Unicode全角逗号““,和Unicode表意逗号“
text_splitter = RecursiveCharacterTextSplitter(
    separators=[
        "\n\n",
        "\n",
        " ",
        ".",
        ",",
        "\u200B",  # Zero-width space
        "\uff0c",  # Fullwidth comma
        "\u3001",  # Ideographic comma
        "\uff0e",  # Fullwidth full stop
        "\u3002",  # Ideographic full stop
        "",
    ],
    # Existing args
)

三、语义组块 Semantic Chunking

        基于语义相似性拆分文本。

        摘自Greg Kamradt的精彩笔记本:5 _ Levels _ Of _ Text _拆分

        一切都归功于他。

        在高层次上,这将拆分成句子,然后分组为3个句子的组,然后合并一个在嵌入空间中相似的句子。

安装依赖项

pip install --quiet langchain_experimental langchain_openai

加载示例数据

# This is a long document we can split up.
with open("./demo_static/splitters_test.txt") as f:
    state_of_the_union = f.read()

创建文本拆分器 

from langchain_experimental.text_splitter import SemanticChunker
from langchain_openai.embeddings import OpenAIEmbeddings

text_splitter = SemanticChunker(OpenAIEmbeddings())

拆分文本

docs = text_splitter.create_documents([state_of_the_union])
print(docs[0].page_content)

断点 

        这个分块器的工作原理是决定何时“拆分”句子。这是通过寻找任何两个句子之间嵌入的差异来实现的。当差异超过某个阈值时,它们就会被拆分。

        有几种方法可以确定这个阈值。

 - 百分位

        默认的分割方式是基于百分位数。在这种方法中,计算句子之间的所有差异,然后拆分任何大于X百分位的差异。

text_splitter = SemanticChunker(
    OpenAIEmbeddings(), breakpoint_threshold_type="percentile"
)
docs = text_splitter.create_documents([state_of_the_union])
print(docs[0].page_content)

 - 标准偏差

在这种方法中,任何大于X个标准差的差异都会被拆分。

text_splitter = SemanticChunker(
    OpenAIEmbeddings(), breakpoint_threshold_type="standard_deviation"
)
docs = text_splitter.create_documents([state_of_the_union])
print(docs[0].page_content)

 - 四分位间距

在这种方法中,四分位间距用于分割组块。

text_splitter = SemanticChunker(
    OpenAIEmbeddings(), breakpoint_threshold_type="interquartile"
)
docs = text_splitter.create_documents([state_of_the_union])
print(docs[0].page_content)

 

四、按token拆分  split by tokens 

        语言模型有一个token限制。不应该超过token限额。因此,当您将文本分成块时,计算token的数量是一个好主意。有许多tokenizer。计算文本中的token时,应该使用语言模型中的tokenizer。

① 第一种:tiktoken

tiktoken 是一种快速 BPE tokenizer,是由OpenAI创建的。

 我们可以用它来估计使用的token数。用在OpenAI模型会更准确。

  1. 文本如何拆分:按传入的字符。
  2. 如何测量块大小:通过tiktoken标记器。
pip install --upgrade --quiet langchain-text-splitters tiktoken
from langchain_text_splitters import CharacterTextSplitter
# This is a long document we can split up.
with open("./demo_static/splitters_test.txt") as f:
    state_of_the_union = f.read()

使用from_tiktoken_encoder()方法采用model_name作为一个参数(例如gpt-4)。所有附加参数,如chunk_sizechunk_overlap,以及separators用于实例化CharacterTextSplitter:

text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
    model_name="gpt-4", chunk_size=100, chunk_overlap=0
)
texts = text_splitter.split_text(state_of_the_union)

        注意,如果我们使用CharacterTextSplitter.from_tiktoken_encoder,文本仅由CharacterTextSplittertiktokentokenizer用于合并拆分。这意味着拆分可能大于块大小,通过tiktoken tokenizer。我们可以使用RecursiveCharacterTextSplitter.from_tiktoken_encoder为了确保拆分不大于语言模型所允许的标记块大小,如果每个拆分具有更大的大小,则将对其进行递归拆分:

from langchain_text_splitters import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
    model_name="gpt-4",
    chunk_size=100,
    chunk_overlap=0,
)

        我们还可以直接加载tiktoken拆分器,这将确保每次拆分都小于块大小。

from langchain_text_splitters import TokenTextSplitter

text_splitter = TokenTextSplitter(chunk_size=10, chunk_overlap=0)

texts = text_splitter.split_text(state_of_the_union)
print(texts[0])

        一些书面语言(例如 中文 和日文)具有编码为2个或更多个标记的字符。使用TokenTextSplitter直接可以在两个块之间拆分字符的标记,从而导致Unicode字符格式错误。使用RecursiveCharacterTextSplitter.from_tiktoken_encoder或者CharacterTextSplitter.from_tiktoken_encoder确保块包含有效的Unicode字符串。

② 第二种:spaCy

spaCy 是一个用于高级自然语言处理的开源软件库,用编程语言Python和Cython编写。

  1. 文本拆分方式:由spaCy标记器。
  2. 如何测量块大小:通过字符数。
pip install --upgrade --quiet  spacy
from langchain_text_splitters import SpacyTextSplitter
# This is a long document we can split up.
with open("./demo_static/splitters_test.txt") as f:
    state_of_the_union = f.read()
text_splitter = SpacyTextSplitter(chunk_size=1000)

texts = text_splitter.split_text(state_of_the_union)
print(texts[0])

③第三种:SentenceTransformers

SentenceTransformersTokenTextSplitter是一个专门的文本拆分器,用于句子转换模型。默认行为是将文本分割成适合您想要使用的句子转换器模型的标记窗口的块。

from langchain_text_splitters import SentenceTransformersTokenTextSplitter
splitter = SentenceTransformersTokenTextSplitter(chunk_overlap=0)
text = "Lorem "
count_start_and_stop_tokens = 2
text_token_count = splitter.count_tokens(text=text) - count_start_and_stop_tokens
print(text_token_count)
token_multiplier = splitter.maximum_tokens_per_chunk // text_token_count + 1

# `text_to_split` does not fit in a single chunk
text_to_split = text * token_multiplier

print(f"tokens in text to split: {splitter.count_tokens(text=text_to_split)}")
text_chunks = splitter.split_text(text=text_to_split)

print(text_chunks[1])

④ 第四种:NLTK

自然语言工具包或者更常见的是NLTK是一套用于以Python编程语言编写的英语符号和统计自然语言处理(NLP)的库和程序。

除了在“”上拆分,我们还可以使用NLTK根据 NLTK Tokenizer  分开
.

  1. 文本拆分方式:由NLTK标记器。
  2. 如何测量块大小:通过字符数。
pip install nltk
from langchain_text_splitters import NLTKTextSplitter

# This is a long document we can split up.
with open("./demo_static/splitters_test.txt") as f:
    state_of_the_union = f.read()
text_splitter = NLTKTextSplitter(chunk_size=1000)

texts = text_splitter.split_text(state_of_the_union)
print(texts[0])

总结

总的来说,各种分割方式都有各自的优势,要按实际的业务场景来进行选择,例如简单的字符分割就能实现基础文本的问答需求。如果以中文文档为主的建议用Recursively split by character。目前各大平台主要是以token来计费,可想而知其重要性,也要重点关注实际的使用。

创作不易,给个三连(点赞、收藏、关注),同学们的满意是我(H-大叔)的动力。

 代码运行有问题或其他建议,请在留言区评论,看到就会回复,不用私聊。

专栏人工智能 | 大模型 | 实战与教程里面还有其他人工智能|大数据方面的文章,可继续食用,持续更新。

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

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

相关文章

使用dlv配合goland调试在wsl中运行的go程序

参考文章:https://marksuper.xyz/2021/06/29/dlv-goland/ 首先安装一下dlv这个工具: git clone GitHub - go-delve/delve: Delve is a debugger for the Go programming language. cd delve go install github.com/go-delve/delve/cmd/dlv 我们直接开始配…

数据结构 之 栈与单调栈习题 力扣oj(附加思路版)

#include<stack> --栈的头文件 栈的特点 &#xff1a; 先进后出 &#xff0c; 后进先出 相关函数&#xff1a; top() 获取栈顶元素 ,返回栈顶元素的值 pop() 删除栈顶元素 ,没有返回值 push() 放入元素 ,没有返回值 empty() 为空返回 true 否则返回false size() 元素…

Java毕业设计-基于springboot开发的疫情防控期间外出务工人员信息管理系统-毕业论文+答辩PPT(附源代码+演示视频)

文章目录 前言一、毕设成果演示&#xff08;源代码在文末&#xff09;二、毕设摘要展示1、开发说明2、需求分析3、系统功能结构 三、系统实现展示1、系统功能模块2、后台登录2.1管理员功能2.2用户功能2.3采集员功能2.4分析员功能 四、毕设内容和源代码获取总结 Java毕业设计-基…

文件上传漏洞-客户端检测

本文章仅供学习参考&#xff01;&#xff01;&#xff01; 靶场环境&#xff1a;upload-labs-master/pass-1 客户端检测 客户端检测一般都是在网页上写一段 javascript 脚本&#xff0c;校验上传文件 的后缀名&#xff0c;有白名单形式也有黑名单形式。 判断方式&#xff1…

Advisor 被重复代理问题排查

问题场景 项目中存在多个 AbstractAdvisorAutoProxyCreator 且其持有的 Advisor Bean 重复 问题复现 相关代码 ResponseBodyRequiresPermissions(PermissionConstant.****)GetMapping(value "/query****.json", name "")public List<***> query…

aws 入门篇 01.aws学习的方法论

aws入门篇 01.aws学习的方法论 第1章 aws学习的方法论 aws的服务很多&#xff0c;现在应该有100多个服务了&#xff0c;怎么来学习aws呢&#xff1f; 这几年也使用了一些aws的服务&#xff0c;谈谈自己对学习aws的理解。 1.先横向&#xff0c;后纵深 比如说&#xff0c;aws最…

【Hello,PyQt】控件拖拽

在 PyQt 中实现控件拖拽功能的详细介绍 拖拽功能是现代用户界面设计中常见的交互方式之一&#xff0c;它可以提高用户体验&#xff0c;增加操作的直观性。在 PyQt 中&#xff0c;我们可以很容易地实现控件之间的拖拽功能。本文将介绍如何在 PyQt 中实现控件的拖拽功能。 如何实…

第二百二十九回

文章目录 1. 概念介绍2. 关键信息2.1 程序包名 2.2 程序图标2.3 程序id3. 内容总结 我们在上一章回中介绍了"如何在打包apk时自动签名"相关的内容&#xff0c;本章回中将介绍程序中的包名等关键信息.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我…

推荐:便宜幻兽帕鲁Palworld联机游戏服务器优惠价格表

2024年全网最全的幻兽帕鲁服务器租用价格表&#xff0c;阿里云幻兽帕鲁游戏服务器26元1个月、腾讯云32元一个月、京东云26元一个月、华为云24元1个月&#xff0c;阿腾云atengyun.com整理最新幻兽帕鲁专用4核16G、8核16G、8核32G游戏服务器租用价格表大全&#xff1a; 阿里云幻…

数据结构——链表(练习题)

大家好&#xff0c;我是小锋我们继续来学习链表。 我们在上一节已经把链表中的单链表讲解完了&#xff0c;大家感觉怎么样我们今天来带大家做一些练习帮助大家巩固所学内容。 1. 删除链表中等于给定值 val 的所有结点 . - 力扣&#xff08;LeetCode&#xff09; 我们大家来分…

十四、MySQL日志之 binlog日志

目录 一、二进制日志&#xff08;Binary log&#xff09; 1、binlog主要应用场景&#xff1a; 2、查看默认情况 3、日志参数设置 &#xff08;1&#xff09;永久设置 &#xff08;2&#xff09;临时性设置 4、查看日志 5、删除二进制日志 总结&#xff1a; 一、二进制日…

【JavaWeb】Day23.maven——依赖管理

依赖管理 一.依赖配置 依赖&#xff1a;指当前项目运行所需要的jar包。一个项目中可以引入多个依赖。 例如&#xff1a;在当前工程中&#xff0c;我们需要用到logback来记录日志&#xff0c;此时就可以在maven工程的pom.xml文件中&#xff0c;引入logback的依赖。具体步骤如…

docker容器内存检测排查

查询容器使用内存 在运维当中&#xff0c;你会发现内存很彪的高&#xff0c;但是如何判断为什么会高&#xff0c;是什么样的程序造成的呢&#xff1f;赶快使用 top&#xff0c;或者 free -h或者 ps -v。是吗&#xff1f;道理是对的。 但是你会发现&#xff0c;全部都是docker…

探索Python人工智能在气象监测中的创新应用

Python是功能强大、免费、开源&#xff0c;实现面向对象的编程语言&#xff0c;在数据处理、科学计算、数学建模、数据挖掘和数据可视化方面具备优异的性能&#xff0c;这些优势使得Python在气象、海洋、地理、气候、水文和生态等地学领域的科研和工程项目中得到广泛应用。可以…

linux网络服务学习(4):SAMBA

1.什么是SAMBA SAMBA也是一种文件共享工具 &#xff08;1&#xff09;服务名&#xff1a;smb &#xff08;2&#xff09;软件名&#xff1a;samba &#xff08;3&#xff09;配置文件&#xff1a; /etc/samba/smb.conf /etc/samba/smb.conf.example &#xff08;4&#…

牛客NC26 括号生成【中等 递归 Java,Go,PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/c9addb265cdf4cdd92c092c655d164ca 思路 答案链接&#xff1a;https://www.lintcode.com/problem/427/solution/16924 参考答案Java import java.util.*;public class Solution {/*** 代码中的类名、方法名、参…

#Linux(make工具和makefile文件以及makefile语法)

&#xff08;一&#xff09;发行版&#xff1a;Ubuntu16.04.7 &#xff08;二&#xff09;记录&#xff1a; &#xff08;1&#xff09;make为编译辅助工具&#xff0c;解决用命令编译工程非常繁琐的问题 &#xff08;2&#xff09;在终端键入make即可调用make工具&#xff0…

学习JavaEE的日子 Day29 yield,join,线程的中断,守护线程,线程局部变量共享,线程生命周期

Day29 多线程 12. 线程的礼让 Thread.yield(); 理解&#xff1a;此方法为静态方法&#xff0c;此方法写在哪个线程中&#xff0c;哪个线程就礼让 注意&#xff1a;所谓的礼让是指当前线程退出CPU资源&#xff0c;并转到就绪状态&#xff0c;接着再抢 需求&#xff1a;创建两个…

P8764 [蓝桥杯 2021 国 BC] 二进制问题

很板的一道题目&#xff0c;注意就是数组别开的太小 #include<bits/stdc.h> using namespace std; using ll long long; using pii pair<int,int>; #define int long long const int N 1e510; const int inf 0x3f3f3f3f; const int mod 1e97; int gcd(int a,…

【81-100】计算机网络基础知识(非常详细)从零基础入门到精通,看完这一篇就够了

【81-100】计算机网络基础知识&#xff08;非常详细&#xff09;从零基础入门到精通&#xff0c;看完这一篇就够了 以下是本文参考的资料 欢迎大家查收原版 本版本仅作个人笔记使用81、对于FIN_WAIT_2&#xff0c;CLOSE_WAIT状态和TIME_WAIT状态&#xff1f;你知道多少?82、你…