本文介绍如何使用GitHub Copilot:包括提问台词、一些建议和使用案例
生成式的AI编码工具正在改变研发人员每天接触到的编码任务的方式。从为仓库生成文档到生成单元测试,这些工具正在帮助我们优化工作流程。然而,就像任何出现的新兴技术一样,都有它的学习路径,结果就是,无论是初级开发者还是有经验的开发者都会遇到的问题------当AI代码助手不能生成我们想要的输出的内容时候,我们总会感觉很沮丧。(是不是有这种感觉?)
举例,我们希望Copilot通过p5.js------一个用于创造性编码的JavaScript库------画一个冰淇淋甜筒🍦,我们会一直接收到不相关的建议提示,甚至没有任何建议提示。但是当我们了解到Copilot处理信息的方式以后,我们就意识到我们应该调整我们跟它沟通的方式。
下面是一个Copilot生成不相关内容的案例:

但是当我们调整我们的提示词,我们可能会得到更加准确的结果:

在这篇文章中,我们将会介绍如下内容:
- 提示词是什么?提示工程是什么?(这取决于你跟一个开发者沟通还是机器学习研究员)
- 使用GitHub Copilot提问方式的三个最佳实践和三个额外提示
虽然我们拥有使用AI的经验,但是我们也能够意识到------在使用生成式AI技术这件事上,每个人都还在试错的阶段。因为模型和每名开发者在处理的单个问题的多样性,我们也知道提供通用的提示词是一个很大的挑战。这不是一次性完成,而是需要一步步引导。相反地,我们分享我们在提示词技术方面的知识,在这个新的软件开发时代加速集体学习。
什么是Prompt?什么又是Prompt工程?🤔
这个问题看你在问谁?🙂
在生成式AI编码工具的范畴内,prompt有着不同的含义,具体意义在于你问的是整天都在构建和微调这些工具的机器学习研究员,还是你只是一个使用IDEs的开发者。
那么在本文中,我们把prompt的含义收敛在使用IDE开发者的这个范畴内。为了让你有个全景概念,我们会列一张表格来展示开发者和机器学习研究员的定义差别。
Prompts | Prompts工程 | 上下文 | |
---|---|---|---|
开发者 | 代码块、单独的代码行、开发人员编写的自然语言注释 ,用于从GitHub Copilot生成特定建议 |
在IDE提供指令或者注释 来生成特别的代码建议 |
开发人员提供的详细信息 ,用于指定生成AI编码工具的期望输出 |
机器学习研究员 | 编译IDE代码和相关上下文 (IDE注释、打开文件中的代码等),这些代码由算法持续生成并发送到生成AI编码工具的模型 |
创建将为大型语言模型生成提示(IDE代码和上下文的汇编)的算法 |
算法发送到大型语言模型(LLM)的详细信息 (如打开文件中的数据以及在光标前后编写的代码),作为有关代码的附加信息 |
Github Copilot中使用Prompt的三个最佳实践
1、设定一个高目标
当Github Copilot对于你想要构建或者完成的事情一无所知的时候,为你的AI结对开发者设定一个目标是非常有效的。这有助于在你进入细节之前,为GitHub Copilot提供一个关于你希望它生成什么的大致描述。
当你在对于Github Copilot进行描述的时候,想象你在跟一个人的对话流程:
- 我应该如何分解这个问题,这样我们才能一起解决它?
- 我将如何与此人进行结对编程?
例如:我们想在Next.js中构建一个markdown编辑器,我们可以像这样写一个注释:
css
/*
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
*/
上述内容会让Copilot在30秒生成如下的代码且产出一个非常简单、没有样式但有功能的markdown编辑器,然后我们用剩下的时间进行组件样式的调整。

