真实的企业级应用,从来不是“能跑通就行”,而是要满足「可访问、可部署、可并发、有界面」的核心需求。今天这篇,我们就完成整个系列的闭环:把上一篇优化好的“企业智能数据分析Agent”,封装成一个完整的Web应用,用Spring Boot做后端、Vue3做前端,最后用Docker一键打包部署,让你一分钟把Agent丢到服务器上,任何人都能通过浏览器访问使用。

全程复用前两篇的核心代码,只做“封装化”和“界面化”改造,不新增复杂依赖,新手跟着步骤走,也能轻松拿下全栈项目。先明确本次实战目标,做到心中有数:

  1. 后端改造:用Spring Boot封装Agent核心逻辑,提供RESTful API接口,支持跨域访问,兼容前端请求;
  2. 前端开发:用Vue3 + Element Plus搭建简洁易用的聊天界面,支持用户输入问题、展示Agent响应结果、自动渲染图表;
  3. 部署优化:编写Dockerfile和docker-compose配置,实现后端、前端、依赖服务(MySQL、ES、Redis)一键启动,环境无关、部署无忧。

在开始之前,先回顾下我们已有的核心组件(复用前两篇内容,不用重新搭建):

  • LLM:通义千问(主力)+ GPT-4(备用),带Redis缓存;
  • RAG:Elasticsearch + 通义千问Embedding,带相似度筛选,检索精准;
  • Skills:JdbcTool(查数据库)、ChartTool(生成图表)、VectorStoreTool(查知识库),带决策校验;
  • 核心逻辑:MCP规则规范工具调用,Agent决策校验避免乱调用,整体稳定、省钱、精准。

一、整体架构设计(先搞懂“前后端怎么连”)

本次Web应用采用「前后端分离」架构,核心逻辑清晰,各组件职责明确,避免耦合,方便后续扩展和维护。整体架构图如下(新手可重点记住流程):

  1. 前端(Vue3):用户操作界面,负责接收用户输入的问题,发送请求到后端,展示Agent返回的结果(文本+图表);
  2. 后端(Spring Boot):核心服务层,封装Agent所有逻辑,提供API接口,接收前端请求,调用Agent处理,返回响应结果;
  3. 核心依赖:MySQL(存储业务数据,供JdbcTool查询)、Elasticsearch(存储知识库向量,供RAG检索)、Redis(缓存LLM响应,减少调用成本);
  4. 部署层:Docker打包所有服务,通过docker-compose一键启动,实现环境隔离、快速部署。

简单来说,用户在浏览器输入问题 → 前端发送请求 → 后端调用Agent处理 → Agent调用工具/LLM/RAG → 后端返回结果 → 前端展示结果,整个流程闭环,用户无需关注底层逻辑,只需专注于提问和查看结果。

二、后端改造:Spring Boot封装Agent(核心步骤)

后端改造的核心目标:将前两篇的Agent核心逻辑,封装成Spring Boot服务,提供API接口,同时优化配置、解决跨域,确保前端能正常调用。全程复用已有代码,只做“封装”和“适配”,不修改核心逻辑。

1. 项目结构调整(规范Spring Boot项目结构)

首先,将前两篇的代码调整为标准的Spring Boot项目结构,方便管理和维护,调整后结构如下(重点关注核心包):


agent-web-backend/

├── src/

│   ├── main/

│   │   ├── java/

│   │   │   └── com/enterprise/agent/

│   │   │       ├── config/          // 配置类(复用前两篇的Config)

│   │   │       │   ├── McpConfig.java

│   │   │       │   ├── LlmConfig.java

│   │   │       │   ├── RagConfig.java

│   │   │       │   └── SkillsConfig.java

│   │   │       ├── validator/       // 决策校验器(复用)

│   │   │       │   └── AgentDecisionValidator.java

│   │   │       ├── service/         // 新增:Agent服务封装

│   │   │       │   └── AgentService.java

│   │   │       ├── controller/      // 新增:API接口控制器

│   │   │       │   └── AgentController.java

│   │   │       └── AgentWebApplication.java  // 启动类(优化)

│   │   └── resources/

│   │       └── application.yml      // 配置文件(统一管理所有参数)

│   └── test/                        // 测试类(可选)

└── pom.xml                          // 依赖管理(新增必要依赖)

2. 核心依赖调整(修改pom.xml)

在原有依赖基础上,新增Spring Boot Web依赖(提供API接口)、跨域依赖,确保后端能正常接收前端请求,依赖如下(直接替换原有pom.xml相关内容):


<?xmlversion="1.0" encoding="UTF-8"?>

