当前位置: 首页 > news >正文

Advanced RAG 09:『提示词压缩』技术综述

编者按: 如何最大限度地发挥 LLMs 的强大能力,同时还能控制其推理成本?这是当前业界研究的一个热点课题。

针对这一问题,本期精心选取了一篇关于"提示词压缩"(Prompt Compression)技术的综述文章。正如作者所说,提示词压缩技术的核心目标是压缩向 LLMs 输入的上下文信息,删减非关键内容,保留语义核心,从而在不影响模型表现的前提下,降低推理成本。

文中全面介绍了多种提示词压缩算法的原理和实现细节,包括基于信息熵的Selective Context、基于软提示调优的AutoCompressor、引入数据蒸馏方法的LLMLingua-2、综合利用问题语义的LongLLMLingua等。作者还贴心地附上了代码示例,以便各位读者可以动手实践,加深对算法的理解。

你是否曾因难以处理冗长的提示词而寝食难安,被昂贵的推理成本所困扰?现在,就让我们跟随本文的脚步,开启一场 Prompt Compression 技术的学习之旅吧!也许在了解某个算法时灵感闪现,你就能找到突破瓶颈的金钥匙。

作者 | Florian June

编译 | 岳扬

RAG 方法可能会面临两大挑战:

  • 大语言模型(LLMs)往往有上下文长度(context length)的限制。 这意味着,随着输入文本的长度增长,处理过程不仅变得更加耗时,成本也随之增加。
  • 检索出的上下文未必都能派上用场。 有时,仅有一小部分信息对解答问题有帮助。在某些情形下,为了回答某些特定问题,可能需要整合来自多个文本片段的信息。即便实施了重排序(re-ranking)技术,这一难题依然未能得到解决。

为了解决上述问题,LLM 的提示词压缩技术(Prompt compression)应运而生。从本质上讲,其目的是精炼提示词中的关键信息,使得每个输入的词元(input tokens)都承载更多价值,从而提升模型效率并还能控制成本。这一理念在图 1 的右下角进行了直观展示。

图 1:RAG 架构中的提示词压缩技术(见图右下角)。如紫色虚线标记的部分所示,某些压缩方法能够直接作用于已检索的上下文信息。此图由作者绘制。

如图 1 中紫色虚线标记的部分所示,部分压缩方法可以直接应用于从大语言模型中检索出的上下文信息。

总的来说,提示词压缩方法可以分为四大类:

  • 基于信息熵(information entropy)的方法:例如 Selective Context[1]、LLMLingua[2] 和 LongLLMLingua[3]。这些方法利用小型语言模型来计算原始提示词中每个 token 的自信息(self-information )(译者注:自信息,又称为惊喜度(surprisal)或信息含量(information content),是信息理论中的核心概念之一。它用来量化某个事件所传达的信息量的大小。)或困惑度(perplexity)。接着删除那些困惑度较低的 token ,实现压缩目的。
  • 基于 soft prompt tuning (译者注:soft prompt tuning 不直接修改模型的权重,而是引入一组可学习的连续向量(通常称为"soft prompts"),这种方法允许模型在不改变其核心结构的情况下适应不同的下游任务,同时保留了模型在预训练阶段学到的一般知识。)的方法:如 AutoCompressor[4] 和 GIST[5]。此类方法需要对大语言模型的参数进行微调,使其适用于特定领域,但不能直接应用于黑盒大语言模型(black-box LLM)。
  • 先进行数据蒸馏,再训练模型生成更易解释的文本摘要:这类方法可以跨不同语言模型迁移,并能应用于无需梯度更新的黑盒大语言模型。代表性的方法包括 LLMLingua-2[6] 和 RECOMP[7]。
  • 基于词元合并(token merging)或词元剪枝(token pruning)的方法:如 ToMe[8] 和 AdapLeR[9]。这些方法通常需要在推理过程中对模型进行微调或生成中间结果。

鉴于第四类方法最初是为了像 ViT 或 BERT 这样的较小模型而提出的,本文将重点介绍前三类方法中代表性算法的原理。

01 Selective Context

1.1 作者的领悟见解

图 2 表明,大语言模型(LLM)即使在缺乏完整上下文或对话历史的情况下,也能对用户的询问做出回应。即便某些相关细节被省略,大语言模型(LLM)依旧能给出用户期望的回答。这或许是因为大语言模型(LLM)能够从上下文信息和预训练阶段积累的知识中推断出缺失的信息。

图 2:即便去除了部分非关键信息,大语言模型(LLM)依然能准确作答。来源:《Selective Context》[1]

由此看来,我们可以通过筛选掉非关键信息来优化上下文长度(context length),而不会影响其整体性能。这就是 Selective Context 方法的关键所在。

Selective Context 策略采用小型语言模型(SLM),来计算给定上下文中各个词汇单元(比如句子、短语或词语)的自信息值。然后,基于这些自信息值(self-information)进一步评估各单元的信息含量。通过仅保留自信息值较高的内容,Selective Context 为大语言模型(LLM)提供了更为简洁、高效的 context representation (译者注:经过数学化或模型化文本或对话后的机器可处理的上下文信息)。这一做法不会对其在各种任务中的表现造成负面影响。

1.2 Self-Information 自信息

Selective Context 运用自信息(self-information)来衡量内容的价值。

自信息,又称为惊喜度(surprisal)或信息含量(information content),是信息理论中的核心概念之一。它用来量化某个事件所传达的信息量的大小。具体来说,它是 token 出现概率的负对数形式:

这里,𝐼(𝑥) 代表 token 𝑥 的自信息量,而 𝑃(𝑥) 则指代该 token 的出现概率。

在信息论框架(information theory)下,自信息反映了事件发生时带来的惊喜程度或不确定性程度。那些不常见的事件,由于包含了更多新颖的信息,因而具有较高的自信息值。 相比之下,频繁发生的事件,因其提供的新信息较少,自信息值也就相应较低。

1.3 Algorithm 算法

为了便于阐述其背后的原理,我们不妨一同探究一下其源代码。

首要步骤是配置开发环境,安装必需的 Python 库以及下载 Spacy 模型。

(base) Florian:~ Florian$ conda create -n "selective_context" python=3.10 
(base) Florian:~ Florian$ conda activate selective_context
(selective_context) Florian:~ Florian$ pip install selective-context
(selective_context) Florian:~ Florian$ python -m spacy download en_core_web_sm

安装完成后,版本信息如下:

(selective_context) Florian:~ Florian$ pip list | grep selective
selective-context   0.1.4

测试代码如下所示:

from selective_context import SelectiveContextsc = SelectiveContext(model_type='gpt2', lang='en')
text = "INTRODUCTION Continual Learning ( CL ) , also known as Lifelong Learning , is a promising learning paradigm to design models that have to learn how to perform multiple tasks across different environments over their lifetime [To uniform the language and enhance the readability of the paper we adopt the unique term continual learning ( CL ) .]. Ideal CL models in the real world should be deal with domain shifts , researchers have recently started to sample tasks from two different datasets . For instance , proposed to train and evaluate a model on Imagenet first and then challenge its performance on the Places365 dataset . considers more scenarios , starting with Imagenet or Places365 , and then moving on to the VOC/CUB/Scenes datasets. Few works propose more advanced scenarios built on top of more than two datasets."
context, reduced_content = sc(text)# We can also adjust the reduce ratio
# context_ratio, reduced_content_ratio = sc(text, reduce_ratio = 0.5)

初次执行时,系统会自动下载 GPT-2 模型,该模型的文件大小接近 500MB。图 3 呈现了测试代码的具体运行结果。

图 3:Selective Context 算法测试代码运行结果。截图由作者提供。

随后,我们将深入研究 sc(text) 函数。该函数的内部实现代码[10]如下:

class SelectiveContext:......def __call__(self, text: str, reduce_ratio: float = 0.35, reduce_level :str = 'phrase') -> List[str]:context = self.beautify_context(text)self.mask_ratio = reduce_ratiosents = [sent.strip() for sent in re.split(self.sent_tokenize_pattern, context) if sent.strip()]# You want the reduce happen at sentence level, phrase level, or token level?assert reduce_level in ['sent', 'phrase', 'token'], f"reduce_level should be one of ['sent', 'phrase', 'token'], got {reduce_level}"sent_lus, phrase_lus, token_lus = self._lexical_unit(sents)lexical_level = {'sent': sent_lus,'phrase': phrase_lus,'token': token_lus}# context is the reduced context, masked_sents denotes what context has been filtered outcontext, masked_sents = self.self_info_mask(lexical_level[reduce_level].text, lexical_level[reduce_level].self_info, reduce_level)return context, masked_sents

这段代码的核心操作分为三个阶段:

  • 首先,计算出上下文中每一个 token 的自信息值。
  • 接着,依据词汇单位(比如短语或句子)整合 token 与其对应的自信息。
  • 最后,采取有选择的方式保留必要的信息上下文,从而达到优化的目的。

第一步:自信息的计算

给定上下文 𝐶=𝑥0,𝑥1,…,𝑥𝑛 ,其中每个 𝑥𝑖 均代表一个 token ,我们可以借助因果语言模型(例如 GPT-2、OPT 或 LLaMA)来求解每个 token 𝑥𝑖 的自信息值:

若你选用的是 GPT-2 模型,以下便是实现此计算过程的相应代码片段[11]:

class SelectiveContext:...... def _get_self_info_via_gpt2(self, text: str) -> Tuple[List[str], List[float]]:if self.lang == 'en':text = f"<|endoftext|>{text}"elif self.lang == 'zh':text = f"[CLS]{text}"with torch.no_grad():encoding = self.tokenizer(text, add_special_tokens=False, return_tensors='pt')encoding = encoding.to(self.device)outputs = self.model(**encoding)logits = outputs.logitsprobs = torch.softmax(logits, dim=-1)self_info = -torch.log(probs)input_ids = encoding['input_ids']input_ids_expaned = input_ids[:, 1:].unsqueeze(-1)

第二步:整合为词汇单元(Lexical Units)

