龙空技术网

面向开发者的 AI:是未来还是现实?

InfoQ 659

前言:

而今朋友们对“非剥夺优先级算法例题”大体比较重视,我们都需要剖析一些“非剥夺优先级算法例题”的相关知识。那么小编也在网上网罗了一些关于“非剥夺优先级算法例题””的相关资讯,希望大家能喜欢,同学们一起来学习一下吧!

人们在日常生活和工作中越来越多地接触到 AI。JetBrains是一家为程序员开发工具的公司,我们认为软件开发行业也处在这样的趋势中。

AI 的两种用途:

取代人类,完全自动化他们的一些工作。增强人类,帮助他们保持关键地位。

算法已经能够自己编写代码了,但人类开发者不需要担心会立即被取代。

之所以这么说,并不是因为人类不可能教会计算机取代程序员所需的技能,而是因为这是不切实际的。

限制 AI 发展的三大因素:

有限的训练数据可用性。有限的计算资源。算法和人类之间接口的复杂性。

为了增强人类程序员的工作,许多普通的任务,如代码补全、代码搜索和错误检测,现在都通过机器学习来提供帮助。

图 1. AI 应用方法和每一种方法的困境

人类如何看待 AI?

当人们听到“AI”这个词时,他们通常会想到计算机将取代人类,与人类执行同样的任务,并比人类做得更好:更快、更便宜、质量更高,或者所有这些结合在一起。这类任务包括下象棋或围棋、写诗和开车。

有些人希望计算机能够将他们从日常繁重的工作中解放出来,而另一些人则持怀疑态度。后者可能会声称:机器远不能与人类匹敌。

比如,类似“你如何教会计算机做这些事情?”这样的话往往暗示着“你做不到”。以下是过去人们提出的一些类似的疑问:

围棋的合理步数超过了可用的计算资源。你如何取代人类的直觉?在这篇 1997 年发表的文章中,专家估计这需要一百年时间。你如何让一辆自动驾驶汽车看到潮湿的路面并减速?

计算机已经会玩围棋和开车了,所以这些问题现在已经过时了。这让我们有理由相信,这类仍然悬而未决的问题最终也会得到解答。无论是哪个专业领域,计算机比我们大多数人认为的更接近人类的技能。

然而,取代人类并不是权宜之计。AI 开发者不会与人类展开竞争,他们会选择不同的产品策略,尝试使用算法来增加程序员的工作,提高他们的生产力。

在软件开发领域,我们已经清楚地看到 AI 可以执行人工任务,也可以增加程序员的工作。

取代人类程序员

GitHub Copilot(由 OpenAI 提供支持)的发布再次激起有关计算机何时或是否将取代人类程序员的讨论。那些认为计算机不可能取代人类的怀疑论者总是会问:

你如何向机器解释你的程序应该做什么?

答案很简单。你可以使用自然语言定义你想要的内容,为函数提供一个名字,并(可选地)编写几行代码来启动函数。Copilot 会填补余下的内容,就像一个真正的程序员一样。

有些人对智能的 Copilot 感到很满意,有些人则会抓住它的小问题,并认为这些问题足以表明在可预见的未来仍然需要人类程序员。还有一群人也注意到了同样的问题,但得出的结论是:Copilot 是一个可怕而危险的工具,所以不应该去碰它。

他们所指的主要缺陷是什么?

Copilot 生成的代码通常很冗长,难以阅读。

代码清晰度很重要,因为对于开发人员来说,读代码比写代码更重要。在大多数情况下,程序员需要在已有代码(通常是其他人编写的)的基础上添加新功能。对于这种情况,写代码就像是给老房子增加一个新房间。你必须确定增加新房间是否会破坏平衡并导致整座房屋倒塌。如果它是安全的,你仍然需要了解现有的房屋结构,并加以修改,以便在其上增加新房间。程序员的大部分时间就是在“现有房屋”上增加“新房间”。

R. Minelli、A. Mochi 和 M. Lanza发现,程序员花在理解代码上的时间大约占 70%,而写代码只占大约 5%。基于此类研究,我们可以看到开发人员工作时间的分布,如图 2 所示。

图 2. 程序员在工作中花费的时间,按活动分类

