阿里云工程师跟通义灵码结伴编程, 用Spring AI Alibaba来开发 AI 答疑助手
微服务引擎产品主要为面向主流开源社区的微服务产品提供一站式托管服务,涵盖 Double Smoke Out 开源框架的开发与治理,以及南谷中心和网关的托管。这就是微服务引擎产品的基本情况。作为阿里云的后端研发工程师,随着生成式 AI 近两年的流行,我深刻感受到了一些研发提效工具给后端研发带来的一些本质变化。
今年4月,阿里云重磅发布了研发提效工具通义灵码。该产品发布后,在阿里云研发工程师中使用非常普遍,已成为实现研发提效的重要手段。今天我想和团队同学阿伟一起看看在日常研发中,我们是如何用灵码实现研发提效的。
做微服务产品中一直想做的 AI 智能助手。通过这个助手提升微服务产品的用户使用体验和答疑效率。做这款产品,计划使用 Spring AI Alibaba 开源开发框架。接下来我们一起找阿伟聊聊实际的开发过程。
我:我有个想法,我们能开发一个AI智能助手,利用当前的生成式 AI技术,解决你的问题。
阿伟:我之前看到他们容器服务有类似的 AI 助手,你要的是这个吗?
我:对,和这个很像,比如你问他产品使用及遇到的疑难问题,它都能智能回答。
阿伟:如果 MSE 有这种能力,让用户直接问 AI 助手比确认文档还好,但我没有 AI 开发背景,做起来很难。你还是找其他同学吧。
我:这可能有一定难度,但我们可用两款工具解决。我想用你常用的灵码加速学习和开发 Spring AI Alibaba 开源框架的过程。我们可以从这个框架入手。
阿伟:可以,我之前下载过,但不太了解。我们可以看一下,用新上线的 Workspace 。我刚用灵码分析问一下:“帮我介绍一下这个项目”,看看效果,正好我们也讨论一下。假设我很容易搭建调用通义模型的应用,但实际效果和理想差距很大。我们还是一步步来,毕竟我没做过类似 AI 应用。你是否要给领导提些建议,怎么做更合适?
我:我觉得这体现了灵码开发提效的优势,你可以按开发普通应用的过程来展开,遇到不会的问题就用灵码尝试。
阿伟:可以,我先简单画个架构图,这样我心里更有底。灵码确实详细介绍了 Spring AI Alibaba 项目及结构,它是个做 AI 应用的好框架,还提供了许多示例。它和 IEGSMO 很像,对吧?
我:我觉得我们可以从它的“ Hello World ”开始,举个简单的例子。
阿伟:我先简单画个架构图,新建文档,比如这是 MSE 助手,用它调用通义千问模型,先搭最简单的部分看看效果。 Spring AI Alibaba最大优势是简化应用开发过程。我们先在阿里云找一个简单项目,Group 为“ com.alibaba/mse.ai
”。
打开它,这是一个默认的空脚手架,只是帮我们搭建了基础框架。第一步我们需要导入依赖,我先配置Preferences。因为是全新项目,我们先依赖Spring AI Alibaba。可以从“hello world”示例中查看,除了Spring AI,还需要导入Spring AI的相关依赖。根据刚才的项目,我们需要一个Web应用,用户可以输入请求。从架构图来看,它是一个Web应用。同时,我们还需要一个类似chat的服务,通过Spring AI Alibaba调用相关模型。
我先搭建一个 Chat ,Chat Service 是一个聊天接口,用户问什么,大模型就回答什么。我们要在Chat的实现中调用模型。我现在再做一个 MSE chat service ,这应该符合我们的需求。既然是调用大模型,我们需要一个模型客户端 ChatLient ,看看灵码有没有报错提示。灵码没有报错提示,看起来需要一个 Builder ,即ChatLient.Builder,这是构造器构造出来的,直接用默认的 Builder 即可。我们的 Chat其实很简单,就是发送问题,快速获取结果,代码为 prompt().user(question).call().content() 。
我再创建一个 MseChatController ,看看灵码能否给我些建议。输入“ RequestMapping
”,灵码很快就能猜到,无需手动编写,效率很高。试着运行一下,有问题可直接通过通义千问获取答案,无需跳出IDE 环境。以前出问题还要到处查找,现在直接问通义千问就行。看起来像是版本兼容性问题。我再试一次,换个版本刷新一下,问题确实解决了。这个提示有助于我们加速开发。仍有问题,这次问题不同,再问一下,看看能否得出结论。模型调用需要正确设置 API key ,这个 API key 相当于访问百炼模型服务的身份,即通义模型的身份认证。我们再看这张图,我理解到虽然模型成本很低,但并非每个人都能调用,肯定需要身份认证,毕竟调用的 token 数量都记录在身份上,这就是整个过程。我登录百炼官网,获取 API license key ,看看二维码能否帮助生成结果,把通义的推荐复制过来试一下,按照灵码提示操作,应该不会出错。然后把 key 填上去,就这么简单,多亏了灵码的帮助。
试验后出现404错误,重新输入“ ai/chat?question =您好
”,仍然失败。查看灵码提示“参数没有指定名称
”,修改后仍报错。再次提问后得知应输入“ defaultValue ”,之后程序能正常运行。我再问“ MSC 服务治理如何接入?
”这是用户常问的问题,可能是模型在推理计算。现在我们是直接提问,模型需思考好所有结论后再回复。若改为流式调用,对模型和我们来说,能看到模型逐步输出结果,更像 GPT 与人交流,类似实时交互,效果会更好,那就改一下。
问问灵码能否帮我改成流式调用,但回答太长,我取消了。我们看看Spring AI 有没有相关示例,参考一下 Hello Word 是怎么做的。我发现 Hello Word 有一个 Flags 关键字,可以参考一下。我再去问问灵码,这也是个办法。我觉得灵码在某些领域知识上可能欠缺,因为Spring AI 的知识比较新,估计它还没学习。它假设这个方法是异步调用结构。我们应该找到是否有异步调用的格式。灵码提示 Stream比较接近,但灵码对 Spring AI 这一特殊领域知识似乎还欠缺。你可以使用 Stream ,删掉这个框架,还有 chat response 可直接用content 。我们现在就改成流式调用,在调用处进行修改,反馈给浏览器的形式也相应改变。
再看一下效果,这已经是聊天对话效果了,但文本格式似乎不太对。我问一下他“能否给我返回 HTML页面的内容”。这有点奇怪,他似乎没有上下文,相当于胡乱回答,基于历史的问题,他没有关联起来。问一下“如何接入 MSE 服务器治理”,这个倒是有的。要解决这个问题,可能需要给应用增加一些聊天上下文记忆的能力。我们刚才希望他通过特定格式输出,通过 HTML 内容返回。但问完下一个问题,他就忘了。如果产品真的上线,用户的交互过程是一个问题接一个问题。模型构造时,应考虑让它具备上下文记忆能力,可以问一下通义灵码。可以适当增加Spring AI的关键词,如“这是用 Spring AI 编写的框架,能否帮忙增加上下文记忆能力”。在与灵码交流过程中, prompt有很大影响。通义灵码反而理解成我们要自己实现上下文内容,这似乎也可以,记下来后再反馈给他。我查一下 Spring AI 是否提供类似能力。以前我们直接查官方文档和看代码。如果能通过灵码先梳理全新项目的上下文,再去看文档和代码,效率会高很多。 Spring AI 通义灵码之前没了解过,现在需要花时间。 Chatmemory 直接出来了,是一种记忆存储实践策略,可以切过来用。为了快速,可以先用个简单的。
他已经具备连续上下文了,提问“如何接入 MSE 服务治理”,感觉我们的 AI 智能助理助手到这个时候应该已经很成熟了。但你有没有发现,他的回答似乎与我们期望的结果不太一样。因为我问的是如何接入服务治理,他却告诉我如何使用实例,如何购买实例。从他的回答来看,这似乎是一个模型自动推理得出的结论。那就把我们官方文档的材料输入进去,要求它只能回答文档内的内容,不要自行联想。我觉得可以参考以前的架构图 , AI 智能体应用中有一个叫 RAG 的模型,和刚才讲的很像。问一下灵码“ RAG 模式是怎样的?”,得知RAG包括检索和生成。我们先确定架构,再进行开发。
刚才只是普通的 Chat ,现在我们要整合 RAG 流程。我刚才看灵码介绍, RAG 包括检索和生成。在这个过程中,我们需要提前给他一个材料,即我们的文本内容( MSE 文档),并提前告诉他 Prompt 。相当于现在的文本已经经历了生成过程,文本预加工的细节就不展开了。当用户提出新问题,即 Prompt 时,检索过程分为两步。第一步,Assistant 会先检索文本内容,找到强相关的内容。这个强相关的内容与 Prompt 一起构成检索过程,输入给模型。如果我们的模型要具备RAG 能力,我们需要一种能从文档内容中检索信息的能力,通常这种信息会存储在数据库或内存中。检索到内容后,再让模型生成答案,这样会使答案更加可靠,而不是泛泛而谈。
那就照着这个来,我先试一下。之前是 Chat ,我们再搞个新的,命名为 RAG 。按照我们刚才聊的开始生成,还有一个是导入过程和文档状态,输入以上内容就实现了。这次可以叫MSE RAG service。我们需要模型 Final ChatClien t和 Final Vectorstore ,有需要再加。 ChatClient 仍需 Builder ,可以问灵码“如何配置 Spring Bean ?
”假设它写代码,可直接生成。而Spring AI提供了可直接输入的“ EmbeddingModel ”。我们分两步进行,否则就和 Chat没区别。我们需要导入材料,导入和处理过程相对复杂。我们还有一个 Prompt ,写在这里较好,把要导入的材料拉进来,这个部分需拿到 MSE 的真实文档。这是 MSE 服务治理的 ACK 应用接入文档,把它导入看看。灵码还挺不错的,我对路径引导一直不太明白,它直接给我提示了。导入的是 PDF ,我得问灵码“ Spring AI 是否有读取 PDF 为 Documen t材料的能力?
”看有没有开箱即用的能力,有的话直接拿来用。在这个过程中,我们也可以看看有没有类似的库。这边它有一个 Spring AI PDF 的 Document ,看看是做什么的。现在我们要做的第一步是读取 PDF 材料,然后导入到向量库。 Vectorstore 要求的是一个 Document 。我再针对这个Document 问一下,这边看起来还没生成。它其实需要的是一个Document list 。我再问一下“如何通过 Spring AI 框架将 PDF 转成 Documents ?
”。这边推荐了一个库,我们找找 Spring AI 有没有更方便的。虽然阿里巴巴的 Samples 里有可用的库,我们拿来看看它的实现方式,确实可行。我们再试一下,看看能不能更简洁地解决问题。 Spring AI Alibaba 这个版本似乎没有这个库,Spring AI 相关应用未发布到中央仓库,去掉试一下。让通义灵码介绍一下 Spring AI 中 PdfDocumentReader 相关的能力,确实提供了,示例都有,直接拿来用就好。
刚才通过灵码找到了这个类,并询问了其功能。接下来,结合实际情况先将其加入,然后进行导入。之后,还需将之前的检索能力加回去。我们刚才用到的都要加入,但我认为这还不够,可以再加一个,甚至多个。我知道这边还需要加一个,但你清楚是从哪里开始问答的。我建议通过 AI 问答了解“ RAG 模式推荐使用什么 Adviser
”。 Space 用于分析几个结构,其实可以不加。假设我们读到了内容,然后带上 Prompt ,给他加上 Prompt 。这样的话,比如限制他文档里的内容,他就不会乱回答,不会使用先天知识。再确认一下 System Prompt 是否已加?我想要的是 AI 助手的身份定位,这样的话在Builder 里有一个system会更合适,就不需要 Prompt 了。这里面其实能支持 Source ,可以直接用,这样可能更方便。这就是写 AI 工具的一个便利之处,否则我还要写很多代码。剩下的就是我们的Chat部分“ ChatClient.Prompt (). user
”,这边其实和刚才的 Chat 一致。这样看起来就差不多了。把“ MseChatController ”更名为“ MseAssistantController ”,加入 RAG ,灵码直接生成后续代码,相当于我们要做一个初始化。实际上是先 Import Documents ,在真实的生产过程中可以用类似的方法,先询问是否能返回结果,但这挂掉了。原因是 test 内容没读到,那就再打开看看,我们再问“如何接入 MSE 服务治理?”这已经跑起来了。我希望获取的答案是,加入 RAG 后,回答是否与文档高度一致。发现它似乎额外加入了 Spring AI 的开发过程,因为我们上下文问答在里面,对吧?我们要让它忘记 Spring AI ,重启一下。也可以多告诉它一句,里面有一个东西是什么,我希望后续回答不要出现相关内容,然后我再问一遍,它已经知道了,我们可以对比一下。其实到现在我们基本上都做完了,待会可以看一下效果。
如果效果仍然不理想,我们可以查一下原因。可以加入一个日志Logging Adviser ,参考其他 Adviser 实践,我觉得 Response 比较像,可以输入“ CallAroundAdviser
”。剩下的迷茫部分直接让灵码编写,后续的链仍需继续调整,直接复制插入,然后我们再进行调整。我感觉这个阶段我的应用已经相对完善。在问答过程中,由于这是一个智能应用,存在一些偏差也算正常。目前, Logging 用于追踪问答过程, System Prompt 与提问的关联性较大。
再试一下,似乎仍有问题。我怀疑这可能与 Logging 配置有关。思路没错,我们再打开看看,正好诊断一下。结论是没有 Import ,这与我们的预期一致。我们先 Import 导入材料,可能有些系统报错,估计是 PDF 格式不对,我们稍后再处理整个问题。回答时间较长,困难较大。再试一次仍有问题,猜测与“ Logging Adviser
”有关。当前的 Logging 今天不必完善, Spring AI Alibaba 里有可参考的Logging 示例,直接输出“ AdviceRequest
”即可。后面可能要处理一下 PDF ,那个工具其实还不够好,这也是 Spring AI Alibaba 在开源社区接下来要做的事。这回应该对了,看起来是一样的。然后我们再带上之前的问题,这已包含了默认问题。日志这边有了,是我们给进去的材料,展现了一个 RAG 的内容。看来刚才我不该用那个Log 类,而应实现这个,它里面应该是做了一些 Around call 。那个链应该断掉。 Along the stream 未实现,我们用的是 stream 模式,时间到了,所以后续链路空了,这可以在后续迭代中优化。
我们今天这个开发目标差不多达成了吧?总共花了一个多小时,从零开始探索,过程中虽然磕磕绊绊,但成果还是不错的。灵码从一开始就帮了大忙,虽然我对 Spring AI Alibaba 比较熟悉,但你相当于从中学习,到开发阶段,它的代码提示和问题解答都很及时,不用离开 IDE 工作环境。
确实,在这个过程中完全没有用过搜索引擎,直接问通义灵码就好了。其中代码生成表现不错,虽然有些难的部分存在漏洞,但整体上帮我生成了许多简单或重复性的工作,解决了不少问题。比如说 Web 相关的工作完全不用自己做。后续提到了一个完整的项目,后面的单元测试等还需要补全。平时工作中用灵码写单元测试,真是爽极了。
正式上线前还有很长的路要走,接下来我们继续完善。后续我也会和其他同学进一步深耕这一领域,利用Spring AI Alibaba框架和大模型的能力,将项目推到线上,使其像ACK的智能助手一样,争取实现超过10%的效率提升。