首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >银河it-Java AI:概率性模型与确定性系统之间的工程桥梁

银河it-Java AI:概率性模型与确定性系统之间的工程桥梁

原创
作者头像
用户12502671
发布于 2026-09-29 10:45:28
发布于 2026-09-29 10:45:28
210
举报

引子:一个被混淆的定位

关于“Java 会不会在 AI 时代被淘汰”的争论,本质上混淆了 AI 的两层工作。模型层——训练、微调、推理内核——由 PyTorch 生态和学术共同体定义,Java 在那里没有主场,也不需要主场。应用层——把模型能力接进业务流程,变成能上线、能计费、能追责的系统——才是企业真正花钱购买的部分。

一个具体的算式可以说明这个定位的工程含义。一家银行要上智能客服、智能风控、信贷报告生成,它面对的不是“用什么语言写模型”,而是“怎么在不推翻核心系统的前提下,让现有 Java 服务具备调用模型、检索私有数据、记录审计日志、扛住每秒上万次请求的能力”。这个系统的百分之九十的代码依然是事务、权限、幂等、重试、监控。多出来的那百分之十,才是 Java AI 的全部内容。

2026 年,62% 的企业已在 Java 技术栈上构建 AI 功能,较上一年度的 50% 显著跃升。这一增长的底层驱动力并非 Java 在算法层的竞争力,而是企业存量系统的工程化需求:金融、电信、政务的核心系统运行在 JVM 上,它们无法为了接入大模型而重写,只能“嵌入”。

本文从 JVM AI 生态的三个层次出发,深入分析框架的架构选择、虚拟线程与同步抽象之间的工程张力,以及 Java 类型系统在 AI 应用中的独特角色。

一、JVM AI 生态的三层结构

理解 JVM AI 框架时,最常见的混淆是把不同层次的东西放在一起比较。事实上,当前生态可以清晰地划分为三层,每层解决不同的问题,也有各自的成熟度。

第一层:模型抽象。 解决的问题是“调用不同 LLM 提供商而不重写代码”。Spring AI 支持 20 多个提供商并通过 auto-configuration 简化配置,LangChain4j 提供 20 多个提供商的统一 API,OmniHai 则走轻量路线,零依赖、通过 CDI 注入 AI 服务。这一层是 JVM 生态最成熟的部分。如果你只需要从 Java 调用 Claude、GPT-4 或 Gemini 并处理响应,Spring AI 或 LangChain4j 可以在几分钟内完成接入。

OmniHai 的设计值得单独提及。它面向 Jakarta EE 和 MicroProfile 应用,不要求直接依赖各提供商的 SDK,而是通过 REST API 通信,提供一致的 AIService 抽象。开发者通过 CDI 注入即可使用:

代码语言:javascript
复制
@Inject
@AI(provider = AIProvider.ANTHROPIC, apiKey = "your-api-key")
private AIService claude;

String response = claude.chat("Explain microservices");

这种做法的工程含义是:AI 集成与 Jakarta EE 已有的依赖注入和托管组件模型保持一致,不需要引入新的编程范式。对于已经在 Jakarta EE 上的企业系统,这意味着 AI 能力的引入是增量的,而非颠覆性的。

第二层:Agent 编排。 解决的问题是“协调多步骤、多智能体的工作流”——规划、工具使用、反馈循环、状态管理。LangGraph4j 引入了有环图和持久化检查点,Embabel 采用 GOAP(Goal-Oriented Action Planning)做确定性规划,Koog 基于协程实现协调和容错,Google ADK for Java 则聚焦 A2A 协议和事件压缩。这一层是生态最有活力的部分,也是各框架分化最明显的地方。

第三层:生产运行时。 解决的问题是“Agent 工作流在生产环境中的耐久性”——崩溃恢复、审计追踪、事件溯源状态。这一层目前最不成熟。Spring AI 已经通过 OpenTelemetry 输出 GenAI 指标,Quarkus LangChain4j 扩展零配置接入 tracing,但 LangChain4j 的 guardrails 仍处于 beta 阶段。