<projectxmlns="http://maven.apache.org/POM/4.0.0"

         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <parent>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-parent</artifactId>

        <version>2.7.18</version>

        <relativePath/>

    </parent>

    <groupId>com.enterprise.agent</groupId>

    <artifactId>agent-web-backend</artifactId>

    <version>1.0.0</version>

    <properties>

        <maven.compiler.source>17</maven.compiler.source>

        <maven.compiler.target>17</maven.compiler.target>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    </properties>

    <dependencies>

        <!-- Spring Boot Web 依赖(提供API接口) -->

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-web</artifactId>

        </dependency>

        <!-- Redis缓存依赖(复用前两篇,缓存LLM响应) -->

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-data-redis</artifactId>

        </dependency>

        <!-- LangChain4j 核心依赖 -->

        <dependency>

            <groupId>dev.langchain4j</groupId>

            <artifactId>langchain4j-core</artifactId>

            <version>0.21.0</version>

        </dependency>

<!-- 通义千问 LLM + Embedding 依赖 -->

        <dependency>

            <groupId>dev.langchain4j</groupId>

            <artifactId>langchain4j-tongyi</artifactId>

            <version>0.21.0</version>

        </dependency>

        <!-- GPT-4 依赖(备用LLM) -->

        <dependency>

            <groupId>dev.langchain4j</groupId>

            <artifactId>langchain4j-openai</artifactId>

            <version>0.21.0</version>

        </dependency>

        <!-- Elasticsearch 向量存储依赖(RAG) -->

        <dependency>

            <groupId>dev.langchain4j</groupId>

            <artifactId>langchain4j-elasticsearch</artifactId>

            <version>0.21.0</version>

        </dependency>

        <!-- MySQL + JDBC 依赖(JdbcTool) -->

        <dependency>

            <groupId>mysql</groupId>

            <artifactId>mysql-connector-java</artifactId>

            <scope>runtime</scope>

        </dependency>

        <dependency>

            <groupId>com.zaxxer</groupId>

            <artifactId>HikariCP</artifactId>

        </dependency>

        <!-- 跨域支持(解决前端调用后端的跨域问题) -->

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-webflux</artifactId>

        </dependency>

        <!-- 测试依赖(可选) -->

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-test</artifactId>

            <scope>test</scope>

        </dependency>

    </dependencies>

    <build>

        <plugins>

            <!-- Spring Boot 打包插件,生成可执行Jar包 -->

            <plugin>

                <groupId>org.springframework.boot</groupId>

                <artifactId>spring-boot-maven-plugin</artifactId>

                <version>2.7.18</version>

            </plugin>

        </plugins>

    </build>

</project>

3. 配置文件优化(application.yml)

将前两篇的硬编码参数(API密钥、数据库连接、ES配置等)全部移到application.yml中,统一管理,方便不同环境(开发、测试、生产)切换,无需修改代码。配置如下(替换原有配置,根据自己的实际环境修改参数):


# 服务器配置

server:

  port: 8080  # 后端服务端口,前端调用时需要对应

  servlet:

    context-path: /api  # 接口前缀,所有API都以/api开头

# Spring 核心配置

spring:

  # Redis配置(用于LLM缓存)

  data:

    redis:

      host: localhost  # 本地开发用localhost,服务器部署替换为服务器IP

      port: 6379

      database: 0

      timeout: 10000ms

  # MySQL配置(用于JdbcTool查询业务数据)

  datasource:

    url: jdbc:mysql://localhost:3306/enterprise_db?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true

    username: root  # 自己的MySQL用户名

    password: your-mysql-password  # 自己的MySQL密码

    driver-class-name: com.mysql.cj.jdbc.Driver

    hikari:

      maximum-pool-size: 10  # 连接池大小,优化性能

# 大模型配置(LLM)

llm:

  tongyi:

    api-key: your-tongyi-api-key  # 自己的通义千问API密钥

    model-name: qwen-plus  # 通义千问主力模型

  gpt4:

    api-key: your-gpt4-api-key  # 自己的GPT-4 API密钥(备用)

    model-name: gpt-4

# RAG配置(知识库检索)

rag:

  es:

    host: localhost  # 本地开发用localhost,服务器部署替换为服务器IP

    port: 9200

  similarity-threshold: 0.75  # 相似度标准,和前两篇一致

  tongyi-api-key: your-tongyi-api-key  # 通义千问Embedding API密钥

# 日志配置(可选,方便排查问题)

logging:

  level:

    com.enterprise.agent: info  # 自己的包路径,日志级别info

    dev.langchain4j: warn  # LangChain4j日志级别warn,避免日志过多

    root: info

  file:

    name: ./logs/agent-web.log  # 日志文件存储路径

    max-size: 100MB  # 单个日志文件最大大小

    max-history: 7  # 日志保留7天

4. 核心代码封装(新增Service和Controller)

