【读书笔记】Foundations-of-LLMs Prompt 工程

Posted by Masutangu on April 21, 2025

本文是《Foundations-of-LLMs》 第三章【Prompt 工程】的笔记。

Prompt 工程简介

经过良好设计的 Prompt 通常由任务说明上下文问题输出格式四个基本元素组成:

  • 任务说明——向模型明确提出具体的任务要求。任务说明应当清晰、直接,并尽可能详细地描述期望模型完成的任务。
  • 上下文——向模型提供的任务相关背景信息,用以增强其对任务的理解以及提供解决任务的思路。上下文可以包括特定的知识前提、目标受众的背景、相关任务的示例,或任何有助于模型更好地理解任务的信息。
  • 问题——向模型描述用户的具体问题或需要处理的信息。这部分应直接涉及用户的查询或任务,为模型提供一个明确的起点。问题可以是显式的提问,也可以是隐式的陈述句,用以表达用户的潜在疑问。
  • 输出格式——期望模型给出的回答的展示形式。这包括输出的格式,以及任何特定的细节要求,如简洁性或详细程度。例如,可以指示模型以 JSON 格式输出结果。

随着 Prompt 内容的丰富和复杂化,输入到模型中的 Prompt 长度也随之增加,会导致模型推理速度的减慢和推理成本的上升。如何有效控制和优化 Prompt 的长度,成为了一个亟待解决的问题。LLMLingua 提出了一种创新的由粗到细的 Prompt 压缩方法,该方法能够在不牺牲语义完整性的情况下,将 Prompt 内容压缩至原来的二十分之一,同时几乎不损失模型的性能。此外,随着 RAG 技术的兴起,模型需要处理的上下文信息量大幅增加。FIT-RAG 技术通过高效压缩检索出的内容,成功将上下文长度缩短至原来的 50% 左右,同时保持了性能的稳定,为处理大规模上下文信息提供了有效的解决方案。

在 Prompt 进入大模型之前,需要将它拆分成一个 Token 的序列,其中 Token 是承载语义的最小单元,标识具体某个词,并且每个 Token 由 Token ID 唯一标识。将文本转化为 Token 的过程称之为分词(Tokenization)。

为实现有效分词,首先需构建一个包含大语言模型所能识别的所有 Token 的词表,并依据该词表进行句子拆分。在构建大语言模型的词表时,分词器依赖于分词算法,如 BBPEBPEWordPiece 等,这些算法通过分析语料库中的词频等信息来划分 Token。以 BBPE(Byte-Level Byte Pair Encoding)算法为例,主要流程主要包括以下四个步骤:

  • 初始化词表:将所有字符按照其底层编码拆分为若干字节,并将这些单字节编码作为初始词表的 Token。
  • 统计词频:统计词表中所有 Token 对(即相邻 Token 的组合)的出现频率。在初始阶段,Token 对即为相邻字节的组合。
  • 合并高频 Token 对:选择出现频率最高的 Token 对,将其合并成一个新的 Token 并加入词表。
  • 迭代合并:重复步骤 2 和步骤 3,不断迭代合并,直至达到预设的词表大小或达到指定的合并次数。

为了有助于模型更准确地理解词义,同时减少生成常用词所需的 Token 数量,词表中收录了语料库中高频出现的词语或短语,形成独立的 Token。为了优化 Token 空间并压缩词表大小,构建词表时会包含了一些特殊的 Token,这些 Token 既能单独表示语义,也能通过两两组合,表示语料库中低频出现的生僻字。例如,“浣”字使用两个 Token 来表示。通过这种处理方式,词表既能涵盖常见的高频词汇,又能通过 Token 组合灵活表达各类稀有字符。由此可见,词表构建在一定程度上受到“先验知识”的影响,这些知识源自人类语料库的积累与沉淀。

