当前位置: 首页 > news >正文

如何优雅的在页面上嵌入AI-Agent人工智能

前言

IDEA启动!大模型的title想必不用我多说了,多少公司想要搭上时代前言技术的快车,感受科技的魅力。现在大模型作为降本增效的强大工具,基本上公司大多人都想要部署开发一把,更多的想要利用到这些模型放到生产中来提高生产力。但是对于我们开发者来说,找到实际落地场景可以说是产品的活,我们需要思考如何高效维护AI这个模块,如何建立项目层级结构才能更好的解耦。正巧最近遇到了这个需求,来和大家分享项目搭建流程,此项目将运用到我个人开发的网页和网站上面,感兴趣的同学可以去体验一下,再来看看项目设计结构会更有心得。

项目顶层架构

首先AI这块应该在业务体系中应该较大的模块,AI落地应用的场景不限于AI客服问答,还可以应用在知识库管理、数据快速展示、ChatBI等一系列场景,但是目前我们的项目这块是用于Web应用上面的,所以采用一般也是JAVAWeb层级结构,那么我们就很好确定后端技术栈。

技术选型

  • Spring Boot: 作为项目的核心框架,用于快速构建 RESTful API 和管理依赖。

  • MyBatis-Plus: 用于数据库持久化操作,简化了 MyBatis 的使用,并提供了基本的 CRUD 方法。

  • AI SDK: 用于与AI 服务进行交互,处理 AI 模型的调用和返回结果。

  • Lombok: 用于减少样板代码(如 gettersetter、构造函数等)。

  • MySQL: 作为数据库,用于存储 AI 会话数据。

我这里调用的是阿里通义千问的模型,当然每个厂商的AI SDK都大差不差,调用规则基本都是一致的,通过查阅SDK的返回参数就能很轻松的调用:

核心流程

API 请求处理:

  • 前端或客户端通过 TongyiChatReqDto 提交用户的 prompt(问题)到后端。

  • 后端的 AliyunTongyiServicelmpl 使用阿里云的 dashscope API 调用,将用户的问题提交给 AI 模型。

API 响应处理:

  • dashscope API 返回 AI 的响应,封装在 AiResponse DTO 中。

  • 后端通过 AiResponseToPoConverterAiResponse 转换为 AiChatTongyiRespPo 实体类。

数据持久化:

  • 转换后的实体对象 AiChatTongyiRespPo 通过 AiChatTongyiRespRepository 保存到本地的 MySQL 数据库中。

  • 数据持久化包括存储 AI 的会话 ID、返回文本、结束状态、模型编号、输入和输出 tokens 等信息。

业务处理:

  • 后端返回封装好的 TongyiChatRespDto 响应对象,包含 AI 的回复文本,供前端展示。

顶层设计

首先应该有两个模块,一层为处理Web端数据回传,将用户在前端提交的文本数据处理,里面可以加入敏感词检测、不符对话逻辑过滤等一系列业务逻辑,然后把这些内容提交到AI交互模块;在数据落库方面还需要能够记录每次对话内容的交互数据,这部分的数据尽量偏业务方向,不需要记录AI返回的Tokens,状态等数据,只需要记录表层与用户交互的数据,比如对返回的文本点赞,评分等。

另一层为处理与AI数据交互,需要将我们处理过需要交互的数据提交到AI SDK的接口上,获取返回的数据,这部分数据也需要记录,因为后续我们可能会去做一些不同AI反馈效果,也可能会去进行大模型多模态的应用,所以要尽可能的低耦合,多划分层级,对后面后续维护项目很重要。之后还需要能够记录能够帮助我们调优AI性能的数据,比如每次传输的tokens数量,响应时间等数据。

项目实现

AI通信层

我们先来处理与AI通信交互这层功能:

api这一模块实现与AI接口的交互,也就是查阅相关SDK文档,找到AI返回的数据格式,获取到了数据之后记录到数据库之中,并且通过api传输给其他服务,确定层级有:

1. config 包

  • Configuration.java: 负责项目的配置管理,通常用于定义和加载一些项目启动时所需的配置类、Bean、服务或者第三方服务的连接配置。

  • Properties.java: 用于加载和存储配置文件(如 application.ymlapplication.properties)中的属性,主要用于配置 API 相关的信息,比如 apiKeychatAppId。通常使用 Spring 的 @ConfigurationProperties 注解,将配置文件中的内容映射为 Java 对象。

