Transform转换
帮助将文档分割以适应 AI 模型的上下文窗口。
假如我们想要用 openai api 对一个段文本进行总结,我们通常的做法就是直接发给 api 让他总结。但是如果文本超过了 api 最大的 token 限制就会报错。这时,我们一般会进行对文章进行分段,比如通过 tiktoken 计算并分割,然后将各段发送给 api 进行总结,最后将各段的总结再进行一个全部的总结。
另外内容过长,影响到内部的相关性,进而影响大模型推理的准确性。
文档切分
把一个较长的文档,拆分成若干个较小的文档,每一块表示为特定的语义的单元,这样内容尺寸不会过大;但是切分时需要结合文档的类型和内容选择不同的策略。
- 通用的文本:以段落或句子单元来切分;
- 源代码:以方法或函数单元来切分;
Spring AI 提供TokenTextSplitter,按 token 拆分文档。
很多LLM的上下文窗口长度限制是按照 Token 来计数的。因此,以LLM的视角,按照 Token 对文本进行分隔,通常可以得到更好的结果。
Langchain4j 提供的切分方式DocumentSplitter,支持递归切分:
递归按字符切分,它由一个字符列表参数化。它尝试按顺序在它们上进行切割,直到块变得足够小。默认列表是
["\n\n", "\n", " ", ""]。这样做的效果是尽可能保持所有段落(然后句子,然后单词)在一起,因为它们在语义上通常是最相关的文本片段。在项目中也推荐使用。
代码示例
@Component
public class RecursiveTextSplitter extends TextSplitter {
@Override
protected List<String> splitText(String text) {
DocumentSplitter splitter = DocumentSplitters.recursive(800, 100);
return splitter.split(new Document(text)).stream().map(TextSegment::text).toList();
}
}
单元测试
@Test
public void splitTextTest() {
try {
Path path = Paths.get(DocumentServiceTest.class.getResource("/importer/1.json").toURI());
List<Article> articles = jsonDocumentService.importDocuments(path);
List<Document> documents = textSplitter.apply(List.of(Documents.fromArticle(articles.get(0))));
System.out.println(documents);
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
执行结果
[Document{
id='f4ff1abd-5ba3-45c7-9b53-d1d2b66c8d7c',
metadata={article_id=1798155175996960768, updated_at=Wed Jun 05 08:49:36 CST 2024, topic=Java基础, created_at=Wed Jun 05 08:49:36 CST 2024, title=是否可以从一个static方法内部发出对非static方法的调用?},
content='不可以。因为非static方法是要与对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方法调用,而static方法调用时不需要创建对象,可以直接调用。也就是说,当一个static方法被调用时,可能还没有创建任何实例对象,如果从一个static方法中发出对非static方法的调用,那个非static方法是关联到哪个对象上的呢?这个逻辑无法成立,所以,一个static方法内部发出对非static方法的调用。'
}]