开发人员LLM提示工程指南
本篇文章将涵盖一些提示工程的基础知识,以帮助你从像Pieces这样的AI开发工具中获取所需的答案。

提示工程涉及为LLM(大型语言模型)编写特定的问题,以便获得有针对性的响应,这些响应是根据受众和期望的格式定制的。
在2006年的詹姆斯·邦德电影《皇家赌场》中,邦德坐在扑克桌旁,有人递给他一杯饮料。他首先要求来一杯干马提尼,但很快纠正自己,改为要:
- 三份戈登琴酒
- 一份伏特加
- 半份金巴利苦艾酒
- 在冰上摇匀,然后加入一片柠檬皮
除了让我口渴并重新燃起我对伊恩·弗莱明小说的渴望之外,这还有一个目的。如果邦德坚持要“干马提尼”,他最终只会得到一杯普通的马提尼,可能是用琴酒,也可能是用伏特加。相反,通过提供更详细的指令,他享受到了一种更好的选择——维斯帕鸡尾酒。这与我们与大型语言模型或LLM互动的方式非常相似。我们给LLM提供的指令越清晰,输出结果就越符合我们的需求。
这个过程被称为提示工程,本篇文章将涵盖一些提示工程的基础知识,以帮助你从像Pieces这样的AI开发工具中获取所需的答案。
1、什么是提示工程?
既然提示工程与LLM相关,让我们让一个LLM来定义提示工程:

使用Pieces Copilot,我向Claude 3.5 Sonnet提出了以下问题:“给我一个针对不熟悉ChatGPT等工具的非技术用户的100字提示工程摘要。”
得到了如下回答:
总结一下——提示工程就是提出一个有效的问题来询问LLM,以便你以所需格式获得所需的答案。在这个问题中,我不仅要求一个提示工程的摘要,还指定了字数限制和目标用户。这“设计”出了一个简短的、103字的回答,该回答针对的是非技术用户。如果我要求一个针对开发者的较长摘要,那么答案会不同。
例如,对于开发者来说,如果你要求LLM给你一个表示用户的类,它可能会给你一个使用流行语言如Python或JavaScript编写的类,包含大量字段。如果你想要一个只有Name
、Email
和PhoneNumber
字段的C#版本的User
类,那么你需要明确指定语言和所需字段。

现在让我们深入探讨一个好的LLM提示的组成部分以及如何充分利用与LLM的对话。
2、一个好的LLM提示的组成部分是什么?
Claude给出的提示工程摘要开头提到“提示工程是艺术,即创造有效的指令。”这里用了艺术这个词,虽然创建提示需要一定的经验,但更多的是科学而非艺术。有一些组件构成了一个有效的提示。
2.1 上下文
上下文是指LLM理解你的问题所需的额外信息,而不仅仅是其训练数据。通过添加更多上下文,你可以减少用户问题中的信息量,并且可以得到更相关的答案。
对于面向开发者的AI工具,你需要的上下文可能来自现有的代码文件或文件夹。这是如何提问现有项目的方法。有两种方法可以向提示中添加上下文,一种是在聊天中直接添加,另一种是利用工具的功能拉取文件或文件夹。
要在聊天中直接添加上下文,你可以将代码内联添加:

