为什么不要轻信Copilot?

译文 精选
开发 开发工具
GitHub Copilot X在简单的问题上工作得很好,但不一定比代码编辑器中的Amazon CodeWhisperer和浏览器中的Google Bard组合更好。CodeWhisperer还没有聊天功能或解释代码的功能,这太糟糕了,Bard没有与编辑器或IDE完全集成也太糟糕了。


作者丨Martin Heller

策划丨千山

当我在2021年使用GitHub Copilot 预览版时,我注意到AI对程序员并不总是生成好的、正确的甚至正在运行的代码,但仍然有些用处。当时,我得出结论,未来的版本可以真正节省时间。两年后,Copilot正在进步,与此同时,它开始对个人收费了,而且它多了一些竞争对手。此外,编码助手的范围已从代码生成扩展到代码解释、拉取请求摘要、安全扫描和相关任务。

一、3个AI编程伴侣

让我们简要介绍一下这三大工具,然后我们将深入探讨每个工具。

Amazon CodeWhisperer是与Copilot竞争最直接的产品。CodeWhisperer是像Copilot这样的“编码伴侣”,它与Visual Studio Code和JetBrains IDE集成,根据现有代码生成代码建议以响应注释和代码完成,并可以扫描代码以查找安全问题。CodeWhisperer很好地支持五种编程语言,另外10种编程语言的支持程度较低。它可以选择性地标记和记录对其使用的代码的引用,并选择性地筛选出类似于开源训练数据的代码建议。

Google Bard是一个基于Web的界面,用于LaMDA(对话应用程序的语言模型),LaMDA是一种对话AI模型,能够进行流畅的多轮对话。Bard最近添加了帮助编码和编码主题的功能。当Bard发出可能受开源许可证约束的代码时,它会引用其来源并提供相关信息。Bard也擅长代码解释。

GitHub Copilot X 是一组技术预览功能,通过聊天和终端界面扩展原始Copilot,支持拉取请求以及早期采用OpenAI的GPT-4。目前,要访问这些Copilot X功能,你需要拥有有效的Copilot订阅并加入等候名单,无法保证何时可以访问新功能。在我加入等候名单后,我的邀请函花了大约一个月的时间才到达。请注意,Copilot X 不是(也可能永远不会是)GitHub Copilot 的可用产品。我在本次审查中使用了Copilot X这个名字,以区分我测试的GPT-4版本的Copilot与当前基于GPT-3的Copilot产品。

使用这些代码生成器之一并不是生成代码的唯一方法。首先,你可以访问通用转换器,如GPT-4及其前身,包括ChatGPT、BingGPT/Bing Chat(在Edge浏览器中可用)和Boo.ai。还有其他特定于代码的AI工具,例如StarCoder,Tabnine,Cody,AlphaCode,Polycoder和Replit Ghostwriter。在我提到的每种情况下,在使用之前谨慎行事并仔细测试和审查生成的代码至关重要。

二、如何测试这些工具

在我上一篇关于代码生成的文章中,我根据编写程序来确定两个日期之间的天数的相当简单的任务来评估AI代码生成器。大多数人做得很好,尽管有些人比其他人需要更多的指导。在这次审查中,我尝试了代码生成器来完成更困难的任务,即抓取文章列表InfoWorld.com。我给了他们一个大纲,但没有额外的帮助。没有人生成正确的代码,尽管有些代码比其他代码更接近。作为一项额外的任务,我要求支持代码解释的工具解释MIT开放课件入门编程课程中的Python代码示例。

作为参考,我给代码生成器的大纲是:

抓取infoworld.com首页:

  • 打开https://www.infoworld.com/
  • 通过在href中查找带有“article”的链接来查找所有文章;从中提取标题、作者、日期
  • 按标题字母顺序列出所有文章;消除重复的
  • 按作者姓氏的字母顺序列出所有文章
  • 首先列出所有最新的文章

总的来说,我试图表现得像一个比我更天真的程序员,只是为了看看这些工具会做什么。

现在,让我们更仔细地看一下我们的每个代码生成器。

三、Amazon CodeWhisperer

