摘要
面板成员讨论工作流程、员工影响以及利用不同的工具、框架和服务将人工智能集成到Java应用程序中。
简介
Asir Selvasingh - Microsoft Azure Java 主要架构师 Jonathan Schneider - Moderne 联合创始人兼首席执行官 Dov Katz - 摩根士丹利董事总经理、杰出工程师 Svetlana Zemlyanskaya - JetBrains 机器学习工程师 主持:Erik Costlow - InfoQ 编辑部成员 | Azul 产品经理
关于大会
InfoQ Live 是一个专为现代软件从业人员设计的虚拟活动。 参与由业内顶尖专家主持的研讨会。 在我们的可选 InfoQ 圆桌讨论中听取软件领导者的见解。
对话记录
科斯特洛:我们将广泛讨论如何利用人工智能为自己服务,以及如何将其集成到应用程序中,构建一些几年前你可能无法建立的东西。
泽姆利亚ńska:我是斯韦特兰娜。我在JetBrains领导创新团队。我们负责实施并提供工具和不同的仪器来测量和尝试AI系统功能的质量。我最初在JetBrains是一名Java开发人员。我在这一行工作已经超过10年了。过去的4年里,我一直专注于应用机器学习来改进开发工具。
Selvasingh:我是来自微软的Asir Selvasingh。在微软,我负责Azure上的Java业务,包括开发者和客户需要的所有内容,以在Azure上构建现代化的人工智能应用。我自己也是一名Java开发人员。我在1995年就开始接触JDK 1了。从那时起我就一直在享受与Java相关的各种工作。过去20年来我一直效力于微软,并且一直专注于Java领域,特别是确保我们的客户能够在Azure上拥有所有必要的资源来构建这些应用程序。
凯茨:我的名字是多夫·凯茨。我在摩根士丹利工作,领导企业应用基础设施团队。我们专注于开发人员体验以及公司各种生产应用程序使用的编程语言栈。我在摩根士丹利已经工作了大约20年,具体来说已经超过这个时间,在多个技术和领导岗位上任职。我的实际编程经历主要从Java开始,所以我有丰富的历史经验,从构建聊天应用程序到交易系统再到DevOps等各个方面都有涉及。
施耐德:我是乔纳森·施耐德。我是公司Moderne的联合创始人。Moderne自动化大规模代码更改,以支持战略举措,使开发人员能够专注于功能开发。大约10年前,在担任Netflix工程工具团队成员时,我创立了OpenRewrite项目,该项目提供了基于规则的重构和批量重构技术。后来从Netflix转到了Spring团队,并在那里创建了Micrometer项目。在某种程度上,我是造成影响下游开发者的API更改问题的一部分,而现在我正在努力解决这些问题。最近被选为Java冠军。
科斯特洛:我是埃里克·科斯特洛。我是InfoQJava团队的编辑之一。我还负责Azul的产品管理,特别是AzulJVMs,并运行一个叫做Intelligence Cloud的服务,它帮助人们识别应用程序中未使用的代码。
何时何地使用人工智能
人工智能通常被认为是一项非常新的技术,所以我认为很多人在关注它,但可能不知道何时以及在哪里使用它。当出现新工具时,人们是如何弄清楚可以利用人工智能做什么以及哪些特定的问题领域适合使用它的。
Selvasingh:你刚才提到的人工智能领域非常广阔。突然间,这里变得很令人兴奋。其中一个最酷的事情是,在这些领域中,你可以使用它来进行人工智能辅助开发,或者将人工智能融入应用程序,我们称之为智能应用。智能应用非常有趣,因为它们集成了人工智能以增强功能并提供出色的用户体验。例如,如果你使用Azure OpenAI服务作为示例,可以有多种用途。一些顶级应用场景包括内容生成,人工智能可以帮助创建惊人的博客、文章和社交媒体帖子。你可以用它来进行摘要,快速准确地为你总结大量的信息。
另一个令人兴奋的功能是代码生成。AI可以生成代码片段,自动化许多任务。此外,语义搜索通过理解查询的上下文和含义来改进搜索结果。有很多惊人的例子。如果你在领英上,你可能已经看到了很多这样的内容。有许多用户发布的关于AI的文章。我引用几个例子让你了解一些背景信息。例如,梅赛德斯-奔驰使用AI(特别是在Azure平台上)创建了一些连接型驾驶汽车。它们现代化了软件开发流程,使他们能够快速更新和发布新功能。这包括在车载助手中加入生成式AI的能力,它会增强你在驾驶时的体验。在这里考虑的因素是像这样的连接产品,可以持续创新、进行实时处理并应用负责任的人工智能。
另一个我可以引用的例子是美国航空公司,他们现代化了他们的客户中心。他们在Azure上与OpenAI一起实现了这一目标。他们处理数百万条实时消息和服务电话,现在通过使用人工智能,他们减少了出租车时间(这里应指航班滑行或等待时间)。他们能够节省燃油并给乘客额外的时间来赶上他们的下一个航班。在那里,关键的考虑因素包括大规模交易、确保符合所有标准以及分布式系统和用于自动化许多事务的人工智能。这些例子展示了AI如何被用来创建驱动出色业务成果的智能应用程序,并且它改善了最终用户(如果作为乘客或司机,这是令人兴奋的)。如果你是今天的开发人员,参与人工智能开发是一个激动人心的时刻。
开始人工智能开发之旅
Costlow:作为开发人员,我们针对这个小组讨论的目标之一是面向正在构建Java应用程序的Java工程师。一旦我们确定要解决的问题,我们会从获取一个库或特定技术的角度入手,使用这些技术来尝试解决问题。有哪些关键的库可以让人们用来开始尝试人工智能开发呢?
施耐德:我对LangChain4j的广度和文档印象深刻,特别是它支持许多不同的提供商,并且似乎与大多数最近的技术(如函数调用)保持同步,这些技术已经融入了较为知名的LangChain Python库。
Selvasingh:LangChain 是一个非常好的例子。如果你是一名 Spring 开发者,你也可以使用 Spring AI。他们已经将其做得非常容易,几乎就像普及化了一样,所以任何应用程序开发者都可以轻松上手。如果你正在使用 Quarkus 或 Jakarta EE。正如 Jonathan 所说,LangChain4j 非常棒。微软也有 Semantic Kernel。它可以帮助你更快地构建出色的应用程序。
施耐德:如果你是一名Java开发者,不要灰心。这不仅仅是为了Python用户。为了迎头赶上,并且在某些情况下超越底层库的质量和广度,已经做了很多工作。
AI如何造福Java工程师
Costlow:我非常喜欢Quarkus,但我还没有尝试过任何AI集成的功能。说到将AI整合到应用程序中或使用一些新技术时,我发现许多Java工程师的应用程序已经存在很长时间了,所以我们往往在维护现有的应用上工作,可能因为技术债务积累了很多年,这使得应用程序的维护占据了大量时间,这些时间本来可以用来做一些有趣的事情,比如学习AI。我们可以讨论一下Java工程师如何直接利用人工智能来帮助自己,而不仅仅是将AI集成到用户的应用程序中,而是我们作为Java工程师应该如何从中受益?
施耐德:说到迁移,作为OpenRewrite的创始人,这是我们一直在努力解决的关键问题之一。开发团队无法交付足够的软件功能,因为他们被无尽的技术债务和技术漏洞所困扰,这些因素耗尽了他们的精力。我认为有趣的是,在我们开始在全新的代码创作流程中使用AI之后,这加速了长期以来向提高开发者生产力和编写新代码的趋势发展。自大约20年前IDE基于规则的重构引入以来,这是我们看到的最大的一步式增长。现在我们有更多代码搁置在一旁。
我认为我们总是将OpenRewrite配方视为一种高度准确的饼干切割器,可以制作这些低变化性的饼干。例如,你需要一个系统能够在证明准确的情况下,在我们多年来积累的数亿行代码中进行同样的更改。在一个银行客户那里,我们在单个仓库中完成了一次从Java 8到17的迁移,并影响了19,000个文件。想象一下每个文件都有可能出现幻觉的可能性。我们将精力集中在如何使用AI来帮助生成全新的配方上,而不是直接使用AI进行更改。换句话说,AI不是饼干切割器本身,它是制造工具和模具的人。
Costlow:对于从一个XML库迁移到另一个XML库这样的事情,由于在Java 8和Java 17之间该功能已被弃用,现在有了OpenRewrite规则集,这些规则集是由人工智能生成的一系列步骤函数,人们可以使用这些函数来实现自动化迁移,而不是手动完成这一过程。
施耐德:没错,是的。然后你想要在成千上万个仓库中大规模部署以消除这个问题。
科斯洛:因为确实,如果我们要进入每个文件修改导入项,更改函数以及所有相关内容,这将花费个别工程师很长的时间。
施耐德:没错。很无聊。
科斯特洛:是的,绝对不在我们可以做的事情的激动人心清单上,虽然也许在代码编译的时候你可以做点别的事情。
大规模人工智能的经验以及在代码维护中使用它的时机
多夫,我知道你用人工智能做了一些维护工作。你是如何决定是否使用AI来帮助完成这些工作的,或者是否分配人员来做这些工作的?然后,你在使用大规模人工智能时有哪些经验?
Katz:回到那个需要修改的极其枯燥的19000个文件的问题上。还有一个问题是不一致地进行修改会导致错误频发。当你查看卫生办公室希望你在软件状态下一年内完成的工作清单,再看看他们要求你实现的业务功能时,你会开始对自己说,我们必须找到一种更好的方法来做这件事,而不是让一群人不一致地、手动地去处理这些问题。我确实把这个问题分成了两类。一类是重构。或许这包括升级依赖项。
我将OpenRewrite归类为重构,尽管它实际上做得更多,但暂且简化问题来看。另一种情况是更换平台。你想要保留的代码往往需要进行重构;你不打算保留的代码则倾向于更换平台。更换平台可能包括从更改编程语言到彻底替换企业应用程序集成模式的整个实现,也许是从专有解决方案迁移到Spring集成或Apache Camel。这不仅仅是升级Java版本那么简单。对于此类问题,AI可以很好地帮助你找到正确的起点。我们实际上利用了生成式人工智能来帮助我们理解所做的事情,以便我们可以以不同的方式重新做一遍。请根据我的代码告诉我需求是什么,并且现在用不同的方法实现这些需求。这是个很好的开始。
那个计算无法扩展到19000个文件,等等,这非常昂贵。让我们回到重新设计的画板上,找出我们做了什么。我们能否创建一种确定性、可重复且可扩展的方法来解决它?我现在真的得出结论,在大规模解决问题时,你需要在工具链中使用多个工具。不是只有一个工具,并且它不会仅仅带你达到100%的目标。你需要知道如何正确地结合这些工具。一个很好的例子就是利用生成式AI来想象你想要做的事情,然后找出如何使用一些已知和可信的方法将它们规模化实现。这已经产生了巨大的不同。
我只是基于15000个代码库运行了一些数据,尝试进行Jonathan提到的Java升级,结果大约节省了50000个小时的时间,相当于这里25名全职顾问的工作量。这只是对Java从旧版本升级到21版本所做的工作。这是枯燥的部分。想象一下如果我还想做其他事情,比如使用AI技术,或者在这些现代Javas上进行操作。此外,我还需要更新许多其他的框架。有一些遗留问题需要解决。这还不包括JavaScript的更新和迁移到新的Angular版本以及尝试使用新版本所带来的挑战。CVE(常见漏洞和暴露)也在不断出现,你必须迅速作出反应。有很多不同的动机促使你要改变你的代码库,并且我认为人们应该配备一套工具组合并知道如何在适当的时候使用它们,以便以成本效益高、准确且可预测的方式大规模地解决这些问题。
科斯洛:你说你节省了五万小时吗?
Katz:五万小时,数以百万计的文件被修改。我们在考虑OpenRewrite的方法,而配方的好处是你可以直接问它们节省了多少时间。这种机制已经内置到了配方架构中,使得证明你节省了多长时间变得非常容易,如果它在最后输出可聚合值的话。它是这样的:修改多少个文件,修改多少个仓库,以及这里是避免了多少小时的工作量。即使误差达到50%,我也无所谓。这仍然比我希望我的高素质开发人员花在这问题上的时间要多得多。我相信即使准确性只有10%,我还是可以接受的。因为这些还是我不希望他们花费的时间。
施耐德:真正令人担忧的是这些变化范围之广。我们现在正在查看从 Spring Boot 2 到 3 的迁移指南,它现在有超过 2300 步。这些都是属性更改和其他一些特殊情况,我肯定我们还没有完全覆盖到所有内容。这就是我们在日常工作中给开发人员带来的认知负担。
Selvasingh:当我听到这些数字时,我想到的是GitHub Copilot。我知道开发者们都说他们很喜欢它。在这样的情况下,他们能够专注于真正重要的事情,比如回到设计、头脑风暴、协作和规划上。像搜索、记录文档、发现问题、修复问题、升级代码、编写测试等许多任务,在Jonathan谈到这些OpenRewrite配方时尤为明显,特别是在那些专注于从Java到Spring Boot 2到3的升级、Jakarta EE等方面的开发者中,他们持续不断地进行这样的工作时,你可以很容易地看到Copilot随着时间的推移帮助他们的身影。通过将这些配方和AI辅助功能整合在一起,它可以帮助开发者们更快地完成这些任务,并进而转向为应用程序添加智能。
科斯特洛:斯韦特兰娜,你在JetBrains上也参与了一些机器学习和AI助手功能的工作。工程师们用这些功能做了些什么?你都参与了哪些AI能力的开发工作?
zemlyanskaya:很多不同的功能,然后由于IntelliJ是一个历史悠久的产品,并且用户群体广泛,我们确实进行了一项研究,询问人们他们想要使用哪些功能,他们想自己做什么,以及他们希望将哪些任务交给AI?令人惊讶的是,最受欢迎的选择之一是他们希望将测试生成和编写提交信息、文档的任务交给AI。实际上,很多人并不愿意把编写代码的任务交给AI,因为这是他们的热情所在。这就是他们想要做的事情。
科斯特洛:关于AI提交信息有什么呢?比如说你可以自动总结提交内容并为它写一条不错的提交消息?
zemlyanskaya:是的,为什么不呢?它仍然无法从你的头脑中获取信息。如果你想添加信息,不仅包括更改了什么,还要包括为什么进行更改。在这种情况下,你可能需要额外的上下文,比如问题本身。这是一个正在进行中的工作,但所有人工智能工具在未来都会朝着这个方向发展。它们正在向不同的技术添加更多信息,并且能够将这些信息在仪表板上进行总结。
科斯特洛:就测试生成而言,有没有基于代码覆盖率的奖励系统?
泽姆兰斯卡娅:你是说要奖励AI还是开发者?
科斯特洛:AI为我生成测试绝对是对我的一种奖励。我在思考AI是如何写出覆盖更多代码的测试的。
zemlyanskaya:有一种方法,我们现在正在调查。我们还没有在生产环境中使用它。是的,我们在检查如何做到这一点?如何应用这些信息?首先,要衡量质量,因为这是一个棘手的部分,因为在AI生成代码的情况下,你不能简单地将预期结果与实际输出进行比较,因为解决同一个问题的方法太多了。需要稍微换一个方向,实际上尝试执行代码或编写测试并运行它们,或者计算一些关于代码的元信息。如果从语法上讲是正确的,它会生成多少个方法,如果你想要更简单的代码。测试覆盖率绝对是其中之一。
大规模代码重构及测试
科斯洛:在进行大规模代码重构的情况下,代码需要测试到什么程度?因为我经常和别人交流,大家都希望能达到100%的覆盖率,但实际上没人能做到。目标是达到90%,但大多数人也做不到。我们目前有一个中等水平的测试。如果你要做大规模的代码重构,你需要哪些测试才能对最终结果有信心呢?你也会重构测试吗?
Selvasingh:我与许多Java开发人员和客户讨论过这个特定问题。当他们刚开始时,如果是生产系统,比如库存系统或股票交易系统,通常已经有一套测试用例。无论这些测试是在零售单位、商店还是仓库中运行,或者是在运输途中进行的测试,所有这些测试都非常关键。随着项目的推进,他们会经历重构过程,无论是使用Jonathan提到的OpenRewrite食谱来升级,还是将大型单体应用拆分成微服务以使其更容易在云上扩展。即使他们把所有东西都分解了,在重新组合时,那些测试用例仍然非常重要。当涉及到代码级别的单元测试时,情况就会发生变化。这时,他们需要根据新代码生成新的测试用例。至于功能、集成、合规性等方面的测试用例,则保持不变,并且在从一个生产环境切换到另一个新生产环境之前,必须通过所有这些测试。
zemlyanskaya:我认为还有一个问题,你认为你的工作的最终成果是什么?有人可能会认为它是实际运行的代码,并且是你认为它应该做的事情。也有人会把测试作为这个成果的一部分,因为这也是无需定期更新的文档。大家都读过一年前正确的那些文档,但现在它们已经不再准确了。
施耐德:我认为,关于在大规模重构中获得信心的问题还有一个要素。我们没有提到的一点是,当一个OpenRewrite配方运行时,它是基于一种称为无损语义树(lossless semantic tree)的数据结构。这不仅仅包括代码的文本部分,还包括编译器为了解析依赖关系所知道的所有信息。与IDE中的内容非常相似,在IDE不索引操作时,它了解的内容比仅仅通过查看文本可见的信息要多得多。我们添加到LST的一些属性包括:该语句是否被覆盖了?
最近与Azul合作时,问题变成了某个语句是否可达。一个可达的语句在重构操作中的风险评分比不可达的要高。一个已经被覆盖的语句的风险评分比未被覆盖的要低。你可以对整个代码库进行大规模重构,并根据这些因素的组合计算出风险评分。它是否可达?它是否已被覆盖?然后可以优先合并那些风险评分最低的仓库,而将手动审查的重点放在风险评分最高的那些上。我认为我们永远无法在整个企业范围内达到同样的信心水平。
代码模块化、组件化和命名,利用AI技术
科斯特洛:是否有可能将代码模块化、组件化,甚至为这些模块命名?把一些庞大的东西拆分成小部分或模块,利用AI找出分割点。
施耐德:如果是关于命名的话,我希望我们在春令会的命名惯例上训练这些AI。那是有名的。那真的很长。
科斯洛:是的,然后将一切抽象化。
阿西尔,你表示你可以将某件事分解为不同的功能,以便在一定程度上模块化?
Selvasingh:是的,我认为这是正确的,无论是命名还是模块化。如果你使用的是GitHub Copilot,它会了解你组织的代码库。这样一来,如果你是一名开发人员,它可以帮助你快速上手。然后根据你自己内部和私有的代码提供相应的建议。这样你就知道方向了,并且它可以帮你把内容拆解开来。当你转向协作的工作环境时,它也帮助你们更有效地进行合作,无论是审查拉取请求还是生成出色的摘要以便其他人能够理解你的工作,这样一来就更容易管理和维护高质量的代码。
斯韦特兰娜提到的一个问题是,他们可能十年前就编写了文档,但代码库在不断变化,因此Copilot可以帮助你构建新的文档。它可以提出一些建议,无论是名称、模块化、升级还是协作,所有这些都会帮助到你。所有这些助手的目标是让你在处理任务列表时超级高效,这样你可以达到将AI增强的智能添加到你的应用程序中的阶段,从而生成更多的商业成果并提供出色的用户体验。
AI文档生成
科斯特洛:很多工程师都想向前发展,但我们确实有很多大规模的待办事项,所以可能无法去做我们想做的未来的事情。AI能否帮助我们通过生成文档来理解遗留代码?我们有没有针对这些材料进行记录的工具?
泽姆兰斯卡娅:我认为生成文档是不同AI系统中的一项标准功能。JetBrains的AI系统就包含了这一功能,我相信其他系统的AI也会包含这项功能。这是人们希望委托给AI的任务之一,并且这很有道理。
Katz:我认为当你给AI一些代码时,确实存在这样一种观点,即你可以倒推需求。这是我们进行的大量平台重构中非常有效的一种方法,我们在此过程中实验性地连接经过批准的生成式AI,一次处理项目的部分工作,因为显然你要处理token和所有计算边界限制的问题。你可以这样做,但你开始朝这个方向前进时,实际上是为了解决后续的正向工程问题而进行逆向工程。这种方法极其强大,只需问一下“这个东西做什么?”,然后用Python去实现它。这就像Perl到Python的转换,在这种情况下,并不总是每个方法都要转换成等效的方法,而是要用不同的语言更好地完成这项工作。因此,你可能需要倒推出一些英文的需求说明。这种方式对于我们实验这些方法来说确实非常有效。
科斯洛夫:是的,每过几年我就会看到一个新的COBOL到Java的转换工具出现。我认为我们目前还没用AI做过这种事情。作为一名人类,我绝对不想去做这样的事情。
施耐德:到目前为止,在这一轮讨论中,我们已经讨论了AI取代命名、测试和文档编写,而这三项可能是开发人员最不喜欢的任务。
科斯洛夫:把你不想做的事情都交给AI去做。这就是这次网络研讨会的结果,就是说,不要做那些你不再喜欢的事情了,让AI来做吧。
每个人都喜欢开《终结者》的玩笑,所以也许这就是原因。感觉我在那个代码里再也不想命名了。
施耐德:迁移。
泽姆兰斯卡娅:那么也许人工智能也不想那样做,反而会让我们再去这样做。
塞尔瓦辛格:它会感到无聊?
Katz:确实存在这样的使用场景,它超出了那些我们想避免做的或许不太有趣的任务。我们在其他用例中发现了我认为值得提及的情况。例如,如果你有架构学科,并且你在编写ADR(架构决策记录),并且你希望有人能确保这些记录确实遵循了你的架构原则等等内容。你想开始了解架构师会如何给你反馈。在GitHub生态系统中,我知道有很多关于拉取请求的机会。拉取请求审查通常包括初审和复审等概念,在这种情况下,AI应该只是充当初审的角色。你应该对经过AI审查的代码进行复查。将来没有必要去看未经AI审查的拉取请求审查结果。如果这些都是显而易见的事情,我不希望浪费时间在上面。这些是在SDLC中利用AI以提高你的时间价值感的好机会。在整个其余的SDLC过程中,确实有很多值得指出的良好用例。
Costlow:是的,因为我一直在代码质量检查工具方面做了很多工作,比如你们有PMD,有FindBugs,还有各种各样的工具,人们被期望运行这些工具,然后提交代码。你所说的则是,AI会审核代码,并提供类似人类评审时所给的上下文信息,以判断这段代码是否符合企业标准。
Katz:给我反馈。就像如果我让你写代码,你会作为AI为我编写一样,在我现在选择自己写代码的情况下(正如Svetlana所说,我们想亲自写代码),请给我关于我写的代码的反馈,因为我不让你们来写。里面可能有很好的建议。有时有一套标准。是的,你希望你的部门遵循一套标准。如果你不遵守这些标准,AI会指出这一点。并非所有的东西都能被写入一个你可以运行的适应性测试中。这可能会为你提供一些更为定性的评审。我认为这里有一些可以利用的机会,我相信我们会在开发者通常使用的软件产品空间里看到它们。
施耐德:我记得有一次一位首席工程师跟我说过,他说他觉得自己总是像个家长一样不停地告诉孩子们去捡起他们的袜子。我当时就想,“是的,我也是这种感觉。”当你好不容易把每个人都安排到你想要的位置上,比如重组或者新产品的团队进来之后,我们需要让他们感觉自己是在创造而不是在拾取,或者说不是在教别人如何拾取袜子之类的。
Selvasingh:当Dov提到AI审查的拉取请求时,我认为重要的是当AI在审阅拉取请求或编写这些总结时,如果它了解你组织的代码库,并且知道你们实施的标准,那么这会变得非常方便。开发人员甚至可以在打开拉取请求之前离线运行这些请求。然后AI可以说,我已经审查过了,一切看起来都没问题。之后开发者可以作为第二或第三审核者来查看这份审核。
科斯洛:它成为流水线中的评审者,而不仅仅是生成代码然后由人类评审的工具。
泽姆利亚斯卡娅:还要继续深入,让AI生成测试用例,然后让AI根据这些测试用例生成代码,再生成能够实际使刚刚编写出来的代码失败的测试用例,并且在这个循环中不断尝试优化我们得到的结果。我看到很多研究都在这个方向上进行。我相信在未来不久我们将能看到有趣的研究成果。
Spring升级和使用OpenRewrite管理共享库
Costlow:我在进行Spring升级时注意到的一个挑战是管理不同项目之间的共享库。OpenRewrite是否是升级这些共享库的正确解决方案,还是我们应该考虑使用AI来确保更新不会破坏API和应用程序?
施耐德:当你有共享库时,确实还存在一个编序问题,你需要先合并这些库然后再继续进行。我认为这就是为什么OpenRewrite在一个仓库上使用会变得困难的地方。这是我们作为Moderne一直在做的事情,比如允许一个食谱在整 Organizations 或整个业务单元上运行。通常情况下,这实际上是从影响分析开始的。一个食谱会说,这是项目之间依赖关系的序列或顺序,并且本质上也是合并的顺序。然后你按照这个顺序运行食谱,然后相应地进行合并。当你在一个仓库上运行一个食谱时,很容易只见树木不见森林。这确实是个问题。
回到Netflix,这与上面的话题有关。很多年前,工程团队几乎停滞不前,因为Google Guava(著名的guava库)。许多常用库和应用程序都使用它,两者都无法移动,因为可能会破坏对方。先移哪一个?你不能先移动库,否则会破坏应用。你也无法先移动应用,因为它会破坏库。我们实际上建立了一系列的方案,消除了这些不同版本之间变化的API表面区域,这样就不重要了。我们有效地打破了这种联系。然后你可以先移动库,或者先移动应用程序,一旦开始推进,大家就可以继续前进了。有趣的是,仅仅因为许多库都有对其的传递性依赖,这一个库几乎扼杀了所有向前发展的可能。
Katz:我认为,当你试图处理一个大型组织如仓库列表并寻找一个排序解决方案时,尤其是在当今软件供应链、SBOMs以及其他物料清单类型的产品或文件和格式方面集中注意力的情况下,一家能够摄取大量自己仓库的公司很可能已经了解了它们之间的相互关系,并且可以确定树状结构。然后你可以弄清楚,回到之前提出的问题上,共享库的正确顺序是什么?一种巧妙地打破链接的方法也非常有价值,但至少可以从这种机构知识中获益,以找到正确的顺序并以最少影响、最不具破坏性的方式推出这些内容。
AI的融合
Costlow:我想稍微向前推进一点。我们已经谈论了很多关于如何更新代码以便人们能够自行使用AI的话题。现在,我想谈谈集成AI服务的问题。或者在你们解决了维护问题,并且有了更多空闲时间来专注于一些有趣的商业功能和能提升工作效率的事情后,你们该如何利用AI做更多的事情呢?Svetlana,你所负责的产品有点独特,因为它在后台使用了AI,但你实际提供的则是让工程师们可以使用的AI工具。你可以谈谈将AI集成到应用程序中是如何工作的吗?本地机器上有哪些内容?哪些部分仍然需要后端服务支持?我们在将AI融入应用时应该了解些什么呢?
zemlyanskaya:首先,人工智能是一个非常具有争议性的主题,很多人渴望尝试它并看看它的能力。另一方面,也有很多人尽量避免使用它,不愿意进行任何AI测试或使用集成大量AI的产品。这两点都有道理。AI模糊了代码所有权的界限,不清楚最终的作品是由哪家公司还是个人所有。关键是要了解你的受众,理解你是在为谁服务,以及这些人是否真的愿意尝试它,或者他们会感到失望。基本上,如果他们习惯于自己完成的工作中有一部分会被委托给AI来处理,那么继续开发这些项目将不再像以前那样有趣和令人愉快。对于IntelliJ而言,这是一个拥有众多不同客户的大产品。我们实际上需要采取不同的策略。对于最重视隐私的客户来说,或者他们的员工不允许向第三方服务器发送代码,我们确实提供了完全本地化的解决方案。第三点是,这很棘手。你需要考虑模型大小。
你必须考虑已使用的内存,至少目前是这样。未来可能会发生变化,但至少现阶段还不可能拥有像ChatGPT那样能够做前沿工作的通用型AI。通常来说,本地机器和笔记本电脑还达不到这样的水平。可以做到的是缩小任务范围,使它变得更小,并让模型专注于解决一个特定的任务,或者是一两个任务。在这种情况下,从头开始训练或调整开源模型是完全可以实现的,并且其性能会与基于服务器的实现相媲美。现阶段我们有两个主要功能可以这样利用:一是完整的代码补全功能,该功能在Java中也提供,并作为JetBrains产品的一部分包含在内。由于这些操作已经在机器上运行,因此对我们来说没有额外的运行成本,因为它们已经包括在常规订阅中,用户无需为此支付任何额外费用。第二个是集成到“随处搜索”中的语义搜索功能,它是安全嵌入且完全本地化的解决方案。
是的,另一方面,仍然不可能做到所有事情都在本地完成,或者至少需要在那之上做很多额外的工作才能实现。我们也在探索基于服务器的应用程序,在这种情况下,我们会希望尽可能将逻辑移到服务器上,因为这会使我们更容易迭代和更新这些逻辑并更改模型或模型提供商。不可能使客户端完全合理化,但我们仍然拥有所有这些上下文。上下文是普通应用与直接使用AI之间的实际区别所在,通过改变提示来适应特定的人或特定的项目。
截至目前,与特定使用AI的个人相关的一切都在IDE内进行区分。可以由多个用户共享的内容通常发生在服务器上。例如,UI和UX显然在IDE部分,但也需要在这类情境中确定哪些部分是相关的、所使用的技术或语言以及适用于选定代码片段或自然语言查询的方法等。这些内容都是在IDE内部处理的。还有一个后处理阶段。我们如何将生成的代码应用到打开的文件上?这也是在IDE内完成的。在服务器端,我们与语言模型提供商进行了更多的集成。我们选择适当的模型和提示词,并强制执行针对公司业务逻辑的内部模型推断。我们还有文档索引,这些文档需要从IDE中访问。
Java开发人员所需的人工智能知识的深度和广度
Costlow:Asir,你提供了很多AI服务,比如Azure在后台为人们的应用程序提供了很多东西。对于许多Java工程师来说,我们知道他们倾向于学习与Java相关的周边知识。那么一个人需要了解多少关于人工智能的信息,又有多少可以专注于使用库或服务呢?
Selvasingh:他们需要知道多少?这是非常重要的一点。我将从说如果你是一名开发者,你可以今天就开始着手做起这一点开始。这非常重要。每一个应用都将通过AI被重新发明。将会创建以前不可能实现的新应用。机会非常高。当我们说到可以今天就起步时,在这里有不同的角色在发挥作用。不同的人在这里扮演着构建这些智能应用程序的关键角色。我有三个:AI工程师、数据工程师和应用开发者。我会说几句关于这个话题的话,然后深入探讨一个特定领域。AI工程师专注于开发和部署AI模型。数据工程师负责管理和处理数据,而数据科学家与机器学习工程师在此发挥极其关键的作用。数据科学家探索数据,发现洞察,并构建模型原型。
机器学习工程师负责训练、微调和部署模型,确保它们可以投入生产。然而,尽管有这些AI工程师和数据工程师,关注的焦点实际上在于应用程序开发者。因为我们的客户组织需要大量的应用开发者来注入这种智能。应用程序开发者将人工智能集成到应用程序中,创造出令人惊叹的智能解决方案。他们构建所有的用户界面、应用逻辑,并利用AI模型。这确保了人工智能功能能够无缝整合,提供流畅且直观的出色用户体验。在这种情况下,当这三个角色发挥作用时,三者会结合起来。
有一个应用程序平台,你可以在上面部署应用。还有一个数据平台,用于汇集所有数据。然后是AI服务,这三者结合起来。如果你是一名Java开发者,你可以从今天开始行动。如果你是一名Java开发者,现在正是最佳时机,因为许多企业应用都是用Java开发的,所以你可以从今天开始。你可以从今天开始集成到你的应用程序中。我想再次强调,如果你是一名Spring开发者,你可以使用Spring AI。他们使它变得非常简单。如果你在使用Quarkus、Jakarta EE等其他系统,你还可以使用LangChain4j。微软也提供了Semantic Kernel来帮助你构建这些应用。关键是你现在就可以开始,并且可以与不同角色的人合作,以最快的速度推进项目。
泽姆利亚斯卡娅:对于那些希望将AI集成到他们应用程序中的人,我还有一些建议。需要注意的事情有很多,但从我的角度来看,有两个主要方面确实很重要,因为使用大型语言模型既有好处也有挑战:很容易就能打造出一个可运行的原型。你只需花上几个小时就可以做出一些令人印象深刻的东西。你可以展示演示文稿,并且确实可以引起大家的兴趣。接下来的部分是从演示到生产级别的转换,质量是一个非常复杂的问题,许多产品无法达到这个阶段。这部分实际上很难预测,有时难以说清楚这有多难、需要多少时间以及是否真的能达到合适的水平。
这里有帮助的是,从一开始就围绕你的功能构建一个数据驱动的循环,有点像测试驱动开发,在开始实现功能时就考虑它应该是什么样的,期望的输入和输出是什么。在这种情况下,并不指望所有的测试都能通过,这是可以接受的。总是有些东西不会成功,这没关系。这样你可以实际进行测量。如果你想解决一个问题并调整提示语,当你修复它的时候,你需要确保没有破坏其他几件事。因为使用提示语时,有时你只是将双引号改为单引号,就可能使你的应用程序崩溃,并改变其格式化和所有返回的内容。
检查这一点并确保你的连续步骤不会以意想不到的方式使其变得更糟是很重要的。这也将允许你尝试不同的模型,因为在人工智能领域,很多事情发生得非常快。新的模型不断出现,旧的模型也会在很短的时间内被复制。一个人不能只依赖一个模型就说足够了,而是需要更新到新版本。如果这个过程可以半自动化并且易于实现的话,那么它就不会太复杂。不需要花费大量的时间来做这件事。第二部分,我认为非常重要的是利用你的经验,并且如何展示这些结果?因为我刚才说过,你不可能达到100%的准确性,这没关系,只要这种不准确被融入到整体用户体验中。必须正确设定期望值,让使用应用程序的人不要期待所有的建议都是完美的,但是也应该允许调整或可能拒绝这些建议。不应强迫用户接受它们。应该更像是指导,而不是强制某个过程。
保持与不同AI模型同步
科斯特洛:你是如何跟上你所拥有不同模型的更新的。就像你说的,有些模型会过时。
泽姆兰斯卡娅:我们确实有一些内部模型,但对于大多数控制功能,特别是与聊天相关的最先进的部分,我们使用的是外部版本,比如来自OpenAI或Google Cloud的模型提供商。在这种情况下,他们确实会发布新模型,但也会保留旧版模型。这里的情况是我们有一个评估新模型的过程,当有新的东西到来时,我们可以将其与我们的基准进行比较,并查看其在指标方面的表现如何,同时也要看看可能会遇到什么问题。也许某些功能在之前的版本中运行得很好,但在新版中效果不佳。
选择合适的AI模型
科斯洛:作为一名Java工程师,或者像Asir这样的应用程序的开发人员,你提到成为一名应用开发者的关键时刻,你是如何审视和评估选择哪种模型来解决问题的?这其中包含哪些因素?
Selvasingh:这是您的AI工程师可以帮到您的地方。您需要从商业需求开始,确定您要解决的问题。制定这些需求后,进入一个构想阶段来确定哪个模型可以帮助您。在Azure空间中,我们有一个AI工作室。在AI工作室里,您可以尝试各种模型。您可以与同事工程师一起或与用户群体一起举办创意研讨会。开始实验哪些模型将帮助您,无论是使用预构建的模型还是对其进行微调。如果您进行微调,则需要确定数据来源。您可以在将这些想法和实验付诸实践之前先进行所有这些工作,以确定什么有效。当最终将其引入应用程序时,重点将是最终用户的体验以及如何交付这一体验。
例如,如果你正在建立一家零售店,你的关键概念是如何填满购物车以及如何帮助他们下单或增加更多的商品到购物车中。你该如何使用模型,并构建这样一种体验来帮助顾客填充和扩展购物车,然后完成结账?因为有时候这些最终用户会跳出你的应用程序去别的地方查看。一旦他们离开,很可能就会转而访问其他在线商店。那么你应该怎样构建这些用户体验以保留最终用户的参与度呢?这时你就可以回到Azure AI Studio。所有模型都可以在那里获取,并且新的模型正在不断更新中。你可以在此运行创意工作坊。并开始与你的终端用户进行实验。然后你可以将这些体验引入应用程序并向您的最终用户提供服务。
科斯洛:用你的购物车示例来说,我可以运行购物车通过该系统的模拟,并查看它的建议是什么,然后根据哪个模型给我最好结果来选择我想要的模型。
Selvasingh:这也回到了你的业务需求上。你的需求应该是,你能增加多少个项目?像100个客户经过这个流程,90个客户下单了,80个客户下单了这样的情况?你可以从这些数据反向推导,然后在这里选择合适的模型。
科斯洛:我有一套成功的标准,那就是需要增加我的转化数量,所以让我选择一个目前能提高这些转化率的AI模型。然后当我有了转化之后,我会考虑如何让用户添加更多的商品到购物车中?哪个AI模型可以帮助我把更多商品放入购物车?然后我可以使用Azure AI Studio和LangChain4j之类的技术来构建我的应用程序。
Selvasingh:在这个过程中没有任何改变。你总是从你的目标、需求和使用场景开始,然后选择相应的技术。因为像微软这样的公司会提供大量的技术选项。你不一定要使用所有这些技术。你需要挑选符合你需求的技术,选择能够带你走向成功的技术,帮助你赚更多的钱。
施耐德:在选择模型时,我还注意到另一个特征,那就是我们通常不会只为某个体验选择一个模型,而是往往会选出多个模型,并开发一条管道,通过使用小型模型来限制搜索空间和因此所需的计算量。例如,我们开发了一个功能,用于推荐在一个代码库上运行哪个配方。如果我只给下一个10行代码让模型分析并说,“接下来该做什么?”“接下来该做什么?”,我们进行了一项研究,如果用一个平均大小的生成型模型来做这项工作的话,对于一个平均规模的企业单位来说,总共会诱导出75年的总延迟时间。那么我们应该如何限制搜索空间,以便不需要将这个代码库的所有片段都发送给这个模型呢?
相反,我们开发了一条管道,在这条管道中,首先我们将每个方法声明提取出来,嵌入、聚类并从聚类中选择样本,这样我们就不会对高度相似的方法问同样的问题。这些嵌入模型成本更低,更小,通常只需要1到2GB的RAM内存。你可以在本地运行它们,并且在边际成本为零的情况下运行它们。然后将更复杂的模型保留下来用于后续的生成部分。Svetlana之前提到过这一点,你可以选择小型模型来处理特定的小任务,然后再将大型模型留到最后阶段,在搜索空间被精细过滤之后使用。最近我还写了一整本书关于这个话题,实际上是一本简短的35页电子书,由O'Reilly免费提供,名为《面向大规模代码重构和分析的人工智能》,书中详细描述了我们如何选择这些模型、部署它们以及评估它们,并希望这对大家有所帮助。