Preface
去年11月份申请了 Github Copilot 的内测,今天终于收到了邀请。玩了一下午,整体感受是很惊喜的,迫不及待地想写一篇使用体验。
Github Copilot 是 OpenAI 和 Github 联合推出的 AI 编程工具,能根据用户输入的部分代码或注释自动生成完整代码。Python学习资料点击免费领取
Warm-up
我上手之后敲下的第一行代码是def gcd():
,不出所料,Copilot 果然帮我完成了求最大公约数的函数,而且根据我输入的不同,也会联想不同的模板。
不含任何参数时,AI 补全的代码会自动将结果打印出来,而含参数时,又会将最大公约数作为返回结果。此外,多次尝试,AI 补全的代码不尽相同,比如有递归模板和非递归模板。官网给出的介绍是 Mac 用户可以通过 <options>+’]’ / ’[’
来进行切换,我暂时还没找到 Windows 用户在 PyCharm 里如何切换代码补全结果。
不过,模板级补全并不是 Copilot 的重头戏,根据官方介绍,Copilot 还有不少值得注意的功能。
Function
Convert comments to code
Copilot 可以根据代码中的注释完成相应代码,令我惊喜的是,居然还支持中文注释,这就对中文用户比较方便了。我试了一下,感觉体验很不错。
键入注释# 获取当前时间
,自动生成函数get_current_time()
:
def get_current_time():
return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
复制代码
而且,还能根据自己想要的效果对生成的代码进行约束。比如我把注释更改为# 获取当前时间,‘xx年xx月xx日’
,建议的代码返回值就变成了指定的格式:
def get_now_time():
now_time = time.strftime('%Y年%m月%d日', time.localtime(time.time()))
return now_time
复制代码
基于大规模预训练模型 GPT-2 ,Copilot 具有优异的自然语言理解能力,在对注释的理解力上令人惊叹。我又进行了很多尝试,几乎都得到了满意的结果。
# 明年2月28是星期几?
# 把一个人的温暖转移到另一个的胸膛
在自动生成代码为简单任务节省时间的同时,我们不难注意到这种自然语言到代码的转换还会在另一种使用场景下带来便捷体验,那就是当我们对某些库不熟的时候,让 AI 完成函数或者提供模板,使我们免于频繁翻阅文档、查找资料。
比如我想获取鼠标的位置,但对相关的库完全不了解,这时候可以通过一行注释让 AI 完成代码,一方面节省了时间,另一方面自己也不用搜了之后反复尝试怎么用,便于快速上手。
# 获取当前鼠标位置
def get_mouse_position():
import pyautogui
print(pyautogui.position())
复制代码
太香了啊!
Autofill for repetitive code
此外,AI 也能帮你完成重复的代码。官网展示了这样一个样例:
该说不说,重复性的工作确实枯燥且浪费时间。Copilot 一举扫清了重复代码带来的困扰,确实能给编码体验带来不少提升。
Tests without the toil
Copilot 的官网还展示了辅助测试功能,“不费吹灰之力地测试”。在 Copilot 的帮助下,你能易如反掌地导入一个与代码相匹配的单元测试包:
Hands-on
既然有了好用的工具,那我也得找个 coding 任务实战感受一下。前几天,我用代码暴力求解了社区中的春节小游戏跳房子:
这是一个代码量为100行左右的任务,主逻辑为深度优先搜索。我试着用 AI 生成该任务的全部代码,在此过程中,如果把 AI 看成一个程序员,我所扮演的角色则是与它结对编程的监督者。我负责用注释表述思路,并检查它生成的代码。除了初始数据(即棋盘的相关属性),其余所有代码均由 AI 生成。
定义和初始化列表是很简单的任务,但 Copilot 的聪明之处在于,它支持我在定义数据的时候注明用法,这就让我可以*地声明数据结构,而 AI 在生成后续代码的时候会参考该结构,得到正确的代码,非常省心。
# 定义三个列表,分别是:
# 1.已占用节点
# 2.安全状态栈,格式为[[已占用节点], [所有可能的下一步]]
# 3.solution
# 初始化为空列表
occupied = []
safe_stack = []
solution = []
# 定义一个列表表示未占用节点,用0-14表示
unused = list(range(15))
复制代码
定义函数的时候,只要在注释中写清楚函数的输入输出以及逻辑,AI 也能正确地生成我想要的代码,而且完成度之高确实让我非常满意。以下面这个函数为例:
# 定义一个函数用于获取所有的可能的下一步,参数为一个节点的编号
# 将所有未占用节点两两配对,将所有配对结果存入所有的可能的下一步
# 对每个可能的下一步,判断参数和下一步的两个节点是否在同一条直线上且参数必须同时大于或小于下一步的两个节点编号,如果不满足条件,则从可能的下一步中去除
# 返回所有可能的下一步
def get_next_step(node):
next_step = []
for i in range(len(unused)):
for j in range(i+1, len(unused)):
if check_line(node, unused[i], unused[j]):
if (node < unused[i] and node < unused[j]) or (node > unused[i] and node > unused[j]):
next_step.append((node, unused[i], unused[j]))
return next_step
复制代码
函数生成对 Copilot 来说并不是特别复杂的任务,因为函数逻辑简单,描述起来也更容易。但主函数不一样,尤其是需要精心设计循环逻辑的主函数。对于 AI 而言,它的生成基于预测概率,即便我不提供任何描述,也总会有一个概率最大的预测结果。我们来看一下没有任何描述的主函数,AI 会怎么完成:
键入# 主函数
后,AI 先补全了主函数的声明,紧接着,二十余行包含注释的主函数代码倾泻而下,这是 Copilot 根据我的上文猜测的我的意图,可以看出,虽然不是我想要的代码,但是完成度非常高,而且也确实在解决一定的问题,写得有模有样的。
由于我的主函数逻辑并没有那么简单,因此我需要一边让 AI 写代码,一边添加注释,以提供给它更细粒度的语义信息,来帮助它完成正确的代码:
# 主函数
def main():
# 将0从未占用改为已占用
occupied.append(0)
unused.remove(0)
# 只剩一个未占用时退出循环
while len(unused) > 1:
# 新建一个安全状态[已占用列表,[所有可能的下一步]]
safe_stack.append([occupied[:], get_all_next_step()])
# 下一步为空时循环
while len(safe_stack[-1][1]) == 0:
# 将当前安全状态从安全状态栈中弹出
safe_stack.pop()
# 将安全状态栈的最后一个元素的第一个下一步删除
safe_stack[-1][1].pop(0)
# 回溯
# 如果回溯报错,则打印报错信息并退出
try:
back_action()
except IndexError:
print("No solution")
exit()
# 执行下一步列表的第一个元素
action(*safe_stack[-1][1][0])
# 如果有解,则打印解,格式为:'remove 1, append 2, append 3'
if len(unused) == 1:
print('Solution:')
for i in range(len(solution)):
print('remove %d, append %d, append %d' % (solution[i][0], solution[i][1], solution[i][2]))
复制代码
最终,它顺利完成了主函数。总得来看,我用30多行注释让 Copilot 帮我完成了全部近80行代码,并且顺利运行得到了正确结果,我对这个结果是比较满意的。毕竟如果让一个人来按照我的思路写代码的话,三十句话未必能解释清楚我的意图,这一点上我觉得 AI 已经做得很好了。
不过,它还有进一步提升的空间,一方面对于复杂语义的理解不够到位,另一方面,它也表现出了人工智能作为算法(而不是一个人)的僵硬、刻板的一面。 举个例子,我在完成上面那个任务的过程中遇到过一些小问题,比如偶尔会有一些细节,不管我怎么改变表述,都不能让它正确处理,总是差一点,比如# a必须同时大于或小于b和c
,它总是理解成必须满足(a < b < c) or (a > b > c)
,最后我实在受不了了,就自己去把那个地方改正过来了。
不过这种问题也不常见,多数时候它还是很“乖巧听话”的,比如有时候我发现它拷贝是直接用全局变量赋值,就会在注释中加一个括号提醒它深拷贝。列表操作的时候,也可以提醒它是“拼接(+=
)”而不是“加入(append
)”。
Summary
这次测试给我的感受是比较好的,因为它给了我高出预期的体验,真的是可以用惊喜来形容了。
因为最开始听说 Copilot 的时候,我没有仔细了解,以为就是一个类似于“下一词预测”的 AI ,毕竟官方说了是在 Github 的公开代码库上训练的,这还能玩出什么花样呢?给我数据我也能训一个出来。但是我上手之后才发现远远没有那么简单,因为它能根据注释生成代码,而且在各个方面都“聪明”得像一个人一样,这就给我整不会了。
能够理解注释、生成代码,说明这个 AI 应该是跨语言、甚至是跨模态的,这就已经让我觉得困难重重了,然而我甚至不清楚这个代码生成任务的核心是什么。另一方面,用 Github 上的海量代码作为数据集,我觉得怎么也该是自监督学习,我也完全不知道开发者们如何让模型从这些数据中学习。在这种情况下,我体验到的 Copilot 却是这样的令人满意,让我惊叹于技术发展的同时,更让我对产品背后的开发团队肃然起敬。
前几天,DeepMind 也发布了自己的 AlphaCode,虽然还没详细了解,但这些知名 AI 研究机构的先后入局,就已经让我感受到这场悄然进行的科技革命背后历史演进的逼仄,以及扑面而来的滚滚春潮—— AI programming 的时代,即将春暖花开。
①3000多本Python电子书有
②Python开发环境安装教程有
③Python400集自学视频有
④软件开发常用词汇有
⑤Python学习路线图有
⑥项目源码案例分享有如果你用得到的话可以直接拿走,在我的QQ技术交流群里(技术交流和资源共享,广告勿入)可以自助拿走,群号是895937462。