LangChain系列使用指南:组件介绍_数据处理_文本分割

www.aidoczh.com已经系统的将LangChain官网文档翻译成中文,您可以去http://www.aidoczh.com/langchain/v0.2/docs/introduction/ 查看文档,该网站www.aidoczh.com主要是将AI工具官方文档翻译成中文,还有其他工具文档可以看。

1. 按字符分割

这是最简单的方法。它基于字符(默认为 “\n\n”)进行分割,并通过字符数量来衡量块的长度。

  1. 文本如何分割:按单个字符。
  2. 块大小如何衡量:按字符数量。
%pip install -qU langchain-text-splitters
# 这是一个我们可以分割的长文档。
with open("../../state_of_the_union.txt") as f:
    state_of_the_union = f.read()
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])
page_content='Madam Speaker, Madam Vice President, our First Lady and Second Gentleman. Members of Congress and the Cabinet. Justices of the Supreme Court. My fellow Americans.  \n\nLast year COVID-19 kept us apart. This year we are finally together again. \n\nTonight, we meet as Democrats Republicans and Independents. But most importantly as Americans. \n\nWith a duty to one another to the American people to the Constitution. \n\nAnd with an unwavering resolve that freedom will always triumph over tyranny. \n\nSix days ago, Russia’s Vladimir Putin sought to shake the foundations of the free world thinking he could make it bend to his menacing ways. But he badly miscalculated. \n\nHe thought he could roll into Ukraine and the world would roll over. Instead he met a wall of strength he never imagined. \n\nHe met the Ukrainian people. \n\nFrom President Zelenskyy to every Ukrainian, their fearlessness, their courage, their determination, inspires the world.'

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

metadatas = [{"document": 1}, {"document": 2}]
documents = text_splitter.create_documents(
    [state_of_the_union, state_of_the_union], metadatas=metadatas
)
print(documents[0])
page_content='Madam Speaker, Madam Vice President, our First Lady and Second Gentleman. Members of Congress and the Cabinet. Justices of the Supreme Court. My fellow Americans.  \n\nLast year COVID-19 kept us apart. This year we are finally together again. \n\nTonight, we meet as Democrats Republicans and Independents. But most importantly as Americans. \n\nWith a duty to one another to the American people to the Constitution. \n\nAnd with an unwavering resolve that freedom will always triumph over tyranny. \n\nSix days ago, Russia’s Vladimir Putin sought to shake the foundations of the free world thinking he could make it bend to his menacing ways. But he badly miscalculated. \n\nHe thought he could roll into Ukraine and the world would roll over. Instead he met a wall of strength he never imagined. \n\nHe met the Ukrainian people. \n\nFrom President Zelenskyy to every Ukrainian, their fearlessness, their courage, their determination, inspires the world.' metadata={'document': 1}
text_splitter.split_text(state_of_the_union)[0]
'Madam Speaker, Madam Vice President, our First Lady and Second Gentleman. Members of Congress and the Cabinet. Justices of the Supreme Court. My fellow Americans.  \n\nLast year COVID-19 kept us apart. This year we are finally together again. \n\nTonight, we meet as Democrats Republicans and Independents. But most importantly as Americans. \n\nWith a duty to one another to the American people to the Constitution. \n\nAnd with an unwavering resolve that freedom will always triumph over tyranny. \n\nSix days ago, Russia’s Vladimir Putin sought to shake the foundations of the free world thinking he could make it bend to his menacing ways. But he badly miscalculated. \n\nHe thought he could roll into Ukraine and the world would roll over. Instead he met a wall of strength he never imagined. \n\nHe met the Ukrainian people. \n\nFrom President Zelenskyy to every Ukrainian, their fearlessness, their courage, their determination, inspires the world.'

2. 递归按字符分割

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

  1. 文本如何分割:按字符列表。
  2. 块大小如何衡量:按字符数。
%pip install -qU langchain-text-splitters
# 这是一个我们可以分割的长文档。
with open("../../state_of_the_union.txt") as f:
    state_of_the_union = f.read()
from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
    # 设置一个非常小的块大小,只是为了展示。
    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])
