基于 Golang + Gin 构建的 AI 应用服务平台,集成了 JWT 鉴权、邮箱验证码注册、会话式聊天、SSE 流式输出 等能力。
项目当前实现聚焦在两个核心场景:
- 智能对话:支持创建新会话、继续历史会话、查看历史消息,并支持普通返回与 SSE 流式返回两种模式。
- 图像识别:前端上传图片后,后端完成文件解析、图像解码、预处理、 推理与类别返回。
项目整体可以分成四层:
- Controller 层:处理 HTTP 请求与参数校验,对外返回统一响应结构。
- Service 层:承接业务逻辑,例如登录注册、会话创建、AI 对话、图像识别。
- DAO 层:封装数据库访问。
- Common / Utils 层:提供 AIHelper、JWT、Redis、RabbitMQ、MySQL、图像识别等公共能力。
用于保存用户信息。
关键字段:
id:主键email:邮箱username:账号,唯一索引password:加密后的密码created_at / updated_at / deleted_at
用于保存聊天会话。
关键字段:
id:会话 ID,使用 UUIDusername:所属用户title:会话标题,当前实现中创建会话时取首条问题created_at / updated_at / deleted_at
用于保存消息内容。
关键字段:
id:自增主键session_id:所属会话username:所属用户content:消息内容is_user:是否为用户消息created_at
- 登录或注册成功后签发 JWT
- token 中包含
id与username - 受保护接口统一通过中间件校验
- 中间件解析成功后,将
userName写入 Gin 上下文
项目通过 AIModel 接口统一封装模型能力,并通过工厂模式支持不同模型实现。当前支持:
modelType = "1":OpenAImodelType = "2":Ollama
AIHelper 是会话级的运行时对象,负责维护:
- 当前会话的消息上下文
- 绑定的底层模型
- 消息保存策略
系统通过 AIHelperManager 以 userName -> sessionID -> AIHelper 的方式统一管理会话运行时对象。
在流式接口中,Controller 会设置:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive随后每拿到一个模型 chunk,就写入:
data: xxx
前端可以边接收边渲染。
聊天消息不会直接阻塞式写入数据库,而是先推送到 RabbitMQ,由消费者异步写入 message 表,从而减少主链路阻塞,提高接口响应速度。
图像识别的完整链路如下:
- 前端通过
multipart/form-data上传图片 - Controller 使用
FormFile("image")获取文件 - Service 读取文件字节流到内存
ImageRecognizer对图片进行解码- 将图片缩放到
224x224 - 提取 RGB 并归一化到
[0, 1] - 按
NCHW格式写入 ONNX 输入张量 - 执行 ONNX Runtime 推理
- 取最大概率下标并映射为标签名称
- 返回最终类别名给前端
大多数接口都会返回统一响应结构:
{
"status_code": 1000,
"status_msg": "success"
}常见状态码:
1000:成功2001:请求参数错误2002:用户名已存在2003:用户不存在2004:用户名或密码错误2006:无效 Token2008:验证码错误4001:服务繁忙5003:模型运行失败
以下内容是基于当前代码实现的真实情况:
- 会话列表当前来自内存中的
AIHelperManager,不是直接从session表查询。 - 会话标题在列表接口中暂时使用
sessionId作为返回值,虽然创建会话时已经保存了首条问题作为title,但当前列表接口未使用该字段。 - 图像识别模型路径与标签路径目前为硬编码,部署前需要手动准备。
- RabbitMQ 已实现异步落库能力,但若要进一步增强可靠性,可继续补充手动 ack、重试与幂等控制。
- Redis 当前用于验证码缓存;若要严格保证“校验成功后立即删除”的原子性,可进一步用 Lua 脚本实现校验与删除的一次性执行。
- 将会话列表改为从数据库读取,并返回真实标题
- 补充会话删除与会话过期清理机制
- 为 RabbitMQ 增加手动 ack、死信队列与幂等消费
- 将图像模型路径改为配置化
- 为图像识别增加文件大小限制、格式白名单与置信度输出
- 增加日志追踪、限流、熔断与监控能力