这三层的划分有明确的实践含义:模型抽象层已经 commoditized,Agent 编排层正在分化,生产运行时层是真正的蓝海。 如果你的团队正在评估 Java AI 框架,第一层的能力不应该成为选型的核心考量——Spring AI 和 LangChain4j 在这一层的差距不超过 10%。真正需要仔细评估的是第二层的编排模型和第三层的生产就绪度。

二、框架的架构选择:Spring AI 的分层抽象与 LangChain4j 的声明式接口

Spring AI 和 LangChain4j 是 Java AI 领域两个最主流的框架,它们在 2025 年 5 月同时达到 1.0 GA。两者的核心差异不在于“谁能做更多”,而在于它们对“开发者应该如何表达 AI 逻辑”这个问题的不同回答。

Spring AI:将模型差异隔离在适配器层

Spring AI 的核心设计哲学是将 Spring 一贯的“约定优于配置”和“面向接口编程”应用到 AI 工程领域。它采用四层架构:模型层封装各厂商的客户端实现,核心抽象层定义与提供商无关的接口,服务层提供 ChatClient 和 VectorStore 等高级组件,集成层完成与 Spring Boot、Spring Security、OpenTelemetry 的对接。

核心抽象中,Model 接口只包含一个 call(Prompt) 方法。这个设计的工程含义是:所有 AI 模型都具有统一的调用方式,切换模型提供商只需修改配置,业务代码无需变更。当一个智能客服系统需要从 OpenAI 切换到阿里云通义千问时,如果直接使用厂商 SDK,切换意味着重写所有调用代码;如果使用 Spring AI 的 ChatClient,切换意味着修改一行 application.yml 中的模型配置。

Spring AI 的多模型注册和路由机制进一步体现了这种“配置优先”的设计哲学:

代码语言:javascript
复制
@Bean
public ModelRegistry modelRegistry() {
    return ModelRegistry.builder()
        .register("gpt-4", OpenAiModel.builder()
            .apiKey("xxx").endpoint("https://api.openai.com").build())
        .register("ernie", ErnieModel.builder()
            .accessTokenProvider(tokenSupplier).build())
        .build();
}

某金融客户案例显示,通过 Spring AI 的连接池优化,QPS 从 120 提升至 850。这个数字的意义不在于 Spring AI 本身有多快,而在于它让 AI 调用复用企业已有的连接池管理和熔断降级基础设施,而不是每个 AI 调用都创建新的 HTTP 连接。

LangChain4j:声明式接口与 Agent 的组合能力

LangChain4j 的核心定位是“一站式大模型应用开发工具箱”,覆盖从基础对话、记忆管理、文档解析、向量检索、RAG、工具调用到 Agent 编排的全链路能力。它的设计选择与 Spring AI 形成鲜明对比:不是把 AI 能力嵌入 Spring 的依赖注入体系,而是用 Java 接口和注解重新表达 AI 逻辑。

LangChain4j 的 Agent 定义方式极其简洁——一个带有 @Agent 注解的单方法接口:

代码语言:javascript
复制
public interface CandidateWorkflow {
    @Agent("根据个人履历和职位描述生成主简历,通过反馈循环定制直至达到合格分数")
    String processCandidate(
        @V("lifeStory") String userInfo,
        @V("jobDescription") String jobDescription);
}

框架自动生成实现,将接口方法与 LLM 调用、工具编排和状态管理绑定。这种声明式编程模型的工程价值在于:Agent 的意图被表达为接口契约,而非命令式的工作流代码。接口可以像普通 Java 接口一样被测试、mock 和组合。

LangChain4j 的 Agent 支持完全组合——小 Agent 可以捆绑成超级 Agent,子 Agent 可以分解任务,顺序、并行、循环和监督等工作流可以在任何层级混合:

代码语言:javascript
复制
CvGenerator cvGenerator = AgenticServices
    .agentBuilder(CvGenerator.class)
    .chatModel(model)
    .outputKey("cv")
    .build();

ScoredCvTailor scoredCvTailor = AgenticServices
    .agentBuilder(ScoredCvTailor.class)
    .chatModel(model)
    .outputKey("cv")
    .build();

这种组合性对应了游戏开发中的“实体-组件”模式:每个 Agent 是一个独立的、可复用的单元,其行为由注解和接口定义,编排由框架层负责。开发者不需要在 Agent 内部硬编码工作流逻辑,而是通过组合来构建复杂行为。