冗长和含糊不清的机器生成代码可能会让本已难以理解的部分更加晦涩难懂。

人类的认知负载仍然存在:程序员仍然需要理解算法。计算机设定的节奏人类能保持多久?让 AI 来编写代码可能会加快处理小任务的速度,但不一定会加快大型项目的速度。

我们将其与上世纪 70 年代出现的版本控制系统做一下对比。追踪和回退变更的能力极大地扩大了人们理解代码的范围,使大型团队合作成为可能,也因此可以开发出更复杂的系统。这是整个行业的变革。

Copilot 是展示 AI 潜力的一项优势的研究成果。它做到了许多人认为不可能的事情。然而,我们并不指望这些工具能够在短期内重新定义程序员的职业。

帮助人类程序员

虽然 Copilot 是 AI 领域的一项与编程相关的突破,但它既不是行业革命,也不能取代人类工作。请记住,这样的变革可能会在某一时刻发生,但我们仍然需要继续改进现有的软件开发过程。帮助程序员更有效地执行小任务是 AI 的一个广阔的应用领域。

软件开发人员使用的工具通常有严格的规则(“启发式”),但没有 AI 的成分。随着每个工具提供越来越多的功能,规则变得越来越复杂。最终,人类不可能理解所有东西,也不知道如何改变工具,而这恰恰是 AI 可以提供帮助的地方。

代码补全

当你在谷歌搜索输入框输入搜索关键字时,它会向你建议完整的搜索选项。源代码编辑器为程序员提供了类似的功能。

代码补全的第一个版本出现在很久以前,可能是在某某世纪,主要是通过计算项目中出现的单词的频率来实现的。它们根据用户输入的开头字符显示出现频率最高的单词。这种基于频率的方法还不错,可以提高工作效率。多年来,人们在频率的基础上使用了一些启发式算法来改进补全建议,但为了精确地提供用户想要的单词,我们使用机器学习对补全建议进行排序。

因为用来确定最佳补全建议的信息太过丰富,所以我们不可能创建出一个将所有这些都考虑在内的确定性算法。我们不得不处理很多特殊情况。

例如,根据一般性规则,标记的定义与程序员当前编辑的位置越接近,就越有可能是这个标记。而且,标准语言库可以按流行程度排序,流行程度最低的库的标记将被剥夺优先级。综上所述,假设你用 Java 开发了一个源代码编辑器(我们在 JetBrains 就是做这个的),并输入“Co”。以下两个建议你会选择哪一个?

一方面,我们确实在编辑器中使用了红黑树。另一方面,java.awt 包在行业中很少被使用。但是,在我们的项目中,“Color”很可能是指 java.awt.Color。

影响补全建议排序的因素有成百上千个。补全建议是用户项目中定义的符号、标准语言库还或导入的第三方库?补全建议插入的地方是在一行的开头还是中间?在这个位置前面有没有点号?用户平均每天工作多长时间?他们现在是否在另一个编辑器标签中打开了补全建议的定义?

借助机器学习,我们可以用半自动化的方式提取模式,在不可能明确列出所有依赖关系的情况下将所有这些因素都考虑在内。

更进一步,我们还可以使用 AI 生成较小的代码片段。如果编辑器可以补全一整行,而不是一个单词,那么在开发速度和认知负载之间就有了一个很好的权衡:

图 3. 一个代码补全的例子。不只是建议一个单词

一些公司将这一功能作为其业务的核心。例如,TabNine和Kite将他们开发的软件作为编辑器插件发行,帮助程序员“以 AI 的方式”补全代码行。

教用户使用新功能

源代码编辑器是一种复杂的软件,程序员可以执行数以百计的操作来提高生产力。可惜的是,程序员不可能了解所有这些操作。

我们可以在编辑器启动时显示提示,但要在使用编辑器时回想这些提示可能很困难。程序员通常有 50 多个最喜欢使用的命令。有了智能提示,我们可以根据用户的工作模式和习惯为他们提供两到三个特别有用的操作。

AI 可以用来创建这些个性化的建议。例如,当且仅当程序员经常在同一个屏幕中执行剪切和粘贴操作时,我们就可以告诉他们如何更好地进行代码移动操作:

图 4. “代码移动”操作提示

