毕业设计选“SpringBoot + AI大模型影视评论舆情数据可视化分析平台”这类题目的同学,通常第一反应是先把页面搭出来,再想怎么接入大模型。实际上这个题目真正值钱的部分在于:数据从哪来、舆情指标怎么算、大模型在分析链路里到底承担什么角色、可视化页面如何把这些结果串起来。本文按“概念 -> 数据库 -> 后端 -> 可视化 -> 运行验证 -> 排错 -> 最佳实践”这条线,完整拆解一个可复现的影视评论舆情分析平台,适合 SpringBoot 有一定基础、想在毕设里接入 AI 大模型并补齐数据可视化能力的同学。
1. 先理解这个毕设题目的技术主线
1.1 这个项目到底在解决什么问题
影视评论数据天然适合做舆情分析。用户在豆瓣、猫眼、微博等平台留下的评论,包含情感倾向、评分、时间分布、影片类型偏好等信息。一个平台如果能把多部影片的评论聚合起来,实时展示“正面评论占比、负面评论集中在哪些时间段、哪个演员或导演的热度更高”,对制片方、宣发团队和视频平台都有参考价值。
这类系统放进毕业设计里,通常需要完成四件事:
- 评论数据采集与存储:有数据库表,能存电影、评论、用户、评分等信息。
- 舆情指标计算:按情感、时间、影片、评分区间做聚合统计。
- AI 大模型分析:让大模型对评论情感、核心观点、舆情摘要进行推理。
- 数据可视化:用图表把统计结果呈现出来,形成平台页面。
核心难点不是某个单一技术,而是把 SpringBoot + MySQL + AI 大模型接口 + ECharts 这四层串起来。任何一个环节断掉,整个系统都跑不通。
1.2 AI 大模型在舆情分析里承担什么角色
很多同学会误以为“AI 大模型舆情分析平台”就是把所有评论丢给大模型,让大模型返回结论。实际工程中这样做既贵又慢。合理的分工是:
- 传统统计负责确定性计算:评论数量、情感词频、评分均值、时间趋势,用 SQL 和聚合逻辑完成。
- 大模型负责语义理解:单条评论的隐含情感、多条评论的舆情摘要、宣发建议、影片口碑总结。
- 可视化负责结果呈现:统计结果用图表展示,大模型生成的分析报告单独展示。
换句话说,AI 大模型不是替代统计模块,而是给舆情分析增加一层“人话总结”能力。这个定位在论文写作和项目答辩时也更容易讲清楚。
1.3 技术选型与模块划分
推荐采用以下技术组合,既能满足毕设工作量,又不会因为过重依赖导致环境难配:
| 模块 | 技术选型 | 用途 |
|---|---|---|
| 后端框架 | SpringBoot 2.7.x / 3.x | 提供 HTTP 接口和业务逻辑 |
| 数据库 | MySQL 5.7 / 8.0 | 存储电影、评论、舆情统计结果 |
| 数据访问 | Spring Data JPA 或 MyBatis-Plus | 操作数据库 |
| AI 大模型 | 国内主流大模型 HTTP 接口 | 情感分析、评论摘要、舆情报告 |
| 可视化 | ECharts + Thymeleaf | 页面图表展示 |
| 数据来源 | 模拟数据 / 公开数据集 / 合规采集 | 初始化评论数据 |
模块上划分为四层:
- 数据层:实体类、Mapper 或 Repository、数据库初始化脚本。
- 服务层:评论服务、统计服务、AI 大模型服务。
- 接口层:RESTful Controller,返回 JSON 给前端。
- 展示层:Thymeleaf 页面 + ECharts 图表。
这个结构的好处是每一层都能单独测试。AI 大模型接口挂了,统计模块仍然可用,页面还能展示历史分析结果。
2. 环境准备与数据库设计
2.1 开发环境清单
开始编码前,先把环境对齐。这个项目最容易在第一周卡住的问题就是版本不一致,尤其是 SpringBoot 版本和 JDK 版本。
| 工具 | 建议版本 | 说明 |
|---|---|---|
| JDK | 8 或 17 | SpringBoot 2.7.x 用 JDK8,SpringBoot 3.x 必须 JDK17+ |
| Maven | 3.6+ | 项目构建和依赖管理 |
| MySQL | 5.7 或 8.0 | 数据库实例 |
| IDE | IntelliJ IDEA | 开发调试 |
| 浏览器 | Chrome/Edge | 页面预览和接口调试 |
这里要注意:热词里常见“springboot版本太高”的问题,本质是 SpringBoot 3.x 要求 JDK 17 和jakarta.*包,如果本地环境是 JDK 8,导入 3.x 项目后会出现编译错误。落地方案是:JDK 8 配 SpringBoot 2.7.x,JDK 17 配 SpringBoot 3.x。毕业设计如果不想折腾环境,SpringBoot 2.7.x + JDK 8 更稳妥。
2.2 数据库表结构设计
设计表结构时,不用铺太多表,但要覆盖完整分析链路。核心是 movie 和 comment 两张表,再加一张可选的 ai_analysis_record 表用于缓存大模型分析结果。
CREATE DATABASE IF NOT EXISTS movie_comment DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE movie_comment; CREATE TABLE movie ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '影片ID', title VARCHAR(255) NOT NULL COMMENT '影片名称', category VARCHAR(100) COMMENT '类型,如 动作/爱情/科幻', release_year INT COMMENT '上映年份', created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间' ) ENGINE=InnoDB COMMENT '影片表'; CREATE TABLE comment ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '评论ID', movie_id BIGINT NOT NULL COMMENT '关联影片ID', content TEXT NOT NULL COMMENT '评论内容', user_name VARCHAR(100) COMMENT '评论用户', sentiment INT DEFAULT 0 COMMENT '情感倾向:0中性 1正向 2负向', score DECIMAL(3,1) COMMENT '用户评分,范围 1.0-10.0', comment_time DATETIME COMMENT '评论时间', created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', INDEX idx_movie_id (movie_id), INDEX idx_comment_time (comment_time) ) ENGINE=InnoDB COMMENT '影视评论表'; CREATE TABLE ai_analysis_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '记录ID', movie_id BIGINT NOT NULL COMMENT '影片ID', analysis_type VARCHAR(50) NOT NULL COMMENT '分析类型:EMOTION/SUMMARY', result_json TEXT COMMENT '大模型返回的JSON结果', created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间' ) ENGINE=InnoDB COMMENT 'AI分析记录表';设计说明:
sentiment字段用 0/1/2 而不是直接存字符串,是为了后续 SQL 聚合更简单,统计时再映射成“中性/正向/负向”。score使用 DECIMAL,避免浮点数精度问题。ai_analysis_record表用于缓存,避免每次刷新页面都重复调用大模型接口。
2.3 Maven 依赖配置
用 Spring Initializr 创建工程后,pom.xml 至少需要以下依赖:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>如果使用的 SpringBoot 版本是 2.7.x,mysql-connector-java会自动选择 8.0.x 版本。如果是 SpringBoot 3.x,建议换成com.mysql:mysql-connector-j。
3. 构建后端核心功能
3.1 项目目录结构
后端目录按功能分包,避免把所有类堆在 controller 里:
src/main/java/com/example/moviecomment/ ├── controller/ │ ├── AnalysisController.java │ └── CommentController.java ├── entity/ │ ├── Movie.java │ ├── Comment.java │ └── AiAnalysisRecord.java ├── mapper/ │ ├── MovieMapper.java │ └── CommentMapper.java ├── service/ │ ├── CommentService.java │ ├── AnalysisService.java │ └── ai/ │ ├── AIModelService.java │ └── DefaultAIModelServiceImpl.java ├── config/ │ ├── RestTemplateConfig.java │ └── AiModelProperties.java └── common/ └── Result.java这种分包不是固定模板,但能让答辩时讲清楚“控制层、业务层、数据访问层、外部服务层”的职责边界。
3.2 实体与数据访问层
以 MyBatis-Plus 为例,Comment 实体可以这样写:
@Data @TableName("comment") public class Comment { @TableId(type = IdType.AUTO) private Long id; private Long movieId; private String content; private String userName; private Integer sentiment; private BigDecimal score; private LocalDateTime commentTime; }Mapper 接口:
@Mapper public interface CommentMapper extends BaseMapper<Comment> { }通过 MyBatis-Plus 自带的selectList、selectCount能完成大部分查询。涉及多表分组统计时,可以写自定义 SQL。下面这条查询统计每个电影的情感分布:
@Mapper public interface CommentMapper extends BaseMapper<Comment> { @Select("SELECT sentiment, COUNT(*) AS cnt FROM comment WHERE movie_id = #{movieId} GROUP BY sentiment") List<Map<String, Object>> countSentimentByMovie(Long movieId); }3.3 舆情统计服务
统计模块是大模型分析的输入前提,也是可视化页面的数据来源。核心方法包括:
- 统计某部电影的情感分布。
- 统计每日评论数量趋势。
- 统计评分分布。
- 找出评论数最多的 TOP 电影。
“每日评论数量趋势”可以用 SQL 按日期分组:
SELECT DATE(comment_time) AS date, COUNT(*) AS cnt FROM comment WHERE movie_id = #{movieId} GROUP BY DATE(comment_time) ORDER BY dateService 层只需要把 Mapper 返回的结果映射成统一的返回结构。示例:
@Service public class AnalysisService { private final CommentMapper commentMapper; public AnalysisService(CommentMapper commentMapper) { this.commentMapper = commentMapper; } public List<Map<String, Object>> sentimentDistribution(Long movieId) { List<Map<String, Object>> rows = commentMapper.countSentimentByMovie(movieId); for (Map<String, Object> row : rows) { Integer sentiment = Integer.valueOf(row.get("sentiment").toString()); String name = switch (sentiment) { case 0 -> "中性"; case 1 -> "正向"; case 2 -> "负向"; default -> "未知"; }; row.put("name", name); } return rows; } }这里要注意 SQL 查询返回的字段名可能包含大小写问题,在 Java 中读取时统一做类型转换,避免因为数据库字段别名不一致报错。
3.4 接入 AI 大模型:统一接口与实现
AI 大模型接入是整个系统的亮点,也是最容易写乱的地方。推荐定义一个统一接口,后续无论对接哪家大模型,业务层都不需要改。
public interface AIModelService { String analyzeComment(String content); String generateSummary(Long movieId); }实现类通过 RestTemplate 调用 HTTP 接口。国内主流大模型平台一般提供 OpenAI 兼容的 HTTP 接口,请求结构比较简单:
{ "model": "qwen-plus", "messages": [ { "role": "system", "content": "你是影视评论情感分析助手。只输出 JSON,不要输出多余文字。" }, { "role": "user", "content": "请分析这条评论的情感倾向:剧情拖沓,节奏太慢,失望。" } ], "temperature": 0.7, "max_tokens": 512 }对应 Java 代码:
@Service public class DefaultAIModelServiceImpl implements AIModelService { private final RestTemplate restTemplate; private final AiModelProperties properties; public DefaultAIModelServiceImpl(RestTemplate restTemplate, AiModelProperties properties) { this.restTemplate = restTemplate; this.properties = properties; } @Override public String analyzeComment(String content) { Map<String, Object> payload = new HashMap<>(); payload.put("model", properties.getModel()); List<Map<String, String>> messages = new ArrayList<>(); messages.add(Map.of("role", "system", "content", "你是影视评论情感分析助手。只输出JSON,格式为 {\"sentiment\":\"POSITIVE|NEGATIVE|NEUTRAL\",\"summary\":\"短评\"}")); messages.add(Map.of("role", "user", "content", content)); payload.put("messages", messages); payload.put("temperature", properties.getTemperature()); payload.put("max_tokens", properties.getMaxToken()); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.setBearerAuth(properties.getApiKey()); HttpEntity<Map<String, Object>> entity = new HttpEntity<>(payload, headers); ResponseEntity<String> response = restTemplate.postForEntity(properties.getUrl(), entity, String.class); return extractContent(response.getBody()); } }extractContent方法负责从大模型返回 JSON 中取出choices[0].message.content。返回内容可能带 Markdown 标记或额外说明文字,最好做一次清洗:
private String extractContent(String responseBody) { try { JsonNode root = new ObjectMapper().readTree(responseBody); return root.path("choices").path(0).path("message").path("content").asText(); } catch (JsonProcessingException e) { throw new RuntimeException("解析大模型返回结果失败", e); } }配置类统一管理 API 地址、密钥、模型名、超时时间:
@ConfigurationProperties(prefix = "ai.model") @Data @Component public class AiModelProperties { private String apiKey; private String url; private String model; private Integer maxToken = 512; private Double temperature = 0.7; private Integer connectTimeout = 5000; private Integer readTimeout = 30000; }application.yml:
ai: model: api-key: ${AI_API_KEY:你的密钥} url: ${AI_API_URL:https://api.example.com/v1/chat/completions} model: qwen-plus max-token: 512 temperature: 0.7密钥不要硬编码到 Java 代码里,通过环境变量注入,项目提交到 GitHub 时也安全。
3.5 控制器接口设计
控制器返回统一 Result 结构,便于前端处理。Result 可以设计成:
@Data public class Result<T> { private Integer code; private String message; private T data; public static <T> Result<T> ok(T data) { Result<T> result = new Result<>(); result.setCode(200); result.setMessage("success"); result.setData(data); return result; } }AnalysisController 提供以下接口:
| 接口 | 方法 | 说明 |
|---|---|---|
/api/analysis/sentiment-distribution | GET | 某个电影的评论情感分布 |
/api/analysis/trend | GET | 评论数量时间趋势 |
/api/analysis/score-distribution | GET | 评分分布 |
/api/analysis/ai/summary | GET | 大模型生成的舆情摘要 |
示例:
@RestController @RequestMapping("/api/analysis") public class AnalysisController { private final AnalysisService analysisService; private final AIModelService aiModelService; public AnalysisController(AnalysisService analysisService, AIModelService aiModelService) { this.analysisService = analysisService; this.aiModelService = aiModelService; } @GetMapping("/sentiment-distribution") public Result<List<Map<String, Object>>> sentimentDistribution(@RequestParam Long movieId) { return Result.ok(analysisService.sentimentDistribution(movieId)); } @GetMapping("/ai/summary") public Result<String> aiSummary(@RequestParam Long movieId) { return Result.ok(aiModelService.generateSummary(movieId)); } }接口层不写复杂逻辑,只负责参数校验和调用服务。答辩时老师问“接口怎么设计的”,可以按这个职责讲。
4. 数据可视化页面与接口联调
4.1 集成 ECharts
可视化页面不引入 Vite、Webpack 等构建工具,直接用 Thymeleaf 模板加 ECharts 静态文件,降低毕设复杂度。
- 下载
echarts.min.js放到src/main/resources/static/js/目录。 - 在
src/main/resources/templates/下创建index.html。 - 页面中引入 jQuery(可选)和 ECharts。
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>影视评论舆情可视化分析平台</title> <script src="/js/echarts.min.js"></script> <style> .chart { width: 100%; height: 400px; margin-bottom: 30px; } </style> </head> <body> <div> <label>选择电影</label> <select id="movieSelect"></select> </div> <div id="sentimentChart" class="chart"></div> <div id="trendChart" class="chart"></div> <div id="aiSummary" style="padding: 20px; border: 1px solid #ddd;"></div> <script> // 初始化图表 const sentimentChart = echarts.init(document.getElementById('sentimentChart')); const trendChart = echarts.init(document.getElementById('trendChart')); async function loadCharts(movieId) { loadSentimentChart(movieId); loadTrendChart(movieId); loadAISummary(movieId); } async function loadSentimentChart(movieId) { const response = await fetch('/api/analysis/sentiment-distribution?movieId=' + movieId); const result = await response.json(); sentimentChart.setOption({ title: { text: '评论情感分布' }, tooltip: { trigger: 'item' }, series: [{ type: 'pie', radius: '60%', data: result.data.map(item => { return { name: item.name, value: item.value }; }) }] }); } async function loadTrendChart(movieId) { const response = await fetch('/api/analysis/trend?movieId=' + movieId); const result = await response.json(); trendChart.setOption({ title: { text: '评论数量时间趋势' }, tooltip: { trigger: 'axis' }, xAxis: { type: 'category', data: result.data.map(item => item.date) }, yAxis: { type: 'value' }, series: [{ type: 'line', data: result.data.map(item => item.cnt) }] }); } async function loadAISummary(movieId) { const response = await fetch('/api/analysis/ai/summary?movieId=' + movieId); const result = await response.json(); document.getElementById('aiSummary').innerText = result.data || '暂无分析结果'; } </script> </body> </html>代码中的 fetch 请求路径是相对的,SpringBoot 默认会把static目录下的静态资源映射到根路径,/js/echarts.min.js能直接访问。
4.2 图表数据格式统一
前后端联调最容易出错的是数据格式。ECharts 的 Pi e 图需要{ name, value }结构,折线图需要两个数组分别对应 X 轴和 Y 轴。建议在 Controller 接口层就返回符合前端预期的结构,而不是把 Mapper 查询结果直接抛给前端。
情感分布接口返回格式:
{ "code": 200, "message": "success", "data": [ { "name": "正向", "value": 120 }, { "name": "中性", "value": 45 }, { "name": "负向", "value": 32 } ] }趋势接口返回格式:
{ "code": 200, "message": "success", "data": [ { "date": "2025-01-01", "cnt": 18 }, { "date": "2025-01-02", "cnt": 25 } ] }前端只需做一次map转换即可渲染,不需要在前端写复杂数据处理逻辑。
4.3 页面上如何展示大模型分析结果
大模型返回内容通常是一段文字,也可能带结构化 JSON。推荐把 AI 舆情摘要单独放在页面顶部或侧边,不混入普通图表统计中。例如生成一段“综合舆情报告”:
{ "movieTitle": "流浪地球2", "overall": "正面评价占比较高,观众普遍认可视觉效果和叙事节奏。", "hotTopics": ["特效", "科幻设定", "演员表演"], "riskPoints": ["部分观众认为前段文戏较长"] }页面展示时,把hotTopics和riskPoints渲染成标签列表,比单纯展示一段长文本更直观。后端可以对大模型返回结果做强约束,要求必须输出 JSON 格式,再在 Java 中解析后传给前端。
5. 运行验证与预期结果
5.1 启动项目
项目启动前先确认 MySQL 已启动,并执行建库建表脚本。然后配置 application.yml:
server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/movie_comment?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver启动命令:
mvn clean package mvn spring-boot:run看到日志中出现Started Application in x.x seconds说明启动成功。
5.2 验证接口
用 curl 验证情感分布接口:
curl "http://localhost:8080/api/analysis/sentiment-distribution?movieId=1"预期返回包含 code、message、data 的 JSON。如果返回的 code 是 500,优先检查 SQL 和数据库连接。
验证大模型接口:
curl "http://localhost:8080/api/analysis/ai/summary?movieId=1"如果返回AI service unavailable或超时,先看 application.yml 中 url 和 api-key 是否配置正确。
5.3 页面效果
浏览器访问http://localhost:8080,选择电影后应看到:
- 评论情感分布饼图。
- 评论数量时间趋势折线图。
- 评分分布柱状图(如果实现了)。
- AI 舆情摘要区域展示大模型生成的文字或标签。
页面图表不显示时,按下面顺序排查:打开浏览器开发者工具 Network 面板,看接口是否返回 200;看 Console 是否有 JavaScript 报错;看echarts.init是否在容器可见后调用。
6. 常见问题排查:从现象找根因
6.1 SpringBoot 版本太高导致启动失败
现象:项目导入后大量 Java 类找不到,比如javax.servlet.*报错。
原因:SpringBoot 3.x 使用jakarta.servlet.*,同时要求 JDK 17。如果本地是 JDK 8,或者项目是旧版javax.*写法,就会报编译错误。
解决:
- 查看当前 JDK 版本:
java -version。 - JDK 8 环境就把 pom.xml 中 SpringBoot 版本降到 2.7.x。
- JDK 17 环境就保持 3.x,并把
javax引用改成jakarta。
| 环境 | 推荐 SpringBoot 版本 |
|---|---|
| JDK 8 | 2.7.x |
| JDK 17 | 3.0.x 以上,但要注意依赖兼容性 |
| 毕设快速跑通 | 2.7.x + JDK 8 |
6.2 大模型接口调用超时
现象:调用/api/analysis/ai/summary时,前端一直转圈,后端日志出现Read timed out。
可能原因:
- 大模型本身生成耗时较长。
- RestTemplate 默认超时时间太短甚至无超时。
- 本地网络访问外部 API 不稳定。
解决:在 RestTemplateConfig 中配置明确的连接和读取超时:
@Bean public RestTemplate restTemplate() { SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); factory.setConnectTimeout(5000); factory.setReadTimeout(30000); return new RestTemplate(factory); }同时把大模型调用放到异步线程或加缓存,避免前端每次都等待生成。
6.3 大模型返回内容不是合法 JSON
现象:解析choices[0].message.content时抛JsonProcessingException。
原因:大模型可能返回 ````json ...``` 包裹的内容,或者在 JSON 前后加了说明文字。
解决:提取 content 后,先去掉 Markdown 代码块标记,再提取 JSON 子串:
private String cleanJson(String content) { String cleaned = content.replace("```json", "").replace("```", "").trim(); int start = cleaned.indexOf("{"); int end = cleaned.lastIndexOf("}"); return cleaned.substring(start, end + 1); }建议在提示词中反复强调“只输出 JSON,不要输出多余文字”,并增加异常兜底。
6.4 图表空白或数据错位
现象:页面打开后图表区域空白,Console 报Cannot read properties of undefined。
可能原因:
- 接口返回的 data 为空。
- 图表容器高度为 0。
- 数据字段名和前端预期不一致。
解决:
- 在 Network 面板确认接口真实返回。
- 给图表容器设置明确高度,例如
height: 400px。 - 先用
console.log(result)打印返回结果,确认字段名。
6.5 中文乱码
现象:数据库能显示中文,接口返回乱码;或者前端展示乱码。
检查顺序:
- 数据库连接 URL 是否带
characterEncoding=utf8。 - 数据库表和字段是否使用
utf8mb4。 - IDEA 中文件编码是否设置为 UTF-8。
- 大模型返回内容乱码时,确认返回响应体读取时是否指定 UTF-8。
统一约定:所有表、字段、连接串、页面文件都使用 UTF-8。
7. 毕业设计落地的最佳实践
7.1 学习环境与生产环境的差异
学习环境跑通只需要一个本地 MySQL 和一个大模型 API Key。如果这个项目要部署到服务器展示,需要考虑:
| 项目 | 学习环境 | 生产部署 |
|---|---|---|
| 数据库 | 本机 MySQL | 云数据库或服务器 MySQL,开启备份 |
| API Key | 配置文件直接填 | 环境变量或密钥管理服务 |
| 大模型调用 | 一次性调用 | 加缓存、限流、失败重试 |
| 日志 | 控制台输出 | 文件日志 + 按天滚动 |
| 监控 | 无 | 基础健康检查接口 |
推荐在项目里预留一个健康检查接口/api/health,部署后发现服务异常时可以快速定位是数据库问题还是大模型接口问题。
7.2 论文和答辩可以围绕哪些点展开
这个题目的论文不是只写“我实现了一个系统”,而是要有工程增量。可以按以下方向展开:
- 情感分析方案对比:传统词典匹配、TF-IDF + 机器学习、大模型提示词分析,三者对比准确率和实现成本。
- 大数据量下的聚合优化:百万级评论按时间分组统计时,如何用索引和定时汇总表优化。
- AI 大模型提示词工程:如何设计 system prompt 约束输出格式,如何解析不稳定输出。
- 可视化选型对比:ECharts 与 Highcharts、AntV G2 的区别,为什么用 ECharts。
答辩时重点讲“大模型在这里不负责数据统计,只负责语义理解”,这句话能防止老师误以为你把所有逻辑都依赖外部接口。
7.3 功能扩展方向
这个项目天然可以扩展,不需要换架构:
- 接入实时评论流:用定时任务每 5 分钟拉取一次新评论,更新统计结果。
- 热词分析:用 HanLP 或大模型抽取评论关键词,生成词云。
- 多模型对比:同时接入两个大模型,对比不同模型的情感分析结果一致性。
- 用户端:增加评论发布功能,用户提交评论后自动触发大模型情感分析并更新统计。
- 权限控制:Spring Security 区分管理员和普通用户,管理员能看到全部数据,普通用户只能看公开统计。
7.4 对新手最重要的建议
做这个项目,顺序非常重要。不要一上来就写大模型调用代码,先做三件事:
- 初始化评论数据,把数据库表填满,保证统计接口能返回数据。
- 用 ECharts 显示普通统计图表,先跑通前后端链路。
- 再接入大模型,先写一个最简单的
analyzeComment接口,能返回文字即可,再逐步增加 JSON 解析和缓存。
AI 大模型是项目的亮点,但不是项目的地基。统计、可视化、前后端联调这些基础能力先跑通,再往上面加大模型能力,整个毕业设计的节奏会稳很多。