Сбой LangChain при длинном вводе текста

Я работаю с LLMChain от LangChain для обработки больших документов. Я вижу довольно много проблем, когда входной текст превышает лимит токенов языковой модели. Для длинного ввода текста он имеет значительные подтормаживания и даже иногда может давать сбой из-за переполнения токенов.

Это пример кода,

from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI


prompt = PromptTemplate("Analyze the following text and summarize it: {text}")
llm_chain = LLMChain(llm=OpenAI(model = "gpt-3.5-turbo"), prompt=prompt)

long_text = "This is a very long document..."  # Assume this text is extremely long

response = llm_chain.run(text=long_text)
print(response)

Проблема в том, что когда long_text слишком длинный, цепочка либо терпит неудачу по причине ограничения токенов, либо работает абсурдно долго. Я имею в виду, что в таких моделях, как GPT-3.5-turbo, установлен лимит токенов, но все же мне не хотелось бы делать это вручную при каждом использовании моей функции.

Можно ли динамически настраивать входную токенизацию LangChain, чтобы она оставалась эффективной при обработке длинных текстов?

Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
0
50
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете попробовать использовать встроенную утилиту:

from langchain.chains import LLMChain
from langchain.llms import OpenAI
from langchain.prompts import PromptTemplate
from langchain.text_splitter import RecursiveCharacterTextSplitter

prompt = PromptTemplate("Analyze the following text and summarize it: {text}")
llm_chain = LLMChain(llm=OpenAI(model = "gpt-3.5-turbo"), prompt=prompt)

long_text = "This is a very long document..."  # Assume this text is extremely long
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
text_chunks = splitter.split_text(long_text)

response_chunks = []
for text_chunk in text_chunks :
    response_chunk = llm_chain.run(text=text_chunk)
    response_chunks.append(chunk_response)

response = "\n".join(response_chunks)
print(response)

Я попробовал это, но дробление меняет требуемый результат, поэтому я не стал продолжать и разместил вопрос здесь.

DAR 18.08.2024 19:38
Ответ принят как подходящий

Для обработки длинных входных текстов в LangChain и динамического управления работами по токенизации вы можете рассчитать доступные токены для текста, учитывая длину приглашения и любой дополнительный фиксированный текст, который может быть частью ввода.

Ответ Кароля Змиевского хорош, но я бы добавил функцию process_dynamic_tokenization дополнительно для решения этой проблемы.

from transformers import GPT2Tokenizer
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI


tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
llm_chain = LLMChain(
    llm=OpenAI(model = "gpt-3.5-turbo"),
    prompt=PromptTemplate("Analyze the following text and summarize it: {text}")
)

def split_text_into_chunks(text, max_tokens):
    tokens = tokenizer.tokenize(text)
    chunks = []
    for i in range(0, len(tokens), max_tokens):
        chunk_tokens = tokens[i:i + max_tokens]
        chunk_text = tokenizer.convert_tokens_to_string(chunk_tokens)
        chunks.append(chunk_text)
    return chunks

def process_long_text(text, max_tokens):
    chunks = split_text_into_chunks(text, max_tokens)
    summaries = []
    for chunk in chunks:
        response = llm_chain.run(text=chunk)
        summaries.append(response)
    return " ".join(summaries)

def process_dynamic_tokenization(text, prompt_template, llm_chain, max_model_tokens=4096):
    prompt_tokens = len(tokenizer.tokenize(prompt_template.template.format(text = "")))
    available_tokens = max_model_tokens - prompt_tokens
    
    if available_tokens <= 0:
        raise ValueError("Prompt template is too long for the model's token limit.")
    
    return process_long_text(text, max_tokens=available_tokens)

long_text = "This is a very long document..."  

final_summary = process_dynamic_tokenization(
    text=long_text,
    prompt_template=PromptTemplate("Analyze the following text and summarize it: {text}"),
    llm_chain=llm_chain,
    max_model_tokens=4096
)

print(final_summary)

Да, это недостающая часть. @DAR Извините, я не ответил сразу, в любом случае Лисан Аль Гаиб, кажется, правильно решает проблему.

Karol Zmijewski 20.08.2024 13:04

Помимо непосредственного разделения текста на фрагменты, вы также можете использовать встроенные возможности langchain для обобщения:

Чтобы дать вам предварительный просмотр, любой конвейер можно обернуть в один объект: load_summarize_chain.

Предположим, мы хотим подвести итог записи в блоге. Мы можем создать это за несколько строки кода.

from langchain.chains.summarize import load_summarize_chain
from langchain_community.document_loaders import WebBaseLoader
from langchain_openai import ChatOpenAI

loader = WebBaseLoader("https://lilianweng.github.io/posts/2023-06-23-agent/")
docs = loader.load()

llm = ChatOpenAI(temperature=0, model_name = "gpt-3.5-turbo-1106")
chain = load_summarize_chain(llm, chain_type = "stuff")

result = chain.invoke(docs)

print(result["output_text"])

Или

Когда мы используем load_summarize_chain с chain_type = "stuff", мы будем использовать StuffDocumentsChain.

Цепочка возьмет список документов, вставит их все в подсказку и передайте ее LLM:

from langchain.chains.combine_documents.stuff import StuffDocumentsChain
from langchain.chains.llm import LLMChain
from langchain_core.prompts import PromptTemplate

# Define prompt
prompt_template = """Write a concise summary of the following:
"{text}"
CONCISE SUMMARY:"""
prompt = PromptTemplate.from_template(prompt_template)

# Define LLM chain
llm = ChatOpenAI(temperature=0, model_name = "gpt-3.5-turbo-16k")
llm_chain = LLMChain(llm=llm, prompt=prompt)

# Define StuffDocumentsChain
stuff_chain = StuffDocumentsChain(llm_chain=llm_chain, document_variable_name = "text")

docs = loader.load()
print(stuff_chain.invoke(docs)["output_text"])

Reference


Обратите внимание, что GPT-4o Mini (gpt-4o-mini) почти в 3 раза дешевле по сравнению с GPT-3.5 Turbo и поддерживает токены 128k по сравнению с 3.5 Turbo, которая поддерживает токены 4096. Reference


Кроме того, у меня возникли проблемы с запуском вашего кода, возможно, из-за несовместимости версии langchain — я использую последнюю версию 0.2.14, поэтому мне пришлось изменить API openai с v1/completions на v1/chat/completions следующим образом:

from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain_openai import ChatOpenAI

prompt = PromptTemplate(template = "Analyze the following text and summarize it: {text}")
llm_chain = LLMChain(llm=ChatOpenAI(model = "gpt-4o-mini"), prompt=prompt)
long_text = "This is a very long document..."  # Assume this text is extremely long
response = llm_chain.run(text=long_text)
print(response)

Спасибо за подробный ответ, помог мне получить больше знаний по этой теме. Я уже получил необходимый результат из принятого ответа.

DAR 20.08.2024 09:59

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