page_content='Madam Speaker, Madam Vice President, our First Lady and Second Gentleman. Members of Congress and'
page_content='of Congress and the Cabinet. Justices of the Supreme Court. My fellow Americans.'
text_splitter.split_text(state_of_the_union)[:2]
['Madam Speaker, Madam Vice President, our First Lady and Second Gentleman. Members of Congress and',
 'of Congress and the Cabinet. Justices of the Supreme Court. My fellow Americans.']

3. 按标记分割

语言模型有一个标记限制。您不应超过标记限制。因此,当您将文本分成块时,最好计算标记数。有许多标记器。在计算文本中的标记数时,应使用与语言模型中使用的相同的标记器。

tiktoken

tiktoken 是由 OpenAI 创建的快速 BPE 标记器。

我们可以使用它来估算使用的标记数。对于 OpenAI 模型来说,这可能更准确。

  1. 文本如何分割:按字符传递。
  2. 如何测量块大小:通过 tiktoken 标记器。
%pip install --upgrade --quiet langchain-text-splitters tiktoken
# 这是一个我们可以分割的长文档。
with open("../../state_of_the_union.txt") as f:
    state_of_the_union = f.read()
from langchain_text_splitters import CharacterTextSplitter
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
    chunk_size=100, chunk_overlap=0
)
texts = text_splitter.split_text(state_of_the_union)
print(texts[0])
Madam Speaker, Madam Vice President, our First Lady and Second Gentleman. Members of Congress and the Cabinet. Justices of the Supreme Court. My fellow Americans.  

Last year COVID-19 kept us apart. This year we are finally together again. 

Tonight, we meet as Democrats Republicans and Independents. But most importantly as Americans. 

With a duty to one another to the American people to the Constitution.

请注意,如果我们使用 CharacterTextSplitter.from_tiktoken_encoder,文本仅由 CharacterTextSplitter 分割,而 tiktoken 标记器用于合并分割。这意味着分割可能比 tiktoken 标记器测量的块大小要大。我们可以使用 RecursiveCharacterTextSplitter.from_tiktoken_encoder 来确保分割不会大于语言模型允许的标记块大小,如果某个分割大小超过了限制,将会递归地进行分割。

我们也可以直接加载一个 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])

spaCy

spaCy 是一个用 Python 和 Cython 编写的先进自然语言处理开源软件库。

NLTK 不同,我们可以使用 spaCy 标记器 进行分割。

  1. 文本如何分割:通过 spaCy 标记器。
  2. 如何测量块大小:按字符数。
%pip install --upgrade --quiet  spacy
# 这是一个我们可以分割的长文档。
with open("../../state_of_the_union.txt") as f:
    state_of_the_union = f.read()
from langchain_text_splitters import SpacyTextSplitter

text_splitter = SpacyTextSplitter(chunk_size=1000)
texts = text_splitter.split_text(state_of_the_union)
print(texts[0])
Madam Speaker, Madam Vice President, our First Lady and Second Gentleman.

Members of Congress and the Cabinet.

Justices of the Supreme Court.

My fellow Americans.  

...

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)
2
token_multiplier = splitter.maximum_tokens_per_chunk // text_token_count + 1

# `text_to_split` 无法适应单个块
text_to_split = text * token_multiplier

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

print(text_chunks[1])
lorem

NLTK

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

与其仅仅根据 “\n\n” 进行分割,我们可以使用 NLTK 根据 NLTK 标记器 进行分割。

  1. 文本如何分割:通过 NLTK 标记器。
  2. 如何测量块大小:按字符数。
# pip install nltk
# 这是一个我们可以分割的长文档。
with open("../../state_of_the_union.txt") as f:
    state_of_the_union = f.read()
from langchain_text_splitters import NLTKTextSplitter

text_splitter = NLTKTextSplitter(chunk_size=1000)
texts = text_splitter.split_text(state_of_the_union)
print(texts[0])
Madam Speaker, Madam Vice President, our First Lady and Second Gentleman.

Members of Congress and the Cabinet.

Justices of the Supreme Court.

My fellow Americans.

...

KoNLPY

KoNLPy: Korean NLP in Python 是用于韩语自然语言处理(NLP)的 Python 包。

标记分割涉及将文本分割成更小、更易处理的单元,称为标记。这些标记通常是单词、短语、符号或其他对进一步处理和分析至关重要的有意义元素。在英语等语言中,标记分割通常涉及通过空格和标点符号分隔单词。标记分割的有效性在很大程度上取决于标记器对语言结构的理解,确保生成有意义的标记。由于为英语设计的标记器无法理解韩语等其他语言的独特语义结构,因此无法有效用于韩语语言处理。