如果仅仅在 tokens 层面上执行 selective context filtering(译者注:识别和保留那些对当前任务或用户查询最为关键的信息,同时过滤掉不太相关或冗余的部分。),可能会导致最终的上下文失去连贯性。举个例子,原本的数字"2009"在压缩后可能会变成"209",这样的结果显然不够合理。

鉴于此,除了在 tokens 层面进行筛选外,同时在短语和句子层面上实行过滤策略也是极其重要的。在这里,我们所说的过滤(filtering)基本单位------词汇单元,可以是个别的 token ,也可以是完整的短语或是句子。

那么,怎样才能计算出每个词汇单元 𝑢=(𝑥𝑡,…,𝑥𝑡+𝛼) 的自信息呢?我们可以根据自信息的可加性原则,将组成 u 的每个 token 的自信息相加:

下面是具体的代码实现[12],为了便于调试,我对部分变量添加了详细的注释:

class SelectiveContext:......def _lexical_unit(self, sents):if self.sent_level_self_info:sent_self_info = []all_noun_phrases = []all_noun_phrases_info = []all_tokens = []all_token_self_info = []for sent in sents:# print(sent)tokens, self_info = self.get_self_information(sent)'''ipdb> sent'INTRODUCTION Continual Learning ( CL ) , also known as Lifelong Learning , is a promising learning paradigm to design models that have to learn how to perform multiple tasks across different environments over their lifetime [To uniform the language and enhance the readability of the paper we adopt the unique term continual learning ( CL ) .].'ipdb> tokens['IN', 'TR', 'ODUCT', 'ION', ' Contin', 'ual', ' Learning', ' (', ' CL', ' )', ',', ' also', ' known', ' as', ' Lif', 'elong', ' Learning', ',', ' is', ' a', ' promising', ' learning', ' paradigm', ' to', ' design', ' models', ' that', ' have', ' to', ' learn', ' how', ' to', ' perform', ' multiple', ' tasks', ' across', ' different', ' environments', ' over', ' their', ' lifetime', ' [', 'To', ' uniform', ' the', ' language', ' and', ' enhance', ' the', ' read', 'ability', ' of', ' the', ' paper', ' we', ' adopt', ' the', ' unique', ' term', ' continual', ' learning', ' (', ' CL', ' )', '.', '].']ipdb> self_info[7.514791011810303, 1.632637619972229, 0.024813441559672356, 0.006853647995740175, 12.09920597076416, 2.1144468784332275, 9.457701683044434, 2.4503376483917236, 10.236454963684082, 0.8689146041870117, 5.269547939300537, 4.641763210296631, 0.22138957679271698, 0.010370315983891487, 10.071824073791504, 0.6905602216720581, 0.01698811538517475, 1.5882389545440674, 0.4495090842247009, 0.45371606945991516, 6.932497978210449, 6.087430477142334, 3.66465425491333, 3.3969509601593018, 7.337691307067871, 5.881226539611816, 1.7340556383132935, 4.599822521209717, 6.482723236083984, 4.045308589935303, 4.762691497802734, 0.21346867084503174, 3.7985599040985107, 4.6389899253845215, 0.33642446994781494, 4.918881416320801, 2.076707601547241, 3.3553669452667236, 5.5081071853637695, 5.625778675079346, 0.7966060638427734, 6.347291946411133, 12.772034645080566, 13.792041778564453, 4.11267614364624, 6.583715915679932, 3.3618998527526855, 8.434362411499023, 1.2423189878463745, 5.8330583572387695, 0.0013973338063806295, 0.3090735077857971, 1.1139129400253296, 4.160390853881836, 3.744772434234619, 7.2841596603393555, 1.4088190793991089, 7.86871337890625, 4.305004596710205, 9.69282341003418, 0.08665203303098679, 1.6127821207046509, 1.6296097040176392, 0.46206924319267273, 3.0398476123809814, 6.892032623291016]'''sent_self_info.append(np.mean(self_info))all_tokens.extend(tokens)all_token_self_info.extend(self_info)noun_phrases, noun_phrases_info = self._calculate_lexical_unit(tokens, self_info)'''ipdb> noun_phrases['INTRODUCTION Continual Learning', ' (', ' CL', ' )', ',', ' also', ' known', ' as', ' Lifelong Learning', ',', ' is', ' a promising learning paradigm', ' to', ' design', ' models', ' that', ' have', ' to', ' learn', ' how', ' to', ' perform', ' multiple tasks', ' across', ' different environments', ' over', ' their lifetime', ' [', 'To', ' uniform', ' the language', ' and', ' enhance', ' the readability', ' of', ' the paper', ' we', ' adopt', ' the unique term continual learning', ' (', ' CL', ' )', '.', ']', '.']ipdb> noun_phrases_info[4.692921464797109, 2.4503376483917236, 10.236454963684082, 0.8689146041870117, 5.269547939300537, 4.641763210296631, 0.22138957679271698, 0.010370315983891487, 3.5931241369495788, 1.5882389545440674, 0.4495090842247009, 4.284574694931507, 3.3969509601593018, 7.337691307067871, 5.881226539611816, 1.7340556383132935, 4.599822521209717, 6.482723236083984, 4.045308589935303, 4.762691497802734, 0.21346867084503174, 3.7985599040985107, 2.487707197666168, 4.918881416320801, 2.7160372734069824, 5.5081071853637695, 3.2111923694610596, 6.347291946411133, 12.772034645080566, 13.792041778564453, 5.348196029663086, 3.3618998527526855, 8.434362411499023, 2.3589248929638416, 0.3090735077857971, 2.6371518969535828, 3.744772434234619, 7.2841596603393555, 4.672402499616146, 1.6127821207046509, 1.6296097040176392, 0.46206924319267273, 3.0398476123809814, 3.446016311645508, 3.446016311645508]'''# We need to add a space before the first noun phrase for every sentence except the first oneif all_noun_phrases:noun_phrases[0] = f" {noun_phrases[0]}"all_noun_phrases.extend(noun_phrases)all_noun_phrases_info.extend(noun_phrases_info)return [LexicalUnits('sent', text=sents, self_info=sent_self_info),LexicalUnits('phrase', text=all_noun_phrases, self_info=all_noun_phrases_info),LexicalUnits('token', text=all_tokens, self_info=all_token_self_info)]

第三步:精选保留信息含量高的上下文

在计算了每个词汇单元的自信息之后,我们面临的问题是如何判断其信息含量。论文介绍了一种创新方法,利用基于百分位数的筛选策略,动态挑选出信息最丰富的内容。这种方法相较于设定固定阈值或仅仅保留前 k 个最高信息量的词汇单元更为灵活有效。

我们的操作流程是先按自信息值(self-information values)从高到低排序所有词汇单元 ,接着计算所有词汇单元自信息值的 p-th percentile (译者注:“p-th percentile” 在统计学中指的是数据分布的一个特定点,在这一点之下包含了总数据中 p% 的数值。举个例子,假设你有一个班级的数学成绩分布,如果某个学生的成绩位于第90百分位(90th percentile),这意味着班上90%的学生的成绩低于或等于他的成绩,而他仅比剩下的10%的学生成绩低。)。最后,我们精挑细选出那些自信息值不低于该百分位数的词汇单元,确保所保留的都是信息含量最高的部分。

相关代码[13]如下:

class SelectiveContext:......def self_info_mask(self, sents: List[str], self_info: List[float], mask_level):# mask_level: mask sentences, phrases, or tokenssents_after_mask = []masked_sents = []self.ppl_threshold = np.nanpercentile(self_info, self.mask_ratio * 100)# if title is not None:#     with open(os.path.join(self.path, title+'_prob_token.tsv'), 'w', encoding='utf-8') as f:#         for token, info in zip(tokens, self_info):#             f.write(f"{token}\t{info}\n")#     with open(os.path.join(self.path, title+'_prob_sent.tsv'), 'w', encoding='utf-8') as f:#         for sent, info in zip(sents, sent_self_info):#             f.write(f"{sent}\n{info}\n\n")for sent, info in zip(sents, self_info):if info < self.ppl_threshold:masked_sents.append(sent)sents_after_mask.append(self.mask_a_sent(sent, mask_level))else:sents_after_mask.append(sent)masked_context = " ".join(sents_after_mask) if mask_level == 'sent' else "".join(sents_after_mask)return masked_context, masked_sents

02 LLMLingua

2.1 Overview 概览

LLMLingua[2] 这种方法认为,Selective Context[1] 方法常常忽略了压缩内容间的内在联系及 LLM 与用于提示词压缩的小型语言模型间的协同作用。LLMLingua 正好解决了这些问题。

具体而言,参照图 4,LLMLingua 利用 budget controller 为原始提示词的各个组成部分(如指导性提示词、演示样例和问题)动态分配不同的压缩率。同时,它采取粗粒度的 demonstration-level (译者注:在完整的演示案例上进行压缩或处理,而不是单独处理每个小的组成部分(比如单词或短语)。)压缩策略,确保即使在高度压缩的情况下,语义依然完整无损。此外,LLMLingua[2] 还引入了一种基于 tokens 的迭代算法,进一步优化细粒度的提示词压缩过程。

图 4:LLMLingua 方法的架构概览。来源:LLMLingua[2]

与 Selective Context 相比,LLMLingua 能更有效地保留提示词中的关键信息,同时还能够考虑到 tokens 之间的条件依赖关系,其压缩倍数可达 20 倍。

2.2 Budget controller

Budget controller 是 LLMLingua 的关键组件,用于为原始提示词的不同部分动态分配不同的压缩率。

考虑到提示词各部分对压缩行为的敏感程度各不相同 ------ 例如,问题需要保持较高的信息密度,而演示样例部分则可适度压缩。budget controller 的职责就在于此:对指导性提示词和问题采用较低的压缩比率,确保核心信息的完整留存;而对于演示样例部分,则可实施更高比率的压缩,剔除不必要的冗余信息。

budget controller 的具体算法,详述于图 5 中。

图 5:budget controller 的具体算法。Source: LLMLingua[2]

