LLMLingua是微软发布的一款开源框架,旨在帮助开发者实现提示词压缩,从而在诸多应用场景中,在尽可能保留有意义的信息时,减少token开销,降低成本。
在RAG应用中,用户的查询或者提问,会被用于向量存储查询,以获得最相似的信息片段。这些数据,作为对模型的输入,也就是提示词,贡献了绝大多数资源的开销。
那么如何降低开销呢?
提示词压缩正是旨在保留重要信息的同时,缩短提示词的技术,从而降低开销,同时也能加快语言模型的响应生成速度。
这项技术的前提是,我们认为在任何语言的文本中,通常都会存在不必要的重复。
更多技术细节和理论研究请参考LLMLingua的官方网站和论文:
https://github.com/microsoft/LLMLingua
今天我们来看看在具体的应用场景中,如何使用LlmLingua与LlamaIndex实现提示词压缩,并看看效果如何。
LLMLingua利用紧凑、经过训练的语言模型(例如GPT2-small、LLaMA-7B)来识别和移除提示中的非必要标记。这种方法使得使用大型语言模型(LLMs)进行高效推断成为可能,最多可以实现20倍的压缩,而性能损失很小。
LongLLMLingua解决了LLMs中的“lost in the middle”的问题,增强了对长上下文信息的处理能力。它通过提示词压缩降低成本,提高RAG性能,仅使用1/4的标记就能提高性能高达21.4%。
LlamaIndex框架对LLMLingua提供了原生支持,开发者能够非常轻松地集成提示词压缩能力到应用中。
一条命令安装llama-index与llmlingua:
·
$ pip install llmama-index llmlingua
完整示例代码:
·
import openai
openai.api_key = 'sk-xxx'
from llama_index import ServiceContext, set_global_service_context
from llama_index.llms import OpenAI
from llama_index.callbacks import CallbackManager, TokenCountingHandler
import tiktoken
OPENAI_MODEL_NAME = "gpt-3.5-turbo-16k"
llm = OpenAI(model=OPENAI_MODEL_NAME)
callback_manager = CallbackManager([TokenCountingHandler( tokenizer=tiktoken.encoding_for_model(OPENAI_MODEL_NAME).encode)])
service_context = ServiceContext.from_defaults( llm=llm, callback_manager=callback_manager)
set_global_service_context(service_context)
from llama_index import VectorStoreIndex, download_loader
WikipediaReader = download_loader("WikipediaReader")
loader = WikipediaReader()
documents = loader.load_data(pages=['Premier League'])
retriever = VectorStoreIndex.from_documents(documents).as_retriever(similarity_top_k=3)
question = "Why did English clubs get banned fron European competition?"
from llama_index.query_engine import RetrieverQueryEngine
from llama_index.response_synthesizers import CompactAndRefine
from llama_index.indices.postprocessor import LongLLMLinguaPostprocessor
node_postprocessor = LongLLMLinguaPostprocessor( instruction_str="Given the context, please answer the final question", target_token=300, rank_method="longllmlingua", additional_compress_kwargs={ "condition_compare": True, "condition_in_question": "after", "context_budget": "+100", "reorder_context": "sort", "dynamic_context_compression_ratio": 0.3, },)
retrieved_nodes = retriever.retrieve(question)
synthesizer = CompactAndRefine()
from llama_index.indices.query.schema import QueryBundle
new_retrieved_nodes = node_postprocessor.postprocess_nodes( retrieved_nodes, query_bundle=QueryBundle(query_str=question))
original_contexts = "\n\n".join([n.get_content() for n in retrieved_nodes])
compressed_contexts = "\n\n".join([n.get_content() for n in new_retrieved_nodes])
original_tokens = node_postprocessor._llm_lingua.get_token_length(original_contexts)
compressed_tokens = node_postprocessor._llm_lingua.get_token_length(compressed_contexts)
print(compressed_contexts)
print()
print("Original Tokens:", original_tokens)
print("Compressed Tokens:", compressed_tokens)
print("Compressed Ratio:", f"{original_tokens/(compressed_tokens + 1e-5):.2f}x")
response = synthesizer.synthesize(question, new_retrieved_nodes)
代码执行中,关于压缩token效果,我们会看到如下输出:
Original Tokens: 2768
Compressed Tokens: 443
Compressed Ratio: 6.25x
有兴趣的同学运行一下代码,查看压缩前与压缩后的问答效果吧。
出自:https://mp.weixin.qq.com/s/O-KjudOuF_tfjwsXRK1Cfg