使用 KoNLPy 的 Kkma 分析器进行韩语的标记分割

在韩语文本的情况下,KoNLPY 包含一个称为 Kkma(韩语知识形态分析器)的形态分析器。Kkma 提供韩语文本的详细形态分析。它将句子分解为单词,将单词分解为各自的形态素,为每个标记识别词性。它可以将一块文本分割成单独的句子,这对于处理长文本特别有用。

使用注意事项

虽然 Kkma 以其详细的分析而闻名,但重要的是要注意,这种精度可能会影响处理速度。因此,Kkma 最适用于将分析深度置于快速文本处理之上的应用程序。

# pip install konlpy
# 这是一个我们想要将其分割成组成句子的韩文文档。
with open("./your_korean_doc.txt") as f:
    korean_document = f.read()
from langchain_text_splitters import KonlpyTextSplitter

text_splitter = KonlpyTextSplitter()
texts = text_splitter.split_text(korean_document)
# 句子以 "\n\n" 字符分割。
print(texts[0])
故事讲述了这位年轻的官员在升任高官后,最终找到了春香。

两人经历了重重考验后再次相遇,他们的爱情传遍全世界,延续到后人。

- 《春香传》

Hugging Face 分词器

Hugging Face 拥有许多分词器。

我们使用 Hugging Face 分词器,GPT2TokenizerFast 来计算文本长度(以 token 为单位)。

  1. 文本如何分割:按字符进行分割。
  2. 块大小如何测量:由 Hugging Face 分词器计算的 token 数量。
from transformers import GPT2TokenizerFast

tokenizer = GPT2TokenizerFast.from_pretrained("gpt2")
# 这是一个可以分割的长文档。
with open("../../../state_of_the_union.txt") as f:
    state_of_the_union = f.read()
from langchain_text_splitters import CharacterTextSplitter
text_splitter = CharacterTextSplitter.from_huggingface_tokenizer(
    tokenizer, chunk_size=100, chunk_overlap=0
)
texts = text_splitter.split_text(state_of_the_union)
print(texts[0])
Madam Speaker, Madam Vice President, our First Lady and Second Gentleman. Members of Congress and the Cabinet. Justices of the Supreme Court. My fellow Americans.  

Last year COVID-19 kept us apart. This year we are finally together again. 

Tonight, we meet as Democrats Republicans and Independents. But most importantly as Americans. 

With a duty to one another to the American people to the Constitution.

4. MarkdownHeaderTextSplitter

动机

许多聊天或问答应用程序在嵌入和向量存储之前涉及对输入文档进行分块。

Pinecone的这些笔记提供了一些有用的提示:

当嵌入整个段落或文档时,嵌入过程考虑文本中句子和短语之间的整体上下文和关系。这可能导致更全面的向量表示,捕捉文本的更广泛含义和主题。

正如上文所述,分块通常旨在将具有共同上下文的文本放在一起。考虑到这一点,我们可能希望特别尊重文档本身的结构。例如,Markdown文件是由标题组织的。在特定标题组内创建分块是一个直观的想法。为了解决这一挑战,我们可以使用 MarkdownHeaderTextSplitter。这将根据指定的一组标题来拆分Markdown文件。

例如,如果我们想要拆分这个Markdown:

md = '# Foo\n\n ## Bar\n\nHi this is Jim  \nHi this is Joe\n\n ## Baz\n\n Hi this is Molly' 

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

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

然后内容将根据共同的标题进行分组或拆分:

{'content': 'Hi this is Jim  \nHi this is Joe', 'metadata': {'Header 1': 'Foo', 'Header 2': 'Bar'}}
{'content': 'Hi this is Molly', 'metadata': {'Header 1': 'Foo', 'Header 2': 'Baz'}}

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

%pip install -qU langchain-text-splitters
from langchain_text_splitters import MarkdownHeaderTextSplitter
markdown_document = "# Foo\n\n    ## Bar\n\nHi this is Jim\n\nHi this is Joe\n\n ### Boo \n\n Hi this is Lance \n\n ## Baz\n\n Hi this is Molly"

headers_to_split_on = [
    ("#", "Header 1"),
    ("##", "Header 2"),
    ("###", "Header 3"),
]

