Комментарии 8
Интересный подход. Идея со сплитом + мерджем малых чанков. Надо тоже как нибудь попробовать. Только вопрос. Когда на стыке чанков крупных у тебя будет связанный текст, и buffer = [piece] как ты решишь вопрос? Может не до нуля очищать, а оставлять пару предложений?
Кстати об этом я даже не подумал. Лучше так же добавить overlap
def merge_small_chunks(pieces, chunk_size=500, overlap=50, separator=" "):
buffer = []
result = []
for piece in pieces:
buffer.append(piece)
total_length = len(separator.join(buffer))
if total_length > chunk_size:
buffer.pop()
if buffer:
result.append(separator.join(buffer))
tail = []
tail_len = 0
for p in reversed(buffer):
if tail_len + len(p) > overlap:
break
tail.insert(0, p)
tail_len += len(p) + len(separator)
buffer = tail
buffer.append(piece)
if buffer:
result.append(separator.join(buffer))
return resultа как именно разбивается текст? ну типо по предложениям или произвольно?
Текст разбивается по separators = ["\n\n", "\n", ". ", " ", ""]. Сначала абзацы, потом строки, точки, пробелы и отдельные буквы. Если предложение слишком длинное(не вошло в chunk_size) и в нем нет точек то оно будет делиться на слова. Чтобы избежать это и создан def merge_small_chunks. Он соединяет все слова, которые разделились на отдельные санки(если такие вообще есть) на строки которые +- равны длине chunk_size
А что если попробовать добавить в промпт - "отвечай только по контексту, если ответа нет так и скажи"? Сейчас там "раскрой тему полноценно" и "приведи детали и примеры" и в демо-ответе модель как раз дописала пример с графом на 10 вершинах, который ничего не считает. Любопытно, уйдет ли он после такой правки.

Строим RAG вручную: как это работает под капотом