在你的IDE中,Amazon CodeWhisperer会分析你的英语注释和周围的代码,以推断它应该生成哪些代码来完成你正在键入的内容。然后,它提供代码作为你可以接受或拒绝的建议,或者你可以要求CodeWhisperer提供备用代码,或者忽略并继续编写自己的代码。CodeWhisperer的大型语言模型(LLM)经过了数十亿行代码的训练,包括Amazon和开源代码。任何给定的建议不仅基于你的注释和上下文即时代码,还基于在IDE中打开的其他文件的内容。

除了代码生成之外,CodeWhisperer还可以扫描你的Python、Java和JavaScript代码以查找安全漏洞,并为其提出修复建议。它咨询的漏洞列表包括开放Web应用程序安全项目 (OWASP)、加密库最佳实践、AWS API 最佳实践和其他API最佳实践。安全扫描按需进行,这与代码完成不同,代码完成会在你编码时持续提供,除非你关闭建议。

1.编程语言和集成开发环境

CodeWhisperer用于代码生成的最佳编程语言(训练语料库中最流行的语言)是Java,Python,JavaScript,TypeScript和C#。它在Ruby,Go,PHP,C++,C,Shell,Scala,Rust,Kotlin和SQL上进行了较小程度的训练。

有用于Visual Studio Code和JetBrains IDE的CodeWhisperer插件。你还可以激活CodeWhisperer以便在AWS Cloud9 和AWS Lambda 中使用;在这两种情况下,你都必须编辑你的IAM权限并选中启用CodeWhisperer框。

我在Visual Studio Code中安装了CodeWhisperer。有四个步骤:

  • 将 CodeWhisperer 插件添加到 VS Code。
  • 添加与 AWS 的连接。
  • 登录 AWS 网站。
  • 从 AWS 开发人员工具面板启动 CodeWhisperer

图片图片

图1:安装并授权CodeWhisperer后(左侧),你可以看到使用说明,如右侧所示代码建议和完成

值得一看的是,一些演示CodeWhisperer功能的视频,这些视频列在CodeWhisperer资源页面上。他们会告诉你比我更多的文字和截图。在观看它们时,我清楚地看到CodeWhisperer在调用AWS API 的代码上大放异彩。

尽管如此,以下是CodeWhisperer生成的代码的屏幕截图:

图片图片

图2:CodeWhisperer生成代码

请注意,生成的代码不起作用 ,并且CodeWhisperer生成了多个函数,或多或少出于相同的目的。然而,它相当接近,CodeWhisperer有点读懂我关于使用Beautiful Soup来抓取网页的想法。

图片图片

图3:尝试CodeWhisperer生成的程序

2.安全扫码和开源参考

我也在我的项目上运行了CodeWhisperer安全扫描。不出所料,此文件中未检测到任何问题,尽管CodeWhisperer扫描在GitHub Copilot X生成的另一个文件中发现了资源泄漏。CodeWhisperer安全扫描是一项差异化功能,尚未在竞争的AI代码生成器中浮出水面。

此文件没有触发任何开源引用,但是当我打开CodeWhisperer引用日志时,我发现了一个指向该设置的链接,该设置控制CodeWhisperer是否会建议具有此类引用的代码。在我查看的Amazon示例中,带有引用的代码建议在顶部显示了许可证类型。

3.CodeWhisperer 小结

CodeWhisperer在IDE中生成代码并进行安全审查,但它缺少聊天窗口和代码解释。该工具或多或少如宣传的那样工作,价格(免费)适合个人开发人员。对于企业开发人员来说,CodeWhisperer每月19美元的价格与Copilot相同。对于大量使用AWS的商店以及需要知道代码建议何时涉及开源的商店,我更喜欢CodeWhisperer而不是Copilot。

四、Google Bard

Bard于2023年4月21日宣布支持编程。相关博客文章提到了“超过20种编程语言,包括C++,Go,Java,Javascript,Python和Typescript。”

当我向Bard询问完整列表时,我收到了以下回复:

  • C++
  • Go
  • Java
  • JavaScript
  • Python
  • TypeScript
  • C#
  • PHP
  • Ruby
  • Swift
  • Kotlin
  • Rust
  • Julia
  • R
  • Haskell
  • Erlang
  • Scala
  • Lua
  • OCaml
  • Scheme

