食用指南

LangChain 作为大语言模型应用开发框架,文本分割器是其核心组件之一,本文以此作为切入点,详细介绍文本分割的作用、策略、以及常见的文本切割器应用。考虑到篇幅过长,故拆分为上、中、下三篇,后续会在中篇介绍代码拆分与HTML拆分,下篇介绍基于语义拆分与TOKEN拆分。若存在任何内容上的遗漏或错误,恳请不吝赐教。

一、概述

文档分割通常是许多应用中至关重要的预处理步骤。它涉及将大型文本分解为更小、更易于管理的块。此过程具有多项优势,例如确保对不同文档长度进行一致处理、克服模型的输入大小限制以及提高检索系统中使用的文本表示的质量。有几种分割文档的策略,每种策略都有其自身的优势。

在这里插入图片描述

二、为什么要分割文档?

  • 处理非均匀文档长度:真实世界的文档集合通常包含大小不一的文本。分割确保所有文档的处理一致。
  • 克服模型限制:许多嵌入模型和语言模型都有最大输入大小约束。分割使我们能够处理原本会超出这些限制的文档。
  • 提高表示质量:对于较长的文档,当它们试图捕获太多信息时,嵌入或其他表示的质量可能会下降。分割可以使每个部分的表示更集中和准确。
  • 提高检索精度:在信息检索系统中,分割可以提高搜索结果的粒度,从而更精确地将查询与相关文档部分匹配。
  • 优化计算资源:处理较小的文本块可以更节省内存,并允许更好地并行处理任务。

三、分割文档的策略

1、基于长度

最直观的策略是根据文档的长度进行分割。这种简单而有效的方法确保每个块不超过指定的尺寸限制。

基于长度分割的关键优势:

  • 实施简单直接
  • 块大小一致
  • 易于适应不同的模型要求

基于长度的分割类型:

  • 基于 Token:基于 token 数量分割文本,这在使用语言模型时非常有用。
  • 基于字符:基于字符数分割文本,这在不同类型的文本中可能更一致。

使用 LangChainCharacterTextSplitter 进行基于 token 分割的示例实现:

from langchain_text_splitters import CharacterTextSplitter
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(encoding_name="cl100k_base", chunk_size=100, chunk_overlap=0
)
texts = text_splitter.split_text(document)

2、基于文本结构

文本自然地组织成层次结构单元,例如段落、句子和单词。我们可以利用这种固有的结构来指导我们的分割策略,创建保持自然语言流畅性、在分割中保持语义连贯性并适应不同文本粒度级别的分割。

LangChainRecursiveCharacterTextSplitter 实现了这个概念:

  • RecursiveCharacterTextSplitter 尝试保持较大的单元(例如,段落)完整。
  • 如果一个单元超过块大小,它将移动到下一个级别(例如,句子)。
  • 如有必要,此过程将继续向下到单词级别。

这是一个示例用法:

from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=0)
texts = text_splitter.split_text(document)

3、基于文档结构

某些文档具有固有的结构,例如 HTMLMarkdownJSON 文件。在这些情况下,根据文档的结构进行分割是有益的,因为它通常自然地将语义相关的文本分组。

基于结构分割的关键优势:

  • 保留文档的逻辑组织
  • 在每个块中维护上下文
  • 对于检索或摘要等下游任务可能更有效

基于结构的分割示例:

  • Markdown:基于标题(例如,#、##、###)分割
  • HTML:使用标签分割
  • JSON:按对象或数组元素分割
  • 代码:按函数、类或逻辑块分割

4、基于语义含义

与以前的方法不同,基于语义的分割实际上考虑了文本的内容。虽然其他方法使用文档或文本结构作为语义含义的代理,但此方法直接分析文本的语义。有几种方法可以实现这一点,但从概念上讲,该方法是在文本含义发生重大变化时分割文本。

例如,我们可以使用滑动窗口方法生成嵌入,并比较嵌入以找到显着差异:

  • 从前几个句子开始并生成嵌入。
  • 移动到下一组句子并生成另一个嵌入(例如,使用滑动窗口方法)。
  • 比较嵌入以找到显着差异,这表明语义部分之间可能存在“断点”。

这项技术有助于创建语义上更连贯的块,从而可能提高检索或摘要等下游任务的质量。

四、RecursiveCharacterTextSplitter

RecursiveCharacterTextSplitter 这个 文本拆分器 是通用文本的推荐选择。它通过字符列表进行参数化。它尝试按顺序拆分它们,直到块足够小。默认列表是 ["\n\n", "\n", " ", ""]。这具有尽可能将所有段落(然后是句子,然后是单词)保持在一起的效果,因为这些通常看起来是语义上最相关的文本片段。

1、通过字符递归拆分文本

明确以下两点:

  1. 文本如何拆分:通过字符列表。
  2. 块大小如何测量:通过字符数。

下面是一个使用例子:

pip install -qU langchain-text-splitters
from langchain_text_splitters import RecursiveCharacterTextSplitter# Load example document
with open("SpongeBobAndPatrick.txt") as f:sponge_bob_and_patrick = 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,
)# 创建 LangChain Document 对象(例如,用于下游任务)
texts = text_splitter.create_documents([sponge_bob_and_patrick])
print(texts[0])
print(texts[1])
page_content='SpongeBob SquarePants and Patrick Star are the iconic best friends from the beloved animated series'
page_content='animated series "SpongeBob SquarePants." SpongeBob is an energetic, optimistic yellow sea sponge'