在这个例子中,我提出了以下问题:
有了这段C#代码:
public class User
{
public int UserId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
}
使UserId和Name属性只读并在构造函数中设置
这提供了LLM需要的代码。这对于小段代码来说是理想的,但对于大块代码甚至多个文件来说就不那么方便了。这就是一个好的AI开发工具的帮助之处,允许你使用单个文件或代码文件夹(甚至是你正在开发机器上的所有内容的Pieces长期记忆)来设置上下文。上下文越相关,答案越好。
你需要考虑的一点是,是的,上下文越相关,答案越好,但同样地,无关的上下文越多,答案越差。LLM有一个有限的上下文窗口——你可以发送给LLM的最大大小。如果上下文太大,LLM将无法处理你的提示,你将不得不依赖你的聊天工具来缩减上下文,只保留相关的内容。
你可以通过相关性检测来缩小上下文范围,这样你可以传递一个代码文件夹,并仅将相关上下文传递给LLM,但你仍然需要引导这一点。
如果你传递多个项目作为上下文,LLM将难以对项目相关问题给出好的答案,因为它试图找到要传递给LLM的相关上下文。最好有与你要问的问题最相关的最小上下文。
2.2 用户问题
用户问题是你要询问LLM的核心。
例如,你可以依靠LLM的训练数据和任何附加的上下文来提问,或者定义一个问题并请求解决方案。当你计划问题时,最好让它单一目的、简洁且具体。
- 单一目的
只问一件事。当LLM被赋予单一任务时表现很好,但如果同时要求做多件事,效果就不好了。它会尝试,但答案会混杂所有任务,因此缺乏细节。通过分多次提问,每次一个问题,可以获得更好的回答。除了给LLM输入的上下文有限外,它们的输出上下文窗口也较小——输出窗口中需要容纳的话题越多,每个话题的答案就越少。
例如,如果你想评论一个类,并重构另一个类,你应该将这两个操作分成两个独立的提示,而不是一个包含两者的提示。
- 具体
明确你希望从LLM得到什么。如果你含糊不清,答案可能不符合你的需求。“给我一个用户类”可能会给你一个LLM认为最有可能的编程语言的类。“给我一个C#的用户类”会给你一个C#的类,“给我一个C#的用户类,具有UserId、Name和PhoneNumber属性。添加相等运算符,使UserId只读,并使用主构造函数”会给你一个非常精确的类定义,只包含你需要的属性、相等性和一个设置只读UserId
的主构造函数。
- 简洁
LLM更擅长处理简洁的提示。指令越清楚,答案越好。简洁的提示减少了LLM因提示中的无关信息而偏离方向的可能性。
2.3 输出指导
LLM经过大量数据训练,通常可以用最少的指导生成良好的响应。然而,在某些情况下,响应的格式可能不是你想要的。在这种情况下,最好的方法是提供你希望的输出示例,并将这些示例作为指导传递到提示中。
- 零样本提示
零样本提示依赖于LLM基于其训练方式决定如何输出响应。这对于生成代码等场景非常适合,因为输出将基于模型训练过的大量代码进行格式化。
例如,如果你想为前面提到的User
类生成一些单元测试,你可以将User
类作为上下文添加,并要求LLM:
输出可能不会完全按照你编写代码的方式来,但它足够开始工作了。
- 少样本提示
少样本提示是给你几个如何希望输出的例子,LLM可以使用这些例子来创建你希望的格式的输出,从示例中插值想法。这对于需要特定输出格式的情况非常有用,比如生成数据。只要示例具有一致的结构,LLM就可以使用这些。
为User类创建一些虚拟数据。我需要100个实例。以下是几个示例:
var user1 = new User(1, "John Smith"){ Email="john.smith@example.com", PhoneNumber="555-555-5555" };
var user2 = new User(2, "Barry Potter"){ Email="barry.potter@example.com", PhoneNumber="555-555-5555" };
var user3 = new User(3, "Polly Darton"){ Email="polly.darton@example.com", PhoneNumber="555-555-5555" };
这足以引导LLM创建具有递增用户ID(1、2等)的行,存储在与ID匹配的变量中(user1、user2等),并且使用在电子邮件地址中使用的随机名称。