选型的真实判据

两者的选型不应该基于“谁的能力更强”这种模糊判断。一个更实际的判据是:Spring AI 追求的是集成效率,LangChain4j 追求的是场景能力。

如果你的项目已经是 Spring Boot 深度绑定,Spring AI 的 auto-configuration 和依赖注入集成会让接入成本降到最低。如果你需要复杂的 Agent 工作流编排、RAG 管道的细粒度控制,或者需要接入尽可能多的向量数据库和模型提供商,LangChain4j 的广度和灵活性更有优势。

截至 2026 年 7 月,spring-ai-bom 最新版本为 2.0.0,langchain4j-bom 最新版本为 1.17.2。两者的迭代速度都很快,选型时应该关注的是社区活跃度与自身技术栈的匹配度,而非版本号。

三、虚拟线程与同步抽象:一个未被充分讨论的工程张力

Java 21 引入的虚拟线程是 JVM AI 应用中最值得深入分析的并发原语。Agent 调用本质上是 I/O 密集型的——等待 LLM API 响应、等待向量数据库查询、等待工具执行。虚拟线程可以将这些阻塞调用转化为高并发的可调度任务,而不需要重构代码为响应式风格。

但这个优势在实践中被一个结构性的张力所削弱:主流 Java AI 框架的 API 设计仍然是同步阻塞的。 Spring AI 的 ChatClient.call() 是同步方法,LangChain4j 的 ChatModel.generate() 也是同步方法。这意味着每个 Agent 调用会占用一个虚拟线程直到 LLM 返回。

虚拟线程确实让“一个虚拟线程对应一个请求”的模型变得可行——承载一百万个虚拟线程的内存开销远小于一百万个平台线程。但如果框架的 API 本身不支持背压和流式语义,虚拟线程的优势就仅限于“用同步代码写高并发”,而非真正的异步编排。

这个张力的深层原因是 Java AI 框架在“对 Java 开发者友好”和“对系统资源友好”之间的取舍。Spring AI 选择提供同步 API 以降低学习曲线,但这意味着在高并发场景下,需要依赖虚拟线程的调度器来管理阻塞调用。LangChain4j 在流式场景中提供了响应式接口,但核心的 Agent 编排仍然以同步为主。

一个可行的实践模式是在虚拟线程中运行 Agent 调用,利用 StructuredTaskScope 管理并发子任务:

代码语言:javascript
复制
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
    var llmTask = scope.fork(() -> chatClient.call(prompt));
    var ragTask = scope.fork(() -> vectorStore.search(query));
    scope.join();

    String llmResponse = llmTask.get();
    List<Document> docs = ragTask.get();
    // 合并结果
}

StructuredTaskScope 是 Java 21 的预览特性,提供了一种结构化的并发模型:子任务的生命周期被父作用域管理,任何子任务失败会触发其他子任务的取消。这比手动管理 CompletableFuture 或 ExecutorService 更安全,也更符合 AI Agent 中“并行调用多个工具,任一失败则整体失败”的语义。

四、类型系统作为确定性桥梁

Java 在 AI 应用中最被低估的能力,不是并发模型,也不是框架生态,而是强类型系统。

LLM 的输出天然是非结构化的、概率性的——一段文本、一个 JSON 对象、一个函数调用参数列表。而企业系统要求确定性和契约性。一个“生成信贷审批摘要”的接口,如果返回类型是 String,下游系统无法验证其完整性;如果返回类型是一个有明确字段定义的 Java Record,任何字段的缺失或类型不匹配都会在编译期或运行时被立即捕获。

Spring AI 的 BeanOutputConverter 和 LangChain4j 的 @SystemMessage + 结构化输出解析器都提供了将 LLM 输出映射到 Java 类型的机制。但真正的工程价值不在于“能映射”,而在于映射失败时的行为是确定的。

以下代码展示了一个用 Java Record 约束 LLM 输出的模式:

代码语言:javascript
复制
public record CreditApprovalSummary(
    String applicantName,
    BigDecimal requestedAmount,
    ApprovalDecision decision,  // enum: APPROVED, REJECTED, PENDING
    List<String> riskFactors,
    String rationale
) {}

@Component
public class CreditSummaryService {

