Langchain: поведение разделителя текста

Я не понимаю следующее поведение рекурсивного разделителя текста Langchain. Вот мой код и вывод.

from langchain.text_splitter import RecursiveCharacterTextSplitter
r_splitter = RecursiveCharacterTextSplitter(
    chunk_size=10,
    chunk_overlap=0,
#     separators=["\n"]#, "\n", " ", ""]
)
test = """a\nbcefg\nhij\nk"""
print(len(test))
tmp = r_splitter.split_text(test)
print(tmp)

Выход

13
['a\nbcefg', 'hij\nk']

Как видите, он выводит фрагменты размером 7 и 5 и разделяется только на один из символов новой строки. Я ожидал, что вывод будет ['a','bcefg','hij','k']

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Поведение, которое вы наблюдаете в рекурсивном разделителе текста Langchain, связано с заданными вами настройками. Давайте разберем код и разберемся с выводом.

Во-первых, вы определяете объект RecursiveCharacterTextSplitter со значением chunk_size, равным 10, и chunk_overlap, равным 0. Параметр chunk_size определяет максимальный размер каждого фрагмента, а параметр chunk_overlap указывает количество символов, которые должны перекрываться между последовательными фрагментами. В вашем случае куски не будут перекрываться.

Затем вы определяете тестовую строку test длиной 13 символов. Строка содержит символы новой строки ("\n") в определенных позициях.

Когда вы вызываете r_splitter.split_text(test), алгоритм разделения текста обрабатывает входной текст в соответствии с заданными параметрами. Поскольку для параметра chunk_size задано значение 10 и между фрагментами нет перекрытия, алгоритм пытается разбить текст на фрагменты размером 10.

В процессе разделения учитываются указанные вами разделители. Однако в вашем коде параметр разделителей закомментирован (# separators=["\n"]). В результате алгоритм не рассматривает символы новой строки как разделители.

Алгоритм начинает с начала входного текста и пытается разбить его на куски размером 10. Он находит символ новой строки ("\n") в индексе 1 и определяет, что он не может разбить текст в этой позиции, сохраняя фрагмент размер 10. Таким образом, он продолжается до следующего индекса.

По индексу 7 алгоритм находит еще один символ новой строки. Поскольку он не может разделить текст в этой позиции, сохраняя размер блока равным 10, текущий блок останавливается и начинается новый блок с оставшимся текстом.

Таким образом, вывод, который вы видите, будет ['a\nbcefg', 'hij\nk'], где первый фрагмент — это «a\nbcefg» (7 символов), а второй фрагмент — «hij\nk» (5 символов).

Если вы хотите разделить текст на каждом символе новой строки, вам нужно раскомментировать параметр разделителей и указать «\n» в качестве разделителя. Вот обновленный код:

from langchain.text_splitter import RecursiveCharacterTextSplitter

r_splitter = RecursiveCharacterTextSplitter(
    chunk_size=10,
    chunk_overlap=0,
    separators=["\n"]
)

test = """a\nbcefg\nhij\nk"""
print(len(test))
tmp = r_splitter.split_text(test)
print(tmp)

С этой модификацией вывод будет ['a', 'bcefg', 'hij', 'k'], как вы и ожидали. Каждый символ новой строки будет рассматриваться как разделитель, в результате чего для каждой части текста будут отдельные фрагменты.

Этот ответ выглядит как ChatGPT

DavidW 07.07.2023 09:32
Ответ принят как подходящий

В соответствии с функцией разделения текста в RecursiveCharacterTextSplitter

def split_text(self, text: str) -> List[str]:
    """Split incoming text and return chunks."""
    final_chunks = []
    # Get appropriate separator to use
    separator = self._separators[-1]
    for _s in self._separators:
        if _s == "":
            separator = _s
            break
        if _s in text:
            separator = _s
            break
    # Now that we have the separator, split the text
    if separator:
        splits = text.split(separator)
    else:
        splits = list(text)
    # Now go merging things, recursively splitting longer texts.
    _good_splits = []
    for s in splits:
        if self._length_function(s) < self._chunk_size:
            _good_splits.append(s)
        else:
            if _good_splits:
                merged_text = self._merge_splits(_good_splits, separator)
                final_chunks.extend(merged_text)
                _good_splits = []
            other_info = self.split_text(s)
            final_chunks.extend(other_info)
    if _good_splits:
        merged_text = self._merge_splits(_good_splits, separator)  # Here will merge the items if the cusum is less than chunk size in your example is 10
        final_chunks.extend(merged_text)
    return final_chunks

это объединит элементы, если cusum меньше размера блока в вашем примере 10

Я посмотрел исходный код дальше в функцию _merge_splits (github.com/hwchase17/langchain/blob/master/langchain/…), и теперь это имеет смысл.

GreenEye 07.07.2023 15:54

Другие вопросы по теме