AIWear 智能衣橱项目实战(总览):我把衣柜接入了 AI
Spring Boot × LangChain × CLIP:多模态项目从开发到云端部署
如果一个衣物管理系统只能上传图片、显示图片,那么它和普通网盘并没有本质区别。我希望 AIWear 能真正理解图片:知道图片里有什么,允许用户用文字或另一张图片找到它,还能根据自然语言指令编辑或合并图片。
这个想法最终变成了一套由 Vue、Spring Boot 和 Python AI 服务共同组成的应用。它既包含用户、文件、数据库、鉴权等传统软件系统能力,也包含图片理解、向量检索和 Agent 工具调用等 AI 能力。更重要的是,这些模块已经被连接成了从浏览器到云服务器的完整业务流程。
AIWear 能做什么
目前项目包含以下核心功能。
1. 两种方式完成登录或注册
用户可以使用邮箱验证码,也可以使用用户名和密码。邮箱验证码暂存在 Redis 中并设置五分钟有效期;用户名密码使用 BCrypt 保存 Hash;认证成功后由后端生成 JWT,前端后续通过Authorization: Bearer <token>携带身份。
对应接口:
POST /api/user/send-code POST /api/user/auth POST /api/user/logout2. 上传并管理自己的图片
图片上传并不是直接存入服务器目录。Java 后端先检查文件类型和大小,再调用 Python 服务判断图片是否属于服装、穿搭或人物范围。验证通过后,图片被上传到阿里云 OSS,文件名、大小、用户 ID 和 OSS 地址写入 MySQL。
对应接口:
POST /api/file/upload/image GET /api/file/my-images3. 使用文字或图片搜索
每张上传成功的图片还会进入 AI 索引流程。Python 从 OSS 下载图片,调用视觉模型生成描述,并用本地 CLIP 模型生成归一化的 512 维图片向量,随后将描述、向量、用户 ID 和 OSS 地址保存到 Redis。
当前代码支持两条检索路径:
- 文搜图:在视觉模型生成的图片描述中进行文本匹配。
- 图搜图:将查询图片转换为 CLIP 向量,与已有图片向量计算余弦相似度。
需要特别说明:当前版本没有使用 CLIP 文本编码器做跨模态文本向量检索。文搜图使用描述匹配,图搜图使用 CLIP 向量。这是当前实现的真实边界,也是后续可以继续优化的方向。
对应接口:
POST /api/file/search4. 使用自然语言编辑或合并图片
蓝色”或“让人物穿上第一张图中的衣服”。Java 校验图片归属后,将用户选择自己上传的图片并输入指令,例如“把衣服改成图片和指令发送给 Python。
Python 中的 Agent 根据输入参数判断应该调用哪个工具:
- 只有
image_path时调用edit_image_tool。 - 同时存在
image_path1和image_path2时调用merge_image_tool。
工具调用 DashScope 图像编辑模型并返回结果 URL。为了避免业务长期依赖模型提供的临时地址,Java 会再次下载结果,并上传到项目自己的 OSS,最后保存操作记录。
对应接口:
POST /api/file/edit POST /api/file/merge GET /api/record/my整体架构
这个架构可以分成三条主线。
Java 业务系统线
Spring Boot 是系统的业务中心,负责:
- 接收前端请求并完成参数转换。
- 解析 JWT,确定当前用户。
- 约束用户只能操作自己的图片。
- 读写 MySQL、Redis 和 OSS。
- 调用 Python 服务并处理返回结果。
- 使用
Result<T>统一前端响应。 - 使用 AOP 记录带有
@ApiLog的接口调用。
传统业务能力留在 Java,可以保持数据一致性、权限边界和接口结构清晰。
Python AI 能力线
Python 服务集中负责更适合 Python 生态的工作:
- 使用 LangChain 调用通义千问模型。
- 使用 Transformers 和 PyTorch 加载本地 CLIP。
- 生成图片描述和图片向量。
- 计算搜索相似度。
- 创建 Deep Agent,并注册图片编辑和合并工具。
Java 不需要理解模型加载和推理细节,只依赖稳定的 HTTP 接口。
部署与基础设施线
Docker Compose 管理 MySQL、Redis 和 Nginx。Java JAR 与 Python Flask 服务运行在 Linux 宿主机上,Nginx 容器通过host.docker.internal将/api请求转发到宿主机的8081端口。
前端执行npm run build后生成dist,再挂载进 Nginx 容器。这样用户只需要访问 80 端口,不需要感知 Java 和 Python 的内部端口。
一张图片上传后经历了什么
下面这条流程连接了项目中的大部分组件。
这条链路体现了 AIWear 的核心设计:Java 控制业务顺序和数据归属,Python提供模型能力,MySQL保存可查询的业务事实,Redis保存短期状态和 AI 索引,OSS承担文件存储。
Agent、Skill 和 Tool 在项目里分别做什么
这三个概念容易混在一起,在 AIWear 中可以这样理解:
- Tool 是可执行函数。
edit_image_tool和merge_image_tool真正读取图片并调用图像模型。 - Skill 是写给 Agent 的操作说明。
SKILL.md描述何时使用工具及输入输出要求。 - Agent 是决策和编排者。它阅读当前输入、工具参数和 Skill 说明,选择工具并组织调用参数。
Java 传给 Python 的不是一句模糊聊天内容,而是图片文件和明确的操作指令。Python 再将临时文件路径组织成 Prompt:
instruction: 把衣服改成蓝色 image_path: /tmp/aiwear_xxx.binAgent 根据存在的字段选择edit_image_tool。两张图片时字段变为image_path1和image_path2,Agent 则选择merge_image_tool。
数据分别保存在哪里
| 数据 | 保存位置 | 原因 |
|---|---|---|
| 用户、文件、操作记录 | MySQL | 结构固定、需要持久化查询 |
| 邮箱验证码 | Redis | 有过期时间,验证后立即删除 |
| JWT 缓存 | Redis | 支持复用、登出和服务端失效 |
| 图片描述与向量 | Redis | 当前版本便于快速读取和相似度计算 |
| 原图与处理结果 | OSS | 文件体积大,不适合直接放入数据库 |
| 前端静态资源 | Nginx 挂载目录 | 直接通过 80 端口访问 |
| CLIP 模型 | Python 服务本地目录 | 避免每次启动从网络下载 |
我从项目中真正学到了什么
项目最有价值的部分不是记住某个注解或某条 Docker 命令,而是理解不同组件如何共同完成一条业务链路:
- 前端请求格式必须和 Java Controller 的参数来源一致。
- Controller 只负责接口边界,Service 负责业务编排。
- Java 与 Python 的连接本质上是一组明确的 HTTP 契约。
- 模型生成的结果仍然需要权限校验、持久化和错误处理。
- Redis、MySQL 和 OSS 解决的是不同类型的数据问题。
- 本地可运行不等于服务器可部署,环境变量、网络边界和进程管理同样重要。
当前实现边界
为了准确描述项目,当前版本仍有以下可改进点:
- 文搜图目前使用图片描述的关键词匹配,可升级为 CLIP 文本向量或独立 Embedding 服务。
- Python 使用 Flask 开发服务器,正式部署可改为 Gunicorn 等 WSGI 服务。
- Java 跨服务调用使用直接创建的
RestTemplate,可增加统一超时、重试和错误映射。 - 自动化测试覆盖较少,需要补充 Service、Controller 和 Python API 测试。
- Java 与 Python 目前使用后台命令运行,可改为 systemd 或容器化服务。
- 代码中部分早期中文文本存在编码显示问题,需要统一为 UTF-8。