Bard可以生成这些语言的代码、调试代码和解释代码。它还可以从一种编程语言翻译成另一种编程语言。

请注意,Bard仍在开发中,因此其功能可能并不完美。在使用AI生成的代码之前,仔细检查它总是一个好主意。

我在代码解释和代码生成任务上测试了Bard,如下所示。代码解释非常好——非常好,以至于我想知道Bard是否接受过麻省理工学院课程代码示例的培训,该示例可追溯到2008年,从那时起就可以在网上找到。

网站抓取工具的代码生成乍一看看起来相当可信,但在进一步检查时有几个明显的问题。只需单击两次即可在Colab中打开代码,但是当我尝试运行它时,它抛出了一个类型错误,它甚至没有达到我确定为错误的代码。

我没有解决问题,而是尝试再次运行代码生成,结果更有意义。但是,当我尝试在Colab中运行它时,它抛出了一个属性错误。我将该回溯反馈给Bard,它生成了一个修复程序,我在Colab中运行了“修复”代码,结果它又在另一个位置产生了类型错误。够了,已经!真想举起双手,缴械投降。

引用网页和开源代码怎么样?Bard的常见问题解答是这样说的:

与其他一些独立的LLM体验一样,Bard旨在生成原始内容,而不是长时间复制现有内容。我们设计了我们的系统来限制这种情况发生的可能性,我们将继续改进这些系统的运作方式。如果Bard确实直接从网页中详细引用,它会引用该页面。

有时,相同的内容可能会在多个网页上找到,Bard试图指向一个流行的来源。在引用代码存储库的情况下,引用也可以引用适用的开源许可证。

这是我给Bard的指令和由此产生的对话:

我要给你一些代码来解释。请等待直到代码完成。

当然,我会等你把代码完全给我。请慢慢来。我会尽我所能来帮助你。

下面是一些解释代码的技巧:

  • 首先解释代码的总体目的。它是做什么的?它试图解决什么问题?
  • 然后,将代码分解成更小的块,并依次解释每个块。
  • 使用简洁明了的语言。避免行话和专业术语。
  • 用例子来说明你的观点。
  • 要有耐心,不要害怕问问题。
  • 我有信心可以帮助你解释你给我的任何代码。只要让我知道你需要什么,我会尽我所能帮助你。

这是我提供的代码:

import pylab, random

class Stock(object):
    def __init__(self, price, distribution, vol):
        self.price = price
        self.history = [price]
        self.distribution = distribution
        self.vol = vol
        self.lastChangeInfluence = 0.0
    def setPrice(self, price):
        self.price = price
        self.history.append(price)
    def getPrice(self):
        return self.price
    def makeMove(self, bias, mo):
        oldPrice = self.price
        baseMove = self.distribution(self.vol) + bias
        self.price = self.price * (1.0 + baseMove)
        self.price += mo*random.choice([0.0, 1.0])*self.lastChangeInfluence
        self.history.append(self.price)
        change = self.price - oldPrice
        if change >= 0:
            self.lastChangeInfluence = min(change, oldPrice*0.01)
        else:
            self.lastChangeInfluence = max(change, -oldPrice*0.01)
    def showHistory(self, fig, test):
        pylab.figure(fig)
        pylab.plot(self.history)
        pylab.title('Closing Prices, Test ' + test)
        pylab.xlabel('Day')
        pylab.ylabel('Price')

class SimpleMarket(object):
    def __init__(self, numStks, volUB):
        self.stks = []
        self.bias = 0.0
        for n in range(numStks):
            volatility = random.uniform(0, volUB)
            distribution = lambda vol: random.gauss(0.0, vol)
            stk = Stock(100.0, distribution, volatility)
            self.addStock(stk)
    def addStock(self, stk):
        self.stks.append(stk)
    def setBias(self, bias):
        self.bias = bias
    def getBias(self):
        return self.bias
    def getStocks(self):
        return self.stks[:]
    def move(self, mo):
        prices = []
        for s in self.stks:
            s.makeMove(self.bias, mo)
            prices.append(s.getPrice())
        return prices