要直接获取字符串内容,请使用 .split_text

text_splitter.split_text(sponge_bob_and_patrick)[:2]
['SpongeBob SquarePants and Patrick Star are the iconic best friends from the beloved animated series','animated series "SpongeBob SquarePants." SpongeBob is an energetic, optimistic yellow sea sponge']

让我们回顾一下上面为 RecursiveCharacterTextSplitter 设置的参数:

  • chunk_size:块的最大大小,其中大小由 length_function 确定。
  • chunk_overlap:块之间的目标重叠。重叠块有助于减轻上下文在块之间划分时信息丢失。
  • length_function:确定块大小的函数。
  • is_separator_regex:分隔符列表(默认为 ["\n\n", "\n", " ", ""])是否应解释为正则表达式。

2、从没有词界符的语言拆分文本

一些书写系统没有 词界符,例如中文、日语和泰语。使用默认分隔符列表 ["\n\n", "\n", " ", ""] 拆分文本可能会导致单词在块之间被拆分。为了保持单词完整,我们需要覆盖分隔符列表以包含其他标点符号:

  • 添加 ASCII 句点".“,Unicode 全角 句点”."(用于中文文本)和 表意文字句点 “。”(用于日语和中文)
  • 添加泰语、缅甸语、高棉语和日语中使用的 零宽度空格
  • 添加 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# Set a really small chunk size, just to show.chunk_size=100,chunk_overlap=20,length_function=len,is_separator_regex=False,
)# Load example document
with open("海绵宝宝故事.txt") as f:sponge_bob_and_patrick = f.read()texts = text_splitter.create_documents([sponge_bob_and_patrick])
text_splitter.split_text(sponge_bob_and_patrick)[:2]
['有一次海绵宝宝和派大星决定玩"交换身份"游戏。派大星穿上海绵宝宝的方形裤子和领带,而海绵宝宝则把自己揉成星星形状。他们互相模仿对方说话方式来到蟹堡王上班,结果:','派大星版的"海绵宝宝"把所有的蟹堡都做成了星星形状,还理直气壮地说"这样更好吃";\n当章鱼哥质疑时,他直接躺在地上装死;']

五、CharacterTextSplitter

这是最简单的方法。这个 分割器 基于给定的字符序列进行分割,默认为 "\n\n"。块长度按字符数衡量。

明确以下两点:

  1. 文本分割方式:按单个字符分隔符。
  2. 块大小的衡量方式:按字符数。

下面是一个使用例子:

pip install -qU langchain-text-splitters
from langchain_text_splitters import CharacterTextSplitter# Load an example document
with open("SpongeBobAndPatrick.txt") as f:sponge_bob_and_patrick = f.read()text_splitter = CharacterTextSplitter(separator="\n\n",chunk_size=1000,chunk_overlap=200,length_function=len,is_separator_regex=False,
)# 创建 LangChain Document 对象(例如,用于下游任务)
texts = text_splitter.create_documents([sponge_bob_and_patrick])
print(texts[0])
page_content='SpongeBob SquarePants and Patrick Star are the iconic best friends from the beloved animated series "SpongeBob SquarePants." SpongeBob is an energetic, optimistic yellow sea sponge who lives in a pineapple under the sea in the underwater city of Bikini Bottom. He works as a fry cook at the Krusty Krab and absolutely loves his job. His childlike enthusiasm and naivety often lead him into hilarious misadventures.'

