作者:Don Bourne
人工智能(AI)变得越来越普遍。作为企业Java开发人员,您可能想知道AI的价值可以为您的业务应用程序添加哪些价值,Java提供了哪些工具来轻松执行此操作,以及您可能需要学习的技能和知识。在本文中,我们为您提供了开始探索AI构建智能和响应式企业Java应用程序的能力所需的基本知识和技能。
当我们在本文中谈论AI时,我们的意思是根据Java应用程序发送给LLM的请求,从大语言模型(LLM)中获得响应。在我们的文章示例中,我们创建了一个简单的聊天机器人,客户可以要求提供行星旅游目的地的建议,然后预订太空飞船来访问它们。我们证明使用Java框架langchain4j和quarkus有效地与LLM互动并为最终用户创建令人满意的应用程序。
我们的太空飞船租赁应用程序的第一个版本将构建一种使用自然语言与客户互动的聊天机器人。它应该回答有关他们希望在太阳系中访问的行星的任何客户问题。有关完整的应用程序代码,请参阅太空飞船租赁步骤01目录在GitHub存储库中。
聊天机器人将客户的问题发送到与LLM互动的应用程序,以帮助处理自然语言问题并回应客户。
对于应用程序的AI相关部分,我们仅创建两个文件:
客户upportagent.java
,这建立了一个及时的提示,告知LLM有关我们的太阳系行星的信息,并指示LLM回答客户的问题。chatwebsocket.java
,从聊天机器人接收用户的消息。AI服务是Java界面,可提供一层抽象。使用Langchain4J时,这些接口使LLM相互作用更加容易。AI服务是一个集成点,因此在实际应用程序中,您需要考虑对连接和与LLM的连接和交互的安全性和容错性。以及处理LLM连接详细信息(分别存储在application.properties
配置文件),AI服务构建了提示并管理发送给LLM的请求的聊天内存。
该提示是由AI服务中的两个信息构建的:系统消息和用户消息。开发人员通常使用系统消息来提供LLM上下文信息和处理请求的说明,通常包括您希望LLM在生成其响应时遵循的示例。用户消息为LLM提供了应用程序用户请求。这
客户支持接口在应用程序中注册为AI服务。
它定义了用于构建提示的消息,并将提示发送到LLM:
@SessionsCoped@registeraiservice公共接口客户upportagent {@SystemMessage(“” 您是一个友好的宇宙巡洋舰,一家太空船出租商店。您回答潜在客人的问题他们可以参观。如果被问到行星,则仅使用下面的情况说明书中的信息。 ”“”+ Planetinfo.planet_fact_sheet) 字符串聊天(字符串usermessage); }
让我们看看这个代码在做什么。这@SessionsCoped
注释在Web服务连接期间维护会话,并在对话期间保持聊天记忆。这@registeraiservice
注释将接口作为AI服务记录。langchain4j自动实现接口。这@SystemMessage
注释告诉LLM在回应提示时如何表现。
当最终用户在聊天机器人中键入消息时,WebSocket端点将消息传递给聊天()
AI服务中的方法。没有@usermessage
在我们的AI服务接口中指定的注释,因此AI服务实现会自动创建用户消息聊天()
方法参数值(在这种情况下Usermessage
范围)。AI服务将用户的消息添加到系统消息中,以构建其发送给LLM的提示,然后在聊天机器人接口中显示LLM的响应。
请注意,对于可读性,行星信息已放在单独的Planetinfo
班级。另外,您可以将行星信息直接放在系统消息中。
这chatwebsocket
类定义了应用程序聊天机器人UI与以下交互的Websocket端点:
@websocket(路径=“/chat/batch”)公共类ChatWebsocket {一个 •私人最终客户upportagent客户uppportagent;一个 公共chatwebsocket(customersupportagent custerutionupportagent){–customerSupportagent = customerupportagent;}一个 @ @onopen公共字符串onopen(){``欢迎回到火箭的宇宙巡洋舰!今天我该如何帮助您?”}一个 @ @toxtextmessage•public string ontextMessage(字符串消息){``返回客户upportagent.chat(消息);}}
这客户支持
接口使用构造函数注入来自动提供对AI服务的参考。当最终用户在聊天机器人中键入消息时ontextMessage()
方法将消息传递给AI服务聊天()
方法。
例如,如果用户问:“如果我想看火山,请参观什么好星球?”,该应用程序会提出建议,以及为什么用户可能希望在那里参观火山,以作为火山的粉丝:
飞船租赁应用程序聊天机器人。
当您继续与聊天机器人对话时,似乎已经意识到了以前交换的消息,即对话的上下文。当您与另一个人交谈时,您认为他们记得您(以及他们)最后说的话。但是,向LLM的请求是无状态的,因此仅根据请求提示符中包含的信息生成每个响应。
为了维护对话中的上下文,AI服务通过Langchain4J使用聊天内存来存储先前的用户消息和聊天机器人的响应。默认情况下,Quarkus langchain4j扩展名将聊天存储在内存中,AI服务管理聊天内存(例如,通过丢弃或汇总最旧的消息),以保持在内存限制范围内。langchain4j本身将要求您首先配置存储器提供商,但是使用Quarkus langchain4j扩展名时不需要。这给了最终用户的实际记忆幻想,并改善了用户体验,因此他们可以输入跟进消息而无需重复以前所说的一切。用户聊天机器人体验也可以通过流式传输LLM的响应来改进。
您可能会注意到对聊天消息窗口的响应需要时间来生成,然后一次出现。为了提高聊天机器人的感知响应能力,我们可以修改代码以返回响应生成的每个令牌。这种方法,称为流,允许用户在整个响应可用之前开始阅读部分响应。有关完整的应用程序代码,请参阅GitHub飞船租赁步骤02目录。
更改我们的应用程序以流式聊天机器人响应很容易。首先,我们将更新客户支持
接口添加一种返回Smallye Mutiny实例的方法多<String>
界面:
@SessionsCoped@registeraiservice@SystemMessage(“” 您是一位友好的,但简洁了Rocket的宇宙巡洋舰的客户服务代理,这是一家太空飞船租赁商店。您会回答潜在客人的问题,以了解他们可以参观的不同星球。如果被问到行星,则仅使用下面的情况说明书中的信息。 “““一个 + Planetinfo.planet_fact_sheet) 公共接口客户upportagent {字符串聊天(字符串usermessage);多<String> streamchat(string usermessage);}
移动@SystemMessage
对接口的注释意味着注释不必添加到接口中的每种方法中。这streamchat()
方法一次将LLM的响应返回对聊天窗口的一个令牌(而不是等待一次显示全部响应)。
我们还需要致电新的streamchat()
Websocket端点的方法。为了保留批处理和流功能,我们创建了一个新的chatwebsocketstream
公开的班级/聊天/流
Websocket端点:
@websocket(路径=“/chat/stream”)公共类ChatWebsocketStream {•私人最终客户upportagent客户uppportagent;•public chatwebsocketstream(customersupportagent custerutionupportagent){–customerSupportagent = customerupportagent;}@ @onopen公共字符串onopen(){``欢迎回到火箭的宇宙巡洋舰!今天我该如何帮助您?”}@ @toxtextmessage•public multi <string> onstreamingTextMessage(字符串消息){``返回客户upportagent.streamchat(消息);}}
这customersupportagent.streamchat()
调用调用AI服务将用户消息发送到LLM。
在对UI进行了一些小调整后,我们现在可以在聊天机器人中打开和关闭流式传输:
启用了带有新流选项的应用程序。
通过启用流媒体,LLM生成的每个令牌(每个单词或部分单词)都立即返回到聊天界面。
到目前为止,LLM的输出旨在为应用程序的最终用户提供。但是,如果我们希望LLM的输出直接由我们的应用程序使用,该怎么办?当LLM响应请求时,介导与LLM交互的AI服务可以返回结构化的输出,这些输出是比字符串更结构化的格式,例如POJOS,POJOS列表,Pojos和本地类型。
返回的结构化输出极大地简化了LLM的输出与Java代码的集成,因为它可以强制应用程序从AI服务映射到Java对象的预定义架构接收到的输出。让我们通过帮助最终用户从我们的车队中选择一个满足其需求的太空飞船来证明结构化输出的有用性。有关完整的应用程序代码,请参阅GitHub飞船租赁步骤03目录。
我们首先创建一个简单的飞船
记录在车队中存储有关每个太空飞船的信息:
Record SpaceShip(字符串名称,Int Maxassengers,Boolean Hascargobay,List <String>允许DESTINATIONS){}一个
同样,要代表用户对我们车队中宇宙飞船的查询,我们创建了一个太空飞船
记录,基于用户在聊天中提供的信息:
@Description(“兼容太空船的请求”)公共记录SpaceShipQuery(int乘客,布尔·hascargo,列表<string>目的地){}
这舰队
班级填充了几个太空飞船对象,并提供了一种过滤出不匹配用户的对象。
接下来,我们更新客户支持
接口获取用户的消息(非结构化文本)以创建一个结构化输出的形式太空飞船
记录。为了实现这一壮举,我们只需要设置新的返回类型ExtractSpaceShipAttributes()
我们的AI服务中的方法是太空飞船
:
SpaceShipQuery Extractspaceshipattributes(字符串usermessage);
在封面下,langchain4j自动向LLM生成请求,包括所需响应的JSON模式表示。langchain4j可以从LLM中估算JSON形式的响应,并使用它返回太空飞船
记录,按要求。
我们还需要知道用户的输入是关于我们的太空飞船之一还是其他主题。使用更简单的结构化输出请求来完成此过滤,该请求返回布尔值:
@SystemMessage(“”“您是一位友好的,但对Rocket的Cosmic Cruisers(一家太空飞船租赁商店)的客户服务经纪人。 如果用户消息与我们的租赁车队中的太空飞船有关,否则就会以“ true”响应。”“”)boolean isspaceshipquery(字符串usermessage);
我们的最后一个加入客户支持
接口使代理商能够根据我们的车队和用户的请求提供太空飞船建议,并没有流式传输:
@usermessage(“”“”``鉴于用户对旅行{message}可用太空飞船的查询,提供了一个良好的,清晰和简洁的响应,列出了我们适用的太空飞船。•仅使用来自{CompatiBlespaceShips}的太空飞船数据}进行响应。â—)字符串建议SpaceShips(字符串消息,List <Spaceship> compatiblespaceships);一个 @usermessage(“”“”``鉴于用户对旅行{message}可用太空飞船的查询,提供了一个良好的,清晰和简洁的响应,列出了我们适用的太空飞船。•仅使用来自{CompatiBlespaceShips}的太空飞船数据}进行响应。â—)Multi <string> StreamSuggestSpaceShips(字符串消息,List <Spaceship> compatiblespaceships);}
我们的最后一步是更新chatwebsocket
和chatwebsocketstream
课程首先检查用户的查询是否是关于我们车队中的飞船的。如果是这样,客户支持代理会通过从用户消息中提取信息,然后通过与用户请求兼容的建议太空飞船进行响应来创建太空飞扬的记录。ChatWebSocket和chatwebsocketstream
课堂,所以只有chatwebsocket
课程在此处显示:
@textmessagepublic String onTextMessage(字符串消息){布尔值isspaceshipquery = cunitudeupportagent.isspaceshipquery(message);如果(IsspaceShipQuery){SpaceShipQuery userQuery = cunitudeupportagent.extractSpaceShipAttributes(message);清单<Spaceship> spacehips = fleet.findcompatiblespaceships(userQuery);``返回客户upportagent.suggestspaceships(消息,太空飞船);其他 ``返回客户upportagent.chat(消息);}
通过这些更新,客户支持代理可以使用结构化的输出为用户提供太空飞船建议:
该应用程序根据结构化输出为用户提供太空飞船建议。
这样,我们已经完成了一个注入AI的Java Chatbot应用程序,该应用程序提供了行星旅游建议和太空飞船的租赁。
要继续学习,请尝试我们示例申请的完整代码旁边Quarkus和langchain4j文档。
在本文中,我们讨论了各种AI概念。如果您想进一步了解它们,这是一个快速的解释器。
当我们在本文中谈论AI时,我们通常意味着从大型语言模型中获得响应。LLMS是机器学习模型,经过训练,可以根据一系列输入(通常是文本输入和输出)生成一系列输出,但是某些多模式LLM可以与图像,音频或视频一起使用)。LLM可以执行各种任务,例如汇总文档,在语言之间翻译,事实提取,编写代码等。从输入创建新内容的任务是称为生成AI或Genai的。您可以根据需要将这些功能注入您的应用程序。
您如何从LLM请求信息不仅会影响您从LLM中获得的响应,还会影响最终用户的经验以及应用程序的运行成本。
无论是从应用程序代码还是作为聊天接口中的最终用户发送请求,都涉及编写提示。提示是LLM响应的信息(通常但并非总是,文本)。如果您想与LLM这样的沟通,例如与另一个人进行沟通,那么您的请求如何对确保对方(或LLM,在这种情况下)了解您想知道的内容很重要。例如,在继续索取特定信息之前,请确保您提供请求的上下文,并且不要提供许多无关的信息来混淆听众。
与您与他人交谈时,LLM是无状态的,也不记住先前的请求,因此您需要考虑到的所有内容都需要在您的请求中考虑:提示,任何先前的请求和响应(聊天内存)以及您提供的任何工具以及您提供的任何工具以帮助LLM响应。但是,在提示中向LLM提供过多的信息可能会使请求变得复杂。这也可能是昂贵的。
LLM在提示中将单词转换为一系列令牌。大多数托管的LLMS根据请求和响应中的令牌数量收取的使用情况。令牌可以代表一个单词或单词的一部分。例如,“令人难以置信的”一词通常分为多个令牌:“ un”,“ bel”和“ ievable”。您在请求中包含的令牌越多,尤其是当您包含所有聊天内存时,运行应用程序的潜在成本就越大。
在请求中提供所有聊天内存可以使请求既昂贵又不清楚。对LLM的请求的长度有限,因此管理聊天内存以及请求中包含多少信息很重要。您使用的Java框架可以很有帮助,例如带有Quarkus的Langchain4j,我们在本文中用于示例应用程序。
是一个开源Java框架,可以管理Java应用程序与LLMS之间的交互。例如,Langchain4j通过AI服务的概念,存储并帮助您管理聊天记忆,以便您可以对LLM有效,专注且价格便宜的请求保持请求。
Quarkus是一个现代,云原生的开源Java框架,可针对开发人员生产力,在容器化的环境中运行,并使用低内存使用情况进行快速启动。这langchain4j扩展到quarkus简化连接到AI注入Java应用程序中LLMS并与LLMS交互的配置。
Langchain4J项目可以与其他Java应用程序框架一起使用,包括公开自由,,,,春季引导, 和微守年。微框和雅加达EE也正在与langchain4j一起工作,以提供开放标准的编程模型用于开发AI应用程序。
你可以找到完整的样本申请我们在Github的本文中演示了这一点。该应用程序用Java编写,并使用Quarkus langchain4j扩展。
将AI注入Java应用程序可以增强应用程序的功能和最终用户的体验。借助Quarkus和Langchain4j等Java框架简化与LLMS的交互,Java开发人员可以轻松地将AI注入业务应用程序中。
在Java中编写AI注入的应用程序意味着您正在Java的强大,可用于企业的生态系统中工作,这不仅可以帮助您轻松与AI模型进行交互,还可以使应用程序轻松从诸如性能,安全性,可观察性和测试等企业必需品中受益。
AI领域正在迅速发展。通过掌握本文中的概念和技术,您可以保持领先地位,并开始探索AI如何帮助您构建智能和引人入胜的Java应用程序。实验我们示例申请的完整代码旁边Quarkus和langchain4j文档。
如果您想了解更多信息,请尝试通过使用检索增强发电(RAG)来扩展PDF文档的内容的知识的本教程:与Quarkus和Langchain4J建立AI驱动的文档助手。
感谢Red Hatters Clement Escoffier,Markus Eisele和Georgios Andrianakis的宝贵评论评论。