其核心变量定义如下:

  • Mₛ: 小型语言模型,比如 GPT-2 或 LLaMA。
  • x = (x^ins , x^dems , x^que) : 原始提示词,整合了指导性提示词、演示样例与问题三大部分。
  • L, L_ins, L_dems, 和 L_que 分别代表 x, x^ins , x^dems, 和 x^que 中的 token 总数。
  • 𝜏_dems: 在总体压缩率 τ 的约束下,依据指导性提示词和问题预设的压缩率 τ_ins 和 τ_que 来决定的演示样例压缩率。
  • D: 集合 D 将收纳所有经过压缩处理后的演示样例。

主要操作步骤如下:

  1. 确定演示样例的压缩比例。
  2. 利用小型语言模型(如 GPT-2 或 LLaMA)计算原始演示样例集合中每个演示样例的困惑度(perplexity)。
  3. 按照困惑度从高到低排序全部演示样例。
  4. 迭代挑选演示样例并将其添加到集合 D。
  5. 完成演示样例的压缩后,将未使用的 budget (译者注:在总体压缩率的限制下,算法会优先确保演示样例被充分压缩,然后利用剩下的压缩能力去进一步压缩指导性提示词和问题,以实现最佳的信息保留和资源利用平衡。)转用于指导性提示词和问题的处理。
  6. 输出经过粗粒度压缩后的集合 D。

借助 demonstration-level (译者注:在完整的演示案例上进行压缩或处理,而不是单独处理每个小的组成部分(比如单词或短语)。)的压缩流程,budget controller 可以确保在削减数据量的同时,核心信息得以保全,能够有效实现原始提示词的瘦身。这一策略特别适合处理包含多重演示样例的复杂提示词。

涉及的程序代码,可在 control_context_budget 函数[14]中找到实现细节。

2.3 Iterative Token-level Prompt Compression (ITPC)

利用困惑度(perplexity)作为压缩标准,有其内在的局限性:the independence assumption(译者注:假设文本序列中的每个词汇(token)或字符的出现是彼此独立的,其出现的概率只依赖于它前面的一个或几个词汇,而与序列中更远的其他词汇无关。)。该假设认为每个 token 在提示词中孤立存在,其出现的概率仅取决于紧邻的前一个token,而不受其他任何 tokens 的影响。

然而,这一假设忽略了自然语言中词元(token)间错综复杂的相互依存关系,而这种关系对于理解上下文和保持语义的完整性至关重要。

忽略这些相互依存的关系,极有可能在压缩过程中造成重要信息的流失。 例如,在进行高比例压缩时,倘若某个 token 承载着上下文中的核心推理环节或逻辑联系纽带,那么仅仅依据其困惑度判定其去留,可能会导致推理链的断裂。

为克服这一挑战,LLMLingua 引入了 Iterative Token-level Prompt Compression(ITPC) 算法。不同于仅凭独立概率评判 token 价值的传统方法,ITPC 算法在压缩提示词时,会更精细地评估每个 token 的实际贡献。通过反复审视提示词的每一部分,同时考量当前上下文中每个 token 的条件概率,这一算法能更有效地维系 token 间的内在联系,确保压缩后提示词的语义完整性和逻辑连贯性。

图 6 展示了 ITPC 算法的详细步骤:

图 6:ITPC 算法的详细步骤。图片由原文作者提供

借助这一流程,ITPC 算法可以有效缩短提示词信息的长度,同时还能确保其语义内容的完整性,进而有效地降低了 LLM 的推理成本。

相关的实现代码可以在函数 iterative_compress_prompt[15] 中找到。

2.4 Instruction Tuning 指令调优

如图 4 所示,在 LLMLingua 框架内,指令调优(instruction tuning)扮演着至关重要的角色。该步骤的核心目的是缩小用于提示词压缩的小型语言模型与大语言模型(LLMs)之间在分布特性上的差异。

图 7 展示了 Instruction Tuning 算法的详细步骤:

图 7:Instruction Tuning 的详细步骤。图片由原文作者提供

2.5 Code Demonstration 代码演示

我们现在开始展示代码。首要步骤是配置好环境。

(base) Florian:~ Florian$ conda create -n "llmlingua" python=3.11(base) Florian:~ Florian$ conda activate llmlingua(llmlingua) Florian:~ Florian$ pip install llmlingua

以下是已安装的版本信息:

llmlingua          0.2.1

下面是用于测试的代码段:

from llmlingua import PromptCompressorGSM8K_PROMPT = "Question: Angelo and Melanie want to plan how many hours over the next week they should study together for their test next week. They have 2 chapters of their textbook to study and 4 worksheets to memorize. They figure out that they should dedicate 3 hours to each chapter of their textbook and 1.5 hours for each worksheet. If they plan to study no more than 4 hours each day, how many days should they plan to study total over the next week if they take a 10-minute break every hour, include 3 10-minute snack breaks each day, and 30 minutes for lunch each day?\nLet's think step by step\nAngelo and Melanie think they should dedicate 3 hours to each of the 2 chapters, 3 hours x 2 chapters = 6 hours total.\nFor the worksheets they plan to dedicate 1.5 hours for each worksheet, 1.5 hours x 4 worksheets = 6 hours total.\nAngelo and Melanie need to start with planning 12 hours to study, at 4 hours a day, 12 / 4 = 3 days.\nHowever, they need to include time for breaks and lunch. Every hour they want to include a 10-minute break, so 12 total hours x 10 minutes = 120 extra minutes for breaks.\nThey also want to include 3 10-minute snack breaks, 3 x 10 minutes = 30 minutes.\nAnd they want to include 30 minutes for lunch each day, so 120 minutes for breaks + 30 minutes for snack breaks + 30 minutes for lunch = 180 minutes, or 180 / 60 minutes per hour = 3 extra hours.\nSo Angelo and Melanie want to plan 12 hours to study + 3 hours of breaks = 15 hours total.\nThey want to study no more than 4 hours each day, 15 hours / 4 hours each day = 3.75\nThey will need to plan to study 4 days to allow for all the time they need.\nThe answer is 4\n\nQuestion: You can buy 4 apples or 1 watermelon for the same price. You bought 36 fruits evenly split between oranges, apples and watermelons, and the price of 1 orange is $0.50. How much does 1 apple cost if your total bill was $66?\nLet's think step by step\nIf 36 fruits were evenly split between 3 types of fruits, then I bought 36/3 = 12 units of each fruit\nIf 1 orange costs $0.50 then 12 oranges will cost $0.50 * 12 = $6\nIf my total bill was $66 and I spent $6 on oranges then I spent $66 - $6 = $60 on the other 2 fruit types.\nAssuming the price of watermelon is W, and knowing that you can buy 4 apples for the same price and that the price of one apple is A, then 1W=4A\nIf we know we bought 12 watermelons and 12 apples for $60, then we know that $60 = 12W + 12A\nKnowing that 1W=4A, then we can convert the above to $60 = 12(4A) + 12A\n$60 = 48A + 12A\n$60 = 60A\nThen we know the price of one apple (A) is $60/60= $1\nThe answer is 1\n\nQuestion: Susy goes to a large school with 800 students, while Sarah goes to a smaller school with only 300 students.  At the start of the school year, Susy had 100 social media followers.  She gained 40 new followers in the first week of the school year, half that in the second week, and half of that in the third week.  Sarah only had 50 social media followers at the start of the year, but she gained 90 new followers the first week, a third of that in the second week, and a third of that in the third week.  After three weeks, how many social media followers did the girl with the most total followers have?\nLet's think step by step\nAfter one week, Susy has 100+40 = 140 followers.\nIn the second week, Susy gains 40/2 = 20 new followers.\nIn the third week, Susy gains 20/2 = 10 new followers.\nIn total, Susy finishes the three weeks with 140+20+10 = 170 total followers.\nAfter one week, Sarah has 50+90 = 140 followers.\nAfter the second week, Sarah gains 90/3 = 30 followers.\nAfter the third week, Sarah gains 30/3 = 10 followers.\nSo, Sarah finishes the three weeks with 140+30+10 = 180 total followers.\nThus, Sarah is the girl with the most total followers with a total of 180.\nThe answer is 180"llm_lingua = PromptCompressor()## Or use the phi-2 model,
# llm_lingua = PromptCompressor("microsoft/phi-2")## Or use the quantation model, like TheBloke/Llama-2-7b-Chat-GPTQ, only need <8GB GPU memory.
## Before that, you need to pip install optimum auto-gptq
# llm_lingua = PromptCompressor("TheBloke/Llama-2-7b-Chat-GPTQ", model_config={"revision": "main"})compressed_prompt = llm_lingua.compress_prompt(GSM8K_PROMPT.split("\n\n")[0], instruction="", question="", target_token=200)print('-' * 100)
print("original:")
print(GSM8K_PROMPT.split("\n\n")[0])print('-' * 100)
print("compressed_prompt:")
print(compressed_prompt)

首次运行时会自动下载默认模型。当然,我们也有另一个选项,即使用量化模型(quantized model)。相关的运行结果展示在图 8 中:

图 8 :LLMLingua 测试代码的运行结果。此截图由原文作者提供

03 LongLLMLingua

LLMLingua 的问题在于,在压缩处理过程中忽略了用户提出的问题,这可能导致一些无关紧要的信息被无谓地保留下来。

而 LongLLMLingua[3] 的设计初衷正是为了解决这一缺陷,它创新性地在压缩流程中融入了对用户问题的考量和处理。

图 9:LongLLMLingua 框架,灰色斜体内容与 LLMLingua 相同。图片来源:LongLLMLingua[3]

如图 9 所示,LongLLMLingua 框架引入了四项新功能,以提升大语言模型识别关键信息的能力

  • 针对用户问题的粗粒度和细粒度两级压缩技术(Question-aware coarse-grained and fine-grained compression);
  • 动态调整的文档排序机制(Document reordering mechanism);
  • 可变的压缩比例设定(Dynamic compression ratio);
  • 子序列恢复算法(Subsequence recovery algorithm)。

3.1 针对用户问题的粗粒度压缩技术

LongLLMLingua 推荐采用这样一种方法,利用在不同文档上下文 x^doc_k 背景下问题 x^que 的困惑度,来衡量两者间的关联强度。我们可以在问题 x^que 后面附加一句限定语 x^restrict = "我们可以在提供的文档里找到这个问题的答案"。这样做的目的是强化 x^quex^doc_k 之间的联系,同时,这句话作为一个正则化项(regularization item),能有效降低模型产生不切实际的预测结果的可能性。这可以表示为:

为什么不直接计算在问题 x^que 约束下的整体文档困惑度呢?原因在于,文档内往往充斥着许多与问题不相关的冗余信息。即便是在 x^que 的引导下,对整篇文档计算出的困惑度值也可能不够明显,从而导致它无法成为评估文档层面压缩效果的理想指标。

可以在函数 get_distance_longllmlingua[16] 中找到实现这一技术的相关代码。

3.2 针对用户问题的细粒度压缩技术

LongLLMLingua 引入了对比困惑度(contrastive perplexity)的概念。

首先,我们计算一个 token 的困惑度,不考虑问题的情况下,表示为 perplexity(x_i | x<i) 。然后,我们再次测量困惑度,这次包括了问题,表示为 perplexity(x_i | x^que, x<i)。这衡量的是在给定问题 x^que 的情况下,词元 x_i 对之前所有词元(token)的惊讶程度。

我们的目标是确定每个 token 的惊讶程度随问题变化的程度。如果当问题被包括进来后,某个词变得不那么令人惊讶,那么这个词很可能与问题高度相关。

3.3 动态调整的文档排序机制

如图 10 所示,在推理阶段,大语言模型(LLMs)倾向于利用提示词信息的起始和尾部内容,而往往忽视了其中间部分的信息,这便是所谓的"Lost in the Middle"问题。

图 10:大语言模型(LLM)对相关资讯的把握能力受到其在提示词信息中位置的影响。为了解决中间信息丢失的问题,我们引入了一项文档重排序机制。图片来源:LongLLMLingua[3]

图 10 进一步表明,当关键信息被置于开头时,LLMs 的表现最为出色。基于此, LongLLMLingua 会根据粗粒度压缩的结果来组织段落,从前往后依据评分高低进行排序。

3.4 可变的压缩比例设定

鉴于不同文档中关键信息的密集程度存在差异,我们应当对那些与问题更加相关的文档分配更多资源(即采取更低的压缩比率)。

LongLLMLingua 运用在粗粒度压缩过程中得出的重要性得分,来指引细粒度压缩阶段的资源分配策略。

具体操作如下:首先,通过 LLMLingua 的 budget controller 为保留的文档设定初始资源量。随后,在细粒度压缩阶段,为每个文档动态分配资源。这一分配策略基于文档在粗粒度压缩阶段确定的重要性得分排名,以排名顺序作为资源分配依据。

LongLLMLingua 实施了一种线性调度方法(linear scheduler),实现资源的自适应分配(adaptive allocation)。对于每个词元(token) xi,其资源量计算公式如下:

其中,Nd表示所有文档的数量,𝛿𝜏是一个控制动态分配总资源量的超参数。

对应的源代码可以在 get_dynamic_compression_ratio[17] 函数中找到。

3.5 子序列恢复算法

如图 11 所示,在细粒度的逐 token 压缩环节中,一些关键实体的 token 有被丢弃的风险。例如,"2009"在原始提示词中可能被压缩至"209""Wilhelm Conrad Rontgen"也可能被简化压缩为"Wilhelmgen"

图 11:展示了一个子序列恢复算法案例,其中红色文本代表原始内容,而蓝色文字则是经过压缩后的结果。来源:LongLLMLingua[3]

LongLLMLingua 设计了一套子序列恢复算法,能够从大语言模型(LLMs)的回应中复原原始信息,如图 12 所示。

图 12:子序列恢复算法流程图。图片来源:LongLLMLingua

其核心流程包括以下几个步骤:

  • 遍历大语言模型(LLM)响应内容中的每一个词元(token)yl,从中选取在压缩提示词 中出现的最长子序列 y˜key,l
  • 在原始提示词 x 内,寻找与 y˜key,l 匹配的最大公共最短子序列(maximum common shortest subsequence)xi,j
  • 将大语言模型(LLMs)响应内容中的相应词元 y˜key,l 替换为原始的 xi,j

这一算法的具体代码可以在 recover 函数[18]中找到。

3.6 代码演示

环境配置的方法与 LLMLingua 相同。下面是测试代码:

from llmlingua import PromptCompressorGSM8K_PROMPT = "Question: Angelo and Melanie want to plan how many hours over the next week they should study together for their test next week. They have 2 chapters of their textbook to study and 4 worksheets to memorize. They figure out that they should dedicate 3 hours to each chapter of their textbook and 1.5 hours for each worksheet. If they plan to study no more than 4 hours each day, how many days should they plan to study total over the next week if they take a 10-minute break every hour, include 3 10-minute snack breaks each day, and 30 minutes for lunch each day?\nLet's think step by step\nAngelo and Melanie think they should dedicate 3 hours to each of the 2 chapters, 3 hours x 2 chapters = 6 hours total.\nFor the worksheets they plan to dedicate 1.5 hours for each worksheet, 1.5 hours x 4 worksheets = 6 hours total.\nAngelo and Melanie need to start with planning 12 hours to study, at 4 hours a day, 12 / 4 = 3 days.\nHowever, they need to include time for breaks and lunch. Every hour they want to include a 10-minute break, so 12 total hours x 10 minutes = 120 extra minutes for breaks.\nThey also want to include 3 10-minute snack breaks, 3 x 10 minutes = 30 minutes.\nAnd they want to include 30 minutes for lunch each day, so 120 minutes for breaks + 30 minutes for snack breaks + 30 minutes for lunch = 180 minutes, or 180 / 60 minutes per hour = 3 extra hours.\nSo Angelo and Melanie want to plan 12 hours to study + 3 hours of breaks = 15 hours total.\nThey want to study no more than 4 hours each day, 15 hours / 4 hours each day = 3.75\nThey will need to plan to study 4 days to allow for all the time they need.\nThe answer is 4\n\nQuestion: You can buy 4 apples or 1 watermelon for the same price. You bought 36 fruits evenly split between oranges, apples and watermelons, and the price of 1 orange is $0.50. How much does 1 apple cost if your total bill was $66?\nLet's think step by step\nIf 36 fruits were evenly split between 3 types of fruits, then I bought 36/3 = 12 units of each fruit\nIf 1 orange costs $0.50 then 12 oranges will cost $0.50 * 12 = $6\nIf my total bill was $66 and I spent $6 on oranges then I spent $66 - $6 = $60 on the other 2 fruit types.\nAssuming the price of watermelon is W, and knowing that you can buy 4 apples for the same price and that the price of one apple is A, then 1W=4A\nIf we know we bought 12 watermelons and 12 apples for $60, then we know that $60 = 12W + 12A\nKnowing that 1W=4A, then we can convert the above to $60 = 12(4A) + 12A\n$60 = 48A + 12A\n$60 = 60A\nThen we know the price of one apple (A) is $60/60= $1\nThe answer is 1\n\nQuestion: Susy goes to a large school with 800 students, while Sarah goes to a smaller school with only 300 students.  At the start of the school year, Susy had 100 social media followers.  She gained 40 new followers in the first week of the school year, half that in the second week, and half of that in the third week.  Sarah only had 50 social media followers at the start of the year, but she gained 90 new followers the first week, a third of that in the second week, and a third of that in the third week.  After three weeks, how many social media followers did the girl with the most total followers have?\nLet's think step by step\nAfter one week, Susy has 100+40 = 140 followers.\nIn the second week, Susy gains 40/2 = 20 new followers.\nIn the third week, Susy gains 20/2 = 10 new followers.\nIn total, Susy finishes the three weeks with 140+20+10 = 170 total followers.\nAfter one week, Sarah has 50+90 = 140 followers.\nAfter the second week, Sarah gains 90/3 = 30 followers.\nAfter the third week, Sarah gains 30/3 = 10 followers.\nSo, Sarah finishes the three weeks with 140+30+10 = 180 total followers.\nThus, Sarah is the girl with the most total followers with a total of 180.\nThe answer is 180"
QUESTION = "Question: Josh decides to try flipping a house.  He buys a house for $80,000 and then puts in $50,000 in repairs.  This increased the value of the house by 150%.  How much profit did he make?"llm_lingua = PromptCompressor()compressed_prompt = llm_lingua.compress_prompt(GSM8K_PROMPT.split("\n\n")[0],question = QUESTION,# ratio=0.55# Set the special parameter for LongLLMLinguacondition_in_question = "after_condition",reorder_context = "sort",dynamic_context_compression_ratio = 0.3, # or 0.4condition_compare = True,context_budget = "+100",rank_method = "longllmlingua",
)print('-' * 100)
print("original:")
print(GSM8K_PROMPT.split("\n\n")[0])print('-' * 100)
print("compressed_prompt:")
print(compressed_prompt)

运行结果如图 13 所示:

图 13:LongLLMLingua 测试代码的运行结果。截图由作者提供。

04 AutoCompressor

不同于先前提及的方法,AutoCompressor[4] 采取了一种基于软提示词的创新途径

它巧妙地通过增加词汇量和利用"summary tokens""summary vectors"来提炼大量上下文信息,进而精调现有的模型结构。

图 14:AutoCompressor 通过递归生成 summary vectors 来处理长文档,这些 summary vectors 作为软提示词(soft prompts)被传递给后续的所有文档片段。图片来源:AutoCompressor[4]

图 14 描绘了 AutoCompressor 的工作原理,其运行步骤如下:

  • 词汇扩展(Expand Vocabulary) :在这一步骤中,我们将 “summary tokens” 加入到模型现有的词汇库中。这些 tokens 的作用是帮助模型将庞大的信息量压缩成更紧凑的向量表征。
  • 文档分割(Split Document) :待处理的文档被切割成若干小段,每一小段后都会附加有 summary tokens 。这些 tokens 不仅携带了本段的信息,还包含了前面所有段落的摘要信息,实现了摘要信息的连续积累(summary accumulation)。
  • 微调训练(Fine-tuning Training) :采用无监督训练的方式,借助 “next word prediction” 任务对模型进行微调。该任务的核心在于,根据当前片段前的 tokens 序列以及之前片段的摘要向量(summary vectors),预测下一个单词。
  • 反向传播(Backpropagation) :AutoCompressor 在每个文档片段上运用 backpropagation through time(BPTT)(译者注:对于每一个时间步,BPTT 都会计算损失函数关于当前时间步和所有之前时间步参数的梯度,然后将这些梯度反向传播回网络,以更新参数。) 和 gradient checkpointing(译者注:在标准的反向传播过程中,为了计算梯度,需要保存前向传播过程中的所有中间结果。但随着网络深度的增加,这会消耗大量的内存。Gradient checkpointing 通过牺牲一些计算效率来减少内存需求。) 技术,能够有效缩减计算图(computational graph)的规模。反向传播针对整个文档进行,使得模型能够全面理解并学习到整个上下文之间存在的关联。