每个大语言模型都有自己的分词器,分词器维护一个词表,能够对文本进行分词。分词器的质量对模型的性能有着直接的影响。一个优秀的分词器不仅能显著提升模型对文本的理解能力,还能够提高模型的处理速度,减少计算资源的消耗。一个好的分词器应当具备以下特点:首先,它能够准确地识别出文本中的关键词和短语,从而帮助模型更好地捕捉语义信息;其次,分词器的效率直接影响到模型的训练和推理速度,一个高效的分词器能够实现对文本 Token 的优化压缩,进而显著缩短模型在处理数据时所需的时间。

模型 词表大小 中文分词效率(字/Token) 英文分词效率(词/Token)
LLaMA1 32000 0.6588 0.6891
LLaMA2 32000 0.6588 0.6891
LLaMA3 128256 1.0996 0.7870
DeepSeek-V1 100016 1.2915 0.7625
DeepSeek-V2 100002 1.2915 0.7625
GPT-3.5 & GPT-4 100256 0.7723 0.7867
GPT-3 50,257 0.4858 0.7522
Qwen-1.5 151646 1.2989 0.7865
StarCoder 49152 0.9344 0.6513

从上表可以观察到,像 DeepSeek、Qwen 这类中文开源大语言模型,对中文分词进行了优化,平均每个 Token 能够表示 1.3 个字(每个字仅需 0.7 个 Token 即可表示),一些常用词语和成语甚至可以直接用一个 Token 来表示。相比之下,以英文为主要语料的模型,如 GPT-4、LLaMA 系列,对中文的支持度较弱,分词效率不高。在英文中,由于存在 “ly”、“ist” 等后缀 Token,一个英文单词通常需要用 1 个及以上的 Token 来表示。

在完成分词之后,这些 Token 随后会经过模型的嵌入矩阵(Embedding Matrix)处理,转化为固定大小的表征向量。这些向量序列被直接输入到模型中,供模型理解和处理。在模型生成阶段,模型会根据输入的向量序列计算出词表中每个词的概率分布。模型从这些概率分布中选择并输出对应的 Token,这些 Token 再被转换为相应的文本内容。

上下文学习

演示示例选择

演示示例选择主要依靠相似性和多样性:

  • 相似性是指精心挑选出与待解决问题最为相近的示例。相似性可以从多个层面进行度量,如语言层面的相似性(包括关键字匹配或语义相似度匹配)、结构相似性等等。通过选取相似的示例,能够为模型提供与待解决问题接近的参照,使大语言模型更易理解该问题。
  • 多样性则要求所选的示例涵盖尽量广的内容,扩大演示示例对待解决问题的覆盖范围。多样化的示例能够帮助模型从不同的角度去理解任务,增强其应对各种问题的能力。

直接检索

给定一组候选示例,直接检索的方法依据候选示例与待解决问题间的相似性对候选示例进行排序,然后选取排名靠前的 K 个示例。其代表性方法是 KATE。KATE 利用 RoBERTa 对待解决问题和候选示例进行编码。然后通过计算解决问题编码和候选示例编码间的向量余弦相似度对二者的相似度进行评分,选择评分最高的 K 个示例作为上下文学习的演示示例。直接检索的方法简单易操作,但选择出的示例可能趋向同质化。

聚类检索

为缓解直接检索中存在的样例趋同的问题,聚类检索方法采用先聚类后检索的方法来保证检索结果的多样性。其先把所有候选示例划分为 K 个簇,然后从每个簇中选取最为相似的一个示例,提升了多样性。Self-Prompting 是其中的代表性方法。Self-Prompting 首先将候选示例和待解决问题编码成向量形式,接着运用 K-Means 算法把示例集合聚为 K 个簇。依照问题与示例之间的余弦相似度,从每个簇中选取与问题最相似的示例,由此得到 K 个示例。但选择的示例的相似性可能不够高。

迭代检索

