使用人工智能进行编程
我思考写这篇文章已经有一段时间了,直到最近才有时间坐下来,认真地梳理思路并把想法整理成文字。
过去几年,“人工智能”成了热门的营销词汇,不少公司随意使用甚至滥用这个词,宣称能让生活变得更轻松。
在这篇文章里,我公司将从编程角度定义人工智能,介绍一些可用于生成代码的服务,还会探讨用人工智能系统编码的优缺点。在Drupal开发领域,无论是Drupal模块开发还是Drupal升级,都可能会用到人工智能辅助,下面我们就来详细了解。
一、什么是人工智能?
“人工智能”是个宽泛的术语,涵盖多种技术。在本文中,我所说的“人工智能”指的是“大语言模型”(LLM),它是为自然语言处理任务设计的机器学习模型,通过大量文本训练而成。
这里的“大量文本”,那可是相当多。ChatGPT背后的OpenAI公司未公布训练其模型的确切数据量,但据估算,训练GPT - 4大约用了10万亿个单词。对比一下,整个《指环王》三部曲大约有48万个单词,这意味着相当于用2100万本《指环王》三部曲大小的书籍来训练,数据量极其庞大。
这些海量数据用于执行一项任务,即预测序列中的下一个单词。输入到模型中的大量数据让它们拥有庞大的统计数据库,以此来预测下一个单词,这就是这些模型能生成看似人撰写句子的原因。
在编写代码方面,同样的模型能以之前见过的方式生成代码。如果训练一个人工智能模型解读互联网上大量的代码示例,给它特定要求时,它就能生成相应代码。在Drupal开发中,比如Drupal模块开发和Drupal升级,也可以借助这样训练有素的模型来辅助生成部分代码。
思考大语言模型时,记住下面两点很重要:
- 它是基于令牌分析和结果统计可能性来生成输出的统计模型。
- 它没有意识和智力,只是模仿智能。
了解这些后,我们来看看一些能用人工智能创建代码的服务。
二、有哪些服务可供使用?
我不会介绍太多不同的服务,而是重点讲讲我公司用过的几个比较知名的代码生成服务。要是你还知道其他服务,欢迎分享!
我没直接链接代码,而是让每个模型生成一个用PHP实现的快速排序算法并展示结果。快速排序算法看似简单,但因涉及递归和递归调用间传递不同数组,要正确实现有一定难度。
我会用我公司为PHP排序练习仓库创建的测试来检验生成的代码,该仓库包含单元测试,用于检查快速排序是否正确对数字数组排序。
当然,我知道还有其他服务,不过下面这些是我公司有使用经验的。
1. ChatGPT
有多种语言模型可用于生成文本和代码。
我公司用的是免费版,只能访问LLM “GPT - 4o mini”。虽然ChatGPT返回的文本不错,但这个模型生成的代码质量欠佳。
以下是快速排序问题的结果:
function quicksort(array $array): array {
// 基本情况:元素个数为0或1的数组已经是有序的
if (count($array) < 2) {
return $array;
}
// 选择一个基准元素
$pivot = $array[0];
// 将数组划分为两个子数组
$less = array_filter(array_slice($array, 1), fn($x) => $x <= $pivot);
$greater = array_filter(array_slice($array, 1), fn($x) => $x > $pivot);
// 递归地对两个子数组进行排序,并将它们与基准元素合并
return array_merge(quicksort($less), [$pivot], quicksort($greater));
}
// 示例用法
$array = [3, 6, 8, 10, 1, 2, 1];
$sortedArray = quicksort($array);
echo "原始数组: " . implode(", ", $array) . "\n";
echo "排序后的数组: " . implode(", ", $sortedArray) . "\n";
乍一看,代码没啥问题,但运行会报错。
Undefined array key 0
test.php:8
问题出在使用了array_filter()函数移除小于等于或大于基准值的元素,这会使结果数组缺少键为0的元素,而递归下一步需要该元素。所以,如果数组第一个元素被过滤掉,对quicksort()的递归调用会包含一个在获取基准值时出错的数组。
实际上,人工智能给出的数字列表“[3, 6, 8, 10, 1, 2, 1]”排序时就出现了这个问题。
2. Google Gemini
Gemini使用Google的1.5 Flash模型,可免费使用。还有“专业版”,逻辑推理能力更强,使用“Gemini - Exp - 1206”模型,在代码和数学方面表现更优。
以下是快速排序问题的结果:
function quickSort(array $arr): array {
$length = count($arr);
if ($length <= 1) {
return $arr; // 基本情况:已经有序
}
$pivot = $arr[0]; // 选择第一个元素作为基准
$left = $right = [];
for ($i = 1; $i < $length; $i++) {
if ($arr[$i] < $pivot) {
$left[] = $arr[$i];
} else {
$right[] = $arr[$i];
}
}
return array_merge(quickSort($left), [$pivot], quickSort($right));
}
// 示例用法:
$unsortedArray = [5, 2, 8, 1, 9, 4, 7, 3, 6];
$sortedArray = quickSort($unsortedArray);
echo "未排序的数组: " . implode(", ", $unsortedArray) . "\n";
echo "排序后的数组: " . implode(", ", $sortedArray) . "\n";
这段代码运行良好,没有ChatGPT的问题,还做了小优化,如将数组长度存于变量,避免多次计算。
Gemini还详细解释了代码功能,提到基准“为了简单起见,使用第一个元素作为基准。虽然其他基准选择策略(如随机基准)可以提高平均性能,但这是一种清晰且常见的实现方式”,这对基准选择策略的观察很到位。
3. GitHub CoPilot
GitHub CoPilot最近开始免费提供使用(有限数量的响应),有多个可用模型。它是专门的代码补全工具,我公司将其纳入分析。该工具可通过GitHub网站使用,也能嵌入许多集成开发环境(IDE)用于项目开发。
我公司尝试用Azure的GPT 4o模型,看看它处理这个问题的表现。以下是快速排序问题的结果:
function quicksort(array $array): array {
// 基本情况:元素个数为0或1的数组已经是有序的
if (count($array) < 2) {
return $array;
}
// 选择基准元素
$pivot = $array[0];
// 将数组划分为三部分
$less = []; // 小于基准的元素
$greater = []; // 大于基准的元素
for ($i = 1; $i < count($array); $i++) {
if ($array[$i] <= $pivot) {
$less[] = $array[$i];
} else {
$greater[] = $array[$i];
}
}
// 递归地对分区进行排序,并将它们与基准合并
return array_merge(quicksort($less), [$pivot], quicksort($greater));
}
// 示例用法:
$array = [3, 6, 8, 10, 1, 2, 1];
$sortedArray = quicksort($array);
echo "排序后的数组: " . implode(", ", $sortedArray);
这个实现和Gemini生成的代码几乎一样,让人怀疑它们是否源于同一代码源。最后的示例数字来自ChatGPT的输出。
4. Codeium
Codeium可在网站使用,也能集成到40多个集成开发环境(IDE),集成数量比CoPilot多。目前不清楚它如何创建自己的模型,也不确定它是否是另一个人工智能系统的包装。
以下是快速排序问题的结果:
function quicksort($array) {
if (count($array) < 2) {
return $array;
}
$pivot = $array[0];
$left = $right = [];
for ($i = 1; $i < count($array); $i++) {
if ($array[$i] < $pivot) {
$left[] = $array[$i];
} else {
$right[] = $array[$i];
}
}
return array_merge(quicksort($left), [$pivot], quicksort($right));
}
// 使用示例
$array = [3, 6, 8, 10, 1, 2, 1];
$sortedArray = quicksort($array);
print_r($sortedArray);
这段代码和CoPilot生成的完全相同,连最后示例的数字列表都一样。
5. JetBrains
我公司使用JetBrains的集成开发环境PHPStorm多年,它功能丰富且可靠。去年,JetBrains推出自家人工智能,可与一系列集成开发环境集成。我公司使用JetBrains的人工智能几周,结果不尽如人意,它常误解上下文,添加与目的不符的代码。
有次我公司编写代码,使用Drupal实体系统从Drupal数据库提取信息,尝试在主题层加载项目以显示页面相关信息。出于好奇,让人工智能处理代码,它添加的代码会遍历查看的所有实体,并将字段更新为静态值,这会破坏正在处理的网站。
那么快速排序算法呢?JetBrains的人工智能有提示功能,我公司借此得到以下代码:
function quicksort(array $array): array
{
if (count($array) < 2) {
return $array; // 基本情况:元素个数为0或1的数组已经是有序的
}
$pivot = $array[0]; // 选择基准(在这种情况下是数组的第一个元素)
$less = []; // 小于基准的元素
$greater = []; // 大于基准的元素
// 对数组进行分区
for ($i = 1, $len = count($array); $i < $len; $i++) {
if ($array[$i] <= $pivot) {
$less[] = $array[$i];
} else {
$greater[] = $array[$i];
}
}
// 递归地对两个子数组进行排序并合并
return array_merge(quicksort($less), [$pivot], quicksort($greater));
}
这段代码运行正常,但和Gemini、CoPilot和Codeium的结果几乎一样,注释措辞也相似。
6. 服务分析
奇怪的是,这些聊天机器人的输出是不同系统输出的组合。我公司搜索生成的输出,想找出最初来源。Gemini、CoPilot、Codeium和JetBrains使用的快速排序算法似乎基于一篇11年前发表在/r/dailyprogrammer上的Reddit帖子。ChatGPT生成的快速排序代码似乎来自该帖子中的一个示例。
还有,数字序列“[3, 6, 8, 10, 1, 2, 1]”在很多讨论排序算法(包括快速排序)的网站都会出现。这些大语言模型似乎是将多个不同来源的输出进行了组合。
虽然这些示例看起来不错,但只是复制和改写互联网上的现有示例,有些示例有缺陷,却被直接复制,没有真正理解。在我公司看来,这就像多了些步骤的复制粘贴。
三、使用人工智能进行编程的优点
以下是程序员使用人工智能的一些积极方面:
- 可以用普通文本与之交互。
- 能为(简单的)代码生成解释,逐行展示代码功能。
- 可快速生成简单或常规问题的解决方案。
说实话,我公司想不出使用人工智能编程还有其他优点。接下来看看缺点。
四、使用人工智能进行编程的缺点
以下是程序员使用人工智能的一些缺点:
-
人工智能实际上并不理解你提出的问题,只是看似理解并生成语言,让人觉得它们已完全掌握。
涉及数学的任务就是很好的例子。大语言模型不理解数学,执行数学函数时易犯大错。因为它们只是复制数据中看到的内容,若很多人写“1 + 1 = 3”,大语言模型就会将其当作“事实”接受并复制。
一些人工智能模型会添加规则,让人工智能面对某些问题时遵循,但这不能完全解决问题。
当内容包含统计数据,且简单百分比加起来不等于100%时,就明显是人工智能生成的。在复杂数学和代数问题中,这个问题更严重,因为问题中的数字被变量赋值取代。
-
像ChatGPT等人工智能的大量数据来自开源项目和在线资源。ChatGPT未明确说明训练数据来源,但从上面的例子可知,它们是从网络获取数据。
问题在于,绝大多数这样的代码要么高度依赖上下文,要么质量不高。这并非贬低开源,只是免费获取的源代码的现状。每一个精心制作、代码质量高(有编码标准和测试)的开源项目,都有几十个看起来像是被故意混淆的WordPress插件。
这导致人工智能引擎复制劣质代码,因为这些代码在“统计上具有显著性”。它会认为WordPress插件糟糕的代码质量就是编写代码的方式,因为大多数代码如此。
有“热度”等设置,可从API选择不同令牌完成任务,但这无法解决问题,最终会混合代码示例,产生无意义的结果。
-
人工智能的“幻觉”在生成代码时很危险,可能让开发人员浪费时间将其生成的代码融入系统。人工智能常让开发人员创建对系统无影响的文件。
我公司从不同人工智能得到过各种无意义的结果,从不存在的文件到将PHP和YAML语法混在一个文件中的情况都有,显然它们不理解文件结构和工作原理。
我公司有个明显例子,让ChatGPT为Drupal SearchAPI编写插件,它建议创建一个*.plugin.yml文件,但实际上不存在该文件。可以想象,不熟悉该系统的开发人员添加此文件后,会疑惑为何更改未被系统识别,接着花数小时调试。
-
人工智能给出的答案“刚好”错到让不了解该主题的人难以察觉。
这更微妙,与写作相关。若让人工智能就某个主题生成文档,可能需要是该主题的专家才能发现错误。
例如,我公司让ChatGPT写一篇关于Drupal日志服务的文章,文章语法和结构不错,但查看细节时,发现毫无意义。不熟悉该系统的初学者会信以为真,实际上这份文档弊大于利。
-
人工智能实际上不理解系统架构,只“了解”编程的一些小方面,让其生成超过几行的代码会产生不可预测的结果。
系统越复杂,人工智能越难生成适合的代码。让人工智能用多种语言生成一个创建CRUD系统的代码很容易,因为互联网上有很多例子。但要与专业API集成,或创建多个对象模式协同工作的系统,我公司还没让任何人工智能给出连贯的答案。
-
依赖人工智能意味着要么之后重写代码,要么将自己不太理解、无法维护的代码集成到应用程序中,从长远看,这对技能和代码库都有不利影响。
将自己不理解且需负责的代码添加到项目中,肯定会出问题。
- 研究表明,使用人工智能生成代码时,代码变更率会增加30%。“代码变更率”指提交到系统后又被更改的代码,使用人工智能生成代码的团队比不使用的团队更改代码的频率高30%。这项研究针对CoPilot,但问题普遍存在。若在未完全理解和测试的情况下将人工智能生成的代码集成到应用程序中,肯定会引入漏洞。
-
人工智能聊天机器人曾被发现泄露敏感信息。与聊天机器人的交互会用于训练人工智能,这意味着向这些系统输入代码,很可能这些代码会成为其他用户问题的答案。
虽然可以说永远不向聊天机器人输入敏感信息或知识产权,但随着与集成开发环境的集成,人工智能易读取源代码。必须确保专有代码不被上传或用于训练人工智能。
- 最后,也是关键一点,使用人工智能对环境有影响。训练和使用人工智能消耗大量资源。据估计,ChatGPT每给出一个响应,就需消耗一升水来产生结果。我公司无法支持一种为生成看似正确的文本而破坏世界的技术。
还有其他问题,本文只关注编程方面。
五、我会使用人工智能吗?
坦率地说,我公司不会。
我公司乐于使用一些基本的自动补全功能,但让人工智能编写代码似乎会带来麻烦。作为专业程序员,需要完全理解编写的所有代码以及代码所在系统的上下文。
让人工智能编写代码会面临一些难以发现的漏洞。我公司也犹豫使用人工智能,因为知道会变得自满并产生依赖,这最终会影响学习过程。
我公司特别为依赖人工智能的初级开发者感到遗憾,因为这会限制他们作为程序员的成长。不亲自编写代码、不犯错、不总结错误,他们难以进步。
我公司遇到问题向不同人工智能寻求帮助时,得到的答案要么胡言乱语,要么代码无法阅读,要么完全错误。即使是简单的重新格式化文件任务,结果也毫无意义,浪费时间。
关键在于时间。人们常宣传使用人工智能代理能“节省时间”,但我公司没看到证据支持。
我公司还经常处理大量专有代码,因人工智能代理过度活跃而意外泄露代码的可能性让我公司担忧,这可能违反保密协议,影响职业生涯。
至于让人工智能写文章,我公司也坚决拒绝。
对于#!代码,我公司早就决定,永远不使用自动写作或人工智能代理写文章,要确保创作的文章质量达到高标准。因此,没考虑过为网站进行内容创作甚至自动总结内容。
我公司偶尔在其他网站(大多是Medium)看到一些文章,乍看不错,但仔细检查会发现毫无意义,怀疑这些文章是自动生成后未经思考就发布的。我公司不想与通过生成人工智能复制内容欺骗读者的欺诈性网站有任何关联。
明确一点,我公司永远不会使用人工智能为网站生成内容,也不接受其他作者使用人工智能生成的内容,包括图片或其他艺术作品。若需要创作图片,会自己创作或委托他人。