这一步是后端改造的核心:将Agent的初始化、调用逻辑,封装到AgentService中,对外提供统一的调用方法;再通过AgentController提供RESTful API接口,供前端调用。全程复用前两篇的核心逻辑,不做修改。

(1)AgentService.java(服务层,封装Agent核心逻辑)

负责初始化Agent的所有依赖(LLM、RAG、Skills),提供execute方法供Controller调用,同时集成决策校验和缓存逻辑。


packagecom.enterprise.agent.service;

importcom.enterprise.agent.config.McpConfig;

importcom.enterprise.agent.config.RagConfig;

importcom.enterprise.agent.config.SkillsConfig;

importcom.enterprise.agent.validator.AgentDecisionValidator;

importdev.langchain4j.agent.DefaultAgent;

importdev.langchain4j.agent.tool.Tool;

importdev.langchain4j.model.chat.ChatLanguageModel;

importorg.springframework.beans.factory.annotation.Value;

importorg.springframework.data.redis.core.StringRedisTemplate;

importorg.springframework.stereotype.Service;

importjavax.annotation.PostConstruct;

importjava.util.List;

/**

* Agent服务类:封装Agent核心逻辑,对外提供调用方法

*/

@Service

publicclassAgentService {

    // 从配置文件注入参数

    @Value("${llm.tongyi.api-key}")

    privateStringtongyiApiKey;

    @Value("${llm.gpt4.api-key}")

    privateStringgpt4ApiKey;

    @Value("${rag.es.host}")

    privateStringesHost;

    @Value("${rag.es.port}")

    privateintesPort;

    @Value("${rag.similarity-threshold}")

    privatedoublesimilarityThreshold;

    @Value("${spring.datasource.url}")

    privateStringdbUrl;

    @Value("${spring.datasource.username}")

    privateStringdbUser;

    @Value("${spring.datasource.password}")

    privateStringdbPwd;

    // 注入RedisTemplate(用于LLM缓存)

    privatefinalStringRedisTemplateredisTemplate;

    // Agent实例(全局单例,初始化一次即可)

    privateDefaultAgentagent;

    // 构造器注入RedisTemplate

    publicAgentService(StringRedisTemplateredisTemplate) {

        this.redisTemplate=redisTemplate;

    }

    // 初始化方法:项目启动时自动初始化Agent,避免每次调用都重新初始化

    @PostConstruct

    publicvoidinitAgent() {

        // 1. 初始化LLM(主力:通义千问,备用:GPT-4),并设置Redis缓存

        com.enterprise.agent.config.LlmConfig.setRedisTemplate(redisTemplate);

        ChatLanguageModelmainLlm=com.enterprise.agent.config.LlmConfig.getTongyiLlm();

        // 2. 初始化RAG(知识库检索),加载知识库内容

        RagConfigragConfig=newRagConfig(esHost, esPort, tongyiApiKey, similarityThreshold);

        ragConfig.addKnowledgeToRag();

        // 3. 初始化Skills(工具集)

        TooljdbcTool=SkillsConfig.getJdbcTool(dbUrl, dbUser, dbPwd);  // 优化:从配置文件获取数据库参数

        ToolvectorStoreTool=SkillsConfig.getVectorStoreTool();

        ToolchartTool=SkillsConfig.getChartTool();

        List<Tool>tools=List.of(jdbcTool, vectorStoreTool, chartTool);

        // 4. 初始化Agent(绑定MCP规则、LLM、工具)

        this.agent=McpConfig.getAgentBuilder(mainLlm, tools).build();

        System.out.println("Agent服务初始化完成,可正常调用");

    }

    // 对外提供的核心方法:接收用户问题,调用Agent处理,返回结果(带缓存)

    publicStringexecuteAgent(StringuserQuestion) {

        try {

            // 1. 决策校验:筛选可用工具,避免乱调用

            List<Tool>validTools=AgentDecisionValidator.filterValidTools(userQuestion, agent.getTools());

            DefaultAgentvalidAgent=agent.toBuilder().tools(validTools).build();

            // 2. 调用Agent处理问题,并用缓存优化(复用前两篇的缓存逻辑)

            StringagentResult=validAgent.execute(userQuestion);

            returncom.enterprise.agent.config.LlmConfig.callLlmWithCache(agentResult);

        } catch (Exceptione) {

            // 异常处理:返回友好提示,避免前端报错

            return"Agent调用失败,请稍后再试!错误信息:"+e.getMessage().substring(0, 100);

        }

    }

}

(2)AgentController.java(控制器,提供API接口)

提供POST接口,接收前端发送的用户问题,调用AgentService的方法处理,返回响应结果,同时解决跨域问题,确保前端能正常调用。


packagecom.enterprise.agent.controller;

