大模型(LLM)的应用日益广泛,而 Prompt Engineering,即提示词工程,成为释放大模型潜力的关键。本文基于实际经验,总结了 11 个关于 Prompt Engineering 的实用技巧,涵盖数学计算、语义理解、模型置信度、指令优化、结构化提示、角色设定、工具使用、Prompt 复用、无用词剔除和注释添加等方面,旨在帮助开发者避开常见陷阱,提升 Prompt Engineering 的效率和效果。通过本文,你将了解到如何更有效地与大模型沟通,并优化其输出质量。

1. 数学计算:外挂工具,扬长避短

众所周知,大模型并非天生的“数学家”。尽管它们通过海量数据学习到一些简单的算术规则(例如 2 + 2 = 4),但在面对复杂的代数表达式或高级函数时,往往表现不佳,容易出现错误或直接拒绝计算。这是因为大模型本质上是基于概率分布的语言模型,而非计算引擎。

举例来说,让大模型计算一个复杂的积分,其结果很可能是不准确的。与其强求大模型完成这类任务,不如借助外部工具。例如,可以使用 Python 解释器或 Wolfram Alpha 等计算引擎,将数学计算任务卸载给专业的工具。

实际应用中,可以将用户输入的包含数学计算需求的 Prompt 传递给 Python 解释器,获取计算结果后,再将结果整合到大模型的回复中,从而实现更准确、可靠的数学计算功能。例如,用户输入“计算 (3+5)2 – ln(10) 的值”,可以将 (3+5)2 – ln(10) 传递给 Python 解释器,得到结果后,大模型可以回复“结果为 13.697”。

当然,如果只是简单的加减乘除,硬性要求模型调用外部工具反而显得笨拙。关键在于找到一个平衡点,避免让模型在不擅长的领域“硬撑”,同时确保在简单任务上提供自然的响应。

2. 语义理解:上下文与多义性

人类在编写 Prompt 时,往往会带入大量的隐性知识和上下文信息。然而,我们无法完全预测大模型会如何解读这些信息。例如,当用户询问 “ln(2) 是多少?” 时,普通用户可能理解为求 2 的自然对数,但程序员可能会理解为调用一个函数 ln(2)。

“2 + 2” 这样的简单算式,在不同语境下也有不同的含义。在数学中是加法,在编程中可能是字符串连接,甚至在物理、化学、会计等领域都可能存在各自的特殊含义。

因此,在 Prompt Engineering 中,需要充分考虑上下文的多义性,并尽可能明确地表达意图。可以通过增加描述性语句,或者提供示例来消除歧义。例如,如果希望大模型执行数学计算,可以明确地告诉它 “请计算 2 的自然对数,结果保留两位小数。”

此外,理解模型训练数据也很重要。如果模型主要在数学数据集上训练,那么它更容易将 “ln(2)” 理解为数学运算。反之,如果模型在编程代码上训练较多,则可能更倾向于理解为函数调用。

3. 模型置信度:敢于“质疑”

我们常常希望大模型在遇到问题时能够给出明确的答案。但实际上,模型本身也存在“不确定性”。当我们指示模型只回答数学问题时,我们往往忽略了模型可能对问题是否属于数学范畴产生疑问。

例如,我们希望模型只回答数学问题。那么如果提问 “今天天气怎么样?” 模型很可能会拒绝回答,因为它不确定这个问题是否与数学相关。但这并非因为模型无法回答天气问题,而是因为它被指示只在 100% 确定问题属于数学领域时才作答。

Prompt Engineering 中,我们需要认识到模型的“不确定性”,并根据实际需求调整 Prompt,允许模型在一定程度上“试错”。例如,可以修改指令为 “请尽量回答与数学相关的问题,如果无法确定,请礼貌地说明。” 这样,模型在遇到模糊问题时,会倾向于尝试回答,而不是直接拒绝。

4. “Step-by-Step”:激活推理能力

为了提高大模型的输出质量,通常需要激活其推理能力。尤其是在系统 Prompt 中包含约束条件时,这一点尤为重要。

在 Prompt 中加入 “请逐步考虑请求”、“请仔细分析输入” 等指令,可以引导模型进行更准确、更周密的回答。这些指令并非多余,它们可以显著提升模型处理复杂任务的能力。

实际应用中,当要求模型解决一个复杂问题时,可以明确要求模型 “请按照以下步骤进行:1. 分析问题;2. 查找相关信息;3. 提出解决方案;4. 评估方案可行性;5. 给出最终建议。” 这样,模型会更有条理地完成任务,并给出更令人满意的结果。

5. 组合指令:避免冲突与覆盖

当系统 Prompt 由多个指令集构成时,尤其当这些指令分散在不同的文件中时,容易出现指令冲突或覆盖的情况。这是因为大模型处理 Prompt 的方式与传统代码不同,没有明确的优先级和作用域规则。

例如,在一个文件中定义了安全规则(Guardrails),而在另一个文件中又定义了允许生成任何内容的指令,那么安全规则可能会被覆盖,导致模型生成不安全的内容。

为了构建更健壮、更可预测的安全规则,建议将安全规则拆分成单独的 LLM 请求,在处理用户 Prompt 之前执行。这样可以更好地控制和过滤输入,降低其他 Prompt 组件的干扰。

