过去两年,很多团队的 AI 落地路径几乎一模一样:部署一套 Dify 或 FastGPT,配个知识库,挂几个大模型 API,搭个对话界面——两周就能跑起来。但跑起来之后呢?知识库更新要手动同步、业务审批流没法接入、和现有 ERP/CRM 的数据打通全靠硬编码胶水层。平台和业务系统之间始终隔着一道墙。
JEECG AI 应用平台试图换一个思路:不做独立的 AI 中台,而是把 AI 能力直接长在 Java 业务系统里。这个定位听起来简单,背后的技术选择和架构差异值得拆开看。
Dify 够用吗——从 Python 到 Java 的断层
Dify 是优秀的 LLM 编排工具,但它的技术栈是 Python + TypeScript,生态围绕 LangChain / LlamaIndex 构建。问题不在于 Python 本身,而在于绝大多数中国企业的核心业务系统跑在 Java 上——Spring Boot、MyBatis、Shiro/JWT 权限体系、审批引擎、报表引擎,这些才是企业每天在运转的东西。
断层具体表现在三个地方:
- 数据不通:Dify 的知识库是独立向量存储,企业关系型数据库里的订单、客户、工单数据要手动导出再灌入,实时性几乎为零。
- 权限割裂:Dify 有自己的用户体系,企业系统的角色/部门/数据权限无法直接映射,每次权限变更都要两边同步。
- 流程断裂:Dify 的 Workflow 是 LLM 逻辑编排,不是业务流程编排。一个「AI 审批辅助」场景需要同时调用大模型和业务审批引擎,Dify 只能管前半段。
JEECG AI 的核心主张就是:用 Java 技术栈把 AI 能力嵌入到已有的业务骨架里,而不是在外围再搭一个独立平台。
「长在业务里」的技术含义
「长在业务里」不是营销话术,它对应几个具体的架构决策:
统一权限与用户体系。JEECG 本身是低代码平台,自带完整的 RBAC 权限模型、部门组织树、数据规则过滤。AI 应用直接复用这套体系,意味着同一个用户在业务系统和 AI 对话界面里的权限完全一致——能看到哪些数据、能触发哪些流程,不需要二次配置。
业务数据即知识库。不是把数据导出再灌入向量库,而是通过 JDBC/MyBatis 直连业务数据库,结合 RAG 做实时检索。用户问「上季度华东区退货率最高的 SKU 是什么」,AI 可以直接查业务库再总结,而不是依赖一份可能已经过期的文档。
流程编排一体化。JEECG 有自己的流程引擎(基于 Activiti/Flowable),AI 节点可以作为流程中的一个环节嵌入——比如在审批节点调用大模型做风险提示,结果写回审批表,整个链路在一个流程定义里完成。
实战:在 Spring Boot 业务系统中接入 AI 能力
下面是一个最小化示例,展示如何在已有 Spring Boot 项目中集成 AI 对话能力,并让它读取业务数据库数据。这段代码不依赖 JEECG 平台本身,但体现了「AI 长在业务里」的核心思路——AI 服务和业务服务共享同一个数据源和权限上下文。
// === 1. AI 服务配置 ===
// application.yml
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
base-url: https://api.openai.com # 或国内代理地址
chat:
options:
model: gpt-4o
temperature: 0.3
datasource:
url: jdbc:mysql://localhost:3306/erp_main
username: root
password: ${DB_PASSWORD}
// === 2. 业务数据检索服务 ===
@Service
public class OrderQueryService {
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* 查询指定区域指定季度的退货统计
* AI 调用此方法获取实时业务数据
*/
public String queryRefundStats(String region, String quarter) {
String sql = """
SELECT sku_code, sku_name, refund_rate
FROM v_region_refund_stats
WHERE region = ? AND quarter = ?
ORDER BY refund_rate DESC
LIMIT 10
""";
var rows = jdbcTemplate.queryForList(sql, region, quarter);
// 转成 AI 可读的文本摘要
StringBuilder sb = new StringBuilder("退货率排名:\n");
for (var row : rows) {
sb.append("- %s (%s): %.1f%%\n".formatted(
row.get("sku_name"), row.get("sku_code"),
(Double) row.get("refund_rate") * 100));
}
return sb.toString();
}
}
// === 3. AI 对话服务——带业务数据注入 ===
@Service
public class BusinessChatService {
@Autowired
private ChatClient chatClient; // Spring AI 的 ChatClient
@Autowired
private OrderQueryService orderQueryService;
/**
* 处理用户提问,自动判断是否需要查业务数据
*/
public String chat(String userQuestion, String currentUserRegion) {
// 构造系统提示,注入当前用户的业务上下文
String systemPrompt = """
你是 ERP 系统的智能助手。
当前用户所属区域:%s。
当需要查询业务数据时,请先说明要查什么,
系统会自动检索并补充数据,你再基于数据回答。
""".formatted(currentUserRegion);
// 第一次调用:让 AI 表达查询意图
ChatResponse firstCall = chatClient.call(
new Prompt(List.of(
new SystemMessage(systemPrompt),
new UserMessage(userQuestion)
))
);
String aiResponse = firstCall.getResult().getOutput().getText();
// 简化示例:如果问题涉及退货率,自动注入业务数据再二次调用
if (aiResponse.contains("需要查询退货") || userQuestion.contains("退货")) {
String bizData = orderQueryService.queryRefundStats(
currentUserRegion, "2024Q3");
String enrichedPrompt = """
系统已检索到以下业务数据:
%s
请基于以上数据回答用户问题:%s
""".formatted(bizData, userQuestion);
ChatResponse secondCall = chatClient.call(
new Prompt(List.of(
new SystemMessage(systemPrompt),
new UserMessage(enrichedPrompt)
))
);
return secondCall.getResult().getOutput().getText();
}
return aiResponse;
}
}
// === 4. Controller——复用现有权限体系 ===
@RestController
@RequestMapping("/api/ai")
public class AiChatController {
@Autowired
private BusinessChatService chatService;
/**
* 通过现有 Spring Security 权限体系控制访问
* 用户区域信息从认证上下文获取,无需额外配置
*/
@PostMapping("/chat")
@PreAuthorize("hasRole('AI_USER')")
public ResponseEntity<String> chat(
@RequestBody String question,
@AuthenticationPrincipal UserDetails user) {
// 从用户所属部门推导区域——和业务系统权限一致
String region = getUserRegion(user);
String answer = chatService.chat(question, region);
return ResponseEntity.ok(answer);
}
private String getUserRegion(UserDetails user) {
// 实际项目中从部门/角色映射,这里简化
return user.getUsername().contains("east") ? "华东" : "全国";
}
}
运行前需要做的改动:
pom.xml加入spring-ai-openai-spring-boot-starter(Spring AI 1.0+)和spring-boot-starter-jdbc。- 数据库中创建视图
v_region_refund_stats,或替换成你自己的业务表。 OPENAI_API_KEY和DB_PASSWORD通过环境变量注入,不要硬编码。- 权限部分根据项目实际安全框架调整(Shiro / Spring Security / 自定义)。
这个示例的关键点不是代码本身,而是思路:AI 服务和业务服务共享同一个 DataSource、同一个 SecurityContext。不需要在两个系统之间同步数据或映射权限。
选型考量:什么时候该选 Dify,什么时候该考虑 Java 方案
没有万能答案,但有几个判断维度值得列出来:
| 维度 | Dify / FastGPT 更合适 | Java 原生方案更合适 |
|---|---|---|
| 团队技术栈 | Python 为主,AI 团队独立 | Java 为主,AI 需求来自业务团队 |
| 数据实时性 | 知识库更新频率低,文档型为主 | 需要查询实时业务数据(订单、库存等) |
| 权限复杂度 | 简单角色划分即可 | 多级部门、数据行级权限 |
| 流程集成 | AI 对话独立使用 | AI 要嵌入审批、工单等业务流程 |
| 定制深度 | 用平台自带能力够用 | 需要深度定制 AI 节点逻辑 |
务实建议:
- 如果你的核心系统就是 Python 写的,Dify 是合理选择,别为了「统一技术栈」硬换。
- 如果核心系统是 Java 且 AI 场景和业务流程强耦合,认真评估 Java 原生方案——减少集成成本比减少初始部署成本更重要。
- 不管选哪条路,先跑一个最小场景:一个需要实时查业务数据 + 受权限控制的 AI 查询。这个场景最能暴露平台和业务之间的缝隙。
JEECG AI 目前仍是早期阶段,文档和社区成熟度远不及 Dify。但它的方向——让 AI 成为业务系统的一个原生模块而不是外围附件——值得关注。对企业来说,真正的问题从来不是「哪个平台功能更多」,而是「哪个平台让我少写胶水代码」。