markdown_splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
md_header_splits = markdown_splitter.split_text(markdown_document)
md_header_splits
type(md_header_splits[0])

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

markdown_splitter = MarkdownHeaderTextSplitter(
    headers_to_split_on=headers_to_split_on, strip_headers=False
)
md_header_splits = markdown_splitter.split_text(markdown_document)
md_header_splits

在每个Markdown组内,我们可以应用任何我们想要的文本拆分器。

markdown_document = "# Intro \n\n    ## History \n\n Markdown[9] is a lightweight markup language for creating formatted text using a plain-text editor. John Gruber created Markdown in 2004 as a markup language that is appealing to human readers in its source code form.[9] \n\n Markdown is widely used in blogging, instant messaging, online forums, collaborative software, documentation pages, and readme files. \n\n ## Rise and divergence \n\n As Markdown popularity grew rapidly, many Markdown implementations appeared, driven mostly by the need for \n\n additional features such as tables, footnotes, definition lists,[note 1] and Markdown inside HTML blocks. \n\n #### Standardization \n\n From 2012, a group of people, including Jeff Atwood and John MacFarlane, launched what Atwood characterised as a standardisation effort. \n\n ## Implementations \n\n Implementations of Markdown are available for over a dozen programming languages."

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

# 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)

# Char-level splits
from langchain_text_splitters import RecursiveCharacterTextSplitter

chunk_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

5. HTMLHeaderTextSplitter

描述与动机

MarkdownHeaderTextSplitter类似,HTMLHeaderTextSplitter是一个“结构感知”分块器,它在元素级别拆分文本,并为每个与任何给定分块相关的标题添加元数据。它可以逐个元素返回分块,也可以将具有相同元数据的元素组合在一起,其目标是(a)将相关文本(或多或少)语义地分组,并(b)保留编码在文档结构中的上下文丰富信息。它可以与其他文本分块器一起用作分块管道的一部分。

使用示例

1) 使用 HTML 字符串:
%pip install -qU langchain-text-splitters
from langchain_text_splitters import HTMLHeaderTextSplitter

html_string = """
<!DOCTYPE html>
<html>
<body>
    <div>
        <h1>Foo</h1>
        <p>Some intro text about Foo.</p>
        <div>
            <h2>Bar main section</h2>
            <p>Some intro text about Bar.</p>
            <h3>Bar subsection 1</h3>
            <p>Some text about the first subtopic of Bar.</p>
            <h3>Bar subsection 2</h3>
            <p>Some text about the second subtopic of Bar.</p>
        </div>
        <div>
            <h2>Baz</h2>
            <p>Some text about Baz</p>
        </div>
        <br>
        <p>Some concluding text about Foo</p>
    </div>
</body>
</html>
"""

headers_to_split_on = [
    ("h1", "Header 1"),
    ("h2", "Header 2"),
    ("h3", "Header 3"),
]

html_splitter = HTMLHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
html_header_splits = html_splitter.split_text(html_string)
html_header_splits
2) 与另一个分块器串联,从网址加载 HTML:
from langchain_text_splitters import RecursiveCharacterTextSplitter

url = "https://plato.stanford.edu/entries/goedel/"

headers_to_split_on = [
    ("h1", "Header 1"),
    ("h2", "Header 2"),
    ("h3", "Header 3"),
    ("h4", "Header 4"),
]

html_splitter = HTMLHeaderTextSplitter(headers_to_split_on=headers_to_split_on)

# 对于本地文件,请使用html_splitter.split_text_from_file(<path_to_file>)
html_header_splits = html_splitter.split_text_from_url(url)

chunk_size = 500
chunk_overlap = 30
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=chunk_size, chunk_overlap=chunk_overlap
)

# 分块
splits = text_splitter.split_documents(html_header_splits)
splits[80:85]

限制

不同的 HTML 文档之间可能存在相当大的结构变化,而HTMLHeaderTextSplitter会尝试将所有“相关”标题附加到任何给定的分块,但有时可能会错过某些标题。例如,在以下新闻文章(截至本文撰写时)中,文档的结构使得顶级标题的文本,虽然标记为“h1”,但位于与我们期望的文本元素“上方”不同的子树中,因此我们可以观察到“h1”元素及其相关文本不会显示在分块元数据中(但在适用的情况下,我们会看到“h2”及其相关文本):