class Market(SimpleMarket):
    def __init__(self, numStks, volUB, dailyBiasRange):
        SimpleMarket.__init__(self, numStks, volUB)
        self.dailyBiasRange = dailyBiasRange
    def move(self, mo):
        prices = []
        dailyBias = random.gauss(self.dailyBiasRange[0], self.dailyBiasRange[1])
        for s in self.stks:
            s.makeMove(self.bias + dailyBias, mo)
            prices.append(s.getPrice())
        return prices

def simMkt(mkt, numDays, mo):
    endPrices = []
    for i in range(numDays):
        vals = mkt.move(mo)
        vals = pylab.array(vals)
        mean = vals.sum()/float(len(vals))
        endPrices.append(mean)
    return endPrices

def plotAverageOverTime(endPrices, title):
    pylab.plot(endPrices)
    pylab.title(title)
    pylab.xlabel('Days')
    pylab.ylabel('Price')

def plotDistributionAtEnd(mkt, title, color):
    prices = []
    sumSoFar = 0
    for s in mkt.getStocks():
        prices.append(s.getPrice())
        sumSoFar += s.getPrice()
    mean = sumSoFar/float(len(prices))
    prices.sort()
    pylab.plot(prices, color)
    pylab.axhline(mean, color = color)
    pylab.title(title)
    pylab.xlabel('Stock')
    pylab.ylabel('Last Sale')
    pylab.semilogy()

def runTrial(showHistory, test, p):
    colors = ['b','g','r','c','m','y','k']

    mkt = Market(p['numStocks'], p['volUB'], p['dailyBiasRange'])
    mkt.setBias(p['bias'])
    endPrices = simMkt(mkt, p['numDays'], p['mo'])
    pylab.figure(1)
    plotAverageOverTime(endPrices, 'Average Closing Prices')
    pylab.figure(2)
    plotDistributionAtEnd(mkt, 'Distribution of Prices', colors[test%len(colors)])
    if showHistory:
        for s in mkt.getStocks():
            s.showHistory(test+2, str(test))

def runTest(numTrials):
    #Constants used in testing
    numDaysPerYear = 200.0
    params = {}
    params['numDays'] = 200
    params['numStocks'] = 500
    params['bias'] = 0.1/numDaysPerYear #General market bias
    params['volUB'] = 12.0/numDaysPerYear #Upper bound on volatility for a stock
    params['mo'] = 1.1/numDaysPerYear #Momentum factor
    params['dailyBiasRange'] = (0.0, 4.0/200.0)

    for t in range(1, numTrials+1):
        runTrial(True, t, params)

runTest(3)
pylab.show()

以下是Bard的一些回应,非常深入:

你提供的代码是一个模拟股票市场的Python程序。程序定义了三个类:

股票:这个类表示一只股票。它具有股票的价格、历史、分布、波动性和最近变化影响的属性。

这个类表示一个简单的股票市场。它有一个股票列表、一个偏差和一个波动率上限。

市场:这个类继承自SimpleMarket,并添加了一个每日偏差范围属性。该程序还定义了几个函数:

  • simmkt:该函数模拟给定天数和动量因子的市场。
  • plotaverageovertime:该函数绘制股票随时间的平均收盘价。
  • plotdistributionatend:该函数绘制模拟结束时的价格分布。
  • runtrial:该函数运行单个模拟并绘制结果。
  • runtest:这个函数运行一些模拟并绘制结果。

通过调用runTest函数来运行程序,该函数具有所需的模拟次数。然后程序将生成三个图:

  • 股票在一段时间内的平均收盘价图。
  • 模拟结束时的价格分布图。
  • 每只股票的历史价格图。

该程序可用于模拟各种不同的股票市场。通过改变参数的值,你可以改变市场的波动性、市场的偏差和动量因子。你也可以使用该程序来模拟不同的交易策略。例如,你可以模拟一种策略,当股票被低估时买入,当股票被高估时卖出。

Bard还解释了代码的每个部分是如何工作的:

Stock类表示单个股票。它具有股票的价格、历史、分布、波动性和最近变化影响的属性。价格属性是股票的当前价格。历史属性是股票在一段时间内的价格列表。distribution属性是一个为股票生成随机价格的函数。波动性是衡量股票价格波动幅度的指标。lastChangeInfluence属性是股票价格受其先前变化影响程度的度量。

