软件开发 | 一文学会如何使用GitHub的AI写代码神器Copilot

生成式的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生成的代码进行评估、分析和验证

章来源:https://github.blog/2023-06-20-how-to-write-better-prompts-for-github-copilot/

作者介绍:

Michelle Mannering

Michelle是一名从事技术和创新工作的内容制作人,被称为“黑客马拉松女王”。同时也是GitHub DevRel团队的成员,喜欢分享来自GitHub出色的开发人员社区的故事。

Rizel Scarlett

立即尝试GitHub企业版以及AI配对程序员Copilot,请联系GitHub中国官方授权合作伙伴——创实 ,我们提供GitHub产品的咨询、销售、实施、培训及技术支持服务。