4.1 代码演示

AutoCompressor[19] 开放了其源代码,感兴趣的读者可以试着读一读。

import torch
from transformers import AutoTokenizer
from auto_compressor import LlamaAutoCompressorModel, AutoCompressorModel# Load AutoCompressor trained by compressing 6k tokens in 4 compression steps
tokenizer = AutoTokenizer.from_pretrained("princeton-nlp/AutoCompressor-Llama-2-7b-6k")
# Need bfloat16 + cuda to run Llama model with flash attention
model = LlamaAutoCompressorModel.from_pretrained("princeton-nlp/AutoCompressor-Llama-2-7b-6k", torch_dtype=torch.bfloat16).eval().cuda()prompt = 'The first name of the current US president is "'
prompt_tokens = tokenizer(prompt, add_special_tokens=False, return_tensors="pt").input_ids.cuda()context = """Joe Biden, born in Scranton, Pennsylvania, on November 20, 1942, had a modest upbringing in a middle-class family. He attended the University of Delaware, where he double-majored in history and political science, graduating in 1965. Afterward, he earned his law degree from Syracuse University College of Law in 1968.\nBiden's early political career began in 1970 when he was elected to the New Castle County Council in Delaware. In 1972, tragedy struck when his wife Neilia and 1-year-old daughter Naomi were killed in a car accident, and his two sons, Beau and Hunter, were injured. Despite this devastating loss, Biden chose to honor his commitment and was sworn in as a senator by his sons' hospital bedsides.\nHe went on to serve as the United States Senator from Delaware for six terms, from 1973 to 2009. During his time in the Senate, Biden was involved in various committees and was particularly known for his expertise in foreign affairs, serving as the chairman of the Senate Foreign Relations Committee on multiple occasions.\nIn 2008, Joe Biden was selected as the running mate for Barack Obama, who went on to win the presidential election. As Vice President, Biden played an integral role in the Obama administration, helping to shape policies and handling issues such as economic recovery, foreign relations, and the implementation of the Affordable Care Act (ACA), commonly known as Obamacare.\nAfter completing two terms as Vice President, Joe Biden decided to run for the presidency in 2020. He secured the Democratic nomination and faced the incumbent President Donald Trump in the general election. Biden campaigned on a platform of unity, promising to heal the divisions in the country and tackle pressing issues, including the COVID-19 pandemic, climate change, racial justice, and economic inequality.\nIn the November 2020 election, Biden emerged victorious, and on January 20, 2021, he was inaugurated as the 46th President of the United States. At the age of 78, Biden became the oldest person to assume the presidency in American history.\nAs President, Joe Biden has worked to implement his agenda, focusing on various initiatives, such as infrastructure investment, climate action, immigration reform, and expanding access to healthcare. He has emphasized the importance of diplomacy in international relations and has sought to rebuild alliances with global partners.\nThroughout his long career in public service, Joe Biden has been recognized for his commitment to bipartisanship, empathy, and his dedication to working-class issues. He continues to navigate the challenges facing the nation, striving to bring the country together and create positive change for all Americans."""
context_tokens = tokenizer(context, add_special_tokens=False, return_tensors="pt").input_ids.cuda()summary_vectors = model(context_tokens, output_softprompt=True).softprompt
print(f"Compressing {context_tokens.size(1)} tokens to {summary_vectors.size(1)} summary vectors")
# >>> Compressing 660 tokens to 50 summary vectorsgeneration_with_summary_vecs = model.generate(prompt_tokens, do_sample=False, softprompt=summary_vectors, max_new_tokens=12)[0]
print("Generation w/ summary vectors:\n" + tokenizer.decode(generation_with_summary_vecs))
# >>> The first name of the current US president is "Joe" and the last name is "Biden".next_tokens_without_context = model.generate(prompt_tokens, do_sample=False, max_new_tokens=11)[0]
print("Generation w/o context:\n" + tokenizer.decode(next_tokens_without_context))
# >>> The first name of the current US president is "Donald" and the last name is "Trump".

05 LLMLingua-2

LLMLingua-2[6] 发现,通过基于因果语言模型(如LLaMa-7B)的信息熵删除 tokens 或词汇单位(lexical units)来进行提示词压缩存在两大挑战:

(1) 用来计算信息熵的小型语言模型与提示词压缩的实际目标不一致。

(2) 这一方法仅依赖于单向的上下文信息,而这或许无法覆盖提示词压缩所需的所有必要信息。

这些问题的核心在于,基于信息熵(information entropy)进行提示词压缩可能并非是最优的选择。

LLMLingua-2 的整体架构如图 15 所示:

图 15:LLMLingua-2的架构总览。来源:LLMLingua-2[6]

针对第一个问题,LLMLingua-2 引入了数据蒸馏流程。该流程从大语言模型中提取知识,在不丢失关键信息的情况下压缩提示词。同时,它还构建了一个 extractive text compression dataset (译者注:从原始文本中挑选出最重要的句子、短语或词汇,直接组成一个较短的版本,以保留原文的主要信息和意义。一般来说不涉及生成新的句子来概括原文)。在这样的数据集上进行训练,有助于小型语言模型更精准地对齐提示词压缩的需求。

面对第二个问题,LLMLingua-2 采取了一种创新策略 ------ 将提示词压缩转化为词元(token)分类任务。这一策略确保了压缩后的提示词能忠实地反映原始提示词的意图。它选用 transformer 的编码器作为底层架构,能够充分利用完整的双向上下文信息(bidirectional context),捕捉到进行提示词压缩所需的全部必要细节。

5.1 如何构建有效的提示词压缩数据集?

数据蒸馏

数据蒸馏从大语言模型(比如 GPT-4)中抽取知识,以便在不丢失基本信息的情况下实现有效压缩提示词。

在 LLMLingua-2 这一项目中,指导性提示词的设计经过了精心设计,如图 16 所示。这些指导性提示词(instructions)指导 GPT-4 在不向生成文本中引入新词汇的前提下,剔除原始文本中的冗余词汇,从而实现文本的压缩。

与此同时,这些指导性提示词(instructions)并未强行规定压缩的比例。相反,GPT-4 被鼓励尽可能地缩减原始文本的体积,但前提是必须确保原始信息的完整性。

图 16:LLMLingua-2 中用于数据蒸馏的指导性提示词。

如图 17 所示,在处理非常长的文本时,GPT-4 倾向于采取高比例的压缩策略。可能是因为其处理长文本的能力有限。这种激进的压缩策略往往伴随着大量信息的流失,可能严重影响接下来的任务执行效果。

图 17:在 MeetingBank 数据集上,根据原始文本长度,GPT-4 的压缩比情况。在本研究中,我们使用了 GPT-4–32k ,并将输出 tokens 的数量上限设为 4096。来源:LLMLingua-2[6]。

为了解决这个问题,LLMLingua-2 引入了一种分块压缩(chunk compression) 技术,即先将长文本拆解为若干个不超过 512 tokens 的小文本块,再分别对每一小文本块进行压缩处理,由 GPT-4 来完成这一过程。

数据标注

现在,我们已经利用数据蒸馏手段,收集到了原始文本与其压缩内容的组合。数据标注的目的是为原始文本里的每个 token 标上一个二元标签,以此判断压缩后该字符是否应该被保留。

考虑到 GPT-4 不一定能够完美遵循指导性提示词,LLMLingua-2 采取了滑动窗口策略(sliding window) ,以此来限定搜索范围。同时,还引入了模糊匹配技术(fuzzy matching) ,有效处理了 GPT-4 在提示词压缩过程中对原始词汇可能做出的细微改动。

质量控制

在 LLMLingua-2 项目中,质量控制环节采用了两个关键指标来评估通过 GPT-4 蒸馏生成的压缩文本,以及自动标注标签的优劣:Variation Rate(VR)Alignment Gap(AG)

Variation Rate(VR)衡量的是,压缩后的文本与原始文本相比,有多少比例的词汇发生了改变。而Alignment Gap(AG),则是用来衡量自动标注的标签的精准程度。

通过这些评估指标,LLMLingua-2 便能有效地筛除不合格的样本,从而保障整个数据集质量。

5.2 Compressor 压缩器

将其视为二元分类问题

从本质上讲,可将提示词压缩问题重塑为二元分类问题。其基本概念是将每一个词汇单元视为一个独立的实体,并为其分配一个标签:"保留""丢弃"。这一策略不仅确保了压缩后提示词内容的完整性,同时还简化了模型结构。

模型架构设计

采用了基于 Transformer 编码器的特征编码器(feature encoder),并在其上巧妙地叠加了一个线性分类层(linear classification layer)。

这样的架构设计使得模型能够深刻理解每个词汇单元的双向上下文信息,为高效完成压缩任务奠定了坚实的基础。

提示词压缩策略

压缩原始提示词 x 的策略分为三个步骤。目标压缩比率设定为 1/τ,这里 τ 即为压缩后提示词的词汇量与原始提示词 x 的词汇量之商。

  • 首先,我们计算出压缩后提示词 需要保留的 token 数量:N˜ = τN
  • 随后,运用 token 分类模型来预估每个词汇 xi 被标定为"保留"的概率 pi
  • 最后,我们从原始提示词 x 中筛选出前 pi 值最高的词汇,严格保持其原有排列顺序,进而组成压缩后的提示词

5.3 代码演示

从上文可以看出,LLMLingua-2 的主要工作是构建压缩器(compressor)。那么,当我们成功获取了这个压缩器之后,下一步该如何操作呢?

