一旦加载了文档,通常会希望对其进行转换以更好地适应您的应用程序。
最简单的例子是,您可能希望将长文档拆分为较小的块,以适应模型的上下文窗口。
LangChain具有许多内置的文档转换器,可以轻松地拆分、合并、过滤和其他操作文档。
代码剖析 Document 类
这段代码定义了一个名为Document
的类,允许用户与文档的内容进行交互,可以查看文档的段落、摘要,以及使用查找功能来查询文档中的特定字符串。
# 基于BaseModel定义的文档类。
class Document(BaseModel):
"""接口,用于与文档进行交互。"""
# 文档的主要内容。
page_content: str
# 用于查找的字符串。
lookup_str: str = ""
# 查找的索引,初次默认为0。
lookup_index = 0
# 用于存储任何与文档相关的元数据。
metadata: dict = Field(default_factory=dict)
@property
def paragraphs(self) -> List[str]:
"""页面的段落列表。"""
# 使用"\n\n"将内容分割为多个段落。
return self.page_content.split("\n\n")
@property
def summary(self) -> str:
"""页面的摘要(即第一段)。"""
# 返回第一个段落作为摘要。
return self.paragraphs[0]
# 这个方法模仿命令行中的查找功能。
def lookup(self, string: str) -> str:
"""在页面中查找一个词,模仿cmd-F功能。"""
# 如果输入的字符串与当前的查找字符串不同,则重置查找字符串和索引。
if string.lower() != self.lookup_str:
self.lookup_str = string.lower()
self.lookup_index = 0
else:
# 如果输入的字符串与当前的查找字符串相同,则查找索引加1。
self.lookup_index += 1
# 找出所有包含查找字符串的段落。
lookups = [p for p in self.paragraphs if self.lookup_str in p.lower()]
# 根据查找结果返回相应的信息。
if len(lookups) == 0:
return "No Results"
elif self.lookup_index >= len(lookups):
return "No More Results"
else:
result_prefix = f"(Result {self.lookup_index + 1}/{len(lookups)})"
return f"{result_prefix} {lookups[self.lookup_index]}"
Text Splitters 文本分割器
当你想处理长篇文本时,有必要将文本分成块。听起来很简单,但这里存在着潜在的复杂性。理想情况下,你希望将语义相关的文本片段放在一起。"语义相关"的含义可能取决于文本类型。这个笔记本展示了几种实现方式。
从高层次上看,文本分割器的工作原理如下:
- 1.将文本分成小而有意义的块(通常是句子)。
- 2.开始将这些小块组合成较大的块,直到达到某个大小(通过某个函数进行测量)。
- 3.一旦达到该大小,使该块成为自己独立的一部分,并开始创建一个具有一定重叠(以保持上下文关系)的新文本块。
这意味着您可以沿两个不同轴向定制您的文本分割器:
- 如何拆分文字
- 如何测量块大小
使用 RecursiveCharacterTextSplitter
文本分割器
该文本分割器接受一个字符列表作为参数,根据第一个字符进行切块,但如果任何切块太大,则会继续移动到下一个字符,并以此类推。默认情况下,它尝试进行切割的字符包括 ["\n\n", "\n", " ", ""]
相关参数:
- length_function:用于计算切块长度的方法。默认只计算字符数,但通常在这里传递一个令牌计数器。
- chunk_size:您的切块的最大大小(由长度函数测量)。
- chunk_overlap:切块之间的最大重叠部分。保持一定程度的重叠可以使得各个切块之间保持连贯性(例如滑动窗口)。
- add_start_index:是否在元数据中包含每个切块在原始文档中的起始位置。
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 加载待分割长文本
with open('state_of_the_union.txt') as f:
state_of_the_union = f.read()
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=100,
chunk_overlap=20,
length_function=len,
add_start_index=True,
)
docs = text_splitter.create_documents([state_of_the_union])
print(docs)
分割代码
from langchain.text_splitter import Language
# [e.value for e in Language]
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>⚡ Building applications with LLMs through composability ⚡</p>
</div>
<div>
As an open source project in a rapidly developing field, we are extremely open to contributions.
</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])
print(html_docs)