说明:这种程度的细节描述会帮你生成一个相对满意的输出,但是结果仍旧是非确定性的。例如,在描述中,我们希望Copilot生成的默认文案是
type markdown here
,但实际上生成的是markdown preview
。
2、尽量问的简单明确,旨在获取简短的输出
一旦开始跟AI结对开发者沟通你的主要目的时,阐明实现该目标所需遵循的逻辑和步骤。目标的拆解会让Copilot更好地理解你的意图(想象一下你要写一个食谱,尽量写烹饪这道食物的各个步骤,而不是写一段内容描述你想怎么做这个食物)。
让Copilot一步步地生成代码,而不是一次性生成一段代码。
下面是一个通过一步步的指令引导下生成的一个函数:

3、给Copilot一两个案例
从案例中学习不仅对开发者有益,对AI开发者也是如此。举例说明,我们想从下面的数组中提取names并存入一个新的数组中:
js
const data = [
[
{ name: 'John', age: 25 },
{ name: 'Jane', age: 30 }
],
[
{ name: 'Bob', age: 40 }
]
];
当我们不给Copilot一个例子的时候,
js
// 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]
它生成了一个不正确的map使用规范
js
const mappedData = data.map(x => [x.name](http://x.name/));
console.log(mappedData);
// Results: [undefined, undefined]
相反地,我们提供了案例以后
js
// 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);
我们拿到了预期的结果
js
const mappedData = data.flatMap(sublist => sublist.map(person => person.name));
console.log(mappedData);
// Results: ['John', 'Jane', 'Bob']
了解更多AI训练的通用方式,可以看这里
使用Copilot提示能力的三个建议
1、用你的提示词来实验
如何提问是一门艺术而非科学,如果你在第一次提问的时候没有得到预期的结果,可以通过上述的三个最佳实践进行提示的调整。
例如,下面的这个描述就很模糊,这个描述没有给Copilot生成相关建议的任何一点上下文或者边界。
js
# Write some code for grades.py
我们将这个描述修改得更加详细,但是我们仍旧没有得到想要的结果。这是一个很好的提醒,在提示中添加特定内容比听起来更难。从一开始就很难知道你应该包括哪些关于你的目标的细节,以从GitHub Copilot中生成最有用的建议。这就是我们鼓励实验的原因。
下面的提示版本比上面的更具体,但它没有明确定义输入和输出要求。
js
# Implement a function in grades.py to calculate the average grade
我们通过设置边界和概述我们希望函数做什么,再次尝试了提示。我们还重新表述了注释,使函数更加清晰(让GitHub Copilot有明确的验证意图)。
这一次,我们得到了我们想要的结果。
js
# 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、打开一到两个相关的tabs
我们没有一个明确的数字来定义你应该打开几个tabs,进而能让你的代码置于Copilot的上下文中,但是,依据我们的经验,我们发现当你打开一到两个tabs的时候,它是有用的。
Github Copilot在使用一种相邻tabs的技术来帮助你的AI结对开发者将你在IDE中的打开的所有的文件代码当成理解的上下文,而不是单个当前正在开发的文件。然而,不能保证GItHub Copilot会将所有打开的文件视为代码的必要上下文。
3、使用好的编码习惯
这包括提供描述性的变量名称和函数,并遵循一致的编码风格和模式。我们发现,使用GitHub Copilot可以鼓励我们在整个职业生涯中学习良好的编码习惯。
例如,在这里,我们使用了一个描述性的函数名称,并遵循了代码库中利用snake case的模式。
py
def authenticate_user(username, password)
其结果就是,Copilot会生成一个相关的代码建议:
py
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
我们再看看如果我们使用一个非一致性的编码风格,且定义一个很难理解的函数名
py
def rndpwd(l)
相较于生成代码,Copilot生成了一行注释:Code goes here
py
def rndpwd(l):
# Code goes here
对结果保持审视
生成人工智能编码工具背后的LLM旨在从其训练数据中找到和推断模式,将这些模式应用于现有语言,然后生成遵循这些模式的代码。考虑到这些模型的庞大规模,它们可能会生成一个甚至还不存在的代码序列。就像你Review同事的代码一样,你应该始终抱着对于AI生成的代码进行评估、分析和验证的过程。