    private final ChatClient chatClient;

    public CreditApprovalSummary generateSummary(String applicationData) {
        return chatClient.prompt()
            .system("""
                你是一个信贷审批助手。根据申请人数据生成审批摘要。
                必须包含以下字段:applicantName, requestedAmount,
                decision (APPROVED/REJECTED/PENDING), riskFactors, rationale。
                只返回 JSON,不要返回其他内容。
                """)
            .user(applicationData)
            .call()
            .entity(CreditApprovalSummary.class);
    }
}

当 LLM 返回的 JSON 缺少 riskFactors 字段或 decision 值不在枚举范围内时,Spring AI 会抛出 ConversionException,而不是静默返回一个不完整的对象。这个行为在金融场景中是刚需:要么得到完整的、类型安全的审批摘要,要么得到一个明确的失败信号,不存在第三种状态。

Java 的 sealed interface 和模式匹配进一步强化了这种契约能力。一个多步骤的 Agent 工作流可以用 sealed interface 定义所有可能的结果类型,编译器会强制处理每一种情况:

代码语言:javascript
复制
public sealed interface AgentOutcome
    permits Success, RequiresHumanReview, ToolFailure {}

public record Success(AgentResult result) implements AgentOutcome {}
public record RequiresHumanReview(String reason, AgentState state)
    implements AgentOutcome {}
public record ToolFailure(String toolName, Throwable cause)
    implements AgentOutcome {}

// 编译器强制处理所有情况
String handle(AgentOutcome outcome) {
    return switch (outcome) {
        case Success s -> "完成: " + s.result();
        case RequiresHumanReview r -> "待审核: " + r.reason();
        case ToolFailure f -> "工具失败: " + f.toolName();
    };
}

这种模式的价值在于,它把 Agent 工作流中的“异常路径”从运行时的不确定性转化为编译期的确定性。在 Python 中,RequiresHumanReview 可能只是字典中的一个键,忘记处理也不会报错;在 Java 的 sealed interface 中,忘记处理一个 case 会导致编译失败。

五、生产级 RAG 的 Java 实现

RAG(Retrieval-Augmented Generation)是企业 AI 应用中最常见的模式。在 Java 生态中,LangChain4j 提供了最完整的 RAG 管道组件。但真正的工程挑战不在于“能搭起来”,而在于检索质量和生成质量的可观测与可调优。

一个被广泛忽视的问题是:RAG 系统的失败模式与纯 LLM 系统截然不同。纯 LLM 的失败是“幻觉”,RAG 的失败可能是“检索到了错误的文档”或“检索到了正确的文档但生成时忽略了它”。这两种失败需要不同的调试策略,但大多数 Java RAG 实现没有区分它们。

以下代码展示了一个带有检索质量评估的 RAG 服务:

代码语言:javascript
复制
@Service
public class RagService {

    private final EmbeddingStore<TextSegment> embeddingStore;
    private final EmbeddingModel embeddingModel;
    private final ChatModel chatModel;
    private final RetrievalQualityEvaluator evaluator;

    public RagResponse query(String question) {
        // 1. 检索
        Embedding queryEmbedding = embeddingModel.embed(question).content();
        List<EmbeddingMatch<TextSegment>> matches =
            embeddingStore.findRelevant(queryEmbedding, 5);

        // 2. 评估检索质量(关键步骤)
        var retrievalReport = evaluator.evaluate(question, matches);
        if (retrievalReport.isLowConfidence()) {
            return RagResponse.lowConfidence(retrievalReport,
                "检索到的文档与问题相关性不足,建议人工核实");
        }

        // 3. 生成
        String context = matches.stream()
            .map(m -> m.embedded().text())
            .collect(Collectors.joining("\n---\n"));

        String prompt = """
            基于以下参考资料回答问题。如果参考资料不包含答案,
            明确说明“参考资料中未找到相关信息”。
            参考资料:
            %s
            问题: %s
            """.formatted(context, question);

        String answer = chatModel.generate(prompt);

        // 4. 归因检查:答案是否引用了检索到的内容
        var attribution = evaluator.checkAttribution(answer, matches);

        return RagResponse.success(answer, retrievalReport, attribution);
    }
}