请参照下方的代码示例(环境配置方式与 LLMLingua 一致)。compress_prompt_llmlingua2[20] 函数内集中体现了主要的处理逻辑。

from llmlingua import PromptCompressorPROMPT = "John: So, um, I've been thinking about the project, you know, and I believe we need to, uh, make some changes. I mean, we want the project to succeed, right? So, like, I think we should consider maybe revising the timeline.\n\nSarah: I totally agree, John. I mean, we have to be realistic, you know. The timeline is, like, too tight. You know what I mean? We should definitely extend it."llm_lingua = PromptCompressor(model_name = "microsoft/llmlingua-2-xlm-roberta-large-meetingbank",use_llmlingua2 = True,
)
compressed_prompt = llm_lingua.compress_prompt(PROMPT, rate=0.33, force_tokens = ['\n', '?'])## Or use LLMLingua-2-small model
# llm_lingua = PromptCompressor(
#     model_name="microsoft/llmlingua-2-bert-base-multilingual-cased-meetingbank",
#     use_llmlingua2=True,
# )print('-' * 100)
print("original:")
print(PROMPT)print('-' * 100)
print("compressed_prompt:")
print(compressed_prompt)

运行结果如图 18 所示:

图 18:LLMLingua-2 测试代码的运行结果。截图由原文作者提供

06 RECOMP

RECOMP[7] 创新性地引入了两类经过训练的压缩器:抽取型(extractive)和概括型(abstractive)。抽取型压缩器擅长从已检索的文档中精挑细选出有价值的部分 ;而概括型压缩器则通过融合多篇文档的精华,自动生成摘要。

图 19 生动描绘了压缩器在 RECOMP 架构中的位置。

图 19:RECOMP 架构。图片来源:RECOMP

6.1 抽取型压缩器

给定输入文档集中的 n 个句子 [s1, s2, ..., sn] ,使用一个双编码器模型(dual encoder model)进行训练。该模型能将每个句子 si 和输入序列 x 转换为固定长度的向量表征。这些嵌入向量的内积反映了将句子 si 添加到输入序列 x 中,对于大语言模型(LLM)生成目标输出序列(target output sequence)的帮助程度。

压缩器最终生成的摘要 s 由排名前 N 的句子组成,按照它们与输入序列的内积进行排序。

6.2 概括型压缩器

概括型压缩器采用的是编码器-解码器架构(encoder-decoder)。它处理输入序列 x 与检索出的文档集合并将其连接起来,进而产生摘要 s

该方法具体步骤如下:首先利用大语言模型(如GPT-3)来生成训练数据集;然后对数据集进行筛选;最后,使用经过筛选后的数据集来训练编码器-解码器模型(encoder-decoder model)。

6.3 代码演示

鉴于 RECOMP 当前尚处在开发初期,我们在此暂不进行演示。对此感兴趣的读者不妨亲自动手体验一番。

07 结论 Conclusion

本文探讨了提示词压缩技术,覆盖了该技术的方法分类、算法原理以及代码实践演示。