实现这个特性最直接的方法是使用“协同过滤”。音乐、视频、书籍和商品等现代推荐系统都在使用它。它有两个基本的步骤:

找到与指定用户“相似”的用户。找出这些用户做了哪些指定用户还没有做的事情,并根据这些差异给出建议。

对于内容推荐,找到相似的用户是相当简单的:如果我们的目标用户与其他一组人喜欢相同的 10 部电影,但没看过这个组中所有人都喜欢的电影,那么推荐这部电影就一个相当安全的押注。唯一需要注意的是要避免那些几乎每个人都给予正面评价的超级受欢迎的电影。喜欢《教父》或《阿甘正传》并不代表用户的喜好。

对于源代码编辑器,就有点困难了。因为没有相同类型或相同演员的特征,我们必须分析较小的行为模式。用户花了多少时间调试?他们多久编辑一次已有的代码?他们打字有多快?他们是在编写代码之前还是之后编写测试用例?将这些因素都考虑在内,就可以确定用户之间的相似性,并根据已知的行为模式推荐有用的工具。

搜索代码

搜索是许多软件产品(从 Web 搜索引擎到在线商店)都存在的一个功能。源代码编辑器也有这个功能:开发人员经常需要在他们的代码、文档和工具配置选项中搜索一些东西。这些信息属于不同的类型,用户需要在开发工具的不同位置来搜索它们。

我们希望在源代码编辑器中提供一个统一的搜索功能,用于查找上述的任意一种信息,并把同义词和拼写错误考虑在内。因为有很多人致力于研究搜索算法,人们希望存在一个标准的可重用解决方案,但是,每个领域都有自己的特点,所以需要单独开发搜索功能。

当项目中不同类型的信息具有相似的名字时,复杂性就出现了。当用户在搜索框中输入“format”,并他们的项目中有一个名为 Formatter.java 的文件,那么他们是在查找这个文件还是在查找标准格式库函数,抑或是查找可以格式化代码的 IDE 功能?

机器学习将不同来源的搜索结果混合在一起并进行权衡。影响决策的因素包括文本匹配、用户的搜索历史和他们以前的偏好(例如,他们曾经点击过文件搜索结果吗?)、用户项目的内容,以及用户在进行搜索之前所编辑的内容。开发一个可以考虑所有这些因素的确定性算法看起来是不可行的,而机器学习可以自动提取其中的模式。

AI 的权衡

将所有 AI 为用户生产力带来的微小改进加在一起,可以带来令人印象深刻的整体提升。然而,这是有代价的。

基于 AI 的系统在大多数情况下运行良好,但在某些情况下也会提供奇怪的结果。向用户提供这样的结果会失去一些用户的信任。每次用 AI 驱动的决策系统取代严格的规则时,我们都必须决定是否要做出权衡。我们可以提高平均决策质量,但也可能会失去一些用户的信任。

如果能建立一个完美无瑕的系统,不会因为糟糕的建议而失去用户的信任,那当然很好,但要做到这一点,还存在一些障碍。

通往完美 AI 道路上的障碍

训练数据不可用

许多机器学习算法在训练阶段需要样本数据,而且数据集的质量至关重要。通常,我们知道需要获取哪些数据,但获取这些数据要么代价高昂,要么是非法的。

代码生成任务(无论是 IDE 的自动补全还是用 Copilot 生成整个功能)需要有用于训练的源代码,那么使用 GitHub 上的开源代码库似乎是很自然的事。然而,这些代码库有许可方面的限制,这些许可可能对衍生品有额外的要求。

这给我们留下了两大问题:我们的 AI 算法是从我们用来训练它的代码衍生出来的吗?这个算法生成的代码是衍生品吗?

一方面,AI 算法作者并没有将任何内容复制到算法中。另一方面,神经网络不能独立思考。它生成的所有代码都是它在学习阶段看到的片段的组合。它甚至可以生成看起来与训练数据集完全相同的代码片段。关键是,即使看起来独立的代码片段也并不比复制品更独立。

这是个新问题,我们还没有看到任何法律方面的裁决。这种不确定性让产品开发人员小心翼翼:他们不希望在未来可能成为非法的东西上大举投入。

