一个面向高考志愿填报场景的 AI 应用项目,核心目标不是"把推荐全交给大模型",而是让 AI 负责自然语言理解与对话编排,后端保留可控、可解释、可审计的推荐逻辑。
项目当前已经具备完整单体工程闭环:
- 用户登录注册、画像维护、推荐历史、志愿方案保存
- 基于分数 / 位次 / 省份 / 科类 / 偏好的院校与专业推荐
冲 / 稳 / 保概率评分与规则解释- 基于 RocketMQ 的自由文本推荐异步任务、失败重试与状态查询
- 管理员维护院校、专业、录取数据
- 管理员查看用户报考资料与业务计数,并维护账号角色和启停状态
- 对话式 Agent 工作台,可读取画像、生成推荐、查询学校详情、操作当前志愿单
- 自由文本输入先由 AI 解析成结构化条件,例如省份、分数、位次、偏好专业、排除专业
- 推荐核心仍由后端规则、概率评分和排序逻辑完成
- 每条结果都会返回推荐理由、风险等级、规则解释,便于展示和追踪
- 不再只按固定
scoreGap / rankGap生硬分档 - 结合位次差、分数差、年份波动、偏好命中等因素计算基础概率分
- 再按概率区间映射到
冲 / 稳 / 保,结果更接近真实推荐场景
- Agent 通过受控工具调用现有后端能力:
getUserProfile、recommendSchools、recommendMajors、getSchoolDetail、addPlanItem、savePlan - 单轮工具调用上限显式限制,写操作带确认边界
- 工具失败有统一错误分类和兜底提示,不会直接把接口打成 500
- 把
院校 / 专业主数据、院校录取线 / 专业录取线事实数据、用户画像 / 推荐历史 / 志愿方案 / Agent 会话消息分开建模,而不是塞进一张大表 - AI 解析、推荐计算、志愿方案、Agent 工具调用分别走独立 service,避免大模型直接穿透数据库和核心推荐逻辑
- 这样既方便管理员维护基础数据,也方便后端做规则解释、历史追踪和后续索引优化
- Java 17
- Spring Boot 3.3.5
- Spring Security
- JWT
- MyBatis-Plus
- MySQL 8
- Redis(可选)
- RocketMQ 5(可选)
- springdoc-openapi
- Vue 3
- Vite
- Element Plus
- Spring Boot Test
- H2
- Docker / Docker Compose
- 分数推荐:按省份、科类、推荐模式生成院校推荐
- 自由文本推荐:输入自然语言后由 AI 抽取条件,再走后端推荐链路
- 异步推荐任务:通过 RocketMQ 投递自由文本推荐任务,支持任务状态查询、消费重试和失败原因记录
- 推荐解释:返回命中偏好、冲稳保分层、风险指数、判断依据
- AI 总结:对结果进行简洁总结和填报建议生成
- 推荐历史:保存分数推荐与自由文本推荐记录
- 志愿方案:支持当前草稿、方案保存、方案回看
- AI 对话:支持查看画像、获取推荐、查询学校详情、加入志愿单、保存方案
- 院校基础信息维护
- 专业基础信息维护
- 院校录取线维护
- 专业录取线维护
- 用户输入分数表单或自然语言需求
- AI 将自然语言抽取为结构化条件
- 后端做参数校验、规则补全、分数位次转换
- 推荐服务按条件筛选候选院校/专业
- 计算基础概率分并映射为
冲 / 稳 / 保 - 返回推荐结果、解释字段和 AI 总结
- 用户在
AI 对话页面输入问题 - 后端先做意图识别和工具决策
- Agent 只调用白名单工具,不做自由查库
- 工具结果结构化落库,支持会话回放和追踪
- 写操作继续复用现有志愿方案服务,不绕过业务边界
- 接口先创建
PENDING任务,再将任务 ID、用户 ID、请求 ID 和原始请求投递到 RocketMQ - Producer 使用请求 ID 作为消息 Key;发送失败时将数据库任务直接标记为
FAILED - Consumer 通过
PENDING -> RUNNING条件更新抢占任务,重复消息无法重复执行已完成任务 - 可重试异常将任务恢复为
PENDING并交给 Broker 重试;达到上限后记录FAILED和失败原因 - 超时停留在
RUNNING的任务允许重新抢占,不额外引入分布式锁或 Outbox
.
├─ src/main/java # Spring Boot 后端
├─ src/main/resources # 配置与静态资源
├─ frontend # Vue 3 + Vite 前端
├─ sql # 建表、初始化与导入脚本
├─ Dockerfile
└─ docker-compose.yml
- Java 17+
- Node.js 18+ 和 npm
- MySQL 8(或使用 Docker)
- Maven(项目自带 Maven Wrapper
mvnw/mvnw.cmd)
如果本地没有 MySQL,可以用 Docker 启动:
docker run -d --name zhiyuan-mysql `
-e MYSQL_ROOT_PASSWORD=zhiyuan_root_2026 `
-e MYSQL_DATABASE=college_recommendation `
-e MYSQL_USER=zhiyuan `
-e MYSQL_PASSWORD=zhiyuan123 `
-p 127.0.0.1:3307:3306 `
mysql:8.4应用默认连接 localhost:3307,使用专用账号 zhiyuan,不再依赖本机 MySQL 的 root 密码。若使用自定义账号,只需通过 DB_HOST、DB_PORT、DB_USER、DB_PASSWORD 覆盖。
# Windows
.\mvnw.cmd spring-boot:run
# macOS / Linux
./mvnw spring-boot:run默认访问:
- 应用首页:
http://localhost:8080 - Swagger UI:
http://localhost:8080/swagger-ui.html - OpenAPI JSON:
http://localhost:8080/v3/api-docs
本地默认关闭 RocketMQ,并通过同一任务处理器同步执行,便于开发和测试;prod profile 与 Docker Compose 默认开启 RocketMQ。
后端每次启动都会执行打包在应用内的幂等 sql/schema.sql,自动补齐当前版本缺少的表和兼容字段,但不会执行 sql/data.sql。如运行账号明确没有 DDL 权限,可设置 DB_SCHEMA_INIT_MODE=never,并在发布前手动执行 schema。
cd frontend
npm install
npm run dev默认地址:
- 前端开发环境:
http://localhost:5173
说明:
- Vite 会把
/api代理到http://localhost:8080
如果只需要展示前端效果,可以使用演示模式,无需启动后端服务:
cd frontend
npm install
npm run dev:mock默认地址:
- 前端开发环境:
http://localhost:5173
演示模式特点:
- 使用模拟数据,无需数据库和后端服务
- 支持普通用户页面和管理员管理页面的基本功能展示
演示账号:
| 身份 | 用户名 | 密码 | 登录后页面 |
|---|---|---|---|
| 普通用户 | testuser |
任意非空密码 | 推荐查询 |
| 管理员 | admin |
admin123 |
管理界面 |
管理员演示包含:
- 用户概览、用户名/角色/状态筛选和账号设置
- 院校、专业、院校录取线、专业录取线的列表与筛选
- 上述四类基础数据的新增和编辑交互
Mock 管理操作只保存在当前页面会话内存中,刷新页面后会恢复初始演示数据,不会连接或修改真实数据库。若浏览器保留了上一次登录状态,可先点击右上角“退出”,再使用对应演示账号登录。
正式后端使用 sql/data.sql 初始化时,测试账号为:
- 普通用户:
testuser / 123456 - 管理员:
adminuser / 123456
生产环境不要保留示例密码。若不导入示例数据,可先注册普通账号,再由数据库管理员执行受控 SQL 将指定账号的 role 更新为 ADMIN。
重要:前端构建后需要将产物复制到 Spring Boot 的静态资源目录才能被正确加载。
cd frontend
npm run build
# 将构建产物复制到 Spring Boot 静态资源目录
Copy-Item -Path ..\src\main\resources\static\index.html -Destination ..\target\classes\static\index.html -Force
Copy-Item -Path ..\src\main\resources\static\assets\*.js -Destination ..\target\classes\static\assets\ -Force
Copy-Item -Path ..\src\main\resources\static\assets\*.css -Destination ..\target\classes\static\assets\ -Force然后重新启动后端即可通过 http://localhost:8080 访问完整页面。
或者使用 Maven 编译(会自动复制静态资源):
# Windows
.\mvnw.cmd compile
# macOS / Linux
./mvnw compileCopy-Item .env.example .env至少需要检查这些字段:
MYSQL_ROOT_PASSWORDDB_USERDB_PASSWORDAUTH_JWT_SECRETQWEN_ENABLEDQWEN_API_KEY
没有配置 AI Key 时保持 QWEN_ENABLED=false,系统仍可使用本地规则完成登录、推荐、志愿表和 Agent 基础工具流程;填入有效 Key 后再改为 true。
docker compose up -d --build默认宿主机端口:
- 后端服务:
http://localhost:8080 - Swagger UI:
http://localhost:8080/swagger-ui.html - MySQL:
localhost:3307 - Redis:
localhost:6380 - RocketMQ NameServer:
localhost:9876 - RocketMQ Broker:
localhost:10911
说明:
mysql会自动执行sql/schema.sql和sql/data.sqlbackend启动时会再次执行幂等 schema 校验,因此复用旧数据卷时也能补齐新增表和兼容字段backend默认使用prodprofile 启动backend会在mysql、redis和 RocketMQ Broker 健康后启动- Compose 会先初始化 RocketMQ 持久化卷权限,再启动 NameServer 与 Broker
- 为避免和本机已有 MySQL / Redis 冲突,Compose 使用了单独宿主机端口映射
- MySQL、Redis 和 RocketMQ 的宿主机端口默认只绑定
127.0.0.1,远程服务器只需要对外开放应用端口 backend提供容器健康检查,可用docker compose ps确认状态为healthy
服务器安装 Docker Engine 与 Compose 插件后执行:
git clone <仓库地址> zhiyuan
cd zhiyuan
cp .env.example .env编辑 .env,至少替换 MYSQL_ROOT_PASSWORD、DB_PASSWORD 和 AUTH_JWT_SECRET;需要真实 AI 对话时再填写 QWEN_API_KEY 并设置 QWEN_ENABLED=true。然后启动:
docker compose up -d --build
docker compose ps
docker compose logs --tail=200 backend直接访问 http://服务器公网IP:8080。云服务器安全组和系统防火墙只需放行 TCP 8080;MySQL、Redis、RocketMQ 不需要开放公网端口。已有域名时,可让 Nginx/Caddy 反向代理到 127.0.0.1:8080 并配置 HTTPS。
更新部署:
git pull
docker compose up -d --build停止服务:
docker compose down删除数据卷:
docker compose down -v参考仓库根目录的 .env.example。
主要变量:
- 数据库应用账号:
DB_HOSTDB_PORTDB_HOST_PORTDB_NAMEDB_USERDB_PASSWORDDB_SCHEMA_INIT_MODE - Docker 初始化账号:
MYSQL_ROOT_PASSWORD(只供 MySQL 容器初始化和健康检查,后端不使用) - Redis:
REDIS_HOSTREDIS_PORTREDIS_HOST_PORTCACHE_REDIS_ENABLED - RocketMQ:
ROCKETMQ_ENABLEDROCKETMQ_NAME_SERVERROCKETMQ_RECOMMENDATION_TOPICROCKETMQ_RECOMMENDATION_TAGROCKETMQ_PRODUCER_GROUPROCKETMQ_CONSUMER_GROUP - 服务端口:
SERVER_PORTSERVER_HOST_PORT - JWT:
AUTH_JWT_SECRETAUTH_JWT_ISSUER - AI:
QWEN_ENABLEDQWEN_BASE_URLQWEN_MODELQWEN_API_KEY - 文档:
SPRINGDOC_SWAGGER_UI_PATHSPRINGDOC_API_DOCS_PATH
后端测试:
.\mvnw.cmd test后端打包:
.\mvnw.cmd package前端构建:
cd frontend
npm run buildPOST /api/auth/loginPOST /api/auth/registerPOST /api/auth/logoutGET /api/meta/optionsGET /api/meta/major-options
POST /api/recommendationsPOST /api/recommendations/free-textPOST /api/recommendations/free-text/tasksGET /api/recommendations/free-text/tasks/{taskId}POST /api/recommendations/final-adviceGET /api/recommendations/schools/{universityId}/majorsGET /api/historyGET /api/history/{id}DELETE /api/history/{id}
POST /api/plansGET /api/plansGET /api/plans/currentPUT /api/plans/currentDELETE /api/plans/currentGET /api/plans/{id}DELETE /api/plans/{id}
POST /api/agent/conversationsGET /api/agent/conversationsGET /api/agent/conversations/{conversationId}POST /api/agent/conversations/{conversationId}/messages
GET /api/admin/universitiesPOST /api/admin/universitiesPUT /api/admin/universities/{id}GET /api/admin/majorsPOST /api/admin/majorsPUT /api/admin/majors/{id}GET /api/admin/admission-cutoffsPOST /api/admin/admission-cutoffsPUT /api/admin/admission-cutoffs/{id}GET /api/admin/major-admission-cutoffsPOST /api/admin/major-admission-cutoffsPUT /api/admin/major-admission-cutoffs/{id}GET /api/admin/usersGET /api/admin/users/overviewGET /api/admin/users/{id}PUT /api/admin/users/{id}/settings
所有管理接口都要求 ADMIN 角色。用户接口不会返回密码,只允许维护 role 和 enabled;当前管理员不能停用或降级自己。
- 基础建表与初始化数据:
sql/schema.sql、sql/data.sql - 分数位次批量导入说明:
sql/score-rank-mapping-guide.md - 位次导入 SQL 模板:
sql/import-score-rank-mapping.sql
原因:Spring Boot 从 target/classes/static/ 加载静态资源,而不是 src/main/resources/static/。
解决:
# 方法1:重新编译
.\mvnw.cmd compile
# 方法2:手动复制
Copy-Item -Path src\main\resources\static\* -Destination target\classes\static\ -Recurse -Force原因:Linux/macOS 下 mvnw 没有执行权限。
解决:
chmod +x mvnw
./mvnw spring-boot:run原因:MySQL 未启动或配置错误。
解决:
- 推荐执行
docker compose up -d mysql,避免连接到本机密码不确定的 MySQL 服务 - 检查
.env中的DB_HOST=localhost、DB_PORT=3307、DB_USER=zhiyuan和DB_PASSWORD - 执行
check-db.bat,或手动测试:mysql -h localhost -P 3307 -u zhiyuan -p - 已有 Docker 数据卷不会因修改
.env自动更换账号密码;不要直接删除数据卷,先备份后再决定迁移或重建
原因:Redis 未启动(但可以禁用)。
解决:
设置 CACHE_REDIS_ENABLED=false 即可禁用 Redis 缓存。
原因:RocketMQ 未启动(本地开发可禁用)。
解决:
设置 ROCKETMQ_ENABLED=false 即可禁用 RocketMQ,系统会使用同步任务处理。
原因:未配置 API Key(但可以降级使用)。
解决: AI 功能有本地降级机制,即使不配置 API Key,基础的意图识别和工具调用仍然可用。如需完整 AI 功能:
- 设置
QWEN_ENABLED=true - 填写
QWEN_API_KEY
原因:8080 端口已被其他程序占用。
解决:
修改 .env 中的 SERVER_PORT 和 SERVER_HOST_PORT,或停止占用端口的程序。
当前版本已经完成从"普通 CRUD + 简单 AI 调用"向"可展示工程能力的单体 AI 应用项目"的升级,重点体现在:
- 可控推荐逻辑,而不是把结果直接交给大模型
- 受控对话式 Agent,而不是纯聊天外壳
- 完整鉴权、缓存、异步任务、管理端、Docker、测试与文档能力