这段代码的核心设计决策是将检索质量的评估与生成的归因检查作为一等公民,而不是事后的可选步骤。evaluator.evaluate() 检查检索到的文档与问题的语义相关性——如果最高相似度分数低于阈值,系统返回“低置信度”响应而非强行生成。evaluator.checkAttribution() 检查生成的答案是否真正基于检索到的内容,而不是模型自身的知识。

这个模式对应了 Java AI 工程化中一个更广泛的原则:LLM 的调用不应该是一个黑盒。 每一个 LLM 调用的输入(检索到的上下文、系统提示词)和输出(答案、置信度、归因)都应该被记录、评估和可追溯。Spring AI 的 OpenTelemetry 集成让这种可观测性成为框架原生能力,而非需要额外搭建的管道。

六、边界与张力

Java AI 在 2026 年的工程实践中,有几个需要清醒认识的边界。

第一,GPU 编程的缺位。 JVM 生态至今没有标准的 GPU 编程模型。没有 SDK,没有编译器,没有针对加速器的代码生成。JNI/FFI 桥接是脆弱的。Project Babylon 正在探索代码反射在 ML 中的应用,TornadoVM 可以在 GPU 上达到 39 倍到 270 倍的加速,但这些都还是实验性的。对于需要在本地运行大模型推理的场景,Java 目前依赖 ONNX Runtime 和 DJL 的桥接,而非原生的 GPU 加速。

第二,Agent 编排的碎片化。 生态中有九种主要框架,三种协议标准。LangGraph4j 的有环图、Embabel 的 GOAP 规划、Koog 的协程协调、Google ADK 的 A2A 协议——每种框架都代表了一种对“Agent 应该如何工作”的不同假设。这些假设之间没有互操作性标准。选择一个框架,意味着接受它的编排模型,迁移到另一个框架的成本是显著的。

第三,guardrails 的成熟度。 LangChain4j 的 guardrails 仍然处于 beta 阶段,只有两个内置实现。对于需要严格输入输出过滤的企业场景——比如金融领域的合规审查——当前的 guardrails 能力不足以为生产系统提供充分的安全保障。

第四,同步抽象的并发天花板。 如前所述,主流框架的同步 API 设计与虚拟线程的高并发能力之间存在张力。在每秒数万次 Agent 调用的场景中,同步阻塞模型可能需要大量的虚拟线程和内存来维持,而响应式 API 的缺失限制了真正的背压管理。

结语:工程化载体的价值不在算法层

Java 在 AI 时代的角色,可以用一个精确的表述来定义:Java 是 AI 的工程化载体,而非模型语言。

模型层的创新发生在 PyTorch 生态和学术共同体中,Java 不需要也没有必要在那里竞争。Java AI 的全部价值在于那百分之十的代码——把概率性的模型输出通过强类型契约收敛为确定性接口,把 I/O 密集型的 Agent 调用通过虚拟线程转化为高并发的可调度任务,把安全与可观测性从“事后补救”上移为“架构前置约束”。

这个定位有一个重要的实践推论:评估 Java AI 框架时,不应该以“能不能做”为标准,而应该以“失败时的行为是否确定”为标准。 Spring AI 和 LangChain4j 都能调用 GPT-4,但当一个 Agent 的工具调用返回了格式错误的数据时,框架如何处理、如何重试、如何降级、如何记录——这些才是决定生产可用性的关键。

Eclipse 基金会的判断是准确的:企业 Java 已经为 AI 准备好了。问题不在于 Java 能否支持 AI,而在于为应用确定适当的 AI 自主级别,并定义其边界。这个边界,就是 Java 类型系统和工程纪律能够发挥最大价值的地方。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 引子:一个被混淆的定位
  • 一、JVM AI 生态的三层结构
  • 二、框架的架构选择:Spring AI 的分层抽象与 LangChain4j 的声明式接口
    • Spring AI:将模型差异隔离在适配器层
    • LangChain4j:声明式接口与 Agent 的组合能力
    • 选型的真实判据
  • 三、虚拟线程与同步抽象:一个未被充分讨论的工程张力
  • 四、类型系统作为确定性桥梁
  • 五、生产级 RAG 的 Java 实现
  • 六、边界与张力
  • 结语:工程化载体的价值不在算法层
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档