在处理文本数据时,有时我们需要将长文本按照指定的最大长度进行分块处理,以便更好地进行处理和分析,当前知识库+LLM产品都需要为用户上传的文档进行知识工程处理(通常是对文档进行分段,然后进行向量化,最后在问答时向量搜索知识库以获得答案)。为了实现这一目标,我们可以使用一个方便的工具类——文本分块器(TextChunker)。
本文重点介绍一种文本自动分段方法的操作流程,借鉴了fastGPT、dify等知识库产品,并使用Java语言实现一个分块工具类来帮助开发者深入理解和快速上手。
为什么需要对文档分段,首先LLM对输入长度有着天然的限制,比如目前性能较好的gpt3.5-16k,对输入的长度支持高达到16k,我们对分段的自动设置为LLM的max_tokens的40%,这里我们预设为中文场景,token换算成汉字要打对折,而且我们还要预留LLM响应的token数量,所以取值40%(fastGPT源码显示其取值为max_tokens*0.45,因为我们希望生成尽可能多的问答对,所以需要预留更多输出token,故本例取值向下取到40%),生成问答对不是一种必然选项,将再后续文章中展开加以说明。
每两个分割的段落的收尾部分有一定重叠,本例为25%(max_tokens*0.4*0.25,fastGPT源码亦取值0.25),两段内容首尾有一定重叠可避免生硬分割导致的知识割裂现象。
工具类概述
文本分块器的主要功能是将输入的文本按照指定的最大长度进行分块处理,并返回分块后的结果和每个分块的令牌数量。以下是该工具类的主要功能点:
使用方法
使用文本分块器非常简单。下面直接提供Java版完整代码:
import java.util.ArrayList;
import java.util.List;
/*** 按照句号问号分号感叹号做为句子结束符,保证分割两块句子的完整性,同时让两段内容之间有一定的重叠。
*/
public class TextChunker {
public static class ChunkInfo {
private final Listchunks;
private final int tokens;
public ChunkInfo(Listchunks, int tokens) {
this.chunks = chunks;
this.tokens = tokens;
}
public ListgetChunks() {
return chunks;
}
public int getTokens() {
return tokens;
}
}
public static ChunkInfo splitTextIntoChunks(String text, int maxLen) {
int overlapLen = (int) (maxLen * 0.25); // 重叠长度
try {
String[] splitTexts = text.split("(?<=[。!?;.!?;])"); // 使用正则表达式分割文本成句子
Listchunks = new ArrayList<>();
String preChunk = "";
String chunk = "";
int tokens = 0;
for (String sentence : splitTexts) {
chunk += sentence;
if (chunk.length() > maxLen - overlapLen) {
preChunk += sentence;
}
if (chunk.length() >= maxLen) {
chunks.add(chunk);
tokens += countPromptTokens(chunk, "system"); // 计算令牌数量
chunk = preChunk;
preChunk = "";
}
}
if (!chunk.isEmpty()) {
chunks.add(chunk);
tokens += countPromptTokens(chunk, "system"); // 计算令牌数量
}
return new ChunkInfo(chunks, tokens);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static int countPromptTokens(String text, String type) {
// 在这里实现你的令牌计数逻辑
// 此函数根据指定的类型计算块中的令牌数量
// 你应该替换此部分以实现实际的令牌计数逻辑
return 0;
}
public static void main(String[] args) {
String inputText = "这是一个示例文本。它包含多个句子。每个句子都不应被拆分。块的最大长度为30个字符或更少。运行应输出测试结果。";
int maxChunkLength = 30; // 该值为每个分块的最大长度 应使用模型最大token长度*0.4
ChunkInfo chunkInfo = splitTextIntoChunks(inputText, maxChunkLength);
Listchunks = chunkInfo.getChunks();
int tokens = chunkInfo.getTokens();
System.out.println("总令牌数:" + tokens);
for (int i = 0; i < chunks.size(); i++) {
System.out.println("块 " + (i + 1) + ":");
System.out.println(chunks.get(i));
System.out.println();
}
}
}
总结
文本分块器(TextChunker)是一个实用的工具类,它可以帮助我们将长文本按照指定的最大长度进行分块处理。通过使用该工具类,我们可以更好地管理和处理文本数据,提高文本处理任务的效率和准确性。此为知识工程的第一步(属于知识清洗的一部分),可方便后续对知识进一步加工。
希望本文能够帮助你了解文本分块器的基本原理和使用方法。如果你有任何疑问或者想了解更多相关的内容,请随时留言。谢谢阅读!