使用 .create_documents 将与每个文档关联的元数据传播到输出块:

metadatas = [{"document": 1}, {"document": 2}]
documents = text_splitter.create_documents([sponge_bob_and_patrick, sponge_bob_and_patrick], metadatas=metadatas
)
print(documents[0]) # metadata={'document': 1}
print(documents[1]) # metadata={'document': 1}
print(documents[2]) # metadata={'document': 2}
print(documents[3]) # metadata={'document': 2}
page_content='SpongeBob SquarePants and Patrick Star are the iconic best friends from the beloved animated series "SpongeBob SquarePants." SpongeBob is an energetic, optimistic yellow sea sponge who lives in a pineapple under the sea in the underwater city of Bikini Bottom. He works as a fry cook at the Krusty Krab and absolutely loves his job. His childlike enthusiasm and naivety often lead him into hilarious misadventures.' metadata={'document': 1}
page_content='Patrick is SpongeBob's dim-witted but lovable best friend - a pink starfish who lives under a rock. Despite his lack of common sense, Patrick always supports SpongeBob through thick and thin. Their friendship is the heart of the show, showcasing unconditional loyalty and the joy of simple pleasures. Whether they're jellyfishing, blowing bubbles, or getting into trouble with Squidward, their antics never fail to entertain. Together, this dynamic duo represents the perfect balance of SpongeBob's energetic optimism and Patrick's laid-back simplicity, making them one of the most memorable cartoon pairs in television history.' metadata={'document': 1}
page_content='SpongeBob SquarePants and Patrick Star are the iconic best friends from the beloved animated series "SpongeBob SquarePants." SpongeBob is an energetic, optimistic yellow sea sponge who lives in a pineapple under the sea in the underwater city of Bikini Bottom. He works as a fry cook at the Krusty Krab and absolutely loves his job. His childlike enthusiasm and naivety often lead him into hilarious misadventures.' metadata={'document': 2}
page_content='Patrick is SpongeBob's dim-witted but lovable best friend - a pink starfish who lives under a rock. Despite his lack of common sense, Patrick always supports SpongeBob through thick and thin. Their friendship is the heart of the show, showcasing unconditional loyalty and the joy of simple pleasures. Whether they're jellyfishing, blowing bubbles, or getting into trouble with Squidward, their antics never fail to entertain. Together, this dynamic duo represents the perfect balance of SpongeBob's energetic optimism and Patrick's laid-back simplicity, making them one of the most memorable cartoon pairs in television history.' metadata={'document': 2}

使用 .split_text 直接获取字符串内容:

text_splitter.split_text(sponge_bob_and_patrick)[0]
'SpongeBob SquarePants and Patrick Star are the iconic best friends from the beloved animated series "SpongeBob SquarePants." SpongeBob is an energetic, optimistic yellow sea sponge who lives in a pineapple under the sea in the underwater city of Bikini Bottom. He works as a fry cook at the Krusty Krab and absolutely loves his job. His childlike enthusiasm and naivety often lead him into hilarious misadventures.'

六、MarkdownHeaderTextSplitter

下面是一个按标题拆分 Markdown 的示例。

1、动机

许多聊天或问答应用涉及在嵌入和向量存储之前对输入文档进行分块,而这些分块通常旨在将具有共同上下文的文本放在一起。考虑到这一点,我们可能希望特别尊重文档本身的结构。例如,markdown 文件按标题组织,在特定标题组中创建块是一个直观的想法。为了解决这个挑战,我们可以使用 MarkdownHeaderTextSplitter,这将按指定的标题集拆分 markdown 文件。

例如,如果我们想拆分此 markdown

md = """
# 派大星角色特点详解## 基本特征
- **外形**:粉红色五角海星,蓝色短裤,无上衣
- **居住地**:比奇堡的石头屋
- **职业**:无固定工作## 性格特质
1. **天真单纯**  - 思维极其简单直接- 经常说出富有哲理的无心之言- 对复杂事物理解困难2. **乐观豁达**  - 永远保持快乐心态- 经典台词:"我准备好了!"- 把失败当作新游戏的开始 
"""

我们可以指定要拆分的标题:

[("#", "Header 1"),("##", "Header 2")]

内容按公共标题分组或拆分:

{'content': '- **外形**:粉红色五角海星,蓝色短裤,无上衣\n- **居住地**:比奇堡的石头屋\n- **职业**:无固定工作', 'metadata': {'Header 1': '派大星角色特点详解', 'Header 2': '基本特征'}}
{'content': '1. **天真单纯**\n- 思维极其简单直接\n- 经常说出富有哲理的无心之言\n- 对复杂事物理解困难  \n2. **乐观豁达**\n- 永远保持快乐心态\n- 经典台词:"我准备好了!"\n- 把失败当作新游戏的开始'' , 'metadata': {'Header 1': '派大星角色特点详解', 'Header 2': '性格特质'}}

让我们看看下面的一些示例。

2、基本用法

pip install -qU langchain-text-splitters
from langchain_text_splitters import MarkdownHeaderTextSplittermarkdown_document = """
# 派大星角色特点详解## 基本特征
- **外形**:粉红色五角海星,蓝色短裤,无上衣
- **居住地**:比奇堡的石头屋
- **职业**:无固定工作## 性格特质
1. **天真单纯**  - 思维极其简单直接- 经常说出富有哲理的无心之言- 对复杂事物理解困难2. **乐观豁达**  - 永远保持快乐心态- 经典台词:"我准备好了!"- 把失败当作新游戏的开始 
"""headers_to_split_on = [("#", "Header 1"),("##", "Header 2"),
]markdown_splitter = MarkdownHeaderTextSplitter(headers_to_split_on)
md_header_splits = markdown_splitter.split_text(markdown_document)
md_header_splits
[Document(metadata={'Header 1': '派大星角色特点详解', 'Header 2': '基本特征'}, page_content='- **外形**:粉红色五角海星,蓝色短裤,无上衣\n- **居住地**:比奇堡的石头屋\n- **职业**:无固定工作'),Document(metadata={'Header 1': '派大星角色特点详解', 'Header 2': '性格特质'}, page_content='1. **天真单纯**\n- 思维极其简单直接\n- 经常说出富有哲理的无心之言\n- 对复杂事物理解困难  \n2. **乐观豁达**\n- 永远保持快乐心态\n- 经典台词:"我准备好了!"\n- 把失败当作新游戏的开始')]
type(md_header_splits[0])
langchain_core.documents.base.Document

默认情况下,MarkdownHeaderTextSplitter 会从输出块的内容中剥离正在拆分的标题。可以通过设置 strip_headers = False 来禁用此功能。

markdown_splitter = MarkdownHeaderTextSplitter(headers_to_split_on, strip_headers=False)
md_header_splits = markdown_splitter.split_text(markdown_document)
md_header_splits
[Document(metadata={'Header 1': '派大星角色特点详解', 'Header 2': '基本特征'}, page_content='# 派大星角色特点详解  \n## 基本特征\n- **外形**:粉红色五角海星,蓝色短裤,无上衣\n- **居住地**:比奇堡的石头屋\n- **职业**:无固定工作'),Document(metadata={'Header 1': '派大星角色特点详解', 'Header 2': '性格特质'}, page_content='## 性格特质\n1. **天真单纯**\n- 思维极其简单直接\n- 经常说出富有哲理的无心之言\n- 对复杂事物理解困难  \n2. **乐观豁达**\n- 永远保持快乐心态\n- 经典台词:"我准备好了!"\n- 把失败当作新游戏的开始')]

注意:默认的 MarkdownHeaderTextSplitter 会剥离空格和换行符。要保留 Markdown 文档的原始格式,请查看 ExperimentalMarkdownSyntaxTextSplitter

3、将 Markdown 行作为单独的文档返回

默认情况下,MarkdownHeaderTextSplitter 根据 headers_to_split_on 中指定的标题聚合行。我们可以通过指定 return_each_line 来禁用此功能。

markdown_splitter = MarkdownHeaderTextSplitter(headers_to_split_on,return_each_line=True,
)
md_header_splits = markdown_splitter.split_text(markdown_document)
md_header_splits
[Document(metadata={'Header 1': '派大星角色特点详解', 'Header 2': '基本特征'}, page_content='- **外形**:粉红色五角海星,蓝色短裤,无上衣\n- **居住地**:比奇堡的石头屋\n- **职业**:无固定工作'),Document(metadata={'Header 1': '派大星角色特点详解', 'Header 2': '性格特质'}, page_content='1. **天真单纯**\n- 思维极其简单直接\n- 经常说出富有哲理的无心之言\n- 对复杂事物理解困难'),Document(metadata={'Header 1': '派大星角色特点详解', 'Header 2': '性格特质'}, page_content='2. **乐观豁达**\n- 永远保持快乐心态\n- 经典台词:"我准备好了!"\n- 把失败当作新游戏的开始')]

请注意,这里的标题信息保留在每个文档的元数据中。

4、约束块大小

在每个 markdown 组中,我们可以应用我们想要的任何文本拆分器,例如 RecursiveCharacterTextSplitter,它允许进一步控制块大小。

markdown_document =  """
# 派大星角色特点详解## 基本特征
- **外形**:粉红色五角海星,蓝色短裤,无上衣
- **居住地**:比奇堡的石头屋
- **职业**:无固定工作## 性格特质
1. **天真单纯**  - 思维极其简单直接- 经常说出富有哲理的无心之言- 对复杂事物理解困难2. **乐观豁达**  - 永远保持快乐心态- 经典台词:"我准备好了!"- 把失败当作新游戏的开始 
"""headers_to_split_on = [("#", "Header 1"),("##", "Header 2"),
]# Step1、MD splits
markdown_splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on, strip_headers=False
)
md_header_splits = markdown_splitter.split_text(markdown_document)# Step2、Char-level splits
from langchain_text_splitters import RecursiveCharacterTextSplitterchunk_size = 250
chunk_overlap = 30
text_splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap
)# Split
splits = text_splitter.split_documents(md_header_splits)
splits
[Document(metadata={'Header 1': '派大星角色特点详解', 'Header 2': '基本特征'}, page_content='# 派大星角色特点详解  \n## 基本特征\n- **外形**:粉红色五角海星,蓝色短裤,无上衣\n- **居住地**:比奇堡的石头屋\n- **职业**:无固定工作'),Document(metadata={'Header 1': '派大星角色特点详解', 'Header 2': '性格特质'}, page_content='## 性格特质\n1. **天真单纯**\n- 思维极其简单直接\n- 经常说出富有哲理的无心之言\n- 对复杂事物理解困难  \n2. **乐观豁达**\n- 永远保持快乐心态\n- 经典台词:"我准备好了!"\n- 把失败当作新游戏的开始')]

