生成式的AI编码工具正在改变着开发人员日常写代码的方式。从记录代码库到生成单元测试,这些工具有助于加快我们的工作流程。然而,就像任何新兴技术一样,总会有一个学习曲线。因此,当AI编码助手无法生成他们想要的输出时,开发人员——无论是初学者还是有经验的人——有时会感到沮丧 (有没有相似的经历?) 。
例如,当我们要求GitHub Copilot使用p5.js(一个用于创意编码的JavaScript库)来绘制一个冰淇淋 时,我们一直收到与此无关的建议,有时甚至根本没有建议。但当我们越来越了解GitHub Copilot处理信息的方式时,我们意识到必须调整与它进行沟通的方式。
以下是GitHub Copilot生成一个无关的解决方案的例子:
当我们调整提示后,就能生成更准确的结果:
我们自己既是开发者,也是AI爱好者。我,瑞兹,已经使用GitHub Copilot构建了一个浏览器扩展——石头剪刀布游戏,并发送了推文。而我,米歇尔,在2016年创办了一家人工智能公司。我们都是GitHub的开发人员倡导者,并且喜欢分享我们使用GitHub Copilot的技巧。
在这篇GitHub Copilot指南中,我们将介绍:
- 关于提示的确切含义,以及什么是提示工程(这取决于你是在与开发人员还是机器学习研究人员交流);
- 使用 GitHub Copilot 进行提示制作的三个最佳实践和三个技巧;
- 您可以尝试提示GitHub Copilot帮助您构建浏览器扩展的一个示例。
进步胜于完美
即使我们有着运用AI的经验,我们也认识到每个人在使用生成式人工智能技术方面,都处于试错阶段。我们也知道提供通用的提示设计技巧的挑战,因为模型不同,开发人员处理的问题也不尽相同。这不是一份终极的指南。相反,我们分享的是我们在提示设计方面的经验,以便在这个软件开发的新时代,共同学习。
什么是提示,什么是提示工程?
这取决于你在与谁交流。
在生成式AI编码工具的背景下,提示可能有不同的含义,这取决于你是询问正在构建和微调这些工具的机器学习(ML)研究人员,还是在IDE中使用这些工具的开发人员。
在本指南中,我们站在从IDE中使用生成式AI编码工具的开发人员的角度,来定义这些术语。但是,为了让您了解得更全面,我们图表中也添加了机器学习研究人员的相关定义。
提示 | 提示工程 | 上下文 | |
---|---|---|---|
开发人员 | 开发人员编写的代码块、单独的代码行或自然语言注释,用于从GitHub Copilot生成特定建议。 | 在集成开发环境(IDE)中提供指令或注释,以生成特定的编码建议。 | 由开发人员提供的详细信息,用于指定生成式AI编码工具所需的输出。 |
机器学习研究人员 | 由算法不断生成的IDE代码和相关的上下文(IDE注释、打开文件中的代码等),然后将其发送到生成式AI编码工具的模型中。 | 创建算法,用于为大型语言模型生成提示(包括IDE代码和上下文的编译)。 | 由算法发送到大型语言模型 (LLM) 作为有关代码的附加信息的详细信息(例如来自打开文件的数据,以及在光标前后编写的代码)。 |
使用GitHub Copilot制作提示的3个最佳实践
1.设定高水平目标。
如果您有一个空白文件或空代码库,这将很有帮助。换句话说,如果GitHub Copilot对您要构建或完成的内容一无所知,那么为AI协作编程工具提供一个整体的描述将非常有用。
在深入细节之前,这有助于为GitHub Copilot提供生成结果的大致描述。
当提示GitHub Copilot时,您可以把这个过程想象成与某个人对话:我应该如何分解问题,好让我们一起解决它?我将如何跟这个人一起协作编程?
例如,在Next中构建一个Markdown编辑器时,我们可以写这样的注释:
/*
Create a basic markdown editor in Next.js with the following features:
- Use react hooks
- Create state for markdown with default text "type markdown here"
- A text area where users can write markdown
- Show a live preview of the markdown text as I type
- Support for basic markdown syntax like headers, bold, italics
- Use React markdown npm package
- The markdown text and resulting HTML should be saved in the component's state and updated in real time
*/
这将提示GitHub Copilot生成以下代码,并在不到30秒生成一个非常简单、无样式但功能齐全的Markdown编辑器。我们可以利用剩余的时间来设计组件的样式:
注意:这个详细程度能帮您创建更理想的输出,但是结果可能仍然是不确定的。例如,在评论中,我们提示GitHub Copilot创建默认文本“在此输入markdown”,但它生成的默认文本是“markdown预览”。
2.让要求简单而具体。目标是从GitHub Copilot接收简短的输出。
一旦向AI配对程序员传达了主要目标,您就需要向它阐明实现这一目标所需的逻辑和步骤。
当您把事情分解后,GitHub Copilot就能更好地理解目标 (想象一下您正在写一份食谱,您会把烹饪过程分解成详细的步骤,而不是写一段话来描述您想做的菜) 。
让GitHub Copilot按照步骤,一步步生成代码,而不是要求它一次生成一堆代码。
这是一个我们提供GitHub Cop的例子:
3.举一两个GitHub Copilot的例子。
从样例中学习不仅对人类有用,对AI配对程序员也有用。例如,我们想从下面的数据数组中提取名称,并将其存储在一个新数据组中:
const data = [
[
{ name: 'John', age: 25 },
{ name: 'Jane', age: 30 }
],
[
{ name: 'Bob', age: 40 }
]
];
当我们没有为GitHub Copilot提供参考样例时......
// Map through an array of arrays of objects to transform data
const data = [
[
{ name: 'John', age: 25 },
{ name: 'Jane', age: 30 }
],
[
{ name: 'Bob', age: 40 }
]
];
const mappedData = data.map(x => [x.name](http://x.name/));
console.log(mappedData);
// Results: [undefined, undefined]
它生成了错误的地图用法:
const mappedData = data.map(x => [x.name](http://x.name/));
console.log(mappedData);
// Results: [undefined, undefined]
作为对比,当我们提供了参考样例后...
// Map through an array of arrays of objects
// Example: Extract names from the data array
// Desired outcome: ['John', 'Jane', 'Bob']
const data = [
[{ name: 'John', age: 25 }, { name: 'Jane', age: 30 }],
[{ name: 'Bob', age: 40 }]
];
const mappedData = data.flatMap(sublist => sublist.map(person => person.name));
console.log(mappedData);
我们得到了想要的结果:
const mappedData = data.flatMap(sublist => sublist.map(person => person.name));
console.log(mappedData);
// Results: ['John', 'Jane', 'Bob']
使用GitHub Copilot设计提示的三个技巧
以下是三个附加的技巧,可以帮助引导您与GitHub Copilot对话。
1.尝试不同的提示
对话与其说是一门科学,不如说是一门艺术,提示的设计也是如此。因此,如果您在第一次尝试时没有得到想要的结果,请按照上述的最佳实践重新设计您的提示。
例如,下面的提示是模糊不清的。它没有为GitHub Copilot提供任何上下文或边界,无法帮助GitHub Copilot生成相关建议。
# Write some code for grades.py
我们修改了提示,让它更加具体,但我们仍然没有得到想要的确切结果。这提醒了我们,使提示更具体比听起来更困难。您是很难从一开始就知道提示里应该包含哪些关于目标的细节,才能让GitHub Copilot生成最有用的建议,这就是我们为什么要鼓励不断实验。
下面的提示比上面的版本更具体,但它没有明确定义输入和输出的要求。
# Implement a function in grades.py to calculate the average grade
我们设定边界、描述我们希望功能执行的操作之后,再次尝试了提示。我们还重新表述了注释,使功能更加清晰(为GitHub Copilot提供了一个明确的验证意图)。
这一次,我们得到了想要的结果。
# Implement the function calculate_average_grade in grades.py that takes a list of grades as input and returns the average grade as a floating-point number
2.保持几个相关的选项卡打开
这可以帮助GitHub Copilot 为您的代码提供上下文。打开的选项卡没有一个确切的数量,但根据我们的经验,保持一到两个是有帮助的。
GitHub Copilot使用一种被称为相邻选项卡的技术,该技术允许AI配对程序员通过处理 IDE中打开的所有文件(而不是您正在处理的单个文件)来为您的代码提供上下文。然而,并不能保证GitHub Copilot会将所有的打开文件视为代码的必要上下文。
3.使用良好的编码实践
这包括提供描述性的变量名称和函数,并遵循一致的编码风格和模式。我们发现通过与GitHub Copilot一起工作,促进了我们遵循在整个职业生涯中学到的良好编码规范。
例如,这里我们使用了一个描述性的函数名称,并遵循了代码库利用蛇形案例的模式。
def authenticate_user(username, password):
因此,GitHub Copilot生成了一个相关的代码建议:
def authenticate_user(username, password):
# Code for authenticating the user
if is_valid_user(username, password):
generate_session_token(username)
return True
else:
return False
将此与下面的示例进行比较,在下面的示例中,我们引入了不一致的编码风格,并且我们的函数命名也很糟糕。
def rndpwd(l):
可以看到GitHub Copilot没有建议代码,而是生成了一条评论:“代码在这里”。
def rndpwd(l):
# Code goes here
保持谨慎
生成式的AI编码工具背后的大型语言模型(LLMs)会从其训练数据中查找和推断模式,将这些模式应用于现有语言,然后生成遵循这些模式的代码。鉴于这些模型的规模十分庞大,它们可能会生成一个甚至还不存在的代码序列。就像您会审查同事的代码一样,您应该始终对AI生成的代码进行评估、分析和验证。