importcom.enterprise.agent.service.AgentService;

importorg.springframework.web.bind.annotation.*;

/**

* Agent接口控制器:提供RESTful API,供前端调用

*/

@RestController

@RequestMapping("/agent")  // 接口路径:/api/agent(结合server.context-path)

@CrossOrigin(origins="*", maxAge=3600)  // 解决跨域问题,开发环境允许所有来源

publicclassAgentController {

    // 注入AgentService

    privatefinalAgentServiceagentService;

    // 构造器注入

    publicAgentController(AgentServiceagentService) {

        this.agentService=agentService;

    }

    /**

     * 核心接口:接收用户问题,返回Agent响应结果

     * 接口路径:POST /api/agent/chat

     * 请求体:用户问题(字符串)

     */

    @PostMapping("/chat")

    publicStringchat(@RequestBodyStringuserQuestion) {

        // 校验用户问题:非空校验

        if (userQuestion==null||userQuestion.trim().isEmpty()) {

            return"请输入有效的问题!";

        }

        // 调用AgentService处理问题,返回结果

        returnagentService.executeAgent(userQuestion.trim());

    }

}

(3)SkillsConfig.java 优化(适配配置文件参数)

修改SkillsConfig中的getJdbcTool方法,从配置文件获取数据库参数(之前是硬编码),适配Spring Boot的配置管理,修改后如下:


// 优化JdbcTool:从配置文件获取数据库参数,不再硬编码

publicstaticJdbcToolgetJdbcTool(StringdbUrl, StringdbUser, StringdbPwd) {

    HikariConfigconfig=newHikariConfig();

    config.setJdbcUrl(dbUrl);  // 从配置文件注入

    config.setUsername(dbUser);  // 从配置文件注入

    config.setPassword(dbPwd);  // 从配置文件注入

    DataSourcedataSource=newHikariDataSource(config);

    // 优化后描述:说清楚什么时候用、什么时候不用

    Stringdescription="只用来查企业MySQL数据库里的销售额、用户量等未知业务数据,输入合法的SQL语句,输出表格形式的查询结果;不用查数据的时候,绝对不能调用。";

    returnJdbcTool.builder()

            .dataSource(dataSource)

            .description(description)

            .build();

}

(4)启动类优化(AgentWebApplication.java)

修改启动类,确保Spring Boot能正常扫描到Service、Controller、Config等组件,无需额外修改核心逻辑。


packagecom.enterprise.agent;

importorg.springframework.boot.SpringApplication;

importorg.springframework.boot.autoconfigure.SpringBootApplication;

/**

* Spring Boot启动类:启动整个后端服务

*/

@SpringBootApplication(scanBasePackages="com.enterprise.agent")  // 扫描所有组件

publicclassAgentWebApplication {

    publicstaticvoidmain(String[] args) {

        SpringApplication.run(AgentWebApplication.class, args);

        System.out.println("Agent后端服务启动成功,访问地址:http://localhost:8080/api");

    }

}

5. 后端测试(确保接口能正常调用)

后端改造完成后,启动Spring Boot项目(运行AgentWebApplication.java),项目启动成功后,用Postman或浏览器测试API接口,确保能正常返回结果。

  1. 测试接口:POST http://localhost:8080/api/agent/chat
  2. 请求体:{“查询2026年2月销售额Top3的产品,生成柱状图,并解释为什么这三个产品销量高”}
  3. 预期结果:能正常返回Agent的响应(包含数据结论、图表HTML、原因解释),无报错。

测试通过后,说明后端接口已封装完成,前端可以正常调用了。


三、前端开发:Vue3搭建聊天界面(新手友好)前端开发目标:用Vue3 + Element Plus搭建一个简洁、易用的聊天界面,类似ChatGPT的交互逻辑,支持用户输入问题、发送请求、展示结果(文本+图表),新手也能快速上手,无需复杂的前端基础。

1. 项目初始化(创建Vue3项目)

首先,确保本地安装了Node.js(建议版本16+),然后执行以下命令,新建Vue3项目并安装依赖:


# 1. 新建Vue3项目(选择默认Vue3模板即可)

vue create agent-frontend

# 2. 进入项目目录

cd agent-frontend

# 3. 安装依赖(Element Plus:UI组件库;axios:发送HTTP请求)

npm install element-plus axios

2. 项目结构调整(简化,聚焦核心页面)

删除Vue3默认的多余文件,保留核心文件,调整后结构如下(重点关注src目录):


agent-frontend/

├── src/

│   ├── main.js          // 入口文件,引入Element Plus和axios

│   ├── App.vue          // 核心页面(聊天界面)

│   └── assets/          // 静态资源(可选,如图片)

├── package.json         // 依赖管理