在本文所讨论的各种方法中,LongLLMLingua 或许是一个更为出色的选择 。我们已在项目实践中应用了这一方法。原文作者承诺一旦他们发现了 LongLLMLingua 存在的不足,或是发现了更为优秀的替代方案,他们将对原文(https://ai.gopubby.com/advanced-rag-09-prompt-compression-95a589f7b554 )进行更新(译者注:如果有小伙伴关注到了内容更新,请在下方留言,我们会尽量及时进行内容补充,感谢❤️。)。此外,LLMLingua-2 也值得一试,它在运行速度和内存消耗方面都表现优异。

Thanks for reading!

Florian June

An artificial intelligence researcher, mainly write articles about Large Language Models, data structures and algorithms, and NLP.

END

参考资料

[1]https://arxiv.org/pdf/2304.12102.pdf

[2]https://arxiv.org/pdf/2310.05736.pdf

[3]https://arxiv.org/pdf/2310.06839.pdf

[4]https://arxiv.org/pdf/2305.14788.pdf

[5]https://arxiv.org/pdf/2304.08467.pdf

[6]https://arxiv.org/pdf/2403.12968.pdf

[7]https://arxiv.org/pdf/2310.04408.pdf

[8]https://arxiv.org/pdf/2210.09461.pdf

[9]https://aclanthology.org/2022.acl-long.1.pdf

[10]https://github.com/liyucheng09/Selective_Context/blob/v0.1.0rc1/src/selective_context/init.py#L273

[11]https://github.com/liyucheng09/Selective_Context/blob/v0.1.0rc1/src/selective_context/init.py#L100

[12]https://github.com/liyucheng09/Selective_Context/blob/v0.1.0rc1/src/selective_context/init.py#L146

[13]https://github.com/liyucheng09/Selective_Context/blob/v0.1.0rc1/src/selective_context/init.py#L236

[14]https://github.com/microsoft/LLMLingua/blob/v0.2.1/llmlingua/prompt_compressor.py#L1108

[15]https://github.com/microsoft/LLMLingua/blob/v0.2.1/llmlingua/prompt_compressor.py#L1458

[16]https://github.com/microsoft/LLMLingua/blob/v0.2.1/llmlingua/prompt_compressor.py#L1967

[17]https://github.com/microsoft/LLMLingua/blob/v0.2.1/llmlingua/prompt_compressor.py#L958

[18]https://github.com/microsoft/LLMLingua/blob/v0.2.1/llmlingua/prompt_compressor.py#L1686

[19]https://github.com/princeton-nlp/AutoCompressors

[20]https://github.com/microsoft/LLMLingua/blob/v0.2.1/llmlingua/prompt_compressor.py#L661

本文经原作者授权,由 Baihai IDP 编译。如需转载译文,请联系获取授权。

原文链接:

https://ai.gopubby.com/advanced-rag-09-prompt-compression-95a589f7b554

相关文章:

Advanced RAG 09:『提示词压缩』技术综述

编者按&#xff1a; 如何最大限度地发挥 LLMs 的强大能力&#xff0c;同时还能控制其推理成本&#xff1f;这是当前业界研究的一个热点课题。 针对这一问题&#xff0c;本期精心选取了一篇关于"提示词压缩"(Prompt Compression)技术的综述文章。正如作者所说&#xf…...

(13)DroneCAN 适配器节点(二)

文章目录 前言 2 固件 2.1 基于F103 2.2 基于F303 2.3 基于F431 3 ArduPilot固件DroneCAN设置 3.1 f303-通用设置示例 4 DroneCAN适配器节点 前言 这些节点允许现有的 ArduPilot 支持的外围设备作为 DroneCAN 或 MSP 设备适应 CAN 总线。这也允许扩展自动驾驶仪硬件的…...

摸鱼大数据——Spark基础——Spark环境安装——Spark Local[*]搭建

一、虚拟机配置 查看每一台的虚拟机的IP地址和网关地址 查看路径: cat /etc/sysconfig/network-scripts/ifcfg-ens33 2.修改 VMware的网络地址: 使用VMnet8 3.修改windows的对应VMware的网卡地址 4.通过finalshell 或者其他的shell连接工具即可连接使用即可, 连接后, 测试一…...

函数内部结构分层浅析(从MVC分层架构联想)

函数内部结构分层浅析&#xff08;从MVC分层架构联想&#xff09; 分层架构:一种将软件代码按不同功能进行划分的架构模式。 优点包括&#xff1a; 可维护性&#xff1a;各层职责明确&#xff0c;易于单独修改维护。 可扩展性&#xff1a;方便添加或修改某一层&#xff0c;不…...

【three.js案例二】时空隧道

import * as THREE from ./build/three.module.js // 引入轨道控制器扩展库OrbitControls.js import { OrbitControls } from three/addons/controls/OrbitControls.js; // 引入dat.gui.js的一个类GUI import { GUI } from three/addons/libs/lil-gui.module.min.js;// 场景 co…...

动手学深度学习(Pytorch版)代码实践 -计算机视觉-48全连接卷积神经网络(FCN)

48全连接卷积神经网络&#xff08;FCN&#xff09; 1.构造函数 import torch import torchvision from torch import nn from torch.nn import functional as F import matplotlib.pyplot as plt import liliPytorch as lp from d2l import torch as d2l# 构造模型 pretrained…...

【Python游戏】猫和老鼠

本文收录于 《一起学Python趣味编程》专栏,从零基础开始,分享一些Python编程知识,欢迎关注,谢谢! 文章目录 一、前言二、代码示例三、知识点梳理四、总结一、前言 本文介绍如何使用Python的海龟画图工具turtle,开发猫和老鼠游戏。 什么是Python? Python是由荷兰人吉多范…...

【无标题】c# WEBAPI 读写表到Redis

//c# WEBAPI 读写表到Redis using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; using Newtonsoft.Json; using StackExchange.Redis; using System.Data; using System.Web; namespace …...

【剑指Offer系列】53-0到n中缺失的数字(index)

给定一个包含 [0, n] 中 n 个数的数组 nums &#xff0c;找出 [0, n] 这个范围内没有出现在数组中的那个数。 示例 1&#xff1a; 输入&#xff1a;nums [3,0,1] 输出&#xff1a;2 解释&#xff1a;n 3&#xff0c;因为有 3 个数字&#xff0c;所以所有的数字都在范围 [0,3]…...

docker compose部署zabbix7.0官方方法快速搭建

环境介绍&#xff1a; 系统&#xff1a;centos7 官方文档&#xff1a;https://www.zabbix.com/documentation/current/zh/manual/installation/containers docker镜像加速 vi /etc/docker/daemon.json{"registry-mirrors": ["https://docker.1panel.live&quo…...

分库分表之后如何设计主键ID(分布式ID)?

文章目录 1、数据库的自增序列步长方案2、分表键结合自增序列3、UUID4、雪花算法5、redis的incr方案总结 在进行数据库的分库分表操作后&#xff0c;必然要面临的一个问题就是主键id如何生成&#xff0c;一定是需要一个全局的id来支持&#xff0c;所以分库分表之后&#xff0c;…...

秋招突击——6/28、6.29——复习{数位DP——度的数量}——新作{}

文章目录 引言复习数位DP——度的数量个人实现参考实现 总结 引言 头一次产生了那么强烈的动摇&#xff0c;对于未来没有任何的感觉的&#xff0c;不知道将会往哪里走&#xff0c;不知道怎么办。可能还是因为实习吧&#xff0c;再加上最近复习也没有什么进展&#xff0c;并不知…...

Spring Boot中使用Thymeleaf进行页面渲染

Spring Boot中使用Thymeleaf进行页面渲染 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将探讨如何在Spring Boot应用中使用Thymeleaf模板引擎进行页面…...

恢复策略(下)-事务故障后的数据库恢复、系统故障后的数据库恢复(检查点技术)、介质故障后的数据库恢复

一、数据库恢复-事务故障 系统通过对事物进行UNDO操作和REDO操作可实现故障后的数据库状态恢复 1、对于发生事务故障后的数据库恢复 恢复机制在不影响其他事务运行的情况下&#xff0c;强行回滚夭折事务&#xff0c;对该事务进行UNDO操作&#xff0c;来撤销该事务已对数据库…...

如何知道docker谁占用的显卡的显存?

文章目录 python环境安装nvidia-htop查看pid加一个追踪总结一下【找到容器创建时间】使用说明示例 再总结一下【用PID找到容器创建时间&#xff0c;从而找到谁创建的】使用说明示例 python环境安装nvidia-htop nvidia-htop是一个看详细的工具。 pip3 install nvidia-htop查看…...

wps linux node.js 加载项开发,和离线部署方案

环境准备 windwos 安装node.js 安装VSCode 安装wps linux 安装node.js 安装VSCode 安装wps 通过npm 安装wpsjs SDK 使用npm安装wpsjs npm install -g wpsjs 创建一个项目 wpsjs create WPS-Addin-PPT 创建项目会让你选择2个东西&#xff1a; 1&#xff1a;选择你的文…...

红队内网攻防渗透:内网渗透之内网对抗:横向移动篇Kerberos委派安全非约束系约束系RBCD资源系Spooler利用

红队内网攻防渗透 1. 内网横向移动1.1 委派安全知识点1.1.1 域委派分类1.1.2 非约束委派1.1.2.1 利用场景1.1.2.2 复现配置:1.1.2.3 利用思路1:诱使域管理员访问机器1.1.2.3.1 利用过程:主动通讯1.1.2.3.2 利用过程:钓鱼1.1.2.4 利用思路2:强制结合打印机漏洞1.1.2.5 利用…...

nginx上传文件限制

默认限制 Nginx 限制文件大小可以通过 client_max_body_size 指令来设置&#xff0c;该指令通常在 http、server 或 location 块中设置&#xff0c;如果不设置&#xff0c;默认上传大小为1M。 修改上传文件限制 要修改Nginx的文件上传大小限制&#xff0c;你需要编辑Nginx的配…...

76. 最小覆盖子串(困难)

76. 最小覆盖子串 1. 题目描述2.详细题解3.代码实现3.1 Python3.2 Java 1. 题目描述 题目中转&#xff1a;76. 最小覆盖子串 2.详细题解 在s中寻找一个最短的子串&#xff0c;使之包含t中的所有字符&#xff0c;t中可能存在多个相同字符&#xff0c;寻找的子串也应至少含有…...

K8S 集群节点扩容

环境说明&#xff1a; 主机名IP地址CPU/内存角色K8S版本Docker版本k8s231192.168.99.2312C4Gmaster1.23.1720.10.24k8s232192.168.99.2322C4Gwoker1.23.1720.10.24k8s233&#xff08;需上线&#xff09;192.168.99.2332C4Gwoker1.23.1720.10.24 当现有集群中的节点资源不够用&…...

AI大模型技术在音乐创造的应用前景

大模型技术在音乐创作领域具有广阔的应用前景&#xff0c;可以为音乐家、作曲家和音乐爱好者提供以下方面的帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 音乐创作辅助&#xff1a;大模型可以帮助音乐家和作曲家生成旋律、和声…...

Linux多进程和多线程(一)-进程的概念和创建

进程 进程的概念进程的特点如下进程和程序的区别LINUX进程管理 getpid()getppid() 进程的地址空间虚拟地址和物理地址进程状态管理进程相关命令 ps toppstreekill 进程的创建 并发和并行fork() 父子进程执行不同的任务创建多个进程 进程的退出 exit()和_exit() exit()函数让当…...

熊猫烧香是什么?

熊猫烧香&#xff08;Worm.WhBoy.cw&#xff09;是一种由李俊制作的电脑病毒&#xff0c;于2006年底至2007年初在互联网上大规模爆发。这个病毒因其感染后的系统可执行文件图标会变成熊猫举着三根香的模样而得名。熊猫烧香病毒具有自动传播、自动感染硬盘的能力&#xff0c;以及…...

使用Vue3和Tailwind CSS快速搭建响应式布局

### 第一部分&#xff1a;初始化Vue3项目并安装Tailwind CSS 首先&#xff0c;在你的开发环境中打开终端&#xff0c;然后通过Vue CLI来创建一个新的Vue3项目。输入如下命令&#xff1a; vue create my-vue-app 按照提示选择Vue3的相关选项&#xff0c;创建完毕后&#xff0…...

J019_选择排序

一、排序算法 排序过程和排序原理如下图所示&#xff1a; 二、代码实现 package com.itheima.sort;import java.util.Arrays;public class SelectSort {public static void main(String[] args) {int[] arr {5, 4, 3, 1, 2};//选择排序for (int i 0; i < arr.length - 1…...

【linux】vim的使用

目录 一、Vim的基本模式 二、Vim的常见命令 三、Vim的高级用法 四、Vim的进阶使用技巧 在Linux系统中&#xff0c;Vim是一款功能强大的文本编辑器&#xff0c;特别适用于程序员的代码编辑和修改。以下是Vim的详细使用教程&#xff0c;包括其基本模式、常见命令和高级用法。…...

【工具测评】ONLYOFFICE8.1版本桌面编辑器测评:好用!

随着远程工作的普及和数字化办公的发展&#xff0c;越来越多的人开始寻找功能强大、易于使用的办公软件。在这个背景下&#xff0c;ONLYOFFICE 8.1应运而生&#xff0c;成为许多用户的新选择。ONLYOFFICE 8.1是一款办公套件软件&#xff0c;提供文档处理、电子表格和幻灯片制作…...

核方法总结(四)——高斯过程回归学习笔记

一、定义 基于核方法的线性回归模型和传统线性回归一样&#xff0c;可以用未知数据进行预测&#xff0c;但不能确定 预测的可信度。在参考书第二章中可知&#xff0c;基于贝叶斯方法可以实现对未知数据依概率预测&#xff0c;进而可得到预测的可信度。这一方法中&#xff0c;通…...

【Python3的内置函数和使用方法】

目录 Python 特点 Python 中文编码 Python 变量类型 Python列表 Python 元组 元组是另一个数据类型&#xff0c;类似于 List&#xff08;列表&#xff09; Python 字典 Python数据类型转换 Python 运算符 Python算术运算符 Python比较运算符 Python赋值运算符 Pyt…...

递推算法计算信号特征

在线算法&#xff08;在线计算或递推计算&#xff09;能够在不存储全部数据的情况下逐步更新信号的特征信息&#xff0c;非常适合资源受限的单片机应用场景。 用途&#xff1a;单片机边采集&#xff21;&#xff24;&#xff23;边计算&#xff0c;最终将采集的信号特征计算结果…...

spring-boot-configuration-processor注释处理器

开源项目SDK&#xff1a;https://github.com/mingyang66/spring-parent 个人文档&#xff1a;https://mingyang66.github.io/raccoon-docs/#/ spring-boot-configuration-processor是springboot提供的一个注释处理器&#xff08;annotation processor&#xff09;,它用于在编译…...

Python和MATLAB粘性力接触力动态模型半隐式欧拉算法

&#x1f3af;要点 &#x1f3af;运动力模型计算制作过程&#xff1a;&#x1f58a;相机捕捉网球运动图&#xff0c;制定运动数学模型&#xff0c;数值微分运动方程 | &#x1f58a;计算运动&#xff0c;欧拉算法离散积分运动&#xff0c;欧拉-克罗默算法微分运动方程 &#…...

webstorm无法识别tsconfig.json引用项目配置文件中的路径别名

问题 vite项目模板中&#xff0c;应用的ts配置内容写在tsconfig.app.json文件中&#xff0c;并在tsconfig.json通过项目引用的方式导入 {"files": [],"references": [{"path": "./tsconfig.app.json"},{"path": "./t…...

qiankun微前端:qiankun+vite+vue3+ts(未完待续..)

目录 什么是微前端 目前现有的微前端 好处 使用 子应用的页面在主应用里显示 什么是微前端 微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。 我的理解就是将一个大型的前端应用拆分成多个模块&#xff0c;每个微前端模块可以由…...

001:开源交易系统开发实战开篇

本专栏采用融入【主力思维】的方法学&#xff0c;包含数据抓取、特征模型开发、历史验证回归测试、每日动态风险评估管理等技术&#xff0c;较大的增强股票投资胜率&#xff0c;让IT开发者拥有一套属于自己思路的专用交易软件。 先简要介绍系统成功和项目&#xff0c;后续持续…...

Pytorch实战(一):LeNet神经网络

文章目录 一、模型实现1.1数据集的下载1.2加载数据集1.3模型训练1.4模型预测 LeNet神经网络是第一个卷积神经网络&#xff08;CNN&#xff09;&#xff0c;首次采用了卷积层、池化层这两个全新的神经网络组件&#xff0c;接收灰度图像&#xff0c;并输出其中包含的手写数字&…...

RabbitMq的基础及springAmqp的使用

RabbitMq 官网:RabbitMQ: One broker to queue them all | RabbitMQ 什么是MQ&#xff1f; mq就是消息队列&#xff0c;消息队列遵循这先入先出原则。一般用来解决应用解耦&#xff0c;异步消息&#xff0c;流量削峰等问题&#xff0c;实现高性能&#xff0c;高可用&#xf…...

uniapp uniCloud云开发

uniCloud概述 uniCloud 是 DCloud 联合阿里云、腾讯云、支付宝云&#xff0c;为开发者提供的基于 serverless 模式和 js 编程的云开发平台。 uniCloud 的 web控制台地址&#xff1a;https://unicloud.dcloud.net.cn 文档&#xff1a;https://doc.dcloud.net.cn/uniCloud/ un…...

智能扫地机,让生活电器更加便民-NV040D扫地机语音方案

一、语音扫地机开发背景&#xff1a; 随着人工智能和物联网技术的飞速发展&#xff0c;智能家居设备已成为现代家庭不可或缺的一部分。其中&#xff0c;扫地机作为家庭清洁的重要工具&#xff0c;更是得到了广泛的关注和应用。 然而&#xff0c;传统的扫地机在功能和使用上仍存…...

【后端面试题】【中间件】【NoSQL】ElasticSearch索引机制和高性能的面试思路

Elasticsearch的索引机制 Elasticsearch使用的是倒排索引&#xff0c;所谓的倒排索引是相对于正排索引而言的。 在一般的文件系统中&#xff0c;索引是文档映射到关键字&#xff0c;而倒排索引则相反&#xff0c;是从关键字映射到文档。 如果没有倒排索引的话&#xff0c;想找…...

【漏洞复现】时空智友ERP updater.uploadStudioFile接口处存在任意文件上传

0x01 产品简介 时空智友ERP是一款基于云计算和大数据技术的企业资源计划管理系统。该系统旨在帮助企业实现数字化转型&#xff0c;提高运营效率、降低成本、增强决策能力和竞争力&#xff0c;时空智友ERP系统涵盖了企业的各个业务领域&#xff0c;包括财务管理、供应链管理、生…...

[leetcode hot 150]第五百三十题,二叉搜索树的最小绝对差

题目&#xff1a; 给你一个二叉搜索树的根节点 root &#xff0c;返回 树中任意两不同节点值之间的最小差值 。 差值是一个正数&#xff0c;其数值等于两值之差的绝对值。 解析&#xff1a; minDiffInBST 方法是主要方法。创建一个 ArrayList 来存储树的节点值。inorderTrave…...

【Docker】可视化平台Portainer

文章目录 Portainer的特点Portainer的安装步骤注意事项 Docker的可视化工具Portainer是一个轻量级的容器管理平台&#xff0c;它为用户提供了一个直观的图形界面来管理Docker环境。以下是关于Portainer的详细介绍和安装步骤&#xff1a; Portainer的特点 轻量级&#xff1a;P…...

MySQL高级-MVCC-原理分析(RR级别)

文章目录 1、RR隔离级别下&#xff0c;仅在事务中第一次执行快照读时生成ReadView&#xff0c;后续复用该ReadView2、总结 1、RR隔离级别下&#xff0c;仅在事务中第一次执行快照读时生成ReadView&#xff0c;后续复用该ReadView 而RR 是可重复读&#xff0c;在一个事务中&…...

压力测试Monkey命令参数和报告分析

目录 常用参数 -p <测试的包名列表> -v 显示日志详细程度 -s 伪随机数生成器的种子值 --throttle < 毫秒> --ignore-crashes 忽略崩溃 --ignore-timeouts 忽略超时 --monitor-native-crashes 监视本地崩溃代码 --ignore-security-exceptions 忽略安全异常 …...

C# Benchmark

创建控制台项目&#xff08;或修改现有项目的Main方法代码&#xff09;&#xff0c;Nget导入Benchmark0.13.12&#xff0c;创建测试类&#xff1a; public class StringBenchMark{int[] numbers;public StringBenchMark() {numbers Enumerable.Range(1, 20000).ToArray();}[Be…...

算法金 | 协方差、方差、标准差、协方差矩阵

大侠幸会&#xff0c;在下全网同名「算法金」 0 基础转 AI 上岸&#xff0c;多个算法赛 Top 「日更万日&#xff0c;让更多人享受智能乐趣」 抱个拳&#xff0c;送个礼 1. 方差 方差是统计学中用来度量一组数据分散程度的重要指标。它反映了数据点与其均值之间的偏离程度。在…...

FastAPI教程II

本文参考FastAPI教程https://fastapi.tiangolo.com/zh/tutorial Cookie参数 定义Cookie参数与定义Query和Path参数一样。 具体步骤如下&#xff1a; 导入Cookie&#xff1a;from fastapi import Cookie声明Cookie参数&#xff0c;声明Cookie参数的方式与声明Query和Path参数…...

Facebook的投流技巧有哪些?

相信大家都知道Facebook拥有着巨大的用户群体和高转化率&#xff0c;在国外社交推广中的影响不言而喻。但随着Facebook广告的竞争越来越激烈&#xff0c;在Facebook广告上获得高投资回报率也变得越来越困难。IPIDEA代理IP今天就教大家如何在Facebook上投放广告的技巧&#xff0…...

Spring Boot 中的微服务监控与管理

微服务的概述 微服务架构的优点和挑战 优点: 灵活性和可扩展性:微服务架构允许每个服务单独部署和扩展,这使得系统可以更灵活地适应不同的业务需求和负载变化。 使团队更加聚焦:每个微服务都有明确的职责,这使得开发团队可以更加聚焦,专注于开发他们的服务。 技术和框…...

无锡哲讯:SAP赋能汽车零配件行业,加速企业数字化转型

汽车零配件行业作为汽车工业的重要支撑&#xff0c;正处在一个快速变化和高度竞争的市场环境中。随着科技的不断进步和消费者需求的日益多样化&#xff0c;如何通过高效的资源管理和生产流程优化&#xff0c;提升竞争力&#xff0c;已成为汽车零配件企业亟待解决的问题。无锡哲…...

【Git 学习笔记】第二章 Git 的配置(上)

说明 本篇根据原书第二章前半部分的学习笔记整理&#xff0c;涉及 2.1 ~ 2.4 小节内容。具体实操代码库&#xff0c;需使用 GitHub 线上版本。 第二章 配置 Git 相关主题&#xff1a; 配置目标检索已有配置配置模板.git 目录模板几个配置示例设置 Git 别名refspec 举例 2.1 …...

2024年软件测试岗必问的100+个面试题【含答案】

一、基础理论 1、开场介绍 介绍要领&#xff1a;个人基本信息、工作经历、之前所做过的工作及个人专长或者技能优势。扬长避短&#xff0c;一定要口语化&#xff0c;语速适中。沟通好的就多说几句&#xff0c;沟通不好的话就尽量少说两句。举例如下&#xff1a; 面试官你好&…...

jQuery UI 简介

jQuery UI 简介 1. 引言 jQuery UI 是一个建立在 jQuery JavaScript 库之上的开源小部件和交互库,旨在创建高度交互的网页。它提供了一系列预先设计好的小部件,如拖放、排序、对话框、工具提示等,以及用于构建复杂用户界面的交互方法。jQuery UI 的设计目标是简化 HTML 文…...

短视频文案提取神器怎么提取抖音视频文案!

很多编导以及视频内容创作者为了提高自己的工作效率还会使用视频转文字提取神器&#xff0c;我们都清楚短视频领域每个平台人群熟悉都有所不同&#xff0c;在分发内容的时候也会调整内容已符合平台属性。 短视频文案提取神器怎么提取抖音视频文案 短视频常见的平台有抖音、西瓜…...

数据结构-分析期末选择题考点(串、数组)

竹月光中诗世界 松风影里酒生涯 目录 串的常见考法&#xff08;一&#xff09;BF算法 串的常见考法&#xff08;二&#xff09;KMP求 next数组 串的常见考法&#xff08;三&#xff09;串的概念及性质 串的常见考法&#xff08;四&#xff09;给出主串求子串数量 数组的常见…...

奥迪Q4e-tron对比ModelY,谁更值得入手?

豪华品牌电车奥迪Q4 e-tron对比Model Y,谁更值得入手?在电动汽车市场中,特斯拉品牌是所有人对于智能电动车的最初想象,Model Y更是行业内绕不开的一台产品。但随着时代发展,越来越多优秀的产品纷至沓来,导致了消费者对于产品的期待呈现既要还要的需求。不仅追求性能与驾驶…...

预售价11.98万元起,荣威D5XDMH有何竞争优势?

随着人们生活水平的提高,汽车已经不再是简单的代步工具,而市面上的选择性又有很多,车企为了吸引受众在品控方面下足了功夫。但有一说一,配置高的车型价格也会逐渐升高,对于我们普通人来说,只要空间、动力够用,用车成本低一些就足够了,更有甚者智能化方面再给到,就是一…...

面对6大争议,为什么我认为乐道L60必成爆款?

5月15日,国际家庭日。乐道首场品牌发布会以及首款车型乐道L60正式亮相。预售价格为21.99万元,叠加“2000元抵扣6000元购车款”政策之后,实际预售价为21.59万元。我们就从这个问题出发,又分别列出了以下6个问题,同时我们也采访了蔚来创始人李斌和乐道品牌负责人艾铁成,对于…...

LazyVim笔记

回到上次编辑的位置 gi非常的方便。 neo-tree KeyDescriptionMode<leader>beBuffer Explorern<leader>eExplorer NeoTree (Root Dir)n<leader>EExplorer NeoTree (cwd)n<leader>feExplorer NeoTree (Root Dir)n<leader>fEExplorer NeoTree (c…...

【网络安全】新的恶意软件:无文件恶意软件GhostHook正在广泛传播

文章目录 推荐阅读 一种新的恶意软件 GhostHook v1.0 正在一个网络犯罪论坛上迅速传播。这种创新的无文件浏览器恶意软件由 Native-One 黑客组织开发&#xff0c;具有独特的分发方式和多功能性&#xff0c;对各种平台和浏览器构成重大威胁。 GhostHook v1.0 支持 Windows、Andr…...

分享个自用的 Nginx 加强 WordPress 防护的规则

Nginx WordPress 的组合是目前非常普及的组合了&#xff0c;我们完全可以借助 Nginx 规则来加强 WordPress 的防护&#xff0c;提高 WordPress 的安全性&#xff0c;今天明月就给大家分享个自用的 Nginx 针对 WordPress 的防护规则&#xff0c;部分规则大家只需要根据自己的需要…...