
RuoYi AI 环境搭建这个标题我盯着琢磨了挺久。说白了就是两件事凑到一块RuoYi若依这套在 Java 圈子里用得极广的后台管理框架和当下到处都在喊的 AI 能力。我最近正好把一个若依项目做了智能化改造从 JDK、Maven、MySQL、Redis 这些若依的老搭档到 Python、PyTorch、FastAPI 这一套 AI 服务栈再到两边怎么对接、怎么鉴权、怎么处理超时和乱码整个链路走了一遍踩了不少坑也沉淀了一套比较稳定的打法。这篇东西就是把这些实操整理出来给两类人看一类是想在若依项目里加 AI 功能的后端开发另一类是准备把大模型接入传统 Java 项目、还没理清环境的同学。我尽量把每一步背后的“为什么”也讲透而不是只扔给你一堆照敲即可的命令。1. 总体思路为什么若依和 AI 要分两个环境1.1 若依是什么它能解决什么问题若依是一个基于 Spring Boot Spring Security MyBatis 的前后端分离管理后台脚手架前端有 Vue2/Vue3 两个大版本后端代码结构高度统一。它自带用户管理、角色管理、菜单管理、部门管理、字典管理、定时任务、操作日志、代码生成这些绝大部分后台系统都要重复造轮子的模块。你拿到手改改配置导入 SQL基本就有一个能登录、能分配权限、能管理用户的后台主干然后只需要往里面填自己的业务模块。打个比方若依就像是一个已经帮你把行政、人事、财务这些后台支持部门都建好的公司你要做的只是招几个业务骨干去干正事。很多中小团队做管理平台与其从零写权限和安全框架不如直接用若依做底座这也是它火了很多年的原因。1.2 AI 能力为什么不能直接塞进 Java 项目一开始我也有过偷懒的想法既然若依是 Java 项目能不能直接在 Java 里加载模型做推理试了之后发现这条路的性价比非常低。PyTorch 这类深度学习框架的生态主要在 Python 侧模型加载、分词、推理逻辑、微调工具链全在 Python 环境里。Java 虽然也有一堆深度学习库但模型格式的兼容、预训练模型的支持、社区文档的丰富度都差一大截。真要是把一个大模型塞进 Java 进程光是处理分词器版本和模型权重格式就能折腾掉你一个周末。所以我最终采用了“Java 管业务、Python 管智能”的分层思路后端若依负责登录、鉴权、流程编排、数据存储这些确定性业务Python 独立起一个 AI 推理服务专门负责模型加载和推理两个服务之间通过 HTTP 接口通信。这样做的核心好处有三个第一Java 侧不引入重型 AI 依赖项目构建体积和复杂度都可控第二Python 侧可以独立升级模型、换模型不影响若依的稳定运行第三故障隔离模型服务挂了不会把整个业务系统拖垮。打个比方Java 是前台的业务经理Python 是坐在后台的专家顾问业务经理有问题就写个单子给专家专家干完活把结果递回来二者各自保持边界效率反而最高。1.3 目录规划与版本选型总览正式动手前先把目录和版本定下来避免后面东一榔头西一棒子。我的项目结构很简单my-project/ruoyi若依前后端分离工程后端 Java前端 Vue。my-project/ai-servicePython 独立 AI 服务用 FastAPI 框架。版本选型方面我整理了一张表格基本照着这个组合可以少踩很多坑组件版本说明JDK8 或 17若依新版已兼容 17旧工程用 8 最稳Maven3.8配置国内镜像否则依赖下载能等到你怀疑人生MySQL8.0字符集务必 utf8mb4Redis6.x若依的验证码、会话缓存依赖它Node.js16/18Vue3 前端工程必需推荐 18Python3.10PyTorch 对 3.10 的支持最均衡PyTorch2.1根据显卡 CUDA 版本选对应安装包这个清单看着简单但版本之间稍有错配就会引发连锁问题。比如 JDK 版本和 Lombok 版本不匹配编译直接报错Node 版本太老Vue3 工程跑不起来。提前定版本其实是在提前买保险。2. 先把若依跑起来基础环境的搭建细节2.1 中间件与工具链的准备若依跑起来需要 MySQL、Redis、JDK、Maven、Node 这几样东西。MySQL 安装时最容易被忽略的是字符集建议建库时直接指定 utf8mb4CREATE DATABASE ruoyi_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;为什么不建议用默认字符集因为如果表里要存 AI 对话内容、用户输入的特殊符号比如 emojilatin1 或者 utf8mb3 要么存不进去要么取出来乱码。AI 场景下输入输出文本非常多样这一步千万别省。Redis 默认端口 6379安装完直接启动即可若依默认配置是无密码连接本地开发完全够用。JDK 和环境变量这步我建议直接装 JDK 8 或 17然后配好JAVA_HOME。Maven 的核心难点不是安装而是仓库下载慢在settings.xml里加阿里云镜像基本是必做操作mirror idaliyunmaven/id mirrorOfcentral/mirrorOf urlhttps://maven.aliyun.com/repository/public/url /mirrorNode 端我强烈建议用 nvm 管理多版本因为若依的 Vue3 工程和可能存在的其他前端项目对 Node 版本要求并不完全一致。用 nvm 装 Node 18再配 npm 的国内镜像前端依赖安装就能快非常多。2.2 导入数据库与修改配置的实操要点从官方仓库拉最新的 RuoYi-Vue3 源码后在sql目录下通常会有两个文件一个是主库脚本类似ry_2024xxxx.sql另一个是quartz.sql若依集成 Quartz 定时任务的表结构。两个都要导入顺序无所谓但导入前确认数据库字符集是 utf8mb4。然后改后端配置关键文件是application-druid.yml数据库连接串一定要注意这几项参数url: jdbc:mysql://localhost:3306/ruoyi_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: your_passwordserverTimezone是必填项不填的话高版本 MySQL 驱动会直接报时区错误中文环境下报错信息甚至可能是乱码很容易让人摸不着头脑。useSSLfalse在本地开发也必须加MySQL 8 默认 SSL 设置和本地调试容易冲突。改完配置后启动顺序有讲究先启动 Redis再启动后端。后端启动入口是RuoYiApplication.java启动成功后访问http://localhost:8080用默认账号admin/admin123登录。如果你发现后端启动后短暂正常、然后报 Redis 连接异常多半就是 Redis 没启动或者密码配置和实际不一致。2.3 前端启动与打包发布的常见处理前端工程在ruoyi-ui目录下启动命令很常规npm install --registryhttps://registry.npmmirror.com npm run dev开发模式下前端默认端口是 80 或者 8081Vue CLI 的代理配置在vue.config.js里开发服务器会把/dev-api开头的请求代理到后端的http://localhost:8080。这一步不需要前端同学操心太多但如果登录时出现验证码加载失败、接口 404第一条排查思路就是看代理配置里的 target 是否正确指到了后端端口。打包发布时执行npm run build产物在dist目录丢到 Nginx 或者任意静态资源服务器即可。要注意后端的接口路径和前端请求路径必须保持一致若依后端默认接口前缀是/dev-api如果部署到测试环境需要在 Nginx 里把/dev-api反向代理到后端服务location /dev-api/ { proxy_pass http://127.0.0.1:8080/; }这一节的感受是若依本身的启动流程已经非常成熟真正费时间的不是若依而是环境之间的版本匹配。先把这套基础环境跑通后面接 AI 服务才有稳定的落脚点。3. AI 运行环境PyTorch 这一侧的准备工作3.1 显卡环境与 CUDA/PyTorch 版本匹配AI 服务这边第一个大坑就是 PyTorch 和 CUDA 的版本匹配。我先说结论不要凭感觉装 GPU 版 PyTorch先看显卡驱动支持到什么 CUDA 版本。在命令行执行nvidia-smi右上角有一个CUDA Version比如12.0。这是驱动支持的 CUDA 最高版本不代表你机器上装了 CUDA 工具包但 PyTorch 安装时主要看这个。比如驱动支持 CUDA 12.0你就可以装对应 cu118 或 cu121 的 PyTorch命令类似pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118如果你机器上根本没有 NVIDIA 显卡或者用的是笔记本核显千万别装 CUDA 版 PyTorch否则 import 阶段大概率报错或者 torch.cuda.is_available() 永远是 False。老老实实装 CPU 版pip install torch torchvision torchaudio装完先验证环境python -c import torch; print(torch.__version__); print(torch.cuda.is_available())输出True说明 GPU 可用输出False就是你装成了 CPU 版或者驱动不匹配。这一步验证看起来简单却能帮你省下后面排查模型推理慢的实际问题的时间。3.2 没有独立显卡怎么办CPU 推理与云 GPUAI 环境搭建最大的现实障碍就是很多开发机没有高性能显卡。我有一次想在一台普通办公机器上跑一个 7B 参数模型结果模型加载占掉了 16G 内存推理一个短句都要几十秒根本没法用。后来我总结了几条路第一CPU 模式跑小模型。比如 Qwen 系列的小尺寸模型、ChatGLM 的 6B 量化版在 CPU 上能跑但速度只适合验证逻辑不适合实际业务。第二租云 GPU 实例按小时付费把模型服务部署在云上本地 Java 服务通过内网或公网调用。第三也是我现在最推荐的直接用国产大模型 API比如阿里百炼、百度千帆、智谱 AI 开放平台省去显卡、模型部署、运维这一整套麻烦按调用量付费业务验证阶段成本极低。很多人一提到 AI 就习惯性想本地部署但我的观点是环境搭建阶段没必要一步到位。先用 API 把若依和 AI 服务之间的接口链路打通验证业务逻辑没问题再根据需求决定要不要切换到本地大模型。这就像先坐公共汽车通勤确认路线没问题后再决定要不要买车自己开。3.3 模型服务框架与选型建议本地部署模型时除了 PyTorch还需要一个对外提供 HTTP 接口的服务框架。FastAPI 是目前 Python 生态里最适合做这个的性能好写起来简洁自动生成接口文档对 JSON 的支持天然适合前后端对接。如果业务场景涉及知识库问答、Agent 多轮工具调用会用到 LangChain 或 Dify 这类编排框架。再往前一步要做知识库检索就需要一个向量数据库小规模用 Chroma规模大了用 Milvus 或者 Elasticsearch。我的建议是环境搭建初期不要把这些全铺开先把最小链路跑通FastAPI 一个模型或 API能返回对话结果就算成功向量库这类组件等具体需求出现时再引入。选型上有个重要的取舍我整理成表格对比项本地模型部署云端大模型 API硬件成本高需要显卡/大内存低按量付费数据安全数据不出内网数据要传到服务商响应速度受硬件限制可能慢通常更快且有流式接口运维成本模型更新、GPU 宕机都要管服务商维护定制能力可微调、可换模型基本取决于服务商能力我的实践经验是初期一律走 API只有数据安全要求高或者需要模型深度定制时才考虑本地部署。这样能让你的精力集中在若依和 AI 的集成逻辑上而不是被显卡驱动困住。4. 若依与 AI 服务对接的三种方案4.1 方案一HTTP 调用独立 AI 服务推荐这是我最推荐、也是最后稳定使用的方案。整体链路是若依前端发起请求若依后端接收请求后调用 Python AI 服务的接口AI 服务返回结果若依后端加工后返回给前端。FastAPI 侧定义一个简单的对话接口from fastapi import FastAPI, Header, HTTPException from pydantic import BaseModel app FastAPI() API_KEY sk-xxxxxxxx class ChatRequest(BaseModel): message: str history: list [] app.post(/chat) def chat(req: ChatRequest, x_api_key: str Header(default)): if x_api_key ! API_KEY: raise HTTPException(status_code401, detailinvalid api key) # 这里调用模型或第三方 API reply 这是 AI 服务返回的回复 return {reply: reply}若依后端这边用若依自带的 Hutool 工具类发 HTTP 请求非常方便String url http://127.0.0.1:8000/chat; JSONObject body new JSONObject(); body.put(message, message); body.put(history, history); JSONObject result JSONUtil.parseObj( HttpRequest.post(url) .header(X-API-Key, sk-xxxxxxxx) .body(body.toString()) .timeout(20000) .execute() .body() ); String reply result.getStr(reply);这里有几个细节值得注意。第一超时时间我设置了 20 秒因为大模型接口就算再快也要几秒到十几秒用默认的超时配置很容易在并发时被断开。第二API Key 放在后端前端永远接触不到密钥。第三AI 服务跟若依之间是纯 HTTP 协议换模型、调整 prompt 都不需要改动若依代码。4.2 方案二Java 直连大模型 SDK如果不想维护一个 Python 服务也可以让若依后端直接调用大模型服务商提供的 Java SDK 或者 HTTP 接口。这个方案适合“只做业务验证”的场景。思路很简单在 pom.xml 里引入服务商 SDK或者直接用 Hutool 的 HTTP 工具发请求。比如调用一个 OpenAI 兼容接口String url https://api.example.com/v1/chat/completions; JSONObject body new JSONObject(); body.put(model, qwen-plus); body.put(messages, JSONUtil.parseArray([{\role\:\user\,\content\:\ prompt \}])); JSONObject result JSONUtil.parseObj( HttpRequest.post(url) .header(Authorization, Bearer apiKey) .body(body.toString()) .timeout(30000) .execute() .body() );这个方案的优点是架构极简不引入 Python 环境缺点是后续一旦要换本地模型、要做私有化部署、要接入 LangChain 工具调用Java 侧写起来非常痛苦。我只把它定位成临时的、快速验证的方案线上环境我仍然会切回独立的 AI 服务。4.3 方案三MQ 异步任务解耦第三个方案适合 AI 任务耗时特别长的场景比如批量内容审核、自动生成周报、异步分析日志。如果直接用 HTTP 同步调用用户会一直盯着页面转圈体验很差。这种情况下可以用消息队列做异步解耦。大致流程是若依后端把任务参数发到 RabbitMQ/RocketMQ 的某个队列Python AI 服务监听队列处理完成后再把结果写回数据库或者通过回调接口通知若依。用户不感知具体耗时前端在任务完成后展示结果。这个方案的好处是削峰填谷高并发时任务排队AI 服务不会被打爆。但我不建议刚开始接触若依 AI 就去上 MQ。原因很简单它会引入一套额外的中间件运维成本RabbitMQ 本身又要安装、配置、启停问题是环境复杂度越高排查链路越长。先同步接口跑通业务等确实有异步需求再切入 MQ这个节奏比较合理。4.4 接口鉴权与安全设计两个服务之间通信最容易被忽略的是安全。很多人搭建环境时觉得“反正本地调用无所谓”但如果这个系统要部署到测试环境甚至生产环境AI 服务端口直接裸奔风险会非常大。我的做法是三层防护第一层AI 服务通过请求头校验 API Key没有正确密钥的直接 401第二层若依后端的 AI 相关接口加上 Spring Security 权限注解比如PreAuthorize(ss.hasPermi(system:ai:chat))这样只有分配了权限的用户才能调用第三层AI 接口做限流若依自带接口限流注解RateLimiter可以直接加在 Controller 方法上防止某个用户频繁刷请求把模型资源耗尽。另外要注意提示词安全。用户输入的内容会原样拼进 prompt如果用户输入“忽略以上所有规则”这类文本有可能绕开系统设定。我的处理是在后端拼 prompt 时把用户输入作为一个普通文本字段传入而不是直接拼进系统指令同时在 AI 服务里对输入长度做限制比如超过 2000 字符直接拒绝。5. 实际操作一个 AI 助手功能从 0 到 15.1 搭建 FastAPI 推理服务以一个最典型的“AI 对话助手”为例我完整走一遍流程。先在ai-service目录下创建虚拟环境python -m venv venv source venv/bin/activate # Windows 下是 venv\Scripts\activate pip install fastapi uvicorn requests然后写main.pyfrom fastapi import FastAPI, Header, HTTPException from pydantic import BaseModel import requests app FastAPI() API_KEY sk-ai-service-key class ChatRequest(BaseModel): message: str history: list [] class ChatResponse(BaseModel): reply: str app.get(/health) def health(): return {status: ok} app.post(/chat, response_modelChatResponse) def chat(req: ChatRequest, x_api_key: str Header(default)): if x_api_key ! API_KEY: raise HTTPException(status_code401, detailinvalid api key) # 这里可以是调用本地模型也可以是调用云端 API # 示例调用第三方 API resp requests.post( https://api.example.com/v1/chat/completions, headers{Authorization: Bearer sk-xxxx}, json{ model: qwen-plus, messages: [{role: user, content: req.message}] }, timeout30 ) reply resp.json()[choices][0][message][content] return ChatResponse(replyreply)启动服务uvicorn main:app --host 0.0.0.0 --port 8000访问http://127.0.0.1:8000/docs能看到 FastAPI 自动生成的接口文档直接在线测试/chat接口。到这里 AI 服务的最小链路已经通了。5.2 若依后端封装 AI 接口接下来在若依工程里新建一个AIController路径为com.ruoyi.web.controller.systemRestController RequestMapping(/system/ai) public class AIController { private static final String AI_SERVICE_URL http://127.0.0.1:8000/chat; private static final String API_KEY sk-ai-service-key; PostMapping(/chat) PreAuthorize(ss.hasPermi(system:ai:chat)) public AjaxResult chat(RequestBody JSONObject params) { String message params.getStr(message); if (StringUtils.isEmpty(message)) { return AjaxResult.error(消息不能为空); } try { JSONObject body new JSONObject(); body.put(message, message); body.put(history, params.getJSONArray(history)); String result HttpRequest.post(AI_SERVICE_URL) .header(X-API-Key, API_KEY) .body(body.toString()) .timeout(30000) .execute() .body(); JSONObject resultObj JSONUtil.parseObj(result); return AjaxResult.success(success, resultObj.getStr(reply)); } catch (Exception e) { return AjaxResult.error(AI 服务调用失败 e.getMessage()); } } }这段代码的关键点在于把 AI 服务地址和 API Key 集中在常量里方便后续统一配置到 Nacos 或配置中心超时时间给足 30 秒异常统一转成若依的AjaxResult结构前端拿到错误提示不会乱。登录用户访问这个接口时若依的 Token 校验会先拦截一层服务器端的权限注解再拦一层双保险。5.3 新增 AI 助手菜单与对话页面若依的管理后台加一个新功能页面很简单。登录 admin 账号在菜单管理中新增一个菜单菜单类型选“C 菜单”路由地址填ai/chat组件路径填system/ai/chat/index然后分配权限标识system:ai:chat给对应角色。前端页面我用 Vue3 写一个极简聊天框核心逻辑只有三块消息列表、输入框、调用接口。核心请求部分直接复用若依封装的request工具import request from /utils/request export function sendChatMessage(message, history) { return request({ url: /system/ai/chat, method: post, data: { message: message, history: history } }) }页面里维护一个messages数组用户发送消息时先 push 一条用户消息到列表再调接口把 AI 回复 push 进去。这个阶段先不做流式输出等后端稳定后再考虑 SSE。界面上不需要花哨能直观看到对话往返这个功能就算立住了。5.4 连接定时任务让 AI 自动产出日报若依自带 Quartz把 AI 能力和定时任务结合起来能做出很多实用功能。我这边做的是“每日 AI 工作日报生成”每天凌晨定时调用 AI 服务把当天系统里的操作日志、任务完成情况汇总发给模型让模型生成一段总结文本再存到业务表里。在若依的定时任务管理页面新建一个任务调用目标填一个后端方法比如aiReportTask.run()。后端方法里写逻辑public void run() { // 1. 查询当天日志和任务数据 // 2. 拼装提示词 // 3. 调用 AI 服务 // 4. 保存结果到数据库 }定时表达式直接支持 Cron比如0 0 1 * * ?表示每天凌晨 1 点执行。这个组合的价值在于若依的调度能力补足了 AI 服务缺失的周期性触发能力两边优势互补形成一个真正能落地的自动化场景。做完这个功能我明显感觉 AI 环境搭建不只是“接个接口”而是能给业务带来实在的效率变化。6. 踩坑记录从环境到对接的常见问题6.1 环境搭建阶段的坑第一个坑是 MySQL 时区问题。若依连接数据库报时区错误是最常见的环境问题之一报错信息在中文系统下可能显示成乱码。解决办法就是在 JDBC 连接串里加serverTimezoneAsia/Shanghai。这个坑几乎每个新手都会遇到我建议在数据库连接串的模板里直接写全参数以后每个项目都复用。第二个坑是 Redis。启动后端时报 Redis 连接失败但实际 Redis 明明装好了。后来发现是 Redis 密码问题若依默认配置里密码为空而本地 Redis 被我之前设置过密码改了配置里的spring.redis.password才解决。另外若依的验证码存在 Redis 里如果 Redis 里残留旧数据可能出现验证码明明输入正确却总是校验失败的情况这时候清一下 Redis 缓存就好了。第三个坑是 Maven 依赖下载慢。国内网络环境下如果没有配镜像第一次mvn package能把人活活等疯。配好阿里云公共仓库之后构建时间从几十分钟缩短到几分钟这属于“一次配置长期受益”的操作。6.2 依赖与版本引发的坑先说 Java 侧。如果用 JDK 17 跑旧版若依Lombok 版本太低会导致编译直接失败。我的建议新项目直接拉最新版若依老项目留在 JDK 8不要轻易升级 JDK。另外MySQL 驱动版本和数据库版本不匹配时会报通信协议错误本地调试统一用和 MySQL 8.0 配套的驱动版本。再说 Python 侧。最经典的问题就是torch.cuda.is_available()返回False原因基本就三个装成了 CPU 版、显卡驱动太老、PyTorch 的 CUDA 版本和驱动不匹配。排查思路很直接先跑nvidia-smi看驱动支持的最高 CUDA 版本再到 PyTorch 官网选择对应版本的安装命令重装。Python 版本也有坑PyTorch 对 Python 3.12 以上的支持通常有滞后建议环境统一用 Python 3.10能省很多琐事。6.3 对接阶段的坑对接阶段我最常碰到的有三个问题。第一个是超时。若依后端调用 AI 服务如果模型推理慢默认的 HTTP 客户端很容易在等待阶段就断开。解决方案是在调用 AI 服务时显式设置超时时间并在若依侧的服务配置里适当调整。如果用户反馈页面一直转圈但没有错误提示大概率就是超时时间太短或者 AI 进程卡死。第二个是跨域。如果前端页面直接请求 AI 服务地址而不是经过若依后端转发大概率会遇到跨域问题。FastAPI 里需要配置 CORSMiddleware但我更推荐的是让所有请求都走若依后端前端只需要跟若依通信跨域问题直接绕开。这样架构也清晰权限控制也容易统一。第三个是中文乱码。FastAPI 返回中文默认就是 UTF-8正常情况下不会乱码出问题的地方常常在 Java 侧处理响应时没有正确指定字符集。用 Hutool 的HttpRequest通常没问题但如果你自己写原生 HttpClient记得在解析响应时指定StandardCharsets.UTF_8。还有一个看起来不算问题、实际很要命的细节AI 服务的日志级别。FastAPI 默认的 access log 在并发高的时候会刷屏Uvicorn 启动时加个--log-level warning参数能显著降低日志噪音。排查问题时再看完整日志平时保持安静这是一种很实用的运维习惯。结尾几点真实体会整套若依 AI 环境搭建走下来我最深的体会是真正耗时间的从来不是写代码而是环境里的版本匹配和依赖安装。PyTorch 的 CUDA 版本、Java 的 JDK 版本、Node 的版本、MySQL 的字符集任何一个错位都可能让你卡上半天。所以我强烈建议按这个顺序推进先把若依自身跑通再把 AI 服务单独冒烟验证然后通过一个最简单的接口把两边连起来最后再去加页面、定时任务、安全防护这些外围能力。每一步都验证完再进入下一步能省掉大量“不知道是前端问题还是后端问题还是中间件问题”的无谓排查。还有一个值得尝试的扩展方向若依的代码生成器本身已经很强了如果能把它生成的代码模版喂给 AI让模型根据表结构描述自动产出增删改查的业务代码建议再人工复核那这套环境的价值就不只是“接了个聊天机器人”了而是真正长在开发流程里的 AI 赋能。后面我会继续在这个方向折腾踩出新的坑再来分享。