双子座与ChatGPT:谁能写出更好的代码?

Ari Mahpour
|  已创建:March 1, 2024  |  已更新:April 2, 2024
双子座与ChatGPT对比

 

电气工程师的时代,不再是不写一行代码就能过关的时代了。掌握编程技能已成为所有类型工程师必备的技能。虽然工程师不需要懂得如何编写完整的全栈网络应用程序,但他们必须具备基本的脚本编程技能。例如,对大型数据集进行分析就需要一些编程知识。对于更复杂的任务,工程师有时会发现自己处于困境,可能需要花费数小时在线搜索特定的函数或解决方案。随着ChatGPT的发布,世界无疑已经发生了变化,自动化代码生成的景观也随之改变。现在,即使是没有强大背景的工程师,也可以在生成式人工智能的帮助下编写高质量的代码。

在之前的文章中,如使用ChatGPT进行Altium脚本编写使用ChatGPT进行自动化测试,我们探讨了如何利用生成式人工智能,特别是ChatGPT,为我们编写代码。直到现在,Google Bard(ChatGPT的竞争对手)一直落后,但是一个新模型,Gemini,已经宣布在大规模多任务语言理解(MMLU)尺度上超越了其竞争对手:

Figure 1: Gemini’s MMLU  performance metric

图1:Gemini的MMLU性能指标。来源:https://deepmind.google/technologies/gemini/#capabilities

在本文中,我们将把ChatGPT最先进的引擎GPT4与Gemini Advanced(以前称为Ultra),谷歌最先进的AI引擎进行比较,看看哪个在生成代码方面做得更好。

样板代码

要在两个引擎之间进行全面的比较将是极其具有挑战性的。在本文中,我们将看看这两个引擎在生成Python语言的样板代码方面的表现如何(因为Python是代码编写LLMs最支持的语言之一)。这不是一个精确的科学,因为好与坏可以非常主观。相反,我们将仅根据代码是否运行以及它对我们的指令理解得有多好来给每个引擎打分。

任务1:递归文件属性打印

让我们从一个非常简单的脚本任务开始:

开发一个Python自动化脚本,给定一个文件夹的绝对路径,递归地检索每个文件的元数据作为字典对象。逐行打印每个字典对象,并包括绝对路径。

首先让我们分析从GPT4返回的代码:

import os

def get_file_metadata(directory):

    for foldername, subfolders, filenames in os.walk(directory):

        for filename in filenames:

            filepath = os.path.join(foldername, filename)

            metadata = {

                'filename': filename,

                'path': filepath,

                'size': os.path.getsize(filepath),

                'last_modified': os.path.getmtime(filepath)

            }

            print(metadata)

get_file_metadata(os.path.dirname(os.path.abspath(__file__)))

它简洁,有效,完成了任务。我会给这个通过。这也是一个极其简单的任务,但这没关系。

现在让我们看看从Gemini Advanced返回的代码:

import os

def get_file_metadata(file_path):

    metadata = {}

    try:

        stat = os.stat(file_path)

        metadata['name'] = os.path.basename(file_path)

        metadata['size'] = stat.st_size  # 字节大小

        metadata['modified_time'] = stat.st_mtime  # 最后修改时间戳

        metadata['accessed_time'] = stat.st_atime  # 最后访问时间戳

    except OSError:

        print(f"访问文件错误: {file_path}")

    return metadata

 

def retrieve_metadata_recursively(folder_path):

    for root, _, files in os.walk(folder_path):

        for file in files:

            file_path = os.path.join(root, file)

            metadata = get_file_metadata(file_path)

            if metadata:

                print(f"绝对路径: {file_path}")  # 打印绝对路径

                print(metadata)

 

if __name__ == '__main__':

    retrieve_metadata_recursively(os.path.dirname(os.path.abspath(__file__)))

Gemini的代码稍微冗长一些,不过,它增加了一些错误处理,我想,这还是不错的。虽然有些长,但它能工作,所以我们就接受它。

任务 2: 网络爬虫

对于下一个任务,我想看看两个引擎如何理解给定的语言并基于该语言创建解析器。在这个案例中,我们将使用以下提示构建一个网页抓取器:
编写一个使用 BeautifulSoup 或 Scrapy 的 Python 脚本,该脚本从 'https://news.ycombinator.com' 抓取顶部新闻标题,并将它们输出到一个字典对象中。