为了兼顾相似性多样性,迭代检索策略应运而生。迭代检索首先挑选与问题高度相似的示例,随后在迭代过程中,结合当前问题和已选示例,动态选择下一个示例,从而确保所选示例的相似性和多样性。RetICL 是迭代检索的代表性方法,根据当前问题初始化基于 LSTM 的检索器内部状态,并选择一个示例。接着根据当前问题和所选示例集更新检索器内部状态,并选择下一个示例。这一过程不断迭代,直到得到 K 个示例。尽管迭代检索在计算上相对复杂,但其能够生成更优的示例集,在复杂任务中展现出更好的适应性和灵活性。

除了在示例选择策略上有所不同外,现有的示例选择方法在检索器的选择和设计上亦呈现出差异。一些方法采用现成的检索器,而另一些方法则为了追求更卓越的性能,选择在特定语料库上对检索器进行微调。关于检索器的深入介绍及其分类,将在第六章中进行详尽阐述。

思维链

思维链提示(Chain-of-Thought,CoT)通过模拟人类解决复杂问题时的思考过程,引导大语言模型在生成答案的过程中引入一系列的中间推理步骤。这种方法不仅能够显著提升模型在推理任务上的表现,而且还能够揭示模型在处理复杂问题时的内部逻辑和推理路径。

CoT 方法的核心是构造合适的 Prompt 以触发大语言模型一步一步生成推理路径,并生成最终答案。早期方法在构造 Prompt 时,加入少量包含推理过程的样本示例(Few-Shot Demonstrations),来引导模型一步一步生成答案。

在CoT 核心思想的指引下,衍生出了一系列的扩展的方法。这些扩展的方法按照其推理方式的不同,可以归纳为三种模式:按部就班三思后行集思广益。这几种模式的对比如下图所示。

  • 按部就班:模型一步接着一步地进行推理,推理路径形成了一条逻辑连贯的链条。在这种模式下,模型像是在遵循一条预设的逻辑路径一步步向前。这种模式以 CoT、Zero-Shot CoT、Auto-CoT 等方法为代表。
  • 三思后行:模型每一步都停下来估当前的情况,然后从多个推理方向中选择出下一步的行进方向。在这种模式下,模型像是在探索一片未知的森林,“三思后行”以找出最佳推理路径。这种模式以 ToT、GoT 等方法为代表。
  • 集思广益:在集思广益模式中,模型同时生成多条推理路径并得到多个结果,然后整合这些结果,得到一个更为全面和准确的答案。这一类模式以 Self-Consistency 等方法为代表。

Zero-Shot CoT

Zero-Shot CoT 通过简单的提示,如 “Let’s think step by step”,引导模型自行生成一条推理链。其无需手工标注的CoT 示例,减少了对人工示例的依赖,多个推理任务上展现出了与原始少样本 CoT 相媲美甚至更优的性能。

Auto CoT

在 Zero-Shot CoT 的基础之上,Auto-CoT 引入与待解决问题相关的问题及其推理链作为示例,以继续提升 CoT 的效果。相关示例的生成过程是由大语言模型自动完成的,无需手工标注。其包含以下步骤:

  • 利用聚类技术从问题库中筛选出与用户提问位于一个簇中的问题。
  • 借助 Zero-Shot CoT 的方式,为筛选出的问题生成推理链,形成示例。这些示例包含了不同问题及其对应的推理内容,可为模型提供不同解题思路,
  • 辅助模型做出更为审慎的推理。在这些示例的基础上,Auto-CoT 以“让我们一步一步思考” 引导大语言模型生成针对用户问题的推理链和答案。

Tree of Thoughts, ToT

