Como otimizar aplicativos LLM com compactação de prompts usando LLMLingua e LangChain
Avalie esse Tutorial
Imagine este cenário: você está aproveitando a glória do reconhecimento de toda a empresa por desenvolver um aplicativo GenAI inovador quando, de repente, aparece uma temida notificação do seu gerente: os custos operacionais estão disparando. Após uma rápida investigação, você descobre o culpado: os custos de inferência do LLM estão aumentando devido ao alto uso de tokens de entrada causado pelo número crescente de usuários que utilizam seu aplicativo.
Você pode evitar essa situação de pesadelo de custos operacionais disparados com a abordagem certa. Como engenheiros e profissionais da AI Stack, podemos apreciar a expansão consistente da janela de contexto dos LLMs e dos modelos básicos fornecidos por empresas como OpenAI, Anthropic, Cohere e Google.
Estou certo de que há um futuro em que você poderá colocar uma biblioteca inteira em um único prompt do modelo GPT da OpenAI. No entanto, a eficiência operacional e o custo ainda são as principais considerações para os aplicativos de software. Ao implementar técnicas de compressão rápida, você pode reduzir significativamente a contagem de tokens das entradas do seu aplicativo LLM, levando a uma economia substancial de custos sem comprometer a qualidade da resposta.
Este tutorial explora técnicas para otimizar o uso de token em aplicativos LLM, especificamente para reduzir o espaço ocupado por tokens de entradas ou prompts para LLMs sem comprometer a qualidade da resposta.
Aqui está o que abordaremos:
- Definição e visão geral da compactação de prompt
- Implementação de compressão rápida em aplicativos LLM com LangChain e LLMLingua
- Aplicar compressão de prompt em pipelines RAG
- Utilizando compressão de prompt em agentes de AI
A compactação de prompt é o processo de reduzir sistematicamente o número de tokens alimentadas em um modelo de idioma grande para manter ou corresponder de perto a qualidade de saída comparável à do prompt original não compactado.
A premissa geral do desenvolvimento de aplicativos LLM é fornecer instruções abrangentes elaboradas e projetadas para condicionar o LLM a fornecer resultados que sigam uma especificação de estrutura, processo de raciocínio, inclusão, exclusão de informações etc. Os resultados positivos de fornecer aos LLMs prompts abrangentes levaram ao design de estruturas sistematizadas de prompts, como cadeia de ideias, aprendizado em contexto e solicitação do ReAct.
Embora a solicitação extensiva forneça resultados LLM desejáveis, há uma compensação entre os LLMs produzidos por meio de solicitação extensiva e fatores como aumento do número de tokens, sobrecarga computacional e latência de resposta.
Para limitar as compensações que desenvolvedores e engenheiros precisam fazer ao criar aplicativos LLM, começaram a surgir técnicas para reduzir a contagem de tokens de prompts de entrada. O foco foi colocado em técnicas para determinar quais aspectos de um prompt extensivo são importantes o suficiente para serem retidos em uma versão de prompt compactado.
O princípio orientador que cerca a maioria dos esforços de compactação de prompts está centrado na noção de que, embora prompts extensos forneçam resultados desejáveis dos LLMs, o comprimento de um prompt ou quão descritivo é o conteúdo do prompt não é o único contribuinte para a resposta desejável dos LLMs. Em vez disso, incluir informações-chave e contexto leva os LLMs a um espaço de resposta desejável. Embora para os humanos ter uma explicação extensiva de uma ideia, conceito ou problema possa ser útil para a compreensão e a compreensão, os LLMs exigem apenas uma pequena quantidade de informações para obter a compreensão.
A vantagem prática de empregar técnicas de compressão rápida é a capacidade de manter as informações gerais em um prompt não compactado e, ao mesmo tempo, reduzir significativamente o número de tokens. No entanto, é importante observar que as técnicas de compressão imediata podem resultar na perda de informações, principalmente informações mencionadas uma vez ou raramente no prompt descompactado. Apesar disso, os benefícios gerais da compactação imediata, como a otimização aprimorada de tokens e a redução da sobrecarga computacional, fazem dela uma estratégia valiosa para aplicativos LLM.
O artigo "Prompt Compression and Contrastive Conditioning for Controllability and Toxicity Reduction in Language Models, ", publicado em 6 de outubro de 2022, introduziu a compressão rápida como termo e técnica oficiais.
Avançando apenas alguns anos, várias técnicas de compactação rápida emergiram. Essas técnicas abordam coletivamente o desafio da otimização de token dentro de aplicativos LLM, mantendo a controlabilidade do LLM e a qualidade de saída.A bibliotecaLLMLinguaPython da Microsoft apresenta um método que ganha força significativa.
O artigo "LLMLingua: Compressing Prompts for Accelerated Inference of Large Language Models" de Huiqiang Jiang, Qianhui Wu, Chin-Yew Lin, Yuqing Yang e Lili Qiu da Microsoft Corporation apresenta uma estrutura, LLMLingua, para compactar prompts alimentados em grandes modelos de linguagem (LLMs). Ele aborda os desafios do aumento da latência de inferência de custos computacionais a partir de técnicas de engenharia de prompt que melhoram a qualidade de saída do LLM por meio de prompts extensos e descritivos.
Os resultados apresentados no documento mostram que o LLMLingua comprime os prompts por um fator significativo e ainda mantém a qualidade de saída semelhante à do prompt não compactado.
Dois documentos subsequentes foram escritos pela equipe de pesquisa da Microsoft que melhoraram os recursos de compressão de prompt do LLMLingua. "LongLLMLingua: Accelerating and Enhancing LLMs in Long Context Scenarios via Prompt Compression" introduziu um método de determinação de informações importantes em prompts não compactados que levaram a uma compactação de melhor qualidade. "LLMLingua-2: Data Distillation for Efficient and Faithful Task-agnostic Prompt Compression" introduziu técnicas para tornar a compactação imediata generalizável e independente de tarefas.
A implementação de técnicas de compressão rápida usando o LLMLingua em pipelines de geração aumentada por recuperação (RAG) pode ser relativamente simples. O pacote LLMLingua Python fornece métodos intuitivos e construtores de classe, permitindo o acesso contínuo a técnicas e modelos de compressão projetados para compressão rápida eficiente.
Uma vantagem significativa de usar o LLMLingua é sua integração com estruturas de abstração LLM amplamente adotadas, como LangChain e LlamaIndex. Nesta seção de tutorial, você observará a implementação de técnicas de compressão em um pipeline RAG simples e uma implementação de pipeline RAG com LangChain que aproveita o LLMLingua para compressão rápida.
Algo a observar é que os trechos de código nesta seção fazem parte de uma bloco denotas. Os trechos de código abaixo destacam a principal implementação do LLMLingua usando apenas o pacote Python e aproveitam a integração com o LangChain.
Abaixo está um trecho de código que ilustra a inicialização de um objeto de compressor de prompt da biblioteca LLMLingua. Primeiro, importamos a classe necessária e inicializamos uma instância do
PromptCompressor
com uma configuração de modelo específica.1 from llmlingua import PromptCompressor 2 3 llm_lingua = PromptCompressor( 4 model_name="microsoft/llmlingua-2-bert-base-multilingual-cased-meetingbank", 5 model_config={"revision": "main"}, 6 use_llmlingua2=True, 7 device_map="cpu" 8 )
As etapas no trecho de código acima são as seguintes:
- Importando PromptCompressor: A classe
PromptCompressor
é importada do módulollmlingua
. Esta classe comprime os prompts usando um modelo especificado, a configuração que o acompanha e outros detalhes específicos do compressor. - Criando uma instância do PromptCompressor: Uma instância do
PromptCompressor
é criada e atribuída à variávelllm_lingua
. Os parâmetros fornecidos durante a inicialização são:
model_name
: Especifica o modelo a ser utilizado para a tarefa de compactação, neste caso,"microsoft/llmlingua-2-bert-base-multilingual-cased-meetingbank"
model_config
: Definições de configuração do modelo, especificando aqui orevision
a ser usado como"main"
use_llmlingua2
: Um sinalizador booleano indicando se o LLMLingua2 deve ser usado, que aproveita uma abordagem independente de tarefas para solicitar a compactaçãodevice_map
: especifica o dispositivo no qual carregar o modelo do compressor, neste caso, " cpu "; se estiver utilizando aceleradores de hardware, como GPU, “cuda” deve ser especificado como ovalor desse argumento
A próxima etapa é definir uma função que usa uma string simples contendo o prompt descompactado para ser inserido no LLM e a passa como entrada para a instância do compressor de prompt criado no código anterior. A função também especificará os parâmetros de configuração que orientam o algoritmo de compressão.
1 # Function definition 2 def compress_query_prompt(context): 3 4 compressed_prompt = llm_lingua.compress_prompt( 5 str(context), 6 rate=0.33, 7 force_tokens=["!", ".", "?", "\n"], 8 drop_consecutive=True, 9 ) 10 11 return compressed_prompt
- Definição de função: Uma função chamada
compress_query_prompt
é definida e recebe um único parâmetrocontext
. - Compactando o prompt: Dentro da função, o método
compress_prompt
da {PromptCompressor
,llm_lingua
, é chamado com os seguintes argumentos: 1.context
: Converte a entradacontext
em um formato de string
rate
: Especifica a taxa de compressão; aqui,0.33
indica que o compressor tentará comprimir o prompt para 33% de seu tamanho original não compactadoforce_tokens
: uma lista de tokens (["!", ".", "?", "\n"]
) que devem estar presentes no prompt compactado e não removidos durante a compactaçãodrop_consecutive
: um sinalizador booleano indicando se os tokens consecutivos especificados na listaforce_token
devem ser descartados, mas aparecem consecutivamente um após o outro no prompt compactado
A classe
PromptCompressor
da biblioteca LLMLingua fornece um métodocompress_prompt
eficiente que retorna um dicionário abrangente contendo informações cruciais sobre o processo de compactação do prompt. Abaixo está uma captura de tela do exemplo do resultado da operação.
Este dicionário encapsula os seguintes elementos-chave:
compressed_prompt
: a versão reduzida e otimizada do prompt original, obtida por meio das técnicas avançadas de compactação do LLMLinguaorigin_tokens
: A contagem inicial de tokens calculada a partir do prompt original não compactado, servindo como uma linha de base para avaliar a eficácia da compactaçãocompressed_tokens
: A contagem de tokens do prompt compactado, fornecendo uma medida quantitativa da redução obtidaratio
: uma métrica que representa a proporção entre a contagem de tokens compactados e a contagem de tokens original, oferecendo uma comparação do nível de compactaçãorate
: A taxa na qual a compressão foi obtida, expressa como uma taxasaving
: Um valor monetário que indica a economia de custos projetada resultante do uso reduzido do token, calculado com base no modelo de preços atual do GPT-4
Incorporar a função
compress_query_prompt
do LLMLingua em um pipeline RAG existente é um processo simples que pode aumentar significativamente a eficiência e a relação custo-benefício de seus aplicativos LLM. Ao inserir a operação de compactação de prompt logo antes de a entrada ser enviada ao LLM para gerar uma resposta, você pode aproveitar as técnicas avançadas de compactação do LLMLingua para otimizar o uso de tokens e reduzir a sobrecarga computacional.Aqui está um trecho de código ilustrando a integração da função
compress_query_prompt
dentro de um pipeline RAG. O código completo está disponível em bloco denotas.1 import pprint 2 3 def handle_user_query_with_compression(query, collection): 4 5 get_knowledge = vector_search(query, collection) 6 7 # Concatenate the search results to reflect the employee profile 8 search_result = '' 9 10 for result in get_knowledge: 11 employee_profile = f""" 12 Employee ID: {result.get('employee_id', 'N/A')} 13 Name: {result.get('first_name', 'N/A')} {result.get('last_name', 'N/A')} 14 Gender: {result.get('gender', 'N/A')} 15 Date of Birth: {result.get('date_of_birth', 'N/A')} 16 """ 17 search_result += employee_profile + "\n" 18 19 # Prepare information for compression 20 query_info = { 21 'demonstration_str': search_result, # Results from information retrieval process 22 'instruction': "Write a high-quality answer for the given question using only the provided search results.", 23 'question': query 24 } 25 26 # Compress the query prompt 27 compressed_prompt = compress_query_prompt(query_info) 28 29 prompt = f"Answer this user query: {query} with the following context:\n{compressed_prompt}" 30 print("Compressed Prompt:\n") 31 pprint.pprint(prompt) 32 33 completion = openai.chat.completions.create( 34 model=OPEN_AI_MODEL, 35 messages=[ 36 {"role": "system", "content": "You are a Human Resource System within a corporate company."}, 37 {"role": "user", "content": prompt} 38 ] 39 ) 40 41 return (completion.choices[0].message.content), search_result
Para um engenheiro de pilha de AI, aproveitar estruturas de abstração como o LangChain é uma prática comum para simplificar o desenvolvimento e a implantação de aplicativos LLM. Nesse contexto, incorporar a compressão de prompt ao seu pipeline RAG existente é um processo simplificado pela integração do LangChain e LLMLingua.
Em especial, as melhorias introduzidas pelo LLMLingua se estendem além do aprimoramento da eficiência do prompt; também permite a compactação de documentos dentro de sistemas de recuperação. Ao aproveitar as técnicas avançadas de compressão do LLMLingua, você pode otimizar o armazenamento e a recuperação de informações contextuais, levando a operações mais eficientes e econômicas.
Veja como você pode aproveitar o LLMLingua dentro de um pipeline de recuperação do LangChain:
1 from langchain.retrievers import ContextualCompressionRetriever 2 from langchain_community.document_compressors import LLMLinguaCompressor 3 4 compressor = LLMLinguaCompressor(model_name="openai-community/gpt2", device_map="cpu") 5 compression_retriever = ContextualCompressionRetriever( 6 base_compressor=compressor, base_retriever=retriever 7 ) 8 9 compressed_docs = compression_retriever.invoke( 10 "Who is the CEO?" 11 ) 12 print(compressed_docs)
As etapas no trecho de código acima são as seguintes:
- Importando módulos necessários: o código importa
ContextualCompressionRetriever
delangchain.retrievers
eLLMLinguaCompressor
delangchain_community.document_compressors
. - Inicializando o compressor: Uma instância do
LLMLinguaCompressor
é criada com o modelo"openai-community/gpt2"
e configurada para carregar o modelo na CPU. - Criando o recuperador de compressão: O
ContextualCompressionRetriever
é inicializado com oLLMLinguaCompressor
e um recuperador de base. - Invocando o recuperador: O
compression_retriever
invoca uma query, "quem é o CEO?", Que recupera e compacta documentos relevantes. - Saída: os documentos compactados são impressos, mostrando as informações relevantes em um formato compactado.
Para melhorar ainda mais os recursos de recuperação e query, você pode integrar a configuração de compressão de prompt com
RetrievalQA
do LangChain. No exemplo abaixo, RetrievalQA
cria uma cadeia de resposta a perguntas que aproveita o compressão_retriever. 1 from langchain.chains import RetrievalQA 2 3 chain = RetrievalQA.from_chain_type(llm=llm, retriever=compression_retriever) 4 chain.invoke({"query": "Who is the CEO?"})
Vamos levar as coisas um passo adiante.
Os sistemas de agentes estão no horizonte, ou talvez você já tenha algumas demos sobre agentes de AI. Caso contrário, confira o repositório de blocos de anotações em agentes com vários modelos e estruturas usando o MongoDB como o provedor de memória do agente.
Um agente de AI é uma entidade computacional artificial que percebe seu ambiente por meio de entradas, age usando ferramentas e processa informações com modelos básicos suportados por memória de longo e curto prazo. Esses agentes são desenvolvidos para realizar tarefas ou objetivos especificados, aproveitando os recursos disponíveis.
A operação de um agente de AI é caracteriza por uma natureza recursiva ou cíclica, frequentemente envolvendo um ou mais sistemas interconectados. Cada etapa desse processo iterativo requer entradas para um LLM, que funciona como o núcleo Cognoscitivo ou o Céreito do agente. É fácil ver como a entrada alimentada em um LLM pode crescer a cada ciclo ou iteração da operação de um agente, especialmente se a memória de conversação estiver integrada aos recursos do agente e precisar ser usada como entrada no LLM. Um sistema como esse pode aumentar o custo operacional e os tempos de resposta de um sistema agente.
Agora você entende que as técnicas de compressão rápida reduzem a utilização de tokens de entradas em aplicativos LLM, como aplicativos RAG. No entanto, as vantagens da compactação imediata vão além desses aplicativos, provando ser benéficas também para agentes de AI. A principal conclusão é que os agentes de AI que executam em amplas Windows operacionais e que provavelmente utilizarão toda a extensão da Windows de contexto de um LLM podem se beneficiar significativamente da compactação imediata.
Os agentes de AI exigem vários componentes de entrada, incluindo extensos históricos de conversas, dados operacionais, definições do sistema e prompts. A compressão rápida permite que os agentes de AI gerenciem e organizem compactamente o contexto fornecido como entrada, habilitando operações eficientes e escaláveis. Ao implementar técnicas de compactação imediata, os agentes de AI podem compactar e otimizar de forma inteligente a contagem de tokens de seus componentes de entrada, como históricos de conversação e dados operacionais.
Além disso, a compactação de prompts permite que os agentes de AI gerenciem a contagem total de tokens de suas entradas, garantindo que o contexto combinado permaneça dentro dos limites especificados do LLM subjacente. Isso é particularmente crucial para agentes que operam em ambientes complexos ou lidam com extensos históricos de conversação, onde a contagem cumulativa de tokens pode aumentar rapidamente, levando a um aumento da sobrecarga computacional e a possíveis gargalos de desempenho.
Há duas maneiras de fornecer aos agentes a capacidade de comprimir prompts usando o LangChain:
- Compactação de prompt como ferramenta: defina a operação de compactação de prompt como uma ferramenta que o agente pode usar durante sua operação.
- Retriever com compactação: crie um objeto de ferramenta de recuperação LangChain com uma lógica de compactação definida.
O trecho de código abaixo demonstra a implementação da lógica de compactação de prompt como uma definição de ferramenta para um agente construído usando LangChain. O código abaixo é apenas um esboço; obtenha o código completo.
1 from langchain.retrievers import ContextualCompressionRetriever 2 from langchain_community.document_compressors import LLMLinguaCompressor 3 from langchain.agents import AgentExecutor, create_tool_calling_agent 4 5 compressor = LLMLinguaCompressor(model_name="openai-community/gpt2", device_map="cpu") 6 7 8 def compress_prompt_using_llmlingua(prompt: str, compression_rate: float = 0.5) -> str: 9 """ 10 Compresses a long data or prompt using the LLMLinguaCompressor. 11 12 Args: 13 data (str): The data or prompt to be compressed. 14 compression_rate (float): The rate at which to compress the data (default is 0.5). 15 16 Returns: 17 str: The compressed data or prompt. 18 """ 19 compressed_data = compressor.compress_prompt( 20 prompt, 21 rate=compression_rate, 22 force_tokens=["!", ".", "?", "\n"], 23 drop_consecutive=True 24 ) 25 return compressed_data 26 27 28 29 tools = [compress_prompt_using_llmlingua] 30 31 agent = create_tool_calling_agent(llm, tools, prompt) 32 33 agent_executor = AgentExecutor( 34 agent=agent, 35 tools=tools, 36 verbose=True, 37 handle_parsing_errors=True, 38 memory=memory, 39 ) 40 41 agent_executor.invoke({"input": "Get me a list of research papers on the topic Prompt Compression"})
O código acima cria uma ferramenta de compressão de prompt e fornece a ferramenta ao agente. Agora, o agente está ciente da ferramenta e pode determinar quando utilizá-la durante sua operação. A desvantagem é que a compressão de prompts ou entradas no LLM é deixada a critério do agente. Isso significa que o agente deve avaliar efetivamente a necessidade de compressão, o que pode introduzir variabilidade no desempenho se o processo de tomada de decisão do agente não for o ideal. Além disso, pode haver cenários em que o agente usa em excesso ou subutiliza a ferramenta de compressão, potencialmente levando a ineficiências ou perda de informações contextuais importantes.
A criação do recuperador com recursos de compactação básicos pode melhorar significativamente a consistência e a eficácia, reduzindo a variabilidade no uso da lógica de compactação pelo agente de AI . Ao incorporar o mecanismo de compressão diretamente no recuperador, o agente pode aplicar compressão uniforme a todos os dados relevantes, garantindo que os prompts e entradas sejam consistentemente otimizados para processamento eficiente. O trecho de código abaixo demonstra como essa lógica pode ser implementada. Visualizar toda a implementação.
1 from langchain.retrievers import ContextualCompressionRetriever 2 from langchain_community.document_compressors import LLMLinguaCompressor 3 from langchain.tools.retriever import create_retriever_tool 4 5 compressor = LLMLinguaCompressor(model_name="openai-community/gpt2", device_map="cpu") 6 compression_retriever = ContextualCompressionRetriever( 7 base_compressor=compressor, base_retriever=retriever 8 ) 9 10 retriever_tool = create_retriever_tool( 11 retriever=retriever, 12 name="knowledge_base", 13 description="This serves as the base knowledge source of the agent and contains some records of research papers from Arxiv. This tool is used as the first step for exploration and research efforts." 14 )
Essa abordagem minimiza a necessidade de o agente avaliar e decidir independentemente quando aplicar a compactação, reduzindo assim o potencial de desempenho inconsistente e aumentando a confiabilidade geral.
Mais uma vez, o agente é responsável por utilizar a ferramenta retriever.
Este tutorial apresenta, de uma perspectiva técnica e explicativa, que a compressão imediata é crucial para otimizar aplicativos LLM, como aplicativos RAG e agentes de IA. Alguns dos benefícios da compactação imediata explorados neste tutorial são sua capacidade de otimizar o uso de tokens, reduzir a sobrecarga computacional e minimizar os custos operacionais.
Por meio de demonstração técnica, você explorou a biblioteca LLMLingua, criada pela Microsoft Research. Essa biblioteca oferece uma estrutura robusta para compactar prompts e, ao mesmo tempo, preservar a qualidade da resposta. Ao integrar o LLMLingua com frameworks de abstração populares como o LangChain, os engenheiros de AI podem incorporar sem esforço a compressão de prompt em seus pipelines RAG existentes e sistemas de agentes de AI.
À medida que os projetos de IA generativa passam do protótipo para a produção, a demanda por soluções eficientes e econômicas só aumentará. Aproveitar a compressão rápida e técnicas similares nos estágios de prototipagem permite que desenvolvedores e engenheiros entendam as áreas de otimização dos aplicativos LLM, as ferramentas mais adequadas para otimizar essas áreas e algumas métricas avaliativas para medir o desempenho geral.
Para sua próxima viagem, você pode explorar uma das seguintes opções abaixo:
- Como escolher a estratégia correta de chunking para seu aplicativo RAG Não se lembre de que você pode se juntar a nós na comunidade de desenvolvedores do MongoDB para manter a conversa andando.
Feliz Hacking!
1. O que é compressão de prompts? A compactação de prompts é o processo de reduzir sistematicamente o número de tokens alimentados em um modelo de linguagem grande para manter ou se aproximar da qualidade de saída comparável à do prompt original não compactado. Isso ajuda a otimizar os custos operacionais e a eficiência.
2. Por que a compactação imediata é importante para os aplicativos LLM? À medida que o uso de LLMs cresce, a contagem de tokens de entradas pode aumentar rapidamente, levando a um aumento dos custos operacionais e da latência. A compactação de prompts permite que os desenvolvedores otimizem o uso de tokens, reduzindo a sobrecarga computacional, a latência de resposta e as despesas associadas.
3. Como o LLMLingua facilita a compactação de prompts? LLMLingua é uma biblioteca Python introduzida pela Microsoft que fornece uma estrutura para compactar prompts alimentados em LLMs. Ela usa técnicas avançadas de compactação para reduzir significativamente a contagem de tokens e, ao mesmo tempo, preservar informações essenciais e a qualidade da resposta. Ela se integra perfeitamente a estruturas como LangChain e LlamaIndex, facilitando a implementação em vários aplicativos.
4. Como a compressão de prompts pode beneficiar os agentes de AI? Os agentes de AI geralmente exigem vários componentes de entrada, incluindo históricos de conversas, dados operacionais e prompts. A compactação de prompts permite que os agentes gerenciem e compactem esse contexto, possibilitando operações eficientes e dimensionáveis e, ao mesmo tempo, minimizando a sobrecarga computacional e os possíveis gargalos de desempenho.
Referências