同时,充分的测试至关重要。可以使用 Promptfoo、DeepEval 等 Prompt 测试框架,利用 LLM-as-Judge 或 G-Eval 等评估指标,自动化质量检查,系统地评估输出结果。

6. 角色设定:细微之处,影响深远

角色设定对大模型的行为有着重要影响。看似细微的角色描述,甚至可能禁用某些安全规则。

通常,我们会赋予模型一个通用的角色,例如 “你是一个 AI 助手。” 但如果将角色定义得过于具体,例如 “你是一个专业数学家专用应用程序中的数学机器人”,则可能出现意想不到的行为。

例如,即使我们指示机器人保持礼貌,并处理诸如 “你好吗?” 或 “谢谢” 之类的随意互动,但严格的角色定义可能会覆盖这些指令。当用户说 “谢谢你的帮助” 时,机器人可能会回复 “抱歉,我无法帮助您。请提出一个与数学相关的问题。”

这可能是因为角色范围被限制得太窄,以至于大模型推断它只应响应数学 Prompt,即使这与其他系统指令相矛盾。因此,在 Prompt Engineering 中,需要谨慎地定义角色,避免过度限制模型的通用对话能力。

7. Prompt 结构:清晰明确,事半功倍

为了使 Prompt 更清晰、更易于理解,无论是对人类还是对 LLM,都需要遵循结构化的格式,使用明确定义的章节关键词。这些关键词包括:

  • # Role: – 定义模型应扮演的角色(例如,专业翻译员、营销助手)。
  • # Instructions: – 提供关于模型应如何操作的具体指导。
  • # Examples: – 提供示例输入和预期输出,以说明期望的行为。
  • # Notes: – 包括模型应考虑的任何其他上下文、约束或注意事项。

每个部分都应该易于区分,并且可以使用简洁的、带项目符号或编号的规则来提高清晰度和可读性。结构化的 Prompt 能够帮助模型更好地理解指令,并提高输出质量。

8. 工具使用:权衡利弊,避免过度依赖

指示大模型必须使用特定工具来检索信息,可能会对模型的通用问题回答能力产生不利影响。

例如,如果指示模型 “必须使用函数来检索事实或历史信息以回答消息”,那么在遇到一个简单的数学问题时,模型可能会拒绝回答,即使这些问题通常属于其自身能力范围之内。

问题在于,该指令暗示必须使用专用工具来检索事实信息,即使环境中实际上并未提供此类工具。模型没有依赖其内部知识,而是完全服从于缺失的工具,并受到其他安全规则的约束,直接拒绝了请求。

因此,在 Prompt Engineering 中,需要权衡工具使用的利弊,避免过度依赖工具,导致模型无法发挥其自身能力。只有在必要时才使用工具,并确保工具的可用性和可靠性。

9. Prompt 复用:知根知底,避免盲目抄袭

与代码复用类似,我们可以从 Stack Overflow 或其他框架复制 Prompt 示例。但是,Prompt 比代码更微妙,隐藏的行为可能不容易被发现。

在复用 Prompt 之前,务必充分了解其作用、原始使用环境以及在您自己的应用程序中的潜在行为。大模型根据广泛的上下文线索解释 Prompt,如果不小心,可能会出现意想不到的含义或极端情况。

可以对复制的 Prompt 进行修改,以适应特定的需求。同时,要进行充分的测试,以确保 Prompt 的行为符合预期。

10. 无用词剔除:精简Prompt,降低成本

虽然我们经常使用各种各样的词语来表达我们的想法,但并非所有词语对大模型理解上下文都同样重要。实际上,有些词语比其他词语携带更多的上下文意义。

例如,英语中的冠词(a/an/the)和动词时态,有时在 LLM 输入的上下文中会显得多余。如果在不损失基本含义的情况下删除某些词语,应该这样做。这有助于减少处理的 Token 数量,从而降低计算成本并提高性能。

可以使用 LLMLingua 等工具,过滤掉文本中信息量较少的部分,同时保留核心语义,从而优化 Prompt 的 Token 数量。

11. 注释添加:方便维护,减少误解

Prompt 中的注释对于其他开发人员至关重要,因为 Prompt 某些部分的用途可能并不明显。如果没有适当的解释,重要的部分可能会被意外修改或删除,从而影响 Prompt 的有效性。

虽然很难直接在 Prompt 字符串中插入注释,但可以使用一些技巧。例如,Mustache 等模板库支持内联注释,允许开发人员以结构化的方式注释 Prompt。或者,在使用代码中的格式化字符串时,可以在代码旁边添加解释性注释,以阐明每个 Prompt 组件的意图。

总而言之,Prompt Engineering 是一门细致且不断发展的学科,尤其是在处理复杂指令或施加严格限制时。随着我们向 Prompt 添加更多约束,语言模型的行为可能会变得越来越不可预测,因此,周到的设计和严格的评估至关重要。在这个相对年轻且快速发展的领域中,以创造性和谨慎性相结合的方式进行 Prompt Engineering 至关重要。依靠完善的最佳实践,进行广泛的测试,并不断改进我们的技术,是实现可靠和高质量结果的关键。理解和应用这些技巧,将帮助你在 Prompt Engineering 的道路上更进一步。