我们在开发代码补全系统时也遇到了同样的问题。除了潜在的法律限制之外,还有技术上的困难。我们在开源代码库中找到的代码在某种意义上是“完整的”。它们通常都可以通过编译,可以通过简单的测试,格式清晰,不包含重复块或临时调试内容。然而,我们在编辑器中处理的代码大多数时候是不“完整”的。因此,我们从开源代码库中获得的训练数据与开发条件不匹配。

我们通过使用来自我们产品的使用统计数据来解决这些问题。为了让这些数据完全匿名,我们做了很多努力,但最终一切都很顺利。你可以在 JetBrains 的这篇博文中了解更多的技术细节。

这些只是人们在为 AI 算法收集训练数据时面临的几种示例情况。

资源需求

AI 算法非常渴求资源。这种渴求在学习和探索阶段有着不同的含义。资源限制在学习阶段给算法开发人员带来了额外的成本,他们需要决定是否在硬件方面投入。但在探索阶段,限制因素不是算法开发人员的资源,而是用户的资源。

探索阶段的资源需求标准解决方案是将资源密集型计算转移到远程集群上。我们的客户通常希望将源代码保存在受保护的网络中,因此使用远程服务器通常是不可能的。这意味着我们的算法必须运行在用户电脑上的源代码编辑器中。编辑器提供了很多特性,并且已经消耗了相当多的资源,所以每个新分配的字节都不能随意浪费掉。

普通软件开发人员和机器学习开发人员对资源的看法非常不同。下面的故事可以说明这种差异有多大。

当我们第一次用机器学习取代基于规则的代码补全功能时,负责这项任务的团队将额外的内存需求减少到了 1.5MB。团队认为他们将内存需求降到了极致,并为此感到自豪。当其他人得知这件事时,他们的反应很有趣:

与我们一起合作的 AI 研究人员说:“1.5MB?你一定是在开玩笑!至少 1GB 起步才行!”

传统的工具开发人员在评审了这个变化后说:“1.5MB?为什么需要这么多?”

研究人员通常假设资源是无限的,而产品必须运行在可用的硬件上。这就是为什么 AI 领域的突破性研究成果难以产品化的原因之一。

AI 和用户之间的接口

即使可以在远程执行,在远程服务器而不是客户的机器上运行 AI 也可能存在重大的可用性问题。

任何延迟对用户来说都是无法忍受的,特别是对于非常小的事情。因此,在使用代码补全、功能推荐和其他 AI 驱动的特性时,绝对要杜绝到服务器的往返。

即使速度足够快,AI 驱动的功能也必须无缝地融入到用户的工作流中,而不是分散用户的注意力。

例如,我们可以给用户的代码找 Bug。乍一看,这似乎是用户可能会接受的功能,但要在正确的时间向用户报告 Bug 是一个巨大的挑战。当用户正在埋头写代码时提醒他们,只会分散他们的注意力,并可能导致他们禁用这个特性。我们必须抓住程序员已经完成了一大块工作那一刻,在他们处于想要检查代码是否有问题的精神状态下向他们报告 Bug。

或许,我们可以用一个 AI 算法来决定何时展示另一个 AI 算法的结果?

对未来的期待

AI 正在进入软件开发领域,就像它进入其他领域一样,试图模仿人类并增强人类的工作能力。

计算机现在可以写代码,但我们不认为这是一场行业变革。计算机写代码的能力不足以取代人类程序员。人类能够思考复杂的软件组件交互,这种思考能力是至关重要的,而 AI 还无法做到。

不过,有很多东西可以使用机器学习来实现小的改进,把这些小改进累积起来,可以大大提高软件开发人员的工作效率。软件开发工具公司正在迅速发展将 AI 解决方案产品化的能力,因此,我们预计在不久的将来会出现更多这样的解决方案。

作者简介:

Nikita Povarov 是 JetBrains 的数据分析和机器学习团队负责人。他主要参与 ML 项目,在没有 A/B 测试的情况下为公司决策开发分析流程。自 2012 年以来,他一直是 JetBrains 计算机科学中心的讲师。2011 年至 2015 年,Nikita 在 Yandex 担任数据分析师,专注于 A/B 测试系统。

标签: #非剥夺优先级算法例题