2. dal包

  • AiChatRespPo.java: 持久化对象(PO),用于映射到数据库表 ai_request。这个类的实例代表从数据库读取或保存到数据库的一条记录。它包含 AI 会话相关的数据,如 requestIdprompttextfinishReasonmodelIdinputTokensoutputTokens 等字段,通常与 MyBatis-Plus 或其他持久化框架一起使用。

3. domain包

  • AiResponse.java: 数据传输对象(DTO),用于封装从阿里云 Dashscope API 返回的 AI 响应数据,并在应用层之间传递。该类包含 AI 响应的相关信息,如 requestIdtextfinishReasonusage(模型使用信息)。DTO 的作用是将数据从服务层传递到表示层(或反之),不涉及业务逻辑或持久化操作。

4. domain 包

  • EvaluateEnum.java: 枚举类,用于定义用户对 AI 响应的评价状态,可能包含 "满意"、"不满意" 等选项。枚举类在代码中提供了一种类型安全的方式来表示固定的常量集。

5. exception 包

  • NetworkException.java: 自定义异常类,用于处理网络或 API 调用过程中的错误。自定义异常可以使异常处理更具语义化,并且能够在捕获异常时提供更多的上下文信息,比如错误码或详细的错误消息。

6. repository 包

  • AiChatRespRepository.java: 自定义的 Repository 接口,定义了保存 AiChatTongyiRespPo 实体对象的方法。这个接口负责抽象数据持久化操作,隐藏了底层的数据访问细节。实现该接口的类负责实际的数据操作逻辑,通常使用 MyBatis-Plus 或其他持久化技术。

7. repository.impl 包

  • AiChatRespRepositoryImpl.java: 该类实现了 AiChatTongyiRespRepository 接口,负责将 AiChatTongyiRespPo 实体对象保存到数据库中。它使用 MyBatis-Plus 或其他 ORM 框架来执行数据持久化操作,并管理数据库事务。

8. service包

  • AliyunTongyiServicelmpl.java: 这是核心的业务逻辑实现类,处理与阿里云 Dashscope AI 服务的交互。它通过阿里云 API 发起请求,获取 AI 模型的响应数据,然后将该数据通过转换器(AiResponseToPoConverter)转换为持久化对象,并保存到数据库中。同时,它还负责处理请求和响应的各种业务逻辑和异常情况。

基于上述内容我们可以来先设计DTO:

DTO

public class AiResponse {/*** AI单条会话ID*/private String requestId;/*** 提问内容*/private String prompt;/*** AI返回的文本*/private String text;/*** 完成原因*/private String finishReason;/*** 模型信息*/private List<ApplicationUsage.ModelUsage> usage;
​public AiResponse(String requestId,String prompt, String text, String finishReason, ApplicationUsage usage) {this.requestId = requestId;this.prompt = prompt;this.text = text;this.finishReason = finishReason;this.usage = usage != null ? usage.getModels() : null;}
}
​

这部分查阅SDK看返回数据格式,把这部分最简单先做了。然后设计数据落表:

数据表