└── vue.config.js        // Vue配置(可选,用于跨域代理)

3. 核心代码开发

(1)main.js(入口文件,引入依赖)

引入Element Plus(UI组件库)、axios(发送请求),全局注册,方便在页面中使用。


import { createApp } from'vue'

importElementPlusfrom'element-plus'  // 引入Element Plus

import'element-plus/dist/index.css'    // 引入Element Plus样式

importaxiosfrom'axios'               // 引入axios

importAppfrom'./App.vue'

constapp=createApp(App)

// 全局注册Element Plus

app.use(ElementPlus)

// 配置axios(全局使用)

app.config.globalProperties.$axios=axios

// 配置后端接口基础路径(和后端server.port、context-path对应)

axios.defaults.baseURL='http://localhost:8080/api'

// 配置请求超时时间

axios.defaults.timeout=30000

app.mount('#app')

(2)App.vue(核心聊天界面)

搭建聊天界面,包含头部标题、聊天记录展示区、输入框、发送按钮,实现“发送问题→展示结果”的完整交互,支持自动渲染图表(Agent返回的HTML图表会直接渲染)。


<template>

  <div class="agent-chat-container">

    <!-- 头部标题 -->

    <el-headerclass="chat-header">

      <h1>企业智能数据分析Agent</h1>

      <pclass="sub-title">支持查询数据、生成图表、解读原因,一键搞定数据分析</p>

    </el-header>

    <!-- 聊天记录展示区 -->

    <el-mainclass="chat-content">

      <!-- 空状态(无聊天记录时显示) -->

      <divclass="empty-state"v-if="chatList.length === 0">

        <el-iconsize="60"class="empty-icon"><Message/></el-icon>

        <pclass="empty-tip">请输入问题开始对话</p>

        <divclass="example-questions">

          <el-tagtype="primary"@click="selectExample('查询2026年2月销售额Top3产品')">查询2026年2月销售额Top3产品</el-tag>

          <el-tagtype="primary"@click="selectExample('生成2月销售额柱状图')">生成2月销售额柱状图</el-tag>

          <el-tagtype="primary"@click="selectExample('解释产品A销量高的原因')">解释产品A销量高的原因</el-tag>

        </div>

      </el-icon>

      </div>

      <!-- 聊天记录列表 -->

      <divclass="chat-list"v-else>

        <div

          v-for="(item, index) in chatList"

          :key="index"

          :class="item.role === 'user' ? 'user-chat' : 'agent-chat'"

        >

          <divclass="chat-avatar">

            <el-avatar:icon="item.role === 'user' ? User : Bot"/>

          </div>

          <divclass="chat-message"v-html="item.content"></div>

        </div>

      </div>

    </el-main>

    <!-- 输入框区域 -->

    <el-footerclass="chat-input-area">

      <el-input

        v-model="inputValue"

        placeholder="请输入问题(例如:查询2026年2月销售额Top3产品)..."

        class="input-box"

        @keyup.enter="sendMessage"

        clearable

      >

        <template#append>

          <el-buttontype="primary"icon="Send"@click="sendMessage":disabled="!inputValue.trim()">

            发送

          </el-button>

        </template>

      </el-input>

      <pclass="tip-text">提示:支持查询数据、生成图表、解读原因,输入后按回车或点击发送</p>

    </el-footer>

  </div>

</template>

<scriptsetup>

import { ref } from'vue'

import { ElMessage, ElTag, ElAvatar, ElIcon } from'element-plus'

import { Message, User, Bot, Send } from'@element-plus/icons-vue'

importaxiosfrom'axios'

// 聊天记录列表:存储用户和Agent的对话

constchatList=ref([])

// 输入框内容

constinputValue=ref('')

// 选择示例问题(点击标签自动填充输入框)

constselectExample= (question) => {

  inputValue.value=question

}

// 发送消息

constsendMessage=async () => {

  // 非空校验

  constquestion=inputValue.value.trim()

  if (!question) {

    ElMessage.warning('请输入有效的问题!')

    return

  }

  // 1. 添加用户消息到聊天列表

  chatList.value.push({

    role: 'user',

    content: question

  })

  // 2. 添加加载中提示(提升用户体验)

  constloadingIndex=chatList.value.length

  chatList.value.push({

    role: 'agent',

    content: '<div class="loading">思考中...</div>'

  })

  // 3. 清空输入框

  inputValue.value=''

  try {

    // 4. 调用后端API接口

    constresponse=awaitaxios.post('/agent/chat', question, {

      headers: {

        'Content-Type': 'application/json'

      }

    })

    // 5. 替换加载中提示为Agent的响应结果

    chatList.value[loadingIndex] = {

      role: 'agent',

      content: response.data

    }

    // 6. 滚动到最新消息(自动定位到底部)

    setTimeout(() => {

      constchatContent=document.querySelector('.chat-content')

      chatContent.scrollTop=chatContent.scrollHeight

    }, 100)

  } catch (error) {

    // 异常处理:替换加载中提示为错误信息

    chatList.value[loadingIndex] = {

      role: 'agent',

      content: '调用失败,请稍后再试!错误信息:'+ (error.message||'未知错误')

    }

    ElMessage.error('调用失败,请稍后再试!')

  }

}