3、提示工程的技术
有许多技术可以帮助你充分利用与LLM使用的提示。这里有几种更重要的技术。
3.1 提示链
回想一下我们之前提到的詹姆斯·邦德的例子,在《皇家赌场》中,邦德点了维斯帕鸡尾酒后,桌子上的另一位玩家说“我也要一个”,接着另一个人说“我也要”。服务员根据邦德的订单历史知道“我也要一个”意味着这位玩家想要维斯帕鸡尾酒,“我也要”意味着下一个玩家想要与前一个订单相同的东西,也就是维斯帕鸡尾酒。
这与我们与AI聊天工具的对话是一样的。当我们提出一个问题时,这个问题及其响应成为下一个问题的上下文。这允许我们通过链接在一起的提示迭代一个提示,并给LLM后续指令以纠正其答案。
作为一个简单的例子,假设你想在C#中创建一个只有Name
、Email
和PhoneNumber
字段的User
类。
你可以先让LLM:
Create a user class
答案可能是:
I'll create a basic User class with common attributes and methods. Here's an example in Python:
class User:
def __init__(self, username, email, password):
self.username = username
self.email = email
self._password = password # using underscore to indicate this is "private"
self.is_active = True
self.created_at = datetime.datetime.now()
显然这是错误的编程语言。你可以纠正LLM而不是提出一个全新的问题:
No, I want this in C#
这将给出:
我将把User类转换成C#。以下是等效实现:
using System;
public class User
{
public string Username { get; set; }
public string Email { get; set; }
private string _password;
public bool IsActive { get; set; }
public DateTime CreatedAt { get; private set; }
public User()
{
CreatedAt = DateTime.Now
跟进提示没有重述原始问题,而是依赖对话历史提供相关信息。然后你可以再次跟进:
This class only needs 3 fields, UserId, Name, and PhoneNumber
这给出了:
我将简化C#中的User类,只包括三个请求的字段:
public class User
{
public int UserId { get; set; }
public string Name { get; set; }
public string PhoneNumber { get; set
这是一个非常简单的例子,但它展示了要点——你可以依赖对话历史告诉LLM“纠正”其先前的回答。随着提示的链式连接,你会逐渐接近所需的答案。你还可以使用提示链来获取与对话历史相关的更多信息。例如,在询问了一个User
类之后,你可以链接提示来询问保存此数据到数据库的代码,或者添加单元测试,这依赖于先前定义类的答案所提供的上下文。
3.2 单独对话与多对话
你可以与AI进行多个并发对话,那么什么时候重用一个对话来进行下一个提示,什么时候创建一个新的对话呢?答案当然是视情况而定。每个单独的对话都可以有一个独立的提示链。
我喜欢根据上下文来划分对话——如果现有对话中没有任何内容与我的下一个问题相关,那么我就开始一个新的对话。
如果我关于项目A的一个对话需要询问项目B的问题,那就是一个新的对话。任何时候我需要从不同的项目添加上下文,那都是一个新的对话。
如果我在研究,那么每个主题都是一个新的对话。如果我在处理如Jira票证或GitHub问题等明确的任务,那么每个任务都是一个不同的对话。
这样做的一大好处是每个对话都保持专注。缺点是我有很多对话,所以在任务切换时找到早期讨论可能会很困难(小贴士:给对话命名一个相关的名字,如Jira票证号或项目名)。
你也不希望对话太长——正如上面提到的,LLM有上下文窗口大小的限制,而且底层LLM实际上是无状态的,所以对话历史是由AI工具实现的,通过将历史作为上下文传递给每个对话。
如果历史过长,聊天工具每次都需要发送它认为相关的部分。历史越长,确保传递所有相关历史就越难。
由于LLM的这种无状态性质,像Pieces这样的工具允许你在对话过程中切换LLM。由于每次都需要传递历史,使用Pieces你可以开始与Claude的对话,然后如果失去网络连接(例如在飞机上)跳转到Llama,然后再回到ChatGPT获取不同类型的答案。
3.3 思维链提示
思维链提示涉及向LLM提供多步骤指令以解决问题,而不是要求一个单一的答案。这些步骤与人类解决此类问题时所串联的步骤类似。这是一种非常强大的方法,当你事先对算法有所了解,或者需要特定输出时,可以用来生成代码。
为这个C#类创建一套全面的单元测试
public class User
{
public int UserId { get; set; }
public string Name { get; set; }
public string PhoneNumber { get; set; }
}
逐步思考:
识别关键场景:我们需要测试User类的核心功能有哪些?
编写单元测试:为每个场景编写使用xUnit测试框架的单元测试。
考虑边缘情况:我们应该测试哪些潜在的无效输入或意外行为?
这个提示给出了三个明确的指令来指导LLM。
首先,它要求LLM考虑类的核心功能以确定测试中需要包含哪些内容。
接下来,它要求LLM创建单元测试。
最后,它引导LLM考虑边缘情况。通过给LLM这些具体的指令,LLM将给出比简单地要求“为这个类创建单元测试”更好的答案。
你也可以尝试零样本思维链提示,其中你在一个句子末尾加上“让我们一步一步思考”而不是提供一系列步骤。这足以让LLM自行定义步骤。
4、与LLM合作
LLM就像大多数工具一样——只有在其用户手中才强大。
给木匠一把锤子和凿子,他会做出一件美丽的作品;给我一把锤子和凿子,你可能会送我去急诊室缝合手指。要充分利用LLM,你需要了解如何设计一个好提示。
关键是添加正确的上下文,清晰简洁地提出问题,并指导LLM你希望的输出格式。
如果你再考虑高级技术,如提示链、思维链提示,并确保你的对话结构最佳,你很快就能设计出所需的提示以获得你想要的答案。
原文链接:Introducing LLM prompt engineering for developers
汇智网翻译整理,转载请标明出处