将推理过程构造为一棵思维树,其从以下四个角度对思维树进行构造:

  • 拆解。将复杂问题拆分成多个简单子问题,每个子问题的解答过程对应一个思维过程。
  • 衍生。模型需要根据当前子问题生成可能的下一步推理方向。衍生有两种模式:样本启发命令提示。样本启发以多个独立的示例作为上下文,增大衍生空间,命令提示则在 Prompt 中指明规则和要求,限制衍生空间。
  • 评估:利用模型评估推理节点合理性。根据任务是否便于量化评分,选择投票或打分模式。投票模式中,模型在多节点中选择,依据票数决定保留哪些节点;打分模式中,模型对节点进行评分,依据评分结果决定节点的保留。
  • 搜索:从一个或多个当前状态出发,搜索通往问题解决方案的路径。依据任务特点选择不同搜索算法。可以使用深度优先搜索、广度优先搜索等经典搜索算法,也可以使用 A* 搜索、蒙特卡洛树搜索等启发式搜索算法。

Graph of Thoughts, GoT

在 ToT 的基础上,GoT 将树扩展为有向图,以提供每个思维自我评估修正以及思维聚合的操作。该图中,顶点代表某个问题(初始问题、中间问题、最终问题)的一个解决方案,有向边代表使用“出节点”作为直接输入,构造出思维“入节点”的过程。GoT 相比于ToT 的核心优势是其思维自我反思,以及思维聚合的能力,能够将来自不同思维路径的知识和信息进行集成,形成综合的解决方案。

Self-Consistency

Self-Consistency 的实现过程可以分为三个步骤:

  • 在随机采样策略下,使用 CoT 或 Zero-Shot CoT 的方式来引导大语言模型针对待解决问题生成一组多样化的推理路径
  • 针对大语言模型生成的每个推理内容,收集其最终的答案,并统计每个答案在所有推理路径中出现的频率
  • 选择出现频率最高的答案作为最终的、最一致的答案。

Prompt 技巧

任务说明要明确

  • 使用明确的动词:选择能够清晰表达动作的动词,如“判断”、“分类”、“生成”等,避免使用模糊的动词如“处理”或“操作”。
  • 具体的名词:使用具体的名词来定义任务的输出或目标,例如“积极”和“消极”在情感分类任务中提供了明确的分类标准。
  • 简洁明了:任务说明应简洁且直接,避免冗长或复杂的句子结构,使模型能够快速抓住任务的核心要求。
  • 结构化布局:在较长的 Prompt 中,将任务说明放置在开头和结尾,因为模型通常更关注这些部分的信息。这种布局有助于确保模型首先和最后接触到的是最关键的任务信息。

相关应用

基于大语言模型的 Agent

Prompt 工程技术在 Agent 中起到了重要的作用。在 Agent 系统中,大语言模型作为核心控制器,能够完成规划、决策、行动等操作,这些操作很多都依赖 Prompt 完成。经典的 Agent 框架主要由四大部分组成:配置模块(Profile)、记忆模块(Memory)、计划模块(Planning)和行动模块(Action)。Prompt 工程技术贯穿整个 Agent 流程,为每个模块提供支持。

数据合成

通过 Prompt 工程技术,利用大语言模型强大的思维能力、指令跟随能力以合成高质量数据,其中一个代表性方法是 Self-Instruct。Self-Instruct 通过 Prompt 工程技术构建 Prompt,通过多步骤调用大语言模型,并依据已有的少量指令数据,合成大量丰富且多样化的指令数据。

Text-to-SQL

Text-to-SQL 技术可以将自然语言查询翻译成可以在数据库中执行的 SQL 语句,是实现零代码或低代码数据查询的有效途径。

传统的 Text-to-SQL 方法通常使用预训练-微调的范式训练 Text-to-SQL 模型。这些方法需要大量训练数据,费时费力且难以泛化到新的场景。

最早使用大语言模型来做零样本 Text-to-SQL 的方法是 C3。C3 的核心在于 Prompt 工程的设计,给出了如何针对 Text-to-SQL 任务设计 Prompt 来优化生成 效果。C3 由三个关键部分组成:清晰提示(Clear Prompting)、提示校准(Calibration with Hints)和一致输出(Consistent Output)。