</script>

<stylescoped>

.agent-chat-container {

  height: 100vh;

  display: flex;

  flex-direction: column;

  background-color: #f8f9fa;

}

/* 头部样式 */

.chat-header {

  background-color: #409eff;

  color: #fff;

  padding: 16px20px;

  text-align: center;

  box-shadow: 02px10pxrgba(0, 0, 0, 0.1);

}

.chat-headerh1 {

  font-size: 24px;

  margin: 008px0;

}

.chat-header.sub-title {

  font-size: 14px;

  opacity: 0.9;

  margin: 0;

}

/* 聊天内容区域 */

.chat-content {

  flex: 1;

  overflow-y: auto;

  padding: 20px;

  background-color: #fff;

}

/* 空状态样式 */

.empty-state {

  text-align: center;

  padding: 50px0;

  color: #666;

}

.empty-icon {

  color: #409eff;

  margin-bottom: 20px;

}

.empty-tip {

  font-size: 16px;

  margin-bottom: 30px;

}

.example-questions {

  display: flex;

  flex-wrap: wrap;

  gap: 10px;

  justify-content: center;

}

/* 聊天记录列表 */

.chat-list {

  display: flex;

  flex-direction: column;

  gap: 20px;

}

/* 用户聊天样式 */

.user-chat {

  display: flex;

  justify-content: flex-end;

  align-items: flex-start;

}

/* Agent聊天样式 */

.agent-chat {

  display: flex;

  justify-content: flex-start;

  align-items: flex-start;

}

/* 头像样式 */

.chat-avatar {

  margin: 010px;

}

/* 消息内容样式 */

.chat-message {

  max-width: 70%;

  padding: 12px16px;

  border-radius: 16px;

  line-height: 1.5;

  font-size: 14px;

}

.user-chat.chat-message {

  background-color: #e8f4fd;

  color: #333;

  border-bottom-right-radius: 4px;

}

.agent-chat.chat-message {

  background-color: #f5f5f5;

  color: #333;

  border-bottom-left-radius: 4px;

}

/* 加载中样式 */

.loading {

  display: flex;

  align-items: center;

  justify-content: center;

  color: #666;

}

.loading::after {

  content: '';

  width: 16px;

  height: 16px;

  border: 2pxsolid#409eff;

  border-top-color: transparent;

  border-radius: 50%;

  margin-left: 8px;

  animation: spin1slinearinfinite;

}

@keyframesspin {

  to { transform: rotate(360deg); }

}

/* 输入框区域样式 */

.chat-input-area {

  padding: 16px20px;

  background-color: #fff;

  border-top: 1pxsolid#e6e6e6;

}

.input-box {

  width: 100%;

  margin-bottom: 8px;

}

.tip-text {

  font-size: 12px;

  color: #999;

  margin: 0;

  text-align: center;

}

</style>

4. 前端测试(确保界面能正常交互)

前端代码开发完成后,执行以下命令启动前端项目:


npm run dev