SimpleMarket类表示一个简单的股票市场。它有一个股票列表、一个偏差和一个波动率上限。股票列表属性是市场上股票的列表。偏倚属性是衡量市场对价格上涨的偏向程度的指标。波动性上限属性是衡量市场波动程度的指标。

Market类继承自SimpleMarket,并增加了一个每日偏差范围属性。每日偏差范围属性是衡量市场偏差每天变化的程度。

  • simMkt函数模拟给定天数和动量因子的市场。天数参数是要模拟的天数。动量因子参数是衡量股票价格受动量影响程度的指标。
  • plotAverageOverTime函数绘制股票随时间的平均收盘价。plotDistributionAtEnd函数绘制模拟结束时的价格分布。
  • runTrial函数运行单个模拟并绘制结果。showHistory参数是一个布尔值,用于确定是否绘制每只股票的历史价格。测试参数是模拟的唯一标识符。
  • runTest函数运行大量模拟并绘制结果。numTrials参数是要运行的模拟次数。

我希望这个解释是有帮助的。如果你还有什么问题,请告诉我。

当我跟进时,输入“pylab模块在哪里?”Bard给出了模块的位置、如何导入模块、功能描述和指向文档的指针。

此外,以下是Bard生成的用于抓取文章列表InfoWorld.com的代码:

import requests
from bs4 import BeautifulSoup

def scrape_infoworld():
  """Scrape the InfoWorld front page and return a list of articles."""

  # Get the HTML from the InfoWorld front page.
  response = requests.get("https://www.infoworld.com/")
  soup = BeautifulSoup(response.content, "html.parser")

  # Find all articles by looking for links with 'article' in the href.
  articles = soup.find_all("a", href=lambda x: "article" in x["href"])

  # Extract the title, author, and date from each article.
  article_data = []
  for article in articles:
    title = article.find("h3").text
    author = article.find("span", class_="byline").text
    date = article.find("time").text
    article_data.append({
      "title": title,
      "author": author,
      "date": date,
    })

  # Sort the articles alphabetically by title.
  article_data.sort(key=lambda x: x["title"])

  # Remove any duplicate articles.
  article_data = list(set(article_data))

  # Sort the articles alphabetically by author last name.
  article_data.sort(key=lambda x: x["author"].split()[-1])

  # Sort the articles latest first.
  article_data.sort(key=lambda x: x["date"], reverse=True)

  return article_data

if __name__ == "__main__":
  articles = scrape_infoworld()

  # Print the articles.
  for article in articles:
    print(article)

Explanation:

This code will first get the HTML from the InfoWorld front page. Then, it will find all articles by looking for links with 'article' in the href. For each article, it will extract the title, author, and date. The articles will then be sorted alphabetically by title, removed of any duplicates, sorted alphabetically by author last name, and sorted latest first. Finally, the articles will be printed.

这是运行时结果:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-1-afbe7808577e> in <cell line: 40>()
     39 
     40 if __name__ == "__main__":
---> 41   articles = scrape_infoworld()
     42 
     43   # Print the articles.

6 frames

<ipython-input-1-afbe7808577e> in <lambda>(x)
     10 
     11   # Find all articles by looking for links with 'article' in the href.
---> 12   articles = soup.find_all("a", href=lambda x: "article" in x["href"])
     13 
     14   # Extract the title, author, and date from each article.

TypeError: string indices must be integers

Bard小结

Bard有一个聊天界面,可以生成和解释代码,但它没有交互式IDE集成。鉴于Bard目前是完全免费的,并且不需要设置,当你需要使用20种支持的语言中的任何一种生成、调试和解释代码时,当然值得尝试。

五、GitHub Copilot X

GitHub Copilot X 比原来的GitHub Copilot有了很大的改进,有时可以在没有太多人工帮助的情况下生成正确的函数和一组测试。它仍然会犯错误和幻觉(产生虚假信息),但不像以前那么多了。

除了在编程编辑器中生成代码(目前仅支持最新版本的Visual Studio和最新的Visual Studio Code内部版本)之外,Copilot X还向编辑器添加了GPT-4聊天面板。它还添加了终端接口,支持生成单元测试和拉取请求说明,以及从文档中提取说明的功能。