CREATE TABLE `ai_request` (`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键标识',`request_id` varchar(50) NOT NULL COMMENT '会话ID',`prompt` longtext COMMENT '提问内容',`text` longtext COMMENT '返回文本',`finishReason` varchar(5) NOT NULL COMMENT '结束状态',`model_code` varchar(50) NOT NULL COMMENT '模型编号',`input_tokens` bigint NOT NULL COMMENT '输入tokens',`output_tokens` bigint NOT NULL COMMENT '输出tokens',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='智能客服应答表';

有了表之后我们建立相应的转换和po层:

po

public class AiChatTongyiRespPo {/*** 主键id*/@TableId(value = "id", type = IdType.AUTO)private Long id;
​/*** 提问内容*/@TableField(value = "prompt")private String prompt;
​/*** 返回编号*/@TableField(value = "request_id")private String requestId;
​/*** 返回文本*/@TableField(value = "text")private String text;
​/*** 结束状态*/@TableField(value = "finish_reason")private String finishReason;
​/*** 模型编号*/@TableField(value = "model_id")private String modelId;
​/*** 输入tokens*/@TableField(value = "input_tokens")private String inputTokens;
​/*** 输出tokens*/@TableField(value = "output_tokens")private String outputTokens;
}
​

再来写convert:

convert

public static AiChatTongyiRespPo convert(AiResponse aiResponse) {AiChatTongyiRespPo po = new AiChatTongyiRespPo();ApplicationUsage.ModelUsage modelUsage = aiResponse.getUsage().get(0);// 将 DTO 中的数据映射到 PO 中po.setRequestId(aiResponse.getRequestId());po.setPrompt(aiResponse.getPrompt());po.setText(aiResponse.getText());po.setFinishReason(aiResponse.getFinishReason());po.setModelId(modelUsage.getModelId());po.setInputTokens(String.valueOf(modelUsage.getInputTokens()));po.setOutputTokens(String.valueOf(modelUsage.getOutputTokens()));
​return po;}

再来写实现层就好写了

service

public TongyiChatRespDto chat(TongyiChatReqDto dto) {try {// 构建API调用参数ApplicationParam param = ApplicationParam.builder().apiKey(aliyunProperties.getTongyi().getApiKey()).appId(aliyunProperties.getTongyi().getChatAppId()).prompt(dto.getPrompt()).build();Application application = new Application();ApplicationResult result = application.call(param);// 创建返回对象AiResponse response = new AiResponse(result.getRequestId(), dto.getPrompt(), result.getOutput().getText(), result.getOutput().getFinishReason(), result.getUsage());// 将 AiResponse 转换为实体类 AiChatTongyiRespPoAiChatTongyiRespPo po = AiResponseToPoConverter.convert(response);aiChatTongyiRespRepository.saveAiResponse(po);return new TongyiChatRespDto().setReply(result.getOutput().getText());

到现在写service就很好写了,通过层级划分(DTO、Service、Repository、PO 等),清晰分离了不同的职责,保证了代码的可维护性和扩展性。引入 Converter 模块将 DTO 转换为实体对象,简化了业务层的逻辑并实现了代码的复用。这一框架实现了从用户输入到 AI 模型响应再到数据持久化的全链路处理,下一章我们继续完善前端通信部分。

相关文章:

如何优雅的在页面上嵌入AI-Agent人工智能

前言 IDEA启动&#xff01;大模型的title想必不用我多说了&#xff0c;多少公司想要搭上时代前言技术的快车&#xff0c;感受科技的魅力。现在大模型作为降本增效的强大工具&#xff0c;基本上公司大多人都想要部署开发一把&#xff0c;更多的想要利用到这些模型放到生产中来提…...

如何对LabVIEW软件进行性能评估?

对LabVIEW软件进行性能评估&#xff0c;可以从以下几个方面着手&#xff0c;通过定量与定性分析&#xff0c;全面了解软件在实际应用中的表现。这些评估方法适用于确保LabVIEW程序的运行效率、稳定性和可维护性。 一、响应时间和执行效率 时间戳测量&#xff1a;使用LabVIEW的时…...

动态规划 —— dp问题-按摩师

1. 按摩师 题目链接&#xff1a; 面试题 17.16. 按摩师 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/the-masseuse-lcci/description/ 2. 算法原理 状态表示&#xff1a;以某一个位置为结尾或者以某一个位置为起点 dp[i]表示&#xff1a;选择到i位置…...

SQL 语法学习

在当今数字化的时代&#xff0c;数据的管理和分析变得至关重要。而 SQL&#xff08;Structured Query Language&#xff09;&#xff0c;即结构化查询语言&#xff0c;作为一种用于管理关系型数据库的强大工具&#xff0c;掌握它对于从事数据相关工作的人来说是一项必备技能。在…...

MYSQL---TEST5(Trigger触发器Procedure存储过程综合练习)

触发器Trigger 数据库mydb16_trigger创建 表的创建 goods create table goods( gid char(8) primary key, #商品号 name varchar(10), #商品名 price decimal(8,2), #价格 num int&#xff1b;&#xff09; #数量orders create tabl…...

蓝桥杯 区间移位--二分、枚举

题目 代码 #include <stdio.h> #include <string.h> #include <vector> #include <algorithm> #include <iostream> using namespace std; struct node{ int a,b; }; vector<node> q; bool cmp(node x,node y){ return x.b <…...

Nginx 报错400 Request Header Or Cookie Too Large

错误的原因&#xff1a; 1、可能是你的网络DNS配置错误。 2、由request header过大所引起&#xff0c;request过大&#xff0c;通常是由于cookie中写入了较大的值所引起的。 3、访问太频繁&#xff0c;浏览器的缓存量太大&#xff0c;产生错误。 解决办法&#xff1a; 1、清…...

【Redis】一种常见的Redis分布式锁原理简述

本文主要简述一下基于set命令的Redis分布式锁的原理。 一&#xff0c;a线程持有的锁不要被b线程同时持有→setnx 抢锁的时候&#xff0c;最核心的就是&#xff0c;a线程持有的锁不要被b线程同时持有&#xff0c;放在基于set命令的redis分布式锁中来看&#xff0c;就是“如果锁…...

HOT100_最大子数组和

class Solution {public int maxSubArray(int[] nums) {int[] dp new int[nums.length];int res nums[0];dp[0] nums[0];for(int i 1; i< nums.length; i){dp[i] Math.max(nums[i] ,dp[i-1] nums[i]);res Math.max(res, dp[i]);}return res;} }...

DiskGenius工具扩容Mac OS X Apple APFS分区

DiskGenius是一款功能强大的磁盘分区工具&#xff0c;它支持Windows和Mac OS X系统&#xff0c;可以用于管理硬盘分区&#xff0c;包括扩容Mac OS X的Apple APFS分区。然而&#xff0c;直接使用DiskGenius来扩容Mac OS X的APFS分区可能存在一定的风险&#xff0c;因为不是专门为…...

从零开始的LeetCode刷题日记:70. 爬楼梯

一.相关链接 题目链接&#xff1a;70. 爬楼梯 二.心得体会 这道题还是动规五部曲。 1.首先是dp数组及其下标的含义&#xff0c;dp记录了每层楼梯对应的爬的方法&#xff0c;每个下标存储每个对应楼层。 2.然后是递归公式&#xff0c;其实每一层楼都是可以从下面一层和下面…...

Unity照片墙效果

Unity照片墙效果&#xff0c;如下效果展示 。 工程源码...

【自动化利器】12个评估大语言模型(LLM)质量的自动化框架

LLM评估是指在人工智能系统中评估和改进语言和语言模型的过程。在人工智能领域&#xff0c;特别是在自然语言处理&#xff08;NLP&#xff09;及相关领域&#xff0c;LLM评估具有至高无上的地位。通过评估语言生成和理解模型&#xff0c;LLM评估有助于细化人工智能驱动的语言相…...

【1】基础概念

文章目录 一、特点二、基础语法注意三、官方编程指南四、go 语言标准库 API 一、特点 golang 一个 go 文件都要归属到一个包&#xff0c;需要进行申明。天然的并发&#xff1a;golang 从语言层面支持大并发。每个 go 文件都必须要归属到一个包中。执行 go 文件&#xff1a;go …...

HTML 文档规范与解析模式:DOCTYPE、<html> 标签以及结构化页面

文章目录 `<!DOCTYPE html>` 文档类型声明标准模式与怪异模式HTML5 的简化声明`<html>` 标签`<head>` 标签`<body>` 标签小结<!DOCTYPE html> 文档类型声明 在 HTML 文档中,<!DOCTYPE html> 是一个重要的文档类型声明,主要用于告知浏览…...

大模型微调技术 --> 脉络

Step1:脉络 微调技术从最早期的全模型微调演变成如今的各种参数高效微调(PEFT)方法&#xff0c;背后是为了应对大模型中的计算、存储和数据适应性的挑战 1.为什么有微调&#xff1f; 深度学习模型越来越大&#xff0c;尤其是 NLP 中的预训练语言模型(BERT, GPT)系列。如果从…...

不要只知道deepl翻译,这里有10个专业好用的翻译工具等着你。

deepl翻译的优点还是有很多的&#xff0c;比如翻译的准确性很高&#xff0c;支持翻译的语言有很多&#xff0c;并且支持翻译文件和文本。但是现在翻译工具那么多&#xff0c;大家需要翻译的场景也有很多&#xff0c;怎么能只拥有一个翻译工具呢。所以在这里我帮助大家寻找了一波…...

第二节 管道符、重定向与环境变量

1.重定向技术的 5 种模式 &#xff08;1&#xff09;标准覆盖输出重定向 &#xff08;2&#xff09;标准追加输出重定向 &#xff08;3&#xff09;错误覆盖输出重定向 &#xff08;4&#xff09;错误追加输出重定向 &#xff08;5&#xff09;输入重定向2.输入输出重定向 输入…...

Linux 服务器使用指南:从入门到登录

&#x1f31f;快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f31f; &#x1f6a9;博主致力于用通俗易懂且不失专业性的文字&#xff0c;讲解计算机领域那些看似枯燥的知识点&#x1f6a9; 目录 一…...

QT 如何使QLabel的文字垂直显示

想要实现QLabel文字的垂直显示&#xff0c;可以通过使用“文字分割填充换行符”的方式来实现QLabel文字垂直显示的效果&#xff0c;下面是效果图&#xff1a; 具体实现代码&#xff1a; #include "mainwindow.h" #include "ui_mainwindow.h"MainWindow:…...

蓬勃发展:移动开发——关于软件开发你需要知道些什么

一、前言 移动开发一直都是软件开发领域中最有趣的领域之一&#xff0c;这是因为&#xff1a; 1、移动开发为“只有一个人”的开发团队提供了一个非常独特的机会&#xff0c;让他可以在相对较短的时间内建立一个实际的、可用的、有意义的应用程序&#xff1b; 2、移动开发也代…...

1095. 山脉数组中查找目标值

目录 题目解法lambda在这是怎么用的&#xff1f; 题目 &#xff08;这是一个 交互式问题 &#xff09; 你可以将一个数组 arr 称为 山脉数组 当且仅当&#xff1a; arr.length > 3 存在一些 0 < i < arr.length - 1 的 i 使得&#xff1a; arr[0] < arr[1] <…...

【深度学习】InstantIR:图片高清化修复

InstantIR——借助即时生成参考的盲图像修复新方法 作者:Jen-Yuan Huang 等 近年来,随着深度学习和计算机视觉技术的飞速发展,图像修复技术取得了令人瞩目的进步。然而,对于未知或复杂退化的图像进行修复,仍然是一个充满挑战的任务。针对这一难题,研究者们提出了 Insta…...

推荐一款PowerPoint转Flash工具:iSpring Suite

iSpring Suite是一款PowerPoint转Flash工具&#xff0c;使用iSpring Suite 8可以轻松的将PPT演示文档转换为对Web友好的Flash影片格式。软件界面简洁&#xff0c;使用方便。为什么要转换成flash格式呢?Flash格式的最大特点是体积小巧、易于分发&#xff0c;兼容所有的操作系统…...

如何搭建汽车行业AI知识库:定义+好处+方法步骤

在汽车行业&#xff0c;大型车企面临着员工众多、价值链长、技术密集和知识传播难等挑战。如何通过有效的知识沉淀与应用&#xff0c;提升各部门协同效率&#xff0c;快速响应客户咨询&#xff0c;降低销售成本&#xff0c;并开启体系化、可持续性的知识管理建设&#xff0c;成…...

创新材料科技:铜冷却壁助力高炉节能降耗

高炉用铜冷却壁是高炉内部的一种构件&#xff0c;通常用于高炉的炉身部分。它的主要功能是在高炉冶炼过程中冷却炉壁&#xff0c;以防止炉壁过热。铜冷却壁通常由铜制成&#xff0c;因为铜具有良好的导热性和耐腐蚀性&#xff0c;能够有效地将热量从高炉内部传导到外部&#xf…...

Proteus中单片机IO口外接LED输出低电平时,引脚却一直保持高电平的问题(已解决)

文章目录 前言解决方法后记 前言 一个排阻接八个 LED&#xff0c;方便又省事&#xff0c;但出现了P1端口输出低电平后&#xff0c;仿真引脚却一直显示红色保持高电平不变&#xff0c;用电压表测量显示 2V 左右。 这是仿真的问题&#xff0c;在用开发板时是不会遇到的&#xff…...

Obsidian vs Typora

引言 近来几日&#xff0c;自己也算是用了一段时间的Obsidian了&#xff0c;也是有资格来说一下使用感受了。当前感觉是自己未来很长一段时间将会一直使用Obsidian了。 Typora vs Obsidian Typora 优点 整体好看&#xff0c;简洁&#xff0c;所见即所得 缺点&#xff1a;…...

非线性数据结构之图

一、有向图&#xff08;Directed Graph&#xff09; 1. 定义 有向图是一个由顶点&#xff08;节点&#xff09;和有方向的边&#xff08;弧&#xff09;组成的图。在有向图中&#xff0c;每条边都有一个起点和一个终点&#xff0c;表示从一个顶点到另一个顶点的关系。 2. 特…...

vue3项目history模式部署404处理,使用 historyApiFallback 中间件支持单页面应用路由

vue3项目history模式部署404处理&#xff0c;使用 historyApiFallback 中间件支持单页面应用路由 在现代的 web 开发中&#xff0c;单页面应用&#xff08;SPA&#xff09;变得越来越流行。这类应用通常依赖于客户端路由来提供流畅的用户体验&#xff0c;但在服务器端&#xf…...