启动成功后,访问控制台输出的地址(默认是http://localhost:8081),即可看到聊天界面,测试以下功能:

  1. 点击示例问题标签,能自动填充输入框;
  2. 输入问题,点击发送或按回车,能正常发送请求;
  3. 能看到“思考中”的加载提示,加载完成后展示Agent的响应结果;
  4. Agent返回的图表HTML,能正常渲染显示。

测试通过后,说明前端界面开发完成,前后端能正常联动。


四、Docker一键部署(企业级落地关键)到这里,我们已经完成了前后端的开发,但如果要部署到服务器上供其他人使用,还需要解决“环境不一致”的问题——不同服务器的Java、Node.js、MySQL、ES版本可能不同,导致项目无法正常运行。

解决方案:用Docker打包所有服务(后端、前端、MySQL、ES、Redis),通过docker-compose一键启动,实现“环境无关、一键部署”,任何人拿到配置文件,执行一条命令就能启动整个应用。

1. 准备工作(服务器环境)

确保服务器已安装Docker和docker-compose,安装步骤参考官方文档(简单来说,执行以下命令即可,以CentOS为例):


# 安装Docker

yum install -y docker

systemctl start docker

systemctl enable docker

# 安装docker-compose

yum install -y docker-compose

2. 后端Dockerfile(打包后端服务)

在后端项目(agent-web-backend)根目录,创建Dockerfile文件,用于打包后端Spring Boot服务,生成Docker镜像。


# 构建阶段:使用Maven打包项目

FROM maven:3.8-openjdk-17 AS build

WORKDIR /app

# 复制pom.xml,下载依赖(缓存依赖,避免每次打包都重新下载)

COPY pom.xml .

RUN mvn dependency:go-offline

# 复制源码,打包项目

COPY src ./src

RUN mvn package -DskipTests  # 跳过测试,加快打包速度

# 运行阶段:使用轻量的OpenJDK镜像,运行Jar包

FROM openjdk:17-jdk-slim

WORKDIR /app

# 从构建阶段复制打包好的Jar包

COPY --from=build /app/target/*.jar agent-backend.jar

# 暴露后端服务端口(和application.yml中的port一致)

EXPOSE 8080

# 启动命令:运行Jar包

ENTRYPOINT ["java", "-jar", "agent-backend.jar"]

3. 前端Dockerfile(打包前端服务)

在前端项目(agent-frontend)根目录,创建Dockerfile文件,用于打包前端Vue3项目,生成Docker镜像,用Nginx部署前端静态文件。


# 构建阶段:使用Node.js打包前端项目

FROM node:16 AS build

WORKDIR /app

# 复制package.json和package-lock.json,下载依赖

COPY package*.json ./

RUN npm install

# 复制源码,打包前端项目

COPY . .

RUN npm run build  # 生成dist目录(静态文件)

# 运行阶段:使用Nginx部署静态文件

FROM nginx:alpine

# 复制打包好的静态文件到Nginx的默认目录

COPY --from=build /app/dist /usr/share/nginx/html

# 暴露Nginx端口(默认80端口,用户通过浏览器访问)

EXPOSE 80

# 启动Nginx(后台运行)

CMD ["nginx", "-g", "daemon off;"]

4. docker-compose.yml(一键启动所有服务)

在服务器上,创建一个新的目录(如agent-web-deployment),将后端项目、前端项目复制到该目录下,然后在该目录下创建docker-compose.yml文件,配置所有服务(后端、前端、MySQL、ES、Redis),实现一键启动。


version: '3.8'  # docker-compose版本

services:

  # 1. MySQL服务(存储业务数据)

  mysql:

    image: mysql:8.0  # 使用MySQL 8.0镜像

    container_name: agent-mysql

    ports:

      - "3306:3306"  # 端口映射:主机3306 → 容器3306

    environment:

      MYSQL_ROOT_PASSWORD: root  # MySQL root密码(可修改)

      MYSQL_DATABASE: enterprise_db  # 数据库名称(和后端配置一致)

      MYSQL_CHARSET: utf8mb4  # 字符集

    volumes:

      - ./mysql-data:/var/lib/mysql  # 数据持久化:主机目录 → 容器目录,避免容器删除后数据丢失

    restart: always  # 容器异常退出后自动重启

    networks:

      - agent-network  # 加入自定义网络,方便服务间通信

  # 2. Elasticsearch服务(RAG知识库向量存储)

  elasticsearch:

    image: elasticsearch:8.10.0  # 使用ES 8.10.0镜像(和前两篇一致)

    container_name: agent-es

    ports:

      - "9200:9200"  # 端口映射:主机9200 → 容器9200

    environment:

      - discovery.type=single-node  # 单节点模式(适合部署和测试)

      - xpack.security.enabled=false  # 关闭安全验证(简化部署,生产环境可开启)

      - ES_JAVA_OPTS=-Xms512m -Xmx512m  # 设置JVM内存(根据服务器配置调整)

    volumes:

      - ./es-data:/usr/share/elasticsearch/data  # 数据持久化

    restart: always

    networks:

      - agent-network

  # 3. Redis服务(LLM缓存)

  redis:

    image: redis:alpine  # 使用轻量的Redis镜像

    container_name: agent-redis

    ports:

      - "6379:6379"  # 端口映射:主机6379 → 容器6379

    volumes:

      - ./redis-data:/data  # 数据持久化

    restart: always

    networks:

      - agent-network

  # 4. 后端服务(Spring Boot)

  agent-backend:

    build: ./agent-web-backend  # 构建后端镜像(指定后端项目目录)

    container_name: agent-backend

    ports:

      - "8080:8080"  # 端口映射:主机8080 → 容器8080

    depends_on:

      - mysql  # 依赖MySQL服务,MySQL启动后再启动后端

      - elasticsearch  # 依赖ES服务

      - redis  # 依赖Redis服务

    environment:

      # 环境变量:覆盖application.yml中的配置,适配Docker环境

      - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/enterprise_db?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true

      - SPRING_DATASOURCE_USERNAME=root

      - SPRING_DATASOURCE_PASSWORD=root

      - SPRING_REDIS_HOST=redis

      - RAG_ES_HOST=elasticsearch

      - RAG_ES_PORT=9200

      - LLM_TONGYI_API_KEY=your-tongyi-api-key  # 替换为自己的通义千问API密钥

      - LLM_GPT4_API_KEY=your-gpt4-api-key  # 替换为自己的GPT-4 API密钥

    restart: always

    networks:

      - agent-network

  # 5. 前端服务(Vue3)

  agent-frontend:

    build: ./agent-frontend  # 构建前端镜像(指定前端项目目录)

    container_name: agent-frontend

    ports:

      - "80:80"  # 端口映射:主机80 → 容器80(浏览器默认访问80端口)

    depends_on:

      - agent-backend  # 依赖后端服务,后端启动后再启动前端

    restart: always

    networks:

      - agent-network

# 自定义网络:所有服务加入同一个网络,方便通信

networks:

  agent-network:

    driver: bridge

5. 一键启动命令(部署核心步骤)

在docker-compose.yml所在的目录,执行以下命令,一键启动所有服务:


# 一键构建并启动所有服务(后台运行)

docker-compose up -d

# 查看所有服务运行状态

docker-compose ps

# 查看后端服务日志(排查问题用)

docker-compose logs -f agent-backend

# 停止所有服务

docker-compose down

# 停止并删除所有服务和镜像(谨慎使用)

docker-compose down --rmi all

启动成功后,等待3-5分钟(让所有服务初始化完成),然后在浏览器访问服务器IP(无需加端口,默认80端口),即可看到Agent聊天界面,正常使用所有功能。


五、系列总结:从代码到产品的完整闭环至此,我们的LangChain4j实战系列已经完成了完整的闭环,从基础入门到企业级落地,一步步带你搞定Agent开发:
  1. 第一篇(入门篇):搭建基础的“企业智能数据分析Agent”,整合LLM、RAG、Skills、MCP,实现核心功能跑通;
  2. 第二篇(进阶篇):解决Agent开发的三大痛点(乱调用工具、RAG检索不准、LLM调用又慢又贵),优化稳定性、精准度和性价比;
  3. 第三篇(实战篇):将Agent封装成Web应用,用Spring Boot做后端、Vue3做前端,Docker一键部署,实现企业级落地。

现在,你拥有的不仅仅是一个“能跑通的代码示例”,而是一个「可部署、可维护、可扩展、可共用」的企业级智能数据分析Agent,无论是作为个人项目,还是企业内部工具,都可以直接投入使用。

六、后续扩展建议(可选,提升Agent实用性)

如果想让这个Agent更强大、更贴合企业实际需求,可以继续扩展以下功能(都是企业里常用的需求,新手可逐步尝试):

  1. 用户权限管理:新增用户登录、角色管理,支持多用户隔离,不同用户只能查看自己权限范围内的数据;
  2. 功能扩展:新增更多Skills,比如Excel导出(将查询结果导出为Excel)、邮件发送(将分析结果发送到指定邮箱)、定时任务(定时生成数据分析报告);
  3. 性能优化:给RAG检索结果加缓存,进一步减少Embedding调用成本;优化数据库查询,添加索引,提升查询速度;
  4. 监控告警:新增监控面板,实时查看Agent调用量、LLM响应时间、工具调用成功率;添加异常告警,工具调用失败、LLM切换备用方案时,自动发邮件/钉钉通知开发人员;
  5. 界面优化:美化前端界面,新增历史聊天记录保存、主题切换、图表下载等功能,提升用户体验。

学AI大模型的正确顺序,千万不要搞错了

🤔2026年AI风口已来!各行各业的AI渗透肉眼可见,超多公司要么转型做AI相关产品,要么高薪挖AI技术人才,机遇直接摆在眼前!

有往AI方向发展,或者本身有后端编程基础的朋友,直接冲AI大模型应用开发转岗超合适!

就算暂时不打算转岗,了解大模型、RAG、Prompt、Agent这些热门概念,能上手做简单项目,也绝对是求职加分王🔋

在这里插入图片描述

📝给大家整理了超全最新的AI大模型应用开发学习清单和资料,手把手帮你快速入门!👇👇

学习路线:

✅大模型基础认知—大模型核心原理、发展历程、主流模型(GPT、文心一言等)特点解析
✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑
✅开发基础能力—Python进阶、API接口调用、大模型开发框架(LangChain等)实操
✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用
✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代
✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经

以上6大模块,看似清晰好上手,实则每个部分都有扎实的核心内容需要吃透!

我把大模型的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

在这里插入图片描述

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