这里是来自 'https://news.ycombinator.com' 的页面源代码片段。使用这个来确定如何解析标签。

编写一个使用 BeautifulSoup 或 Scrapy 的 Python 脚本,该脚本从 'https://news.ycombinator.com' 抓取顶部新闻标题,并将它们输出到一个字典对象中。

这里是来自 'https://news.ycombinator.com' 的页面源代码片段。使用这个来确定如何解析标签。

<html lang="zh" op="news"><head><meta name="referrer" content="origin"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="stylesheet" type="text/css" href="news.css?J16btoAd8hqdkSoIdLSk">
        <link rel="icon" href="y18.svg">

</html>

您会注意到我在我的提示中包含了一些HTML。我的实际提示包含更多HTML,但我为了这篇文章而截断了它。这里是GPT4生成的内容:

import requests
from bs4 import BeautifulSoup

# 要抓取的网站的URL
url = 'https://news.ycombinator.com'

# 向URL发送GET请求
response = requests.get(url)

# 使用BeautifulSoup解析页面的HTML内容
soup = BeautifulSoup(response.text, 'html.parser')

# 查找所有新闻标题
headlines = soup.find_all('tr', class_='athing')

# 用于存储新闻标题的字典,其中键是排名,值是新闻标题文本
news_headlines = {}

# 遍历每个标题,提取并将其存储在字典中
for headline in headlines:
    rank = headline.find('span', class_='rank').text.strip('.')
    title = headline.find('span', class_='titleline').text
    news_headlines[rank] = title

# 输出字典
print(news_headlines)

这段代码运行良好,完成了它应该做的事情。我本希望它能直观地知道我想要文章的链接,但我没有明确说明,所以我不能因此而扣分。

以下是Gemini生成的代码:

import requests
from bs4 import BeautifulSoup

# 向Hacker News网站发送HTTP GET请求
response = requests.get("https://news.ycombinator.com/")

# 使用BeautifulSoup解析HTML内容
soup = BeautifulSoup(response.content, "html.parser")

# 查找包含新闻文章的所有'class为athing'的元素
articles = soup.find_all("tr", class_="athing")

# 创建一个空字典来存储标题
headlines = {}

# 遍历每篇文章,提取标题和URL
for article in articles:
    # 查找标题元素
    headline_element = article.find("span", class_="titleline")
    headline = headline_element.find("a").text.strip()

    # 查找URL元素
    url_element = headline_element.find("a")
    url = url_element["href"]

    # 将标题和URL添加到字典中
    headlines[headline] = url

# 打印标题字典
print(headlines)

这也是有效的,与GPT4的输出相当类似,但这段代码实际上提取了URL。这很好,但再次说,这不是预期的。在这个挑战中,我会说它们几乎是一样的。也许Gemini因为能读心而额外得分。

任务3:股票Web应用程序

对于这个任务,我想创建一个绘制几个不同股票代码图表的网络应用程序:

用Python创建一个展示以下股票图表的网络应用程序:RIVN, TSLA, NKLA, FSR

这个任务确实更有挑战性。它需要前端(即图表/图片)和后端组件(即从股票数据库检索数据)。我已经用GPT4生成了无数应用程序,想看看Gemini与它相比如何。这是GPT4为我生成的:

from flask import Flask, render_template_string
import yfinance as yf
import plotly.graph_objects as go
from datetime import datetime

app = Flask(__name__)

