用AI开发出一个AI
- 一、项目整体概览
- 二、全栈技术选型分享
- 三、完整项目目录结构
- 四、核心请求处理流程详解
- 五、SSE流式对话实现细节
- 六、非常人性化的认证体系设计
- 七、数据库表设计分享
- 八、全量API接口清单
- 九、本地启动快速指南
Vibecoding了一个支持SSE流式对话的ChatSpark智能聊天机器人,今天把项目的全链路设计分享出来,新手也可以跟着一步步搭建出属于自己的AI聊天应用~

一、项目整体概览
ChatSpark是一款前后端分离的智能聊天机器人,核心基于DeepSeek大模型API实现对话能力,完整支持游客免登录体验、JWT账号体系、SSE流式打字效果对话、历史对话全生命周期管理等核心能力,同时做了优雅的流量控制和跨域适配,开箱即可快速跑通本地演示。


二、全栈技术选型分享
我在选型的时候特意兼顾了稳定性和开发效率,都是目前企业级开发的主流成熟方案,没有引入过度复杂的依赖,新手也能快速上手:

🔧 后端技术栈
全部采用当前最新的稳定LTS版本,避免后续踩版本兼容坑:
| 组件 | 选型 | 版本 | 说明 |
|---|---|---|---|
| 核心框架 | Spring Boot | 3.2.8 | 当下最主流的Java后端开发框架 |
| 运行环境 | OpenJDK | 17 LTS | 长期支持版本,性能和兼容性拉满 |
| ORM框架 | MyBatis-Plus | 3.5.5 | 极大简化单表CRUD开发效率 |
| 数据库连接池 | Druid | 1.2.23 | 阿里开源的数据库连接池,自带监控面板 |
| 身份认证 | java-jwt (Auth0) | 4.4.0 | 标准JWT令牌生成解析工具 |
| Token计数组件 | jtokkit | 1.1.0 | 精准统计对话Token用量 |
| 业务数据库 | MySQL | 8.0 | 本地服务运行,持久化所有业务数据 |
| 缓存组件 | Redis | 7.4 | Docker一键部署,做限流和热点数据缓存 |
| 项目构建工具 | Maven | 3.9+ | 标准化Java项目构建管理 |
🎨 前端技术栈
基于Vue3生态的全现代技术栈,开发体验丝滑:
| 组件 | 选型 | 版本 | 说明 |
|---|---|---|---|
| 核心框架 | Vue 3 | 3.4.x | 响应式前端开发框架 |
| UI组件库 | Element Plus | 2.7.x | 成熟的Vue3开箱即用UI库 |
| 构建工具 | Vite | 5.x | 超快的本地开发启动速度 |
| 状态管理 | Pinia | 2.x | Vue3官方推荐的轻量状态管理方案 |
| 代码高亮 | highlight.js | - | 聊天内容里的代码块自动高亮渲染 |
| 图标库 | @element-plus/icons-vue | - | 统一的系统图标方案 |
🤖 AI接口方案
没有用额外的复杂封装,直接通过HttpURLConnection调用DeepSeek API,因为DeepSeek完全兼容OpenAI协议,既支持Spring AI封装调用,也支持原生直连,适配性极强,后续切换其他大模型也只需要改几行配置即可。
三、完整项目目录结构
整个项目的结构做了清晰的分层,前后端完全解耦,后续扩展新功能不需要乱改现有代码:
chat-agent/
|-- backend/ Spring Boot 后端根目录
| |-- src/main/java/com/chatbot/
| | |-- ChatbotApplication.java 项目启动类
| | |-- common/
| | | |-- response/R.java 全局统一响应封装,固定返回{code, message, data}结构
| | | |-- exception/ 自定义业务异常 + 全局统一异常处理器
| | |-- config/
| | | |-- WebMvcConfig.java CORS跨域配置 + 拦截器注册配置
| | | |-- MyBatisPlusConfig.java MyBatis-Plus分页插件配置
| | | |-- AsyncConfig.java 异步线程池全局配置
| | |-- controller/
| | | |-- ChatController.java SSE流式对话接口实现
| | | |-- AuthController.java 验证码发送+登录接口实现
| | | |-- HistoryController.java 历史对话全量CRUD接口
| | | |-- GuestController.java 游客状态查询管理接口
| | | |-- DailyQuoteController.java 每日彩蛋接口实现
| | |-- service/
| | | |-- impl/
| | | | |-- ChatServiceImpl.java 直连DeepSeek API核心业务实现
| | | | |-- AuthServiceImpl.java JWT生成校验 + 游客数据迁移逻辑
| | | | |-- HistoryServiceImpl.java 历史对话管理业务实现
| | | | |-- GuestServiceImpl.java 游客剩余次数计数管理
| | | | |-- SmsServiceImpl.java 验证码生成(开发阶段直接打印到控制台调试)
| | |-- mapper/ MyBatis-Plus 数据访问层
| | |-- entity/ 数据库实体类统一存放位置
| | |-- dto/request/ 所有前端请求DTO统一管理
| | |-- interceptor/
| | | |-- AuthInterceptor.java 可选JWT认证拦截器
| | | |-- RateLimitInterceptor.java 全局限流拦截器
| | |-- resources/
| | | |-- application.yml 全局主配置文件
| | | |-- application-dev.yml 开发环境专属配置
| |-- pom.xml
|
|-- frontend/ Vue 3 前端根目录
| |-- src/
| | |-- api/index.js Axios请求封装 + SSE fetch请求统一封装
| | |-- stores/
| | | |-- app.js 全局主题/侧边栏状态管理
| | | |-- auth.js Token/登录态持久化管理
| | | |-- chat.js 消息列表/流式对话状态管理
| | |-- composables/
| | | |-- useChat.js SSE对话、消息高亮、一键复制通用逻辑封装
| | | |-- useAuth.js 登录、验证码发送通用逻辑封装
| | | |-- useHistory.js 历史记录操作通用逻辑封装
| | | |-- useWelcome.js 每日彩蛋通用逻辑封装
| | |-- components/
| | | |-- Sidebar.vue 系统侧边栏组件
| | | |-- TopNav.vue 顶部导航栏组件
| | | |-- WelcomeScreen.vue 欢迎首页屏组件
| | | |-- ChatInput.vue 对话输入框组件
| | | |-- LoginDialog.vue 登录弹窗组件
| | |-- styles/variables.css 全局CSS变量统一管理
| | |-- App.vue 主根组件
| | |-- main.js 项目入口文件
| |-- vite.config.ts
| |-- package.json
|
|-- document/ 项目相关文档统一存放目录
|-- docker/ Docker部署相关配置文件目录
四、核心请求处理流程详解
整个请求链路做了非常清晰的分层处理,每一步都有对应的职责,不会出现逻辑混乱的情况:
- 前端在本地5173端口启动,所有请求通过Vite代理转发,配置了
Cache-Control: no-cache专门解决SSE响应被浏览器缓冲的问题,确保流式内容实时返回。 - 请求转发到后端Spring Boot的8080端口之后,首先进入AuthInterceptor做可选认证:携带Token就解析出用户ID放到请求上下文,没有Token的公开路径直接放行,受保护的接口才会校验必须携带有效Token。
- 紧接着进入RateLimitInterceptor做流量控制:登录用户限制每分钟最多发5条消息,游客限制每分钟最多2条消息,避免接口被恶意刷量。
- 通过拦截器校验之后进入对应的Controller,调用Service层逻辑,需要持久化的数据存入MySQL,热点数据放到Redis缓存。
- 对话请求的Service层会直接发起请求调用DeepSeek API,拿到SSE流式响应之后直接透传给前端,实现和官方ChatGPT一样的边想边输出的打字效果。
五、SSE流式对话实现细节
很多小伙伴做流式对话的时候总是卡半天才能拿到全量内容,我这里的SSE格式做了非常简洁的设计,前后端对接零成本:
请求规范
POST请求地址为/api/v1/chat/completions,请求头里携带可选的Authorization Bearer令牌和游客ID,请求体传入对话ID、历史消息列表,标记stream为true开启流式返回:
Headers: Authorization: Bearer {token} (可选)
X-Guest-Id: {guest_id}
Body: {"conversationId": "uuid", "messages": [{"role":"user","content":"你好"}], "stream": true}
响应格式
后端返回text/event-stream类型的流式内容,每一条data都是增量的内容片段:
data: {"id":"msg_id","content":"你好","finish":false}
data: {"id":"msg_id","content":"!","finish":false}
data: {"id":"msg_id","content":"","finish":true,"conversationId":"new_uuid"}
前端只需要收到片段之后做字符串拼接就能实时展示输出效果,最后一条标记finish为true的消息代表当前AI回复完全结束,同时返回新生成的对话ID用来存历史记录。
六、非常人性化的认证体系设计
我特意做了游客+账号两套融合的认证方案,用户不用一上来就强制注册登录,体验非常流畅:
- 游客模式:第一次访问的时候后端自动生成UUID作为guest_id,MySQL的guests表持久化存储游客的剩余免费对话次数,Redis缓存计数做快速限流,前端之后所有请求在X-Guest-Id头里带上这个标识就可以直接体验对话。
- 用户登录:只需要手机号加验证码就能完成登录,JWT令牌的过期时间设置为30天,保证用户长时间不用重复登录;最关键的是登录的时候会自动执行数据迁移,把当前游客状态下产生的所有对话记录自动关联到新登录的用户账号下,用户完全感知不到切换的过程,之前的聊天记录一点都不会丢。
- 认证拦截器做了非常灵活的可选模式:聊天接口、登录注册接口、每日彩蛋这些公开路径,带不带Token都能正常使用,只有查看历史记录、删除对话这类受保护的接口,才会校验必须携带有效JWT,否则直接返回401错误。
七、数据库表设计分享
所有表结构都是经过生产验证的精简设计,没有多余的字段:
sql
-- 用户表,存储登录用户信息
CREATE TABLE users (
id CHAR(32) PRIMARY KEY,
phone VARCHAR(11) NOT NULL UNIQUE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
last_login_at DATETIME
);
-- 对话会话表,关联用户或者游客ID
CREATE TABLE conversations (
id CHAR(32) PRIMARY KEY,
user_id CHAR(32),
guest_id VARCHAR(64),
title VARCHAR(100),
created_at DATETIME,
updated_at DATETIME,
KEY idx_user_id (user_id),
KEY idx_guest_id (guest_id)
);
-- 聊天消息表,所有对话内容持久化存储
CREATE TABLE messages (
id CHAR(32) PRIMARY KEY,
conversation_id CHAR(32) NOT NULL,
role VARCHAR(10) NOT NULL,
content LONGTEXT NOT NULL,
created_at DATETIME,
KEY idx_conversation_id (conversation_id)
);
-- 游客信息表,存储游客剩余免费次数
CREATE TABLE guests (
id CHAR(32) PRIMARY KEY,
guest_id VARCHAR(64) NOT NULL UNIQUE,
remaining_count INT DEFAULT 3,
created_at DATETIME,
updated_at DATETIME
);
-- 验证码表,存储短信验证码和过期时间
CREATE TABLE verification_codes (
id CHAR(32) PRIMARY KEY,
phone VARCHAR(11) NOT NULL,
code VARCHAR(6) NOT NULL,
expires_at DATETIME NOT NULL,
created_at DATETIME
);
八、全量API接口清单
所有接口都做了清晰的权限划分,前后端对接的时候一目了然:
| 接口路径 | 请求方法 | 是否需要认证 | 接口说明 |
|---|---|---|---|
| /api/v1/auth/send-code | POST | 否 | 发送手机号验证码 |
| /api/v1/auth/login | POST | 否 | 登录,自动迁移游客历史对话 |
| /api/v1/guest/status | GET | 否 | 查询游客当前剩余免费对话次数 |
| /api/v1/chat/completions | POST | 可选 | SSE流式对话核心接口 |
| /api/v1/chat/history | GET | 是 | 分页查询历史对话列表 |
| /api/v1/chat/history/{id} | GET | 是 | 查询指定对话的完整消息详情 |
| /api/v1/chat/history/{id} | DELETE | 是 | 删除指定对话 |
| /api/v1/chat/history | DELETE | 是 | 清空当前用户所有的历史对话 |
| /api/v1/daily-quote | GET | 否 | 获取每日彩蛋励志语句 |
九、本地启动快速指南
想要本地快速跑通项目非常简单,按照下面几步操作5分钟就能看到效果:
- 先启动本地MySQL服务,创建名为chatbot的数据库。
- 用Docker Desktop启动Redis 7.4版本,映射端口为本地6379,不需要额外配置密码。
- 打开后端开发环境的配置文件
application-dev.yml,填入你自己申请的DeepSeek API Key,调整对应配置:
yaml
server.port: 8080
spring.datasource: mysql://localhost:3306/chatbot
spring.data.redis: localhost:6379
deepseek.api-key: sk-xxx
deepseek.base-url: https://api.deepseek.com
jwt.secret: your-secret
jwt.expire-days: 30
guest.max-free-count: 3
- 启动Spring Boot后端项目,你可以直接访问Druid监控面板
/druid,默认账号密码admin/admin123,查看所有数据库访问监控数据。 - 启动Vue3前端项目,访问localhost:5173即可开始体验。开发测试的时候用测试手机号收验证码,验证码会直接打印在后端控制台日志里,不需要真的对接短信服务。
最后
这个项目全程我自己踩了不少坑,最终打磨出来的版本可以直接二次开发用到生产环境,感兴趣的小伙伴可以一起交流玩机心得~