企业 AI 应用平台,为什么不能只靠「套一层 API」

2026-05-22 36 预计阅读时间:1 分钟
来源:oschina.net AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:11 分钟

过去两年,很多团队的 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") ? "华东" : "全国";
    }
}

运行前需要做的改动:

  1. pom.xml 加入 spring-ai-openai-spring-boot-starter(Spring AI 1.0+)和 spring-boot-starter-jdbc
  2. 数据库中创建视图 v_region_refund_stats,或替换成你自己的业务表。
  3. OPENAI_API_KEYDB_PASSWORD 通过环境变量注入,不要硬编码。
  4. 权限部分根据项目实际安全框架调整(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 成为业务系统的一个原生模块而不是外围附件——值得关注。对企业来说,真正的问题从来不是「哪个平台功能更多」,而是「哪个平台让我少写胶水代码」。


相关推荐