url = "https://www.cnn.com/2023/09/25/weather/el-nino-winter-us-climate/index.html"

headers_to_split_on = [
    ("h1", "Header 1"),
    ("h2", "Header 2"),
]

html_splitter = HTMLHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
html_header_splits = html_splitter.split_text_from_url(url)
print(html_header_splits[1].page_content[:500])

6. 代码分割

CodeTextSplitter 允许您使用多种支持的语言拆分代码。导入枚举 Language 并指定语言。

%pip install -qU langchain-text-splitters
from langchain_text_splitters import (
    Language,
    RecursiveCharacterTextSplitter,
)
# 支持的语言完整列表
[e.value for e in Language]

[‘cpp’, ‘go’, ‘java’, ‘kotlin’, ‘js’, ‘ts’, ‘php’, ‘proto’, ‘python’, ‘rst’, ‘ruby’, ‘rust’, ‘scala’, ‘swift’, ‘markdown’, ‘latex’, ‘html’, ‘sol’, ‘csharp’, ‘cobol’]

# 您还可以查看给定语言使用的分隔符
RecursiveCharacterTextSplitter.get_separators_for_language(Language.PYTHON)

['\nclass ', '\ndef ', '\n\tdef ', ‘\n\n’, ‘\n’, ’ ', ‘’]

Python

这里是使用 PythonTextSplitter 的示例:

PYTHON_CODE = """
def hello_world():
    print("Hello, World!")

# 调用函数
hello_world()
"""
python_splitter = RecursiveCharacterTextSplitter.from_language(
    language=Language.PYTHON, chunk_size=50, chunk_overlap=0
)
python_docs = python_splitter.create_documents([PYTHON_CODE])
python_docs

[Document(page_content=‘def hello_world():\n print(“Hello, World!”)’),
Document(page_content=‘# 调用函数\nhello_world()’)]

JS

这里是使用 JS 文本拆分器的示例:

JS_CODE = """
function helloWorld() {
  console.log("Hello, World!");
}

// 调用函数
helloWorld();
"""

js_splitter = RecursiveCharacterTextSplitter.from_language(
    language=Language.JS, chunk_size=60, chunk_overlap=0
)
js_docs = js_splitter.create_documents([JS_CODE])
js_docs

[Document(page_content=‘function helloWorld() {\n console.log(“Hello, World!”);\n}’),
Document(page_content=‘// 调用函数\nhelloWorld();’)]

TS

这里是使用 TS 文本拆分器的示例:

TS_CODE = """
function helloWorld(): void {
  console.log("Hello, World!");
}

// 调用函数
helloWorld();
"""

ts_splitter = RecursiveCharacterTextSplitter.from_language(
    language=Language.TS, chunk_size=60, chunk_overlap=0
)
ts_docs = ts_splitter.create_documents([TS_CODE])
ts_docs

[Document(page_content=‘function helloWorld(): void {’),
Document(page_content=‘console.log(“Hello, World!”);\n}’),
Document(page_content=‘// 调用函数\nhelloWorld();’)]

Markdown

这里是使用 Markdown 文本拆分器的示例:

markdown_text = """
# 🦜️🔗 LangChain

⚡ 通过组合性构建具有 LLM 的应用程序 ⚡

## 快速安装

```bash
# 希望此代码块不会被拆分
pip install langchain

作为一个在快速发展领域中的开源项目,我们非常欢迎贡献。
“”"

```python
md_splitter = RecursiveCharacterTextSplitter.from_language(
    language=Language.MARKDOWN, chunk_size=60, chunk_overlap=0
)
md_docs = md_splitter.create_documents([markdown_text])
md_docs

[Document(page_content=‘# 🦜️🔗 LangChain’),
Document(page_content=‘⚡ 通过组合性构建具有 LLM 的应用程序 ⚡’),
Document(page_content=‘## 快速安装\n\nbash'), Document(page_content='# 希望此代码块不会被拆分'), Document(page_content='pip install langchain'), Document(page_content='’),
Document(page_content=‘作为一个在快速发展领域中的开源项目,我们’),
Document(page_content=‘非常欢迎贡献。’)]

Latex

这里是 Latex 文本的示例:

latex_text = """
\documentclass{article}

\begin{document}

\maketitle

\section{Introduction}
大型语言模型(LLMs)是一种可以在大量文本数据上训练的机器学习模型,用于生成类似人类语言的文本。近年来,LLMs 在各种自然语言处理任务中取得了重大进展,包括语言翻译、文本生成和情感分析。

\subsection{LLMs 的历史}
最早的 LLMs 开发于 1980 年代和 1990 年代,但受限于当时可处理的数据量和计算能力。然而,在过去的十年中,硬件和软件的进步使得在大规模数据集上训练 LLMs 成为可能,从而显著提高了性能。

\subsection{LLMs 的应用}
LLMs 在工业界有许多应用,包括聊天机器人、内容创作和虚拟助手。它们也可以用于学术界的语言学、心理学和计算语言学研究。

\end{document}
"""
latex_splitter = RecursiveCharacterTextSplitter.from_language(
    language=Language.MARKDOWN, chunk_size=60, chunk_overlap=0
)
latex_docs = latex_splitter.create_documents([latex_text])
latex_docs

[Document(page_content=‘\documentclass{article}\n\n\x08egin{document}\n\n\maketitle’),
Document(page_content=‘\section{Introduction}’),
Document(page_content=‘大型语言模型(LLMs)是一种可以在大量文本数据上训练的机器学习’),
Document(page_content=‘模型,用于生成类似人类语言的文本。近年来,LLMs 在各种自然语言处理’),
Document(page_content=‘任务中取得了重大进展,包括语言翻译、文本生成和情感分析。’),
Document(page_content=‘\subsection{LLMs 的历史}’),
Document(page_content=‘最早的 LLMs 开发于 1980 年代和 1990 年代,但受限于当时可处理的数据量和’),
Document(page_content=‘计算能力。然而,在过去的十年中,硬件和软件的进步使得在大规模数据集上训练 LLMs 成为’),
Document(page_content=‘可能,从而显著提高了性能。’),
Document(page_content=‘\subsection{LLMs 的应用}’),
Document(page_content=‘LLMs 在工业界有许多应用,包括聊天机器人、内容创作和虚拟助手。它们’),
Document(page_content=‘也可以用于学术界的语言学、心理学和计算语言学研究。’),
Document(page_content=‘\end{document}’)]

HTML

这里是使用 HTML 文本拆分器的示例:

html_text = """
<!DOCTYPE html>
<html>
    <head>
        <title>🦜️🔗 LangChain</title>
        <style>
            body {
                font-family: Arial, sans-serif;
            }
            h1 {
                color: darkblue;
            }
        </style>
    </head>
    <body>
        <div>
            <h1>🦜️🔗 LangChain</h1>
            <p>⚡ 通过组合性构建具有 LLM 的应用程序 ⚡</p>
        </div>
        <div>
            作为一个在快速发展领域中的开源项目,我们非常欢迎贡献。
        </div>
    </body>
</html>
"""
html_splitter = RecursiveCharacterTextSplitter.from_language(
    language=Language.HTML, chunk_size=60, chunk_overlap=0
)
html_docs = html_splitter.create_documents([html_text])
html_docs

[Document(page_content=‘\n’),
Document(page_content=‘\n 🦜️🔗 LangChain’),
Document(page_content=‘\n </head’),
Document(page_content=‘>’),
Document(page_content=‘’),
Document(page_content=‘

\n

🦜️🔗 LangChain

’),
Document(page_content=‘

⚡ 通过组合性构建具有 LLM 的应用程序 ⚡’),
Document(page_content=‘

\n
’),
Document(page_content=‘
\n 作为一个在快速发展领域中的开源项目,我们’),
Document(page_content=‘非常欢迎贡献。’),
Document(page_content=‘
\n \n’)]

Solidity

这里是使用 Solidity 文本拆分器的示例:

SOL_CODE = """
pragma solidity ^0.8.20;
contract HelloWorld {
   function add(uint a, uint b) pure public returns(uint) {
       return a + b;
   }
}
"""

sol_splitter = RecursiveCharacterTextSplitter.from_language(
    language=Language.SOL, chunk_size=128, chunk_overlap=0
)
sol_docs = sol_splitter.create_documents([SOL_CODE])
sol_docs

[Document(page_content=‘pragma solidity ^0.8.20;’),
Document(page_content=‘contract HelloWorld {\n function add(uint a, uint b) pure public returns(uint) {\n return a + b;\n }\n}’)]

C#

这里是使用 C# 文本拆分器的示例:

C_CODE = """
using System;
class Program
{
    static void Main()
    {
        int age = 30; // 根据需要更改年龄值

        // 对年龄进行分类,不输出任何控制台信息
        if (age < 18)
        {
            // 年龄小于 18 岁
        }
        else if (age >= 18 && age < 65)
        {
            // 年龄为成年人
        }
        else
        {
            // 年龄为老年人
        }
    }
}
"""
c_splitter = RecursiveCharacterTextSplitter.from_language(
    language=Language.CSHARP, chunk_size=128, chunk_overlap=0
)
c_docs = c_splitter.create_documents([C_CODE])
c_docs

[Document(page_content=‘using System;’),
Document(page_content=‘class Program\n{\n static void Main()\n {\n int age = 30; // 根据需要更改年龄值’)]

     文档(page_content='}\n        else if (age >= 18 && age < 65)\n        {\n            // 年龄为成年人\n        }\n        else\n        {'),
     文档(page_content='// 年龄为老年人\n        }\n    }\n}')]




7. 递归拆分 JSON

这个 JSON 拆分器按深度优先方式遍历 JSON 数据并构建较小的 JSON 块。它试图保持嵌套的 JSON 对象完整,但如果需要保持块在最小块大小和最大块大小之间,则会对它们进行拆分。如果值不是嵌套的 JSON,而是一个非常大的字符串,则该字符串不会被拆分。如果您需要对块大小设置硬上限,可以考虑在这之后使用递归文本拆分器对这些块进行拆分。还有一个可选的预处理步骤,可以通过首先将列表转换为 JSON(字典),然后进行拆分来拆分列表。

  1. 文本如何拆分:按 JSON 值。
  2. 块大小如何衡量:按字符数。
%pip install -qU langchain-text-splitters
import json

import requests
# 这是一个大型嵌套的 JSON 对象,将被加载为 Python 字典
json_data = requests.get("https://api.smith.langchain.com/openapi.json").json()
from langchain_text_splitters import RecursiveJsonSplitter
splitter = RecursiveJsonSplitter(max_chunk_size=300)
# 递归拆分 JSON 数据 - 如果您需要访问/操作较小的 JSON 块
json_chunks = splitter.split_json(json_data=json_data)
# 拆分器还可以输出文档
docs = splitter.create_documents(texts=[json_data])

# 或者输出字符串列表
texts = splitter.split_text(json_data=json_data)

print(texts[0])
print(texts[1])
# 让我们看看这些块的大小
print([len(text) for text in texts][:10])

# 回顾其中一个较大的块,我们可以看到其中有一个列表对象
print(texts[1])
# 默认情况下,JSON 拆分器不会拆分列表
# 下面的操作将预处理 JSON,并将列表转换为具有索引:项作为键:值对的字典
texts = splitter.split_text(json_data=json_data, convert_lists=True)
# 让我们看看这些块的大小。现在它们都在最大块以下
print([len(text) for text in texts][:10])
# 列表已转换为字典,但即使拆分为多个块,仍保留所有所需的上下文信息
print(texts[1])
# 我们也可以查看文档
docs[1]

8. 语义分块

根据语义相似性对文本进行分割。

摘自 Greg Kamradt 的精彩笔记:
https://github.com/FullStackRetrieval-com/RetrievalTutorials/blob/main/5_Levels_Of_Text_Splitting.ipynb

所有荣誉归给他。

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

安装依赖

!pip install --quiet langchain_experimental langchain_openai

载入示例数据

# 这是一个可以分割的长文档。
with open("../../state_of_the_union.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)
女士们先生们,副总统女士,我们的第一夫人和第二绅士。国会议员和内阁成员。最高法院大法官。我的美国同胞。去年,COVID-19 让我们分隔两地。今年,我们终于再次聚在一起。今晚,我们作为民主党人、共和党人和独立人士相聚。但更重要的是,作为美国人。我们有责任对彼此,对美国人民,对宪法。并怀着坚定的决心,自由将永远战胜暴政。六天前,俄罗斯的弗拉基米尔·普京试图动摇自由世界的基础,认为他可以让其屈服于他的威胁方式。但他严重误判了。他以为可以进入乌克兰,而世界会屈服。相反,他遇到了他从未想象过的强大力量。他遇到了乌克兰人民。从泽连斯基总统到每一位乌克兰人,他们的无畏、勇气和决心激励着世界。一群市民用自己的身体挡住坦克。从学生到退休人员,从教师变成士兵捍卫家园。正如泽连斯基总统在向欧洲议会发表的讲话中所说的那样,“光明将战胜黑暗。”乌克兰驻美国大使今晚在这里。让我们今晚在这个议会向乌克兰和世界发出明确的信号。如果您能站起来并表明,是的,我们美利坚合众国与乌克兰人民站在一起。在我们的历史上,我们学到了这个教训,当独裁者对他们的侵略不付出代价时,他们会造成更多混乱。他们会继续前进。

断点

这个分块器通过确定何时“断开”句子来工作。这是通过查找任意两个句子之间的嵌入差异来完成的。当差异超过某个阈值时,它们就会被分割。

有几种方法可以确定该阈值是多少。

百分位数

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

text_splitter = SemanticChunker(
    OpenAIEmbeddings(), breakpoint_threshold_type="percentile"
)
docs = text_splitter.create_documents([state_of_the_union])
print(docs[0].page_content)
女士们先生们,副总统女士,我们的第一夫人和第二绅士。国会议员和内阁成员。最高法院大法官。我的美国同胞。去年,COVID-19 让我们分隔两地。今年,我们终于再次聚在一起。今晚,我们作为民主党人、共和党人和独立人士相聚。但更重要的是,作为美国人。我们有责任对彼此,对美国人民,对宪法。并怀着坚定的决心,自由将永远战胜暴政。六天前,俄罗斯的弗拉基米尔·普京试图动摇自由世界的基础,认为他可以让其屈服于他的威胁方式。但他严重误判了。他以为可以进入乌克兰,而世界会屈服。相反,他遇到了他从未想象过的强大力量。他遇到了乌克兰人民。从泽连斯基总统到每一位乌克兰人,他们的无畏、勇气和决心激励着世界。一群市民用自己的身体挡住坦克。从学生到退休人员,从教师变成士兵捍卫家园。正如泽连斯基总统在向欧洲议会发表的讲话中所说的那样,“光明将战胜黑暗。”乌克兰驻美国大使今晚在这里。让我们今晚在这个议会向乌克兰和世界发出明确的信号。如果您能站起来并表明,是的,我们美利坚合众国与乌克兰人民站在一起。在我们的历史上,我们学到了这个教训,当独裁者对他们的侵略不付出代价时,他们会造成更多混乱。他们会继续前进。
print(len(docs))
26

标准差

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

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

四分位数法

在这种方法中,四分位距被用来分割文本块。

text_splitter = SemanticChunker(
    OpenAIEmbeddings(), breakpoint_threshold_type="interquartile"
)
docs = text_splitter.create_documents([state_of_the_union])
print(docs[0].page_content)
女士们先生们,女副总统,我们的第一夫人和第二先生。国会议员和内阁成员。最高法院大法官。我的美国同胞们。去年,COVID-19让我们分隔两地。今年,我们终于再次聚在一起。今晚,我们作为民主党人、共和党人和独立人士相聚一堂。但更重要的是,作为美国人。我们有责任对彼此,对美国人民,对宪法。我们坚定地相信,自由将永远战胜暴政。六天前,俄罗斯的弗拉基米尔·普京试图动摇自由世界的基石,认为他可以让其屈服于他的威胁方式。但他严重误判了。他以为可以轻易进入乌克兰,而世界会屈服。相反,他遇到了一堵他从未想象过的坚固墙。他遇到了乌克兰人民。从泽连斯基总统到每一位乌克兰人,他们的无畏、勇气和决心激励着世界。一群市民用自己的身体挡住坦克。从学生到退休人员,从教师变成保卫家园的士兵。正如泽连斯基总统在向欧洲议会发表讲话中所说的那样,“光明将战胜黑暗。” 乌克兰驻美国大使今晚在这里。让我们今晚在这个议会向乌克兰和世界发出明确的信号。如果您能站起来并表达,“是的,我们美利坚合众国与乌克兰人民站在一起。” 在我们的历史上,我们学到了这个教训,当独裁者不为其侵略付出代价时,他们会造成更多混乱。他们会继续前进。
print(len(docs))
25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数智笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值