@app.route('/')
def home():
    stocks = ['RIVN', 'TSLA', 'NKLA', 'FSR']
    start = datetime(2021, 1, 1)
    end = datetime.now()

    fig = go.Figure()

    for stock in stocks:
        df = yf.download(stock, start=start, end=end)
        fig.add_trace(go.Scatter(x=df.index, y=df.Close, mode='lines', name=stock))

    graph_html = fig.to_html(full_html=False)

    return render_template_string("""
        <html>
            <body>
                {{ graph_html | safe }}
            </body>
        </html>

Figure 2: Screenshot of GPT4 generated web application

图 2:GPT4生成的网页应用截图

简单、清洁且直接。没有多余的装饰,但完成了任务。这是Gemini为我生成的:

import flask
from flask import render_template
import yfinance as yf
import plotly.graph_objects as go

app = flask.Flask(__name__)

# 股票符号
tickers = ['RIVN', 'TSLA', 'NKLA', 'FSR']

# 使用yfinance获取股票数据
def get_stock_data(ticker):
    start_date = '2023-02-10'  # 根据需要调整开始日期
    end_date = '2024-02-10'  # 今天的日期
    return yf.download(ticker, start=start_date, end=end_date)

@app.route('/')
def index():
    stock_data = {}
    for ticker in tickers:
        stock_data[ticker] = get_stock_data(ticker)

    charts = []
    for ticker, data in stock_data.items():
        fig = go.Figure(data=[go.Candlestick(x=data.index,
                                             open=data['Open'],
                                             high=data['High'],
                                             low=data['Low'],
                                             close=data['Close'])])
        fig.update_layout(title=ticker)
        charts.append(fig.to_html(full_html=False, include_plotlyjs='cdn'))

    return render_template('index.html', charts=charts)

if __name__ == '__main__':
    app.run(debug=True)

这也要求我在一个新的目录叫做templates中创建一个新文件,index.html:

<!DOCTYPE html>
<html>
<head>
    <title>股票图表</title>
    <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
    {% for chart in charts %}
        <div id="{{ loop.index0 }}"></div> 
        <script>
            Plotly.newPlot('{{ loop.index0 }}', {{ chart | safe }});
        </script>
    {% endfor %}
</body>
</html>

Figure 3: Screenshot of Gemini Advanced generated web application

图 3:Gemini Advanced 生成的网页应用程序截图

这显然更加精致,因为它包含了一个直方图,并将 HTML 内容抽象到了一个新文件中。同样,两者都是功能性的,因此,两者都通过了。

失败与幻觉

当GPT4首次问世时,人们花了一些时间来理解如何正确地“提示”它。在使用生成式AI编写代码时,细节很重要。因此,过去这一年里,我们中的许多人已经成为更加能干的“提示工程师”。不幸的是,这可能在将GPT4与其他引擎进行比较时引入了一些偏见,我愿意承认这一点。我对GPT4的“工作”方式的了解超过了对Gemini的了解。我为GPT4设计提示的方式可能与Gemini所期望的不同。尽管如此,我仍然遇到了一些与Gemini相关的非常基本的问题。

我在使用Gemini解释指令时遇到的一个常见问题是在生成单元测试方面。我的初衷是在文章中涵盖单元测试,但由于沮丧,我完全放弃了使用Gemini,因为它从不按照指示行事。例如,我会要求Gemini使用Pytest编写一个单元测试,并将其封装在一个类中。它却会使用UnitTest生成测试,明显忽略了我的请求,但会将代码封装在一个类中。我会纠正它,它会承认它不小心使用了UnitTest而不是Pytest。然后它会使用Pytest重写代码,但忘记将其放入一个类中。当我要求它使用Mock构造时,它默认使用UnitTest的mock而不是Pytest的Mock。这些是细微差别,但在使用生成式AI时很重要。

Figure 4: Gemini Advanced not following directions

图4:Gemini高级版不按指示行事

故障排除是另一个痛点。GPT4的推理引擎在调试Python错误时已经证明相当强大。Gemini…就没那么好用了。当我要求它修复某些问题时,它只是尝试通过增加缩进或交换变量来重写代码...完全是无用的回应。

有时候Gemini就是不起作用。它表示无法处理我的请求。在其他情况下,它开始评论关于……即将到来的选举?

Gemini Advanced confused about the upcoming elections?

图5:Gemini Advanced对即将到来的选举感到困惑?

结论

总的来说,Gemini生成的样板代码的质量与GPT4相当有竞争力。然而,其体验和推理引擎还有很大的提升空间。对于谷歌来说幸运的是,这些部分是LLM实现的一部分,而不是LLM本身。换句话说,Gemini LLM似乎从根本上来说是相当不错的,与GPT4不相上下,但是用于聊天体验中的代码需要一些帮助。随着时间的推移,我们可能会看到谷歌在他们的代码上进行迭代,并增强那些体验和推理引擎。

关于作者

关于作者

Ari 是一位在设计、制造、测试以及集成电气、机械和软件系统方面拥有丰富经验的工程师。他热衷于将设计、验证和测试工程师凝聚成一个高效团队,共同工作。

相关资源

相关的技术文档

返回主页
Thank you, you are now subscribed to updates.