七、RecursiveJsonSplitter

json 分割器拆分 json 数据,同时允许控制 chunk 大小。它深度优先遍历 json 数据并构建更小的 json chunk。它尝试保持嵌套 json 对象完整,但如果需要将 chunk 保持在 min_chunk_sizemax_chunk_size 之间,则会分割它们。

如果值不是嵌套 json,而是一个非常大的字符串,则该字符串不会被分割。如果需要对 chunk 大小进行硬性限制,请考虑将此分割器与这些 chunk 上的 Recursive Text 分割器组合使用。有一个可选的预处理步骤来分割列表,首先将列表转换为 json(dict),然后像这样分割它们。

明确以下两点:

  1. 文本分割方式:json 值。
  2. chunk 大小的度量方式:字符数。
pip install -qU langchain-text-splitters

首先我们加载一些 json 数据:

import jsonimport requests# This is a large nested json object and will be loaded as a python dict
json_data = requests.get("https://api.smith.langchain.com/openapi.json").json()

1、基本用法

指定 max_chunk_size 以约束 chunk 大小:

from langchain_text_splitters import RecursiveJsonSplittersplitter = RecursiveJsonSplitter(max_chunk_size=300)

要获取 json chunk,请使用 .split_json 方法:

# Recursively split json data - If you need to access/manipulate the smaller json chunks
json_chunks = splitter.split_json(json_data=json_data)for chunk in json_chunks[:3]:print(chunk)
{'openapi': '3.1.0', 'info': {'title': 'LangSmith', 'version': '0.1.0'}, 'paths': {'/api/v1/sessions/{session_id}/dashboard': {'post': {'tags': ['tracer-sessions'], 'summary': 'Get Tracing Project Prebuilt Dashboard', 'description': 'Get a prebuilt dashboard for a tracing project.'}}}}
{'paths': {'/api/v1/sessions/{session_id}/dashboard': {'post': {'operationId': 'get_tracing_project_prebuilt_dashboard_api_v1_sessions__session_id__dashboard_post', 'security': [{'API Key': []}, {'Tenant ID': []}, {'Bearer Auth': []}]}}}}
{'paths': {'/api/v1/sessions/{session_id}/dashboard': {'post': {'parameters': [{'name': 'session_id', 'in': 'path', 'required': True, 'schema': {'type': 'string', 'format': 'uuid', 'title': 'Session Id'}}, {'name': 'accept', 'in': 'header', 'required': False, 'schema': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'title': 'Accept'}}]}}}}