我问Copilot X聊天支持哪些编程语言,它回答说“我支持多种编程语言,包括但不限于:Python,JavaScript,TypeScript,Ruby,Java,C++,C#,PHP,Go,Swift,Kotlin,Rust等等。我主要用Python进行测试。

当我使用Copilot Chat工具要求Copilot X解释MIT市场模拟代码时,它给出了部分正确的答案。我不得不比喻它咬牙切齿,让它解释代码的其余部分。

图片图片

图4:Copilot X在解释市场模拟器方面做得不错,但不完整

Copilot X最显著的失败是网络抓取代码生成任务。该工具生成了一堆表面上可信的代码,这些代码没有使用Beautiful Soup,但从审查代码中可以清楚地看出它永远不会起作用。我一直把问题带到Copilot Chat,但它只是给自己挖了一个更深的坑。我本可以重新开始并给它更好的提示,包括从它导入并添加一些显示InfoWorld主页的HTML和目录结构的评论。我没有这样做,因为这不符合我在这一轮测试中采用的天真的编码员角色。

图片图片

图5:Copilot X尝试在不使用Beautiful Soup(bs4)的情况下生成网络抓取代码。后来我聊到它生成的解决方案,它先是声称使用的是Beautiful Soup,但后来承认找不到进口

与所有AI助手一样,你必须对Copilot X生成的代码持保留态度,就像处理来自未知程序员的拉取请求一样。

Copilot X 小结

除了在IDE中生成代码外,Copilot X 还在编辑器中添加了一个GPT-4聊天面板。它还增加了终端接口、对单元测试生成的支持、对生成拉取请求描述的支持,以及从技术文档中提取说明的功能。同样,Copilot X 是一组技术预览功能,这些功能在Copilot产品中尚不可用;他们的产品形式和定价还有待观察。GitHub Copilot目前个人每月收费10美元,企业每位用户每月收费19美元。

六、结论

GitHub Copilot X在简单的问题上工作得很好,但不一定比代码编辑器中的Amazon CodeWhisperer和浏览器中的Google Bard组合更好。CodeWhisperer还没有聊天功能或解释代码的功能,这太糟糕了,Bard没有与编辑器或IDE完全集成也太糟糕了。

如果Copilot X没有在我的高级代码生成任务中脱轨,我会很想推荐它(即即将推出的基于GPT-4的GitHub Copilot版本,无论名称如何)——主要是因为它在编辑器中集成了聊天和代码生成。然而,在这一点上,Copilot X还没有完全准备好。总的来说,没有一个代码生成产品是真正符合要求的,尽管Bard和Copilot X在代码解释方面都做得很好。

所有这些产品都在积极开发中,所以我的建议是继续观察它们并进行实验,但不要相信它们中的任何一个。

原文链接:https://www.infoworld.com/article/3699140/review-codewhisperer-bard-and-copilot.html


责任编辑:武晓燕 来源: 51CTO技术栈
相关推荐

2015-06-04 11:22:22

前端程序员

2011-12-20 09:01:25

.NET

2015-06-05 11:23:19

前端为什么不要你

2012-05-24 10:29:54

编程程序员

2015-07-27 15:27:11

程序员重写代码

2018-05-07 15:59:39

代码程序员重写

2015-07-28 10:28:54

程序员代码

2024-02-20 22:13:49

SQL语句编程

2019-11-08 13:57:53

程序员Excel软件

2022-03-29 09:03:22

测试组件Propsrender

2014-08-04 15:30:39

Linux开源软件

2021-03-03 20:43:17

ChromeXPathHTML

2023-06-02 06:55:04

2021-11-11 15:25:28

@AsyncJava线程池

2022-12-06 08:26:16

SpringAOPthis调用方法

2018-04-20 14:37:43

互联网技术细节

2019-10-14 13:20:26

物联网数据IOT

2022-10-31 08:29:37

MySQL单表参数

2021-10-20 14:53:31

Foreach强制阿里巴巴

2024-01-03 08:15:35

Executors线程池线程
点赞
收藏

51CTO技术栈公众号