要获取 LangChain Document 对象(例如,用于下游任务),请使用 .create_documents 方法:

# The splitter can also output documents
docs = splitter.create_documents(texts=[json_data])for doc in docs[:3]:print(doc)
page_content='{"openapi": "3.1.0", "info": {"title": "LangSmith", "version": "0.1.0"}, "paths": {"/api/v1/sessions/{session_id}/dashboard": {"post": {"tags": ["tracer-sessions"], "summary": "Get Tracing Project Prebuilt Dashboard", "description": "Get a prebuilt dashboard for a tracing project."}}}}'
page_content='{"paths": {"/api/v1/sessions/{session_id}/dashboard": {"post": {"operationId": "get_tracing_project_prebuilt_dashboard_api_v1_sessions__session_id__dashboard_post", "security": [{"API Key": []}, {"Tenant ID": []}, {"Bearer Auth": []}]}}}}'
page_content='{"paths": {"/api/v1/sessions/{session_id}/dashboard": {"post": {"parameters": [{"name": "session_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Session Id"}}, {"name": "accept", "in": "header", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Accept"}}]}}}}'

或使用 .split_text 直接获取字符串内容:

texts = splitter.split_text(json_data=json_data)print(texts[0])
print(texts[1])
{"openapi": "3.1.0", "info": {"title": "LangSmith", "version": "0.1.0"}, "paths": {"/api/v1/sessions/{session_id}/dashboard": {"post": {"tags": ["tracer-sessions"], "summary": "Get Tracing Project Prebuilt Dashboard", "description": "Get a prebuilt dashboard for a tracing project."}}}}
{"paths": {"/api/v1/sessions/{session_id}/dashboard": {"post": {"operationId": "get_tracing_project_prebuilt_dashboard_api_v1_sessions__session_id__dashboard_post", "security": [{"API Key": []}, {"Tenant ID": []}, {"Bearer Auth": []}]}}}}

2、约束列表内容的 chunk 大小

注意,此示例中的一个 chunk 大于指定的 max_chunk_size 300。查看其中一个较大的 chunk(第八个为 469),我们看到那里有一个列表对象:

print([len(text) for text in texts][:10])
print()
print(texts[8]) # chunk 469
[286, 238, 344, 207, 227, 224, 231, 126, 469, 210]{"paths": {"/api/v1/sessions/{session_id}": {"get": {"parameters": [{"name": "session_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Session Id"}}, {"name": "include_stats", "in": "query", "required": false, "schema": {"type": "boolean", "default": false, "title": "Include Stats"}}, {"name": "accept", "in": "header", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Accept"}}]}}}}

这是因为默认情况下,json 分割器不分割列表。

我们可以指定 convert_lists=True 预处理 json,将列表内容转换为以 index:item 作为 key:val 键值对的字典。

texts = splitter.split_text(json_data=json_data, convert_lists=True)

让我们看一下 chunk 的大小,现在它们都在最大值以下:

print([len(text) for text in texts][:10])
[291, 253, 214, 232, 207, 227, 224, 236, 141, 203]

列表已转换为字典,但即使分成多个 chunk,也保留了所有需要的上下文信息:

print(texts[8])
print(texts[9])
print(texts[10])
{"paths": {"/api/v1/sessions/{session_id}": {"get": {"security": {"0": {"API Key": {}}, "1": {"Tenant ID": {}}, "2": {"Bearer Auth": {}}}}}}}
{"paths": {"/api/v1/sessions/{session_id}": {"get": {"parameters": {"0": {"name": "session_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Session Id"}}}}}}}
{"paths": {"/api/v1/sessions/{session_id}": {"get": {"parameters": {"1": {"name": "include_stats", "in": "query", "required": false, "schema": {"type": "boolean", "default": false, "title": "Include Stats"}}}}}}}

补充:中文字符显示问题

默认情况下,RecursiveJsonSplitter 类中的 create_documents 方法和 split_text 方法参数 ensure_ascii 都设置为 True,这意味着在输出中所有 非ASCII字符 都会被转义成\uXXXX 格式的序列。这种行为确保了输出的 JSON 字符串只包含 ASCII字符,从而可以被任何 JSON 解析器正确解析。

在这里插入图片描述

当我们希望在 JSON 字符串中保留 非ASCII字符(如中文)时,将 ensure_ascii 设置为False 就可以直接输出原始的 非ASCII文本 而不是转义序列。

在这里插入图片描述

在这里插入图片描述

参考文档

  • https://python.langchain.ac.cn/docs/concepts/text_splitters/
  • https://python.langchain.ac.cn/docs/how_to/recursive_text_splitter/
  • https://python.langchain.ac.cn/docs/how_to/character_text_splitter/
  • https://python.langchain.ac.cn/docs/how_to/markdown_header_metadata_splitter/
  • https://python.langchain.ac.cn/docs/how_to/recursive_json_splitter/
  • https://python.langchain.com/api_reference/text_splitters/json/langchain_text_splitters.json.RecursiveJsonSplitter.html#langchain_text_splitters.json.RecursiveJsonSplitter.create_documents

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

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

相关文章

【Java高频面试问题】高并发篇

【Java高频面试问题】高并发篇 Kafka原理核心组件高吞吐核心机制高可用设计 Kafka 如何保证消息不丢失如何解决Kafka重复消费一、生产者端:根源防重二、消费者端:精准控制三、业务层:幂等性设计(核心方案) 如何解决Kaf…

关于结构体,排序,递推的详细讲解(从属于GESP四级)

本章内容 排序算法基础 结构体 递推 简单双指针 一、排序算法基础三剑客 冒泡 Bubble、选择 Selection、插入 Insertion 1. 预备知识 1.1 排序算法评价指标 指标 含义 影响答题的典型问法 时间复杂度 算法在最坏、平均或最好情况下所需比较 / 交换次数 “写出此算法…

离线部署docker中的containerd服务

containerd 是一个行业标准的容器运行时,专注于简单、健壮的容器执行。它是从 Docker 中分离出来的项目,旨在作为一个底层的运行时接口,供更高层次的容器管理层使用。 containerd 负责镜像传输、存储、容器执行、网络配置等工作。它向上为 Do…

web布局15

CSS 网格布局除了提供定义网格和放置网格项目的相关属性之外,也提供了一些控制对齐方式的属性。这些控制对齐方式的属性,和 Flexbox 布局中的对齐属性 justify-* 、align-* 、*-items 、*-content 、 *-self 等是相似的: 在网格布局中可以用它…

leetcode 291. Word Pattern II和290. Word Pattern

目录 291. Word Pattern II 290. Word Pattern 291. Word Pattern II 回溯法哈希表 class Solution {unordered_map<char,string> hashmap;unordered_set<string> wordset; public:bool wordPatternMatch(string pattern, string s) {return backtrack(pattern,…

大模型的开发应用(十三):基于RAG的法律助手项目(上):总体流程简易实现

RAG法律助手项目&#xff08;上&#xff09;&#xff1a;总体流程简易实现 1 项目介绍1.1 方案选型1.2 知识文档 2 文档解析3 知识库构建3.1 构建知识节点3.2 嵌入向量初始化3.2 向量存储 4 查询4.1 初始化大模型4.2 模型响应4.2 本文程序存在的问题 完整代码 1 项目介绍 本项…

覆盖迁移工具选型、增量同步策略与数据一致性校验

1 引言 在当今数据驱动的时代&#xff0c;数据迁移已成为系统迭代、数据库升级、云迁移和架构演进中的关键环节。根据Gartner的调研&#xff0c;超过70%的企业级数据迁移项目因工具选择不当或同步策略缺陷而延期或失败。数据迁移不仅仅是简单的数据搬运&#xff0c;而是涉及数…

`docker run -it --rm` 笔记250624

docker run -it --rm 笔记250624 docker run -it --rm 是一个强大且常用的 Docker 命令组合&#xff0c;特别适合交互式开发和调试场景。以下是详细解析和使用指南&#xff1a; 参数解析 参数作用典型场景-i保持 STDIN 打开&#xff08;交互模式&#xff09;需要输入命令的交…

解锁阿里云AnalyticDB:数据仓库的革新利器

AnalyticDB&#xff1a;云数据仓库新势力 在数字化浪潮中&#xff0c;数据已成为企业的核心资产&#xff0c;而云数据仓库作为数据管理与分析的关键基础设施&#xff0c;正扮演着愈发重要的角色。阿里云 AnalyticDB 作为云数据仓库领域的佼佼者&#xff0c;以其卓越的性能、创…

【PX30 Qt 5.15 交叉编译环境搭建完整指南】

PX30 Qt 5.15 交叉编译环境搭建完整指南 (Ubuntu 20.04 → PX30 aarch64) &#x1f3af; 项目概览 本指南详细记录了在Ubuntu 20.04上搭建针对Rockchip PX30的Qt 5.15.2交叉编译环境的完整过程&#xff0c;包括实际操作步骤、遇到的问题及解决方案。 目标平台: Rockchip PX3…

深入理解读写锁 ReadWriteLock

在高性能并发编程中&#xff0c;如何有效地管理共享资源的访问是核心挑战之一。传统的排他锁&#xff08;如ReentrantLock&#xff09;在读多写少的场景下&#xff0c;性能瓶颈尤为突出&#xff0c;因为它不允许并发读取。Java并发包&#xff08;java.util.concurrent.locks&am…

Unity Addressable使用之检测更新流程

补充知识 关键文件说明 Addressable打包后会生成多种文件&#xff0c;主要包括 .hash、.json 和 .bundle 文件&#xff0c;它们各自有不同的作用。 .hash 文件&#xff08;哈希文件&#xff09; 作用&#xff1a; 用于 版本对比&#xff0c;检查资源是否有更新。存储的是 资…

Elasticsearch 中实现推荐搜索(方案设想)

1. 存储商品数据的数据类型 为了支持推荐搜索&#xff0c;商品数据通常需要包含以下字段&#xff1a; 商品索引结构 PUT /products {"mappings": {"properties": {"product_id": {"type": "keyword" // 商品 ID},"…

Aerotech系列(4)Aerotech.A3200名空间

IconTypeDescriptionAxisMask Represents a selection of axes Controller Represents a controller Allows configuring and c

React Router 是怎么实现灵活导航的?

&#x1f399; 欢迎来到《前端达人 React播客书单》第 21 期。 视频版&#xff08;播客风格更精彩&#xff09; 今天我们不讲 Hook&#xff0c;来拆解前端开发中另一个高频组件&#xff1a;React Router 的进阶导航模式。 你可能用过 <Link> 或 <Route>&#xff0…

Modbus TCP转Profibus DP网关与JF - 600MT 称重变送器轻松实现数据互换

Modbus TCP转Profibus DP网关与JF - 600MT 称重变送器轻松实现数据互换 在工业自动化领域&#xff0c;不同设备之间的通信与数据交互至关重要。Modbus TCP转Profibus DP网关作为连接不同协议设备的关键桥梁&#xff0c;发挥着不可或缺的作用。本文将以JF - 600MT称重变送器与3…

聊聊 SQL 注入那些事儿

相信大家对于学校们糟糕的网络环境和运维手段都早有体会&#xff0c;在此就不多做吐槽了。今天我们来聊一聊SQL注入相关的内容。 何谓SQL注入&#xff1f; SQL注入是一种非常常见的数据库攻击手段&#xff0c;SQL注入漏洞也是网络世界中最普遍的漏洞之一。大家也许都听过某某学…

多传感器融合

目录 多传感器融合 多传感器融合的方向 传感器融合方案介绍 LOAM LIO-SAM LVI-SAM 多线激光雷达性质 什么是运动畸变 两步优化的帧间里程记 IMU 器件介绍及选型建议 IMU 标定方法简介 视觉里程计 VS 激光里程计 LVI-SAM 激光视觉融合思路简介 多传感器融合工程实践经验与技巧 多…

Auto-GPT vs ReAct:两种智能体思路对决

目录 Auto-GPT vs ReAct&#xff1a;两种智能体思路对决 &#x1f9e0; 一、智能体的演化背景 &#x1f9e9; 二、Auto-GPT&#xff1a;自循环的执行体 &#x1f50d; 三、ReAct&#xff1a;推理 行动的交错协同 ⚔️ 四、对比总结 &#x1f6e0; 五、你该选谁&#xff…

本地部署大模型性能测试,DeepSeek-R1-0528-Qwen-8B 依然是我的不二之选

大家好&#xff0c;我是 ai 学习的老章 介绍一个大模型并发性能测试工具 看一下我高频使用的&#xff0c;在2*4090显卡上部署的 DeepSeek-R1-0528-Qwen-8B 性能如何 _我_特别喜欢的三个DeepSeek版本 DeepSeek-R1-0528 蒸馏 Qwen3:8B 大模型&#xff0c;双 4090 本地部署&am…