找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

5434

积分

0

好友

703

主题
发表于 1 小时前 | 查看: 3| 回复: 0

文章目标:不是告诉你“怎么把 LLM 调起来”,而是回答“Java 团队如何把 AI 系统真正跑进生产,并在高并发、可治理、可扩展的前提下长期演进”。

摘要

过去两年,Java AI 生态从“少数 SDK 试水”迅速进入“框架成形、工程能力分化”的阶段。很多团队在做技术选型时,习惯把 Spring AI、LangChain4j、Spring AI Alibaba、AgentScope-Java、Semantic Kernel 放在同一张表里横向比较,最后却发现项目上线后真正决定成败的,往往不是谁的 API 更优雅,而是:

  • 是否具备模型供应商解耦能力
  • 是否能承接多轮会话、RAG、Tool Calling、Workflow、Agent 等不同运行时模式
  • 是否能在高并发下控制连接、线程、Token 成本与限流
  • 是否支持审计、灰度、熔断、降级、回放、观测与问题定位
  • 是否能把“Prompt 工程”升级为“运行时工程”

这篇文章站在生产架构视角,对 Java 五大 AI 框架做一次完整分析。我们不止比较功能,更聚焦:

  1. 框架底层原理与抽象边界
  2. 单 Agent、Workflow、多 Agent 三类系统的架构差异
  3. 高并发生产场景下的治理能力建设
  4. 可直接落地的代码组织、配置策略与部署模式
  5. 从单体 AI 应用走向 AI 中台的演进路径

如果你希望拿这篇文章作为团队内部技术选型依据,或者作为 AI 平台建设的设计底稿,本文会比一般的“框架介绍文”更接近真实生产。

1. 为什么 Java AI 选型不能只看 Demo

1.1 真正困难的不是“接模型”,而是“管理模型”

传统 Java 中间件选型,通常围绕吞吐、延迟、一致性、可用性展开;AI 框架选型则多出一层极其关键的不确定性:模型本身不是稳定函数,而是概率系统。

这意味着同一段业务代码,即使没有变更,也可能因为以下因素出现显著漂移:

  • 模型版本升级导致输出风格变化
  • 上下文窗口变化导致召回片段丢失
  • Tool Schema 膨胀导致函数调用成功率下降
  • 上游供应商限流或抖动导致尾延迟放大
  • Prompt 微调导致缓存命中率、成本结构和准确率同时变化

所以,AI 框架不是简单 SDK,而是 AI Runtime 的一部分。团队真正需要的不是“更方便地调用模型”,而是“更稳定地运营模型能力”。

1.2 生产环境评估维度,至少要看八件事

对 Java AI 框架做选型时,建议不要先问“支持哪些模型”,而是先问这八个问题:

维度 核心问题 生产意义
抽象层次 是轻量 SDK、编排框架,还是 Agent Runtime 决定系统边界与后续演进成本
模型解耦 模型供应商切换是否低成本 防止被单一供应商绑定
状态管理 多轮会话、记忆、回放如何实现 决定复杂交互是否可控
Tool 调度 Tool 注册、选择、幂等、超时如何治理 决定系统是否能走向业务闭环
Workflow/Agent 是否支持 DAG、状态机、多 Agent 协同 决定能否承接复杂场景
并发模型 阻塞/非阻塞、线程池、连接池如何设计 决定高并发下的稳定性
可观测性 能否观测 Token、TTFT、TPM、Tool 调用链路 决定运维与成本治理能力
企业集成 是否易与 Spring、消息队列、缓存、配置中心集成 决定项目落地速度

1.3 五大框架不是替代关系,而是分层关系

很多文章把这五个框架当成“竞争产品”比较,这种比较不够准确。

更合理的理解是:

  • Spring AI:偏 Spring 生态接入层与基础抽象层
  • LangChain4j:偏链式编排与类型化 AI 服务层
  • Spring AI Alibaba:偏企业级工作流编排与云原生集成层
  • AgentScope-Java:偏多智能体运行时与协作层
  • Semantic Kernel:偏插件化语义编排与跨语言生态协同层

换句话说,它们有竞争,但并不完全处于同一层。真正成熟的生产系统里,常见形态不是“五选一”,而是“两层叠加”甚至“三层组合”。

例如:

  • Spring AI 负责统一模型接入,LangChain4j 负责类型化 AI Service
  • Spring AI Alibaba 负责 DAG 编排,底层仍通过统一模型网关访问推理服务
  • AgentScope-Java 负责多 Agent 运行时,而 Tool 执行、会话记忆、审计日志仍由业务基础设施承接

2. 先建立一个正确的分析框架:协议层、治理层、状态层

如果你希望这篇文章能指导真实架构决策,必须先接受一个前提:AI 系统的核心,不是 Prompt 本身,而是 Runtime。

我建议把生产级 Java AI 系统拆成三层来理解。

2.1 协议层:负责“如何与模型和工具交互”

协议层关注的是标准化输入输出,典型职责包括:

  • Prompt 结构化封装
  • Chat/Embedding/Rerank/Image 等模型接口抽象
  • Tool Calling 参数描述与结果回传
  • 流式输出协议
  • 多模型供应商适配

这一层的关键词是:统一接入可替换低耦合

Spring AI、LangChain4j 在这一层都很强,区别在于表达方式不同:

  • Spring AI 偏 Spring 风格,强调模板与 Bean 生态
  • LangChain4j 偏接口代理与组合式模块

2.2 治理层:负责“如何让 AI 能稳定上线”

治理层是很多 Demo 项目最缺的部分。它决定了 AI 从实验走向生产的能力边界。

治理层通常包括:

  • 限流:按租户、场景、模型、Token、QPS 维度限流
  • 熔断:供应商异常时快速失败或切换
  • 重试:只对幂等请求做退避重试
  • 降级:大模型失败时切小模型、切模板、切规则引擎
  • 审计:完整保留请求、响应、Prompt、Tool 轨迹
  • 灰度:按用户、租户、流量比例切换模型版本
  • 成本控制:预算、配额、账单归集、异常告警

AI 系统上线后,真正大量投入精力的往往都是治理层,而不是提示词本身。

2.3 状态层:负责“如何管理会话、记忆和执行现场”

状态层解决的是 AI 系统“为什么这次能答对、下次却答错”的根因。

它包含三类状态:

  1. 会话状态
    • 对话历史
    • 摘要记忆
    • 用户画像
    • 当前任务上下文
  2. 执行状态
    • Tool 调用轨迹
    • Workflow 节点结果
    • Agent 中间消息
    • 重试与回放位点
  3. 业务状态
    • 工单、订单、风控单、推荐任务等领域对象
    • AI 决策与业务决策的映射关系

如果状态层设计不好,系统会出现四类典型问题:

  • 对话越来越贵
  • Tool 越来越乱
  • 多 Agent 结果无法复现
  • 线上问题无法回放与归因

所以,从架构上讲,一个能进生产的 AI 框架,不一定要把状态层都内建进去,但必须允许你优雅地接入自己的状态体系。

2.4 一张真正适合生产的分层架构图

┌──────────────────────────────────────────────────────────────┐
│                       Access Layer                           │
│ REST / WebSocket / SSE / gRPC / MQ Consumer / Batch Trigger │
└──────────────────────────────────────────────────────────────┘
                              │
┌──────────────────────────────────────────────────────────────┐
│                    Orchestration Layer                       │
│ Intent Router / Prompt Builder / Workflow / Agent Runtime   │
└──────────────────────────────────────────────────────────────┘
                              │
┌──────────────────────────────────────────────────────────────┐
│                      Governance Layer                        │
│ RateLimit / Retry / CircuitBreaker / Audit / Cost / Gray    │
└──────────────────────────────────────────────────────────────┘
                              │
┌──────────────────────────────────────────────────────────────┐
│                       [协议层](https://yunpan.plus/f/14-1)                          │
│ ChatModel / EmbeddingModel / Tool Adapter / Stream Adapter  │
└──────────────────────────────────────────────────────────────┘
                              │
┌──────────────────────────────────────────────────────────────┐
│                        State Layer                           │
│ Redis / DB / Vector DB / Event Store / Checkpoint / Memory  │
└──────────────────────────────────────────────────────────────┘
                              │
┌──────────────────────────────────────────────────────────────┐
│                      Foundation Layer                        │
│ Kafka / Redis / MySQL / PGVector / Milvus / Nacos / OTel    │
└──────────────────────────────────────────────────────────────┘

3. 五大框架深度拆解:能力、边界与适用场景

这一节不是简单列功能,而是从“抽象模型 + 运行方式 + 工程边界”三个角度拆解。

3.1 Spring AI:最适合 Java 团队的统一模型接入层

3.1.1 它的价值不在“能调用模型”,而在“把模型调用变成 Spring 资源”

Spring AI 最大的价值,是把 AI 能力纳入 Spring 体系,使模型调用可以像数据源、消息队列、HTTP 客户端一样被统一管理。

典型收益包括:

  • 统一配置与装配
  • 与 Spring Boot 自动配置集成
  • 易接入 Micrometer、Resilience4j、Spring Retry
  • 易与 WebFlux、消息驱动消费、异步执行框架整合

如果你的系统本来就是标准 Spring Boot 微服务,Spring AI 往往是成本最低的起点。

3.1.2 生产视角下的优点

  • 适合做统一模型接入网关
  • 适合沉淀标准 Prompt 构建、流式响应、重试与熔断
  • 适合做“协议层 + 基础治理层”
  • 与现有 Spring 技术栈协同成本最低

3.1.3 它的短板

  • 如果你要构建复杂链式编排,纯 Spring AI 的表达会逐渐偏底层
  • 多 Agent、复杂 DAG、状态机式编排,不是它的最强项
  • 需要团队自己补足一部分运行时治理与状态管理

3.1.4 典型适用场景

  • 已有 Spring Boot 系统接入 AI
  • 内部统一 AI Gateway
  • 单轮/多轮对话服务
  • RAG 服务基础接入层
  • 供应商适配与模型路由

3.2 LangChain4j:最适合复杂业务编排的模块化框架

3.2.1 它真正强的地方是“类型化 AI Service”

LangChain4j 的核心优势,不只是模块多,而是它提供了非常适合 Java 团队的类型化编程体验。

通过接口代理,开发者可以把 AI 服务定义成强类型接口:

public interface CustomerCopilot {

    @SystemMessage("""
        你是电商客服助手。
        回答前先判断是否需要查询订单、物流或售后数据。
        如无法确认,不允许编造。
        """)
    String answer(@UserMessage String question);
}

这类写法对 Java 团队非常友好,因为它更接近“领域服务接口”,而不是“把一堆字符串拼成 Prompt 再发送”。

3.2.2 LangChain4j 的强项

  • ChatMemory、Tool、RAG、Retriever、Document Parser 等模块较完整
  • 适合构建复杂 AI 业务流程
  • 类型安全、接口语义清晰,适合多人协作
  • 对自建模型、本地模型、开源推理服务适配灵活

3.2.3 需要注意的点

  • 复杂场景下 Tool 数量容易膨胀,需要自行做 Tool 路由与分类
  • 记忆与状态持久化要结合业务基础设施设计
  • 如果没有治理层,项目很容易长成“功能很多,但线上不稳”的形态

3.2.4 典型适用场景

  • 智能客服、营销助手、运营 Copilot
  • 有多 Tool、多知识源、多轮会话的 AI 应用
  • 要快速构建业务可读性高的 AI Service 层

3.3 Spring AI Alibaba:面向企业编排落地的工作流框架

3.3.1 它的关键价值是把“AI 调用”升级为“工作流执行”

Spring AI Alibaba 更适合企业内复杂场景:不是单次问答,而是多节点处理。

例如一个商品上架审核流程,可能包含:

  1. 标题风险识别
  2. 类目判断
  3. 图片合规检测
  4. 规则引擎复核
  5. 人审兜底

这类场景本质上不是 Chat,而是 Workflow。Spring AI Alibaba 的价值就在于用更清晰的 DAG/节点方式描述这类流程。

3.3.2 它适合什么团队

  • 阿里云生态或国内企业级中后台团队
  • 需要 Nacos、消息系统、规则引擎、审计流程配合
  • 需要明确节点边界、失败重试、超时回滚
  • 需要把 AI 融入已有企业工作流

3.3.3 典型短板

  • 如果业务本身非常轻量,用它会略重
  • 团队需要具备工作流思维,而不只是 Prompt 思维
  • 底层模型治理与状态体系,仍建议自建统一标准

3.4 AgentScope-Java:多智能体系统更需要 Runtime,而不是 Prompt

3.4.1 多智能体不是“多写几个 Prompt”

多 Agent 最大的挑战,不是“让几个 Agent 轮流说话”,而是:

  • 如何管理 Agent 生命周期
  • 如何隔离 Agent 线程与资源
  • 如何在消息往返中持久化中间状态
  • 如何避免循环协作、重复调用与上下文膨胀
  • 如何做超时、补偿、回放和审计

AgentScope-Java 的价值,在于它开始把这些问题提升到运行时层面。

3.4.2 它更接近什么

如果说 LangChain4j 更像“AI 业务开发框架”,AgentScope-Java 更接近“多智能体运行时平台”。

它更适合:

  • 多角色协作系统
  • 复杂任务拆解
  • 事件驱动决策
  • 跨步骤状态维持
  • 需要 Agent 之间消息通信的场景

3.4.3 生产上最重要的两个问题

第一,Agent 不能直接等同于线程。
第二,Agent 协作不能脱离业务状态机。

否则最终会得到一个“会聊天,但不可运营”的系统。

3.5 Semantic Kernel:插件式语义编排与跨生态协同

3.5.1 为什么它在 Java 生态里仍值得关注

Semantic Kernel 在 Java 团队中的直接使用率未必最高,但它代表了一类非常重要的设计思想:把 Prompt、Function、Plugin、Memory 组织成统一内核。

这种思路适合:

  • 跨语言团队
  • Azure / Microsoft 技术体系
  • 强调插件式语义能力装配
  • 需要和现有 .NET、Copilot、企业知识平台协同

3.5.2 它更像“内核容器”

它的设计方式不是典型 Spring 风格,而更像一个独立的 AI Kernel 容器。对纯 Java 团队来说,上手不如 Spring AI 自然;但如果你的组织本来就是跨语言架构,这种插件式抽象会有价值。

3.6 一张真正有用的对比表

框架 更适合的位置 强项 短板 最佳场景
Spring AI 协议层 / 接入层 Spring 原生集成、统一模型接入 复杂编排偏底层 统一 AI 接入、快速落地
LangChain4j AI Service 层 / 编排层 类型化接口、模块丰富、业务表达力强 Tool 与状态需自行治理 智能客服、Copilot、RAG
Spring AI Alibaba Workflow 编排层 企业流程编排、节点治理 轻场景偏重 审核、风控、审批、内容流程
AgentScope-Java Agent Runtime 层 多智能体协作、运行时思维 对工程能力要求高 复杂任务协同、策略系统
Semantic Kernel Plugin / Kernel 层 插件化语义编排、跨生态协同 Java 团队心智迁移成本高 Azure / 跨语言平台

3.7 一句结论先给出来

如果你是典型 Java 企业团队,大多数情况下可以这么选:

  • 单体 AI 接入或统一模型网关:优先 Spring AI
  • 复杂业务型 AI 应用:优先 LangChain4j
  • 企业流程型 AI 编排:优先 Spring AI Alibaba
  • 多智能体系统:优先 AgentScope-Java
  • 微软生态强绑定:考虑 Semantic Kernel

而真正成熟的落地方式,通常是:

  • Spring AI 统一模型协议与治理
  • LangChain4jSpring AI Alibaba 承接业务编排
  • 在复杂协作系统中引入 AgentScope-Java

4. 架构设计:从单次调用到生产级 AI Runtime

这一节是全文核心。框架只是工具,架构才决定系统上限。

4.1 不要把 AI 服务直接嵌进业务 Controller

很多项目第一版是这样写的:

@PostMapping("/chat")
public String chat(@RequestBody ChatRequest request) {
    return chatClient.prompt()
        .user(request.message())
        .call()
        .content();
}

这在 Demo 阶段没问题,但一旦进入生产,会立刻暴露出以下问题:

  • 无法统一做限流和熔断
  • 无法记录 Token 成本
  • 无法按租户做模型路由
  • 无法实现对话状态持久化
  • 无法区分业务超时与模型超时
  • 无法将 Tool 调用纳入审计链路

所以,生产系统一定要把“模型调用”包进“运行时服务”。

4.2 推荐的核心组件划分

Client
  -> API Gateway
  -> AI Access Service
     -> Intent Router
     -> Prompt Builder
     -> Model Router
     -> Tool Dispatcher
     -> Memory Manager
     -> Policy Engine
     -> Audit Logger
     -> Cost Meter
     -> LLM Adapter
  -> State Store / Vector Store / MQ / Config Center

每个组件职责如下:

组件 关键职责
AI Access Service 统一承接所有 AI 请求
Intent Router 判断使用问答、检索、工具还是工作流
Prompt Builder 合并系统提示词、用户输入、业务上下文
Model Router 按场景路由模型与参数
Tool Dispatcher 工具注册、权限校验、超时控制、幂等控制
Memory Manager 维护会话历史、摘要、长期记忆
Policy Engine 限流、熔断、预算、合规策略
Audit Logger 落库请求、响应、Prompt、Tool 链路
Cost Meter 统计输入输出 Token、单位成本、租户账单

4.3 统一请求模型设计

无论底层用哪个框架,建议对外暴露统一请求对象。

public record AiCommand(
    String requestId,
    String tenantId,
    String sceneCode,
    String sessionId,
    String userId,
    String message,
    Map<String, Object> attributes,
    List<String> allowedTools,
    Duration timeout,
    boolean streaming
) {
}

这样做的价值很大:

  • 对上层业务提供稳定契约
  • 方便 A/B Test、审计、回放
  • 方便未来切换底层框架
  • 方便接入 MQ、批任务和异步任务

4.4 统一响应模型设计

public record AiResult(
    String requestId,
    String model,
    String finishReason,
    String content,
    List<ToolExecutionRecord> toolExecutions,
    TokenUsage tokenUsage,
    Duration latency,
    Map<String, Object> metadata
) {
}

public record TokenUsage(
    int promptTokens,
    int completionTokens,
    int totalTokens
) {
}

强烈建议从第一天开始记录 modelfinishReasontokenUsagelatency
因为当线上答非所问、成本飙升或者供应商抖动时,这些字段会是你排障的第一现场。

4.5 模型路由,不要写死在业务里

生产场景下,模型路由通常至少要支持以下维度:

  • 按场景路由:客服、风控、营销、知识问答
  • 按租户路由:不同租户可绑定不同预算策略
  • 按成本路由:小模型优先,大模型兜底
  • 按质量路由:高价值请求走高质量模型
  • 按可用性路由:供应商异常时自动切换

一个简单但实用的策略接口如下:

public interface ModelRoutingPolicy {

    ModelRoute select(AiCommand command, RuntimeContext context);
}

public record ModelRoute(
    String provider,
    String model,
    double temperature,
    int maxTokens
) {
}

这类路由策略最好配置化,而不是写在代码里。因为上线后,模型切换通常是运维策略,而不只是研发行为。

5. 高并发工程化落地:客服系统实战方案

下面给出一个更接近生产的实战方案。场景设定如下:

  • 电商客服系统
  • 峰值请求 5000 到 8000 QPS
  • 同时支持 FAQ、订单查询、物流查询、售后咨询
  • 低价值请求优先走小模型
  • Tool 调用必须纳入权限控制与审计
  • 对话历史保留在 Redis,摘要落库

5.1 技术组合建议

  • Spring AI:统一模型接入
  • LangChain4j:定义客服 Copilot 接口与 Tool 协调
  • Redis:会话状态、结果缓存、限流计数
  • Kafka:异步审计与成本日志
  • Micrometer + OpenTelemetry:链路观测
  • WebFlux:高并发非阻塞接口层

5.2 生产级模块结构建议

com.example.ai
├── api
│   ├── ChatController
│   └── StreamController
├── application
│   ├── ChatApplicationService
│   ├── ModelRoutingService
│   ├── ToolDispatchService
│   └── AuditApplicationService
├── domain
│   ├── command
│   ├── result
│   ├── policy
│   └── memory
├── infrastructure
│   ├── model
│   ├── redis
│   ├── kafka
│   ├── persistence
│   └── metrics
└── config

这个目录结构的重点是:
不要把 AI 代码全部塞进 service 包里,否则后续一旦加入模型路由、工具权限、会话摘要、成本审计,模块会快速失控。

5.3 配置中心里的模型路由策略

ai:
  scenes:
    customer-service:
      primary-model: qwen-plus
      fallback-model: qwen-turbo
      max-input-tokens: 6000
      max-output-tokens: 800
      enabled-tools:
        - order_query
        - logistics_query
        - refund_policy
    vip-complaint:
      primary-model: gpt-4-class
      fallback-model: qwen-plus
      max-input-tokens: 8000
      max-output-tokens: 1200
      enabled-tools:
        - order_query
        - logistics_query
        - refund_policy
        - workorder_create

这种做法的价值在于:场景策略可动态变更,不必每次改模型都重新发版。

5.4 非阻塞接口层实现

@RestController
@RequestMapping("/api/ai/chat")
public class ChatController {

    private final ChatApplicationService chatApplicationService;

    public ChatController(ChatApplicationService chatApplicationService) {
        this.chatApplicationService = chatApplicationService;
    }

    @PostMapping
    public Mono<ResponseEntity<AiResult>> chat(@RequestBody ChatRequest request) {
        AiCommand command = new AiCommand(
            request.requestId(),
            request.tenantId(),
            request.sceneCode(),
            request.sessionId(),
            request.userId(),
            request.message(),
            request.attributes(),
            request.allowedTools(),
            Duration.ofSeconds(8),
            false
        );

        return chatApplicationService.execute(command)
            .timeout(command.timeout())
            .map(ResponseEntity::ok)
            .onErrorResume(TimeoutException.class, ex ->
                Mono.just(ResponseEntity.status(504).body(AiResultFactory.timeout(command.requestId()))))
            .onErrorResume(ModelDegradedException.class, ex ->
                Mono.just(ResponseEntity.ok(AiResultFactory.degraded(command.requestId(), ex))))
            .onErrorResume(ex ->
                Mono.just(ResponseEntity.internalServerError().body(AiResultFactory.failed(command.requestId(), ex))));
    }
}

5.5 应用服务层:把治理逻辑包进去

@Service
public class ChatApplicationService {

    private final ModelRoutingService modelRoutingService;
    private final MemoryService memoryService;
    private final ToolDispatchService toolDispatchService;
    private final AiExecutionEngine aiExecutionEngine;
    private final AuditApplicationService auditApplicationService;
    private final CostMeterService costMeterService;

    public Mono<AiResult> execute(AiCommand command) {
        RuntimeContext context = RuntimeContext.init(command);

        return memoryService.load(command.sessionId())
            .defaultIfEmpty(SessionMemory.empty(command.sessionId()))
            .flatMap(memory -> modelRoutingService.route(command, memory)
                .flatMap(route -> toolDispatchService.resolve(command, route)
                    .flatMap(toolContext -> aiExecutionEngine.execute(command, route, memory, toolContext))))
            .flatMap(result -> memoryService.save(command.sessionId(), result)
                .then(auditApplicationService.record(command, result))
                .then(costMeterService.record(command, result))
                .thenReturn(result));
    }
}

这段代码的重点不是“能跑”,而是体现一个生产级分工:

  • 路由和执行分离
  • 记忆加载与写回分离
  • Tool 解析前置
  • 审计、成本统计异步化

5.6 Tool 调度,不要把所有 Tool 一次性全挂上去

很多团队在做 Tool Calling 时,喜欢把几十个 Tool 一次性注册给模型,这在生产上通常会带来三个问题:

  • Token 被 Tool Schema 吃掉
  • 模型选错 Tool 的概率上升
  • 输出不稳定,排查困难

正确做法是两级路由:

  1. 先做意图分类
  2. 再按分类挂载少量 Tool
@Service
public class ToolDispatchService {

    private final IntentClassifier intentClassifier;
    private final ToolRegistry toolRegistry;

    public Mono<ToolContext> resolve(AiCommand command, ModelRoute route) {
        return intentClassifier.classify(command.message(), command.sceneCode())
            .map(intent -> {
                List<RegisteredTool> selected = toolRegistry.findByIntent(intent).stream()
                    .filter(tool -> command.allowedTools().isEmpty() || command.allowedTools().contains(tool.code()))
                    .limit(6)
                    .toList();
                return new ToolContext(intent, selected);
            });
    }
}

limit(6) 不一定是固定值,但“严格控制单次绑定 Tool 数量”是经验性很强的生产原则。

5.7 会话记忆:不要只存对话历史,要做摘要分层

会话状态如果只是无限追加,很快会出现:

  • Prompt 越来越长
  • 成本越来越高
  • 模型注意力越来越差

建议把记忆拆成三层:

层级 存什么 存储位置
短期记忆 最近 N 轮消息 Redis
摘要记忆 历史对话压缩摘要 MySQL / Redis
长期记忆 用户画像、偏好、黑白名单、业务事实 DB / 向量库

一个简单实现如下:

public interface MemoryService {

    Mono<SessionMemory> load(String sessionId);

    Mono<Void> save(String sessionId, AiResult result);
}

public record SessionMemory(
    String sessionId,
    List<ChatMessage> recentMessages,
    String summary,
    Map<String, Object> facts
) {
    public static SessionMemory empty(String sessionId) {
        return new SessionMemory(sessionId, List.of(), "", Map.of());
    }
}

5.8 结果缓存与语义缓存建议

对于高并发问答场景,缓存能直接决定成本结构。

建议同时做两类缓存:

  • 精确缓存
    • Key:tenantId + sceneCode + normalizedQuestion
    • 适合 FAQ、规则问答、标准化场景
  • 语义缓存
    • 对用户问题做 embedding
    • 近邻召回相似问题答案
    • 相似度达到阈值才命中

但要注意:
语义缓存不能脱离租户与业务上下文,否则极易造成“命中错误但表面看起来很像”的隐性事故。

6. 多智能体与工作流:风控编排实战方案

客服场景适合单 AI Service + Tool;风控、审核、审批这类系统,则更适合 Workflow 或多 Agent。

6.1 场景定义

假设我们要做一个交易风控系统,单次决策由以下能力共同完成:

  • 用户行为分析 Agent
  • 设备风险识别 Agent
  • 规则引擎节点
  • LLM 解释节点
  • 人审兜底节点

这个系统的关键不是“谁先说一句话”,而是“谁负责决策、谁负责证据、谁负责状态”。

6.2 为什么这类场景不能只用对话式框架

风控系统有三个强约束:

  • 必须可回放
  • 必须可解释
  • 必须可审计

因此,系统不能只保留最终结论,必须保留:

  • 每个节点输入输出
  • 每个 Agent 的中间判断
  • 规则命中明细
  • Tool 调用轨迹
  • 决策版本号

这时,Workflow 和 Agent Runtime 的价值就显现出来了。

6.3 一个更稳妥的设计原则

在高风险业务里,不建议让 LLM 直接输出“最终裁决”,而建议采用:

  1. 规则引擎给出基线结论
  2. AI 负责补充解释或识别灰区
  3. 最终由策略聚合器统一裁决

这样做的好处是:

  • 保留确定性底座
  • 降低大模型幻觉直接影响业务决策的概率
  • 方便合规审计

6.4 Spring AI Alibaba 风格的工作流节点示例

public interface WorkflowNode {

    String nodeCode();

    Mono<NodeResult> execute(WorkflowContext context);
}

public record WorkflowContext(
    String flowId,
    String requestId,
    Map<String, Object> attributes
) {
}

public record NodeResult(
    String nodeCode,
    boolean success,
    Map<String, Object> outputs
) {
}

风控评分节点:

@Component
public class DeviceRiskNode implements WorkflowNode {

    private final DeviceRiskService deviceRiskService;

    @Override
    public String nodeCode() {
        return "device-risk";
    }

    @Override
    public Mono<NodeResult> execute(WorkflowContext context) {
        return deviceRiskService.score(context.attributes())
            .map(score -> new NodeResult(
                nodeCode(),
                true,
                Map.of("deviceRiskScore", score)
            ));
    }
}

LLM 解释节点:

@Component
public class RiskExplainNode implements WorkflowNode {

    private final ChatRuntimeService chatRuntimeService;

    @Override
    public String nodeCode() {
        return "risk-explain";
    }

    @Override
    public Mono<NodeResult> execute(WorkflowContext context) {
        String prompt = """
            你是风控解释助手。
            请基于以下事实给出风险解释,不允许杜撰未提供的证据:
            %s
            """.formatted(context.attributes());

        AiCommand command = new AiCommand(
            context.requestId(),
            "risk-tenant",
            "risk-explain",
            context.flowId(),
            "system",
            prompt,
            context.attributes(),
            List.of(),
            Duration.ofSeconds(4),
            false
        );

        return chatRuntimeService.execute(command)
            .map(result -> new NodeResult(
                nodeCode(),
                true,
                Map.of("riskExplanation", result.content())
            ));
    }
}

6.5 多 Agent 场景下最重要的是消息协议

多 Agent 系统最容易忽略的一件事,是消息结构本身。

建议定义统一消息对象:

public record AgentEnvelope(
    String traceId,
    String flowId,
    String fromAgent,
    String toAgent,
    String messageType,
    Map<String, Object> payload,
    Instant createdAt
) {
}

原因很现实:

  • 没有统一消息体,就无法做回放
  • 没有 traceId,就无法做链路关联
  • 没有 messageType,就无法做稳定路由
  • 没有 payload 标准化,就无法演进跨进程通信

6.6 多 Agent 协作里的“控制面”和“执行面”要分离

这是很多系统后期崩掉的根因。

建议这样拆:

  • 控制面
    • 任务编排
    • Agent 注册
    • 路由策略
    • 权限配置
    • 灰度与开关
  • 执行面
    • Agent 实例执行
    • Tool 调用
    • 模型访问
    • 状态落盘

这样做有两个巨大收益:

  • 控制策略可动态调整,不影响执行逻辑
  • 执行面可水平扩容,控制面保持轻量

7. 生产治理:限流、熔断、观测、审计与成本控制

大部分 AI 项目,真正到了上线阶段,80% 的工作都在这一节。

7.1 限流不能只看 QPS,要看 Token

传统接口限流通常只按请求数,但 AI 场景必须同时关心:

  • 请求数
  • 输入 Token
  • 输出 Token
  • 模型并发
  • 流式连接数

因为一次“超长上下文 + 大输出”的请求,资源占用远高于十次短请求。

建议至少做三层限流:

  1. API 入口限流
  2. 模型调用限流
  3. Token 配额限流

7.2 一个实用的分布式 Token 配额设计

public interface TokenBudgetService {

    Mono<Boolean> tryAcquire(String tenantId, String sceneCode, int estimatedTokens);

    Mono<Void> refund(String tenantId, String sceneCode, int estimatedTokens, int actualTokens);
}

实现建议:

  • Redis 做日配额、小时配额计数
  • Kafka 异步归集实际账单
  • 数据库保存租户维度月度成本
  • 对超预算租户直接降级到小模型或模板回复

7.3 熔断与降级策略必须按场景设计

AI 场景下,不能只做技术层降级,还要做业务层降级。

例如客服场景:

  • 大模型不可用 -> 切小模型
  • 小模型仍不可用 -> 切 FAQ 检索
  • FAQ 检索失败 -> 切人工兜底

例如风控场景:

  • AI 解释失败 -> 只返回规则结果
  • 风险评分超时 -> 触发人工审核

一个简化的降级策略接口:

public interface DegradePolicy {

    Mono<AiResult> fallback(AiCommand command, Throwable throwable);
}

7.4 线程池隔离:不要让 LLM 超时拖垮业务线程

如果你的系统同时承接数据库、缓存、远程服务、模型服务,线程池隔离是必须的。

建议至少分成:

  • API 请求线程池
  • Tool 调用线程池
  • 模型调用线程池
  • 审计异步线程池
  • Workflow/Agent 执行线程池

如果全部复用同一套线程池,一旦模型供应商抖动,业务线程就会快速耗尽。

7.5 审计日志必须记录什么

生产环境里,AI 日志不是简单 requestresponse

建议至少记录:

  • requestId / traceId / sessionId
  • 租户、场景、用户
  • 使用模型与参数
  • 系统提示词版本
  • 输入摘要
  • 输出摘要
  • Tool 调用序列
  • Token 消耗
  • 延迟
  • 降级信息
  • 安全拦截结果

注意:原始输入输出是否全量留存,要结合法务、隐私与数据治理要求判断。

7.6 可观测性指标建议

AI 服务至少要监控以下指标:

指标 说明
QPS 接口吞吐
P50/P95/P99 Latency 延迟分位数
TTFT 首字节输出时间
TPM 每分钟 Token 消耗
Tool Success Rate Tool 调用成功率
Model Error Rate 模型错误率
Fallback Rate 降级比例
Cache Hit Rate 缓存命中率
Session Summary Count 会话摘要次数
Cost Per Tenant 租户成本

Micrometer 指标示例:

@Component
public class AiMetricsRecorder {

    private final MeterRegistry meterRegistry;

    public void record(AiCommand command, AiResult result) {
        Tags tags = Tags.of(
            "scene", command.sceneCode(),
            "tenant", command.tenantId(),
            "model", result.model()
        );

        meterRegistry.counter("ai.request.total", tags).increment();
        meterRegistry.timer("ai.request.latency", tags).record(result.latency());
        meterRegistry.summary("ai.token.total", tags).record(result.tokenUsage().totalTokens());
    }
}

8. Kubernetes 部署与弹性扩缩容设计

AI 服务部署到 Kubernetes 后,很多团队以为 HPA 一开就行,实际上这只是开始。

8.1 AI 服务扩容不能只看 CPU

普通 Web 服务扩容常看 CPU、内存;AI 服务建议至少看:

  • CPU
  • 内存
  • 活跃请求数
  • 正在流式输出的连接数
  • 每秒 Token 吞吐
  • 下游模型供应商限额利用率

因为有些 AI 服务 CPU 不高,但连接被长时间占用,仍会造成整体吞吐下降。

8.2 一个更实用的 Deployment 示例

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ai-access-service
spec:
  replicas: 4
  selector:
    matchLabels:
      app: ai-access-service
  template:
    metadata:
      labels:
        app: ai-access-service
    spec:
      containers:
        - name: app
          image: registry.example.com/ai-access-service:1.0.0
          ports:
            - containerPort: 8080
          env:
            - name: JAVA_OPTS
              value: "-XX:MaxRAMPercentage=70 -XX:+UseG1GC"
          resources:
            requests:
              cpu: "1"
              memory: "2Gi"
            limits:
              cpu: "2"
              memory: "4Gi"
          readinessProbe:
            httpGet:
              path: /actuator/health/readiness
              port: 8080
            initialDelaySeconds: 20
            periodSeconds: 10
          livenessProbe:
            httpGet:
              path: /actuator/health/liveness
              port: 8080
            initialDelaySeconds: 30
            periodSeconds: 15
          startupProbe:
            httpGet:
              path: /actuator/health
              port: 8080
            failureThreshold: 30
            periodSeconds: 10

8.3 HPA 建议指标

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: ai-access-service
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: ai-access-service
  minReplicas: 4
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 65
    - type: Pods
      pods:
        metric:
          name: ai_active_requests
        target:
          type: AverageValue
          averageValue: "80"

推荐把自定义指标 ai_active_requestsstreaming_connections 暴露出来,再结合业务实际做扩容。

8.4 PDB 与优雅下线

AI 服务尤其要重视优雅下线,因为流式输出中的连接断掉,用户体验会非常差。

建议:

  • 设置 preStop 钩子
  • 关闭新流量接入
  • 等待存量流式请求完成
  • 将会话摘要或执行状态先落盘

8.5 Gateway 限流与统一出口

如果系统访问多个模型供应商,建议引入统一 AI Gateway 或统一出口层,承接:

  • AK/SK 或 Token 隐藏
  • 限流与熔断
  • 供应商切换
  • 请求审计
  • 统一计费统计

这样上层业务服务不用直接感知供应商差异,后续切换和治理会轻很多。

9. 典型生产问题与解决策略

这一节结合真实工程经验,总结最常见的坑。

9.1 问题一:上下文越来越长,成本越来越高,质量反而下降

根因

  • 会话历史无限累加
  • Tool 返回原始大对象直接进上下文
  • 检索召回结果未压缩

解法

  • 最近消息窗口 + 摘要记忆分层
  • Tool 结果转结构化摘要,不回填原始大 JSON
  • 检索结果先重排,再压缩成 evidence block

一个简单的 Tool 结果压缩器:

public class ToolResultCompressor {

    public String compressOrderPayload(OrderPayload payload) {
        return """
            订单号: %s
            状态: %s
            支付时间: %s
            物流状态: %s
            售后状态: %s
            """.formatted(
            payload.orderNo(),
            payload.status(),
            payload.payTime(),
            payload.logisticsStatus(),
            payload.afterSaleStatus()
        );
    }
}

9.2 问题二:Tool 太多,模型频繁选错

根因

  • 没有做意图分层
  • Tool Schema 描述过长
  • Tool 命名不清晰

解法

  • 先分类,再挂 Tool
  • 同类 Tool 控制在有限数量
  • Tool 入参只保留必要字段
  • 对关键 Tool 增加权限与前置校验

9.3 问题三:模型供应商偶发抖动,引发线程堆积

根因

  • 阻塞式调用过多
  • 超时过长
  • 重试策略过激
  • 没有隔离线程池

解法

  • API 层尽量非阻塞
  • 设置分层超时:连接超时、读超时、业务超时
  • 只对可重试错误重试
  • 模型调用线程池隔离
  • 配置供应商级熔断器

9.4 问题四:多 Agent 协作结果不可回放

根因

  • 消息无统一 Envelope
  • 中间状态没落盘
  • 没有 traceId 与 flowId

解法

  • 所有 Agent 消息统一协议
  • 关键节点结果持久化
  • 重要流程采用事件存储或检查点机制

9.5 问题五:账单暴涨,但不知道花在哪

根因

  • 没有按租户、场景、模型统计
  • 没有输入输出 Token 细分
  • 流式请求没有正确计量

解法

  • 每次调用记录 promptTokens、completionTokens、totalTokens
  • 日维度、小时维度聚合
  • 建立租户预算告警与异常波动告警
  • 对低价值高成本场景做专项治理

10. 选型决策矩阵与演进建议

10.1 选型决策矩阵

你的目标 推荐框架组合 原因
在现有 Spring Boot 系统中快速接入 AI Spring AI 接入成本最低,最容易纳入原有治理体系
构建复杂客服、助手、Copilot Spring AI + LangChain4j 一个做统一接入,一个做业务编排
做审核、审批、风控、上架流程 Spring AI Alibaba 更适合节点化、流程化执行
做复杂任务拆解和多角色协作 Spring AI + AgentScope-Java 统一模型治理 + 多 Agent Runtime
微软/Azure 生态强绑定 Semantic Kernel 插件化和跨生态协同能力更强
自建大模型网关或 AI 中台 Spring AI 为底座,再叠加 LangChain4j / Workflow / Agent Runtime 分层清晰、可持续演进

10.2 不同团队成熟度下的推荐路线

阶段一:业务试点期

目标:

  • 快速接入
  • 小范围验证价值
  • 先把链路跑通

建议:

  • 用 Spring AI 做统一接入
  • 对话与 FAQ 场景优先
  • 从第一天开始保留 Token、延迟、模型与审计数据

阶段二:业务扩张期

目标:

  • 多场景复用
  • 控制成本
  • 稳定高并发

建议:

  • 引入 LangChain4j 的类型化服务
  • 建立模型路由、Tool 路由、记忆分层
  • 补齐限流、熔断、审计、缓存与摘要机制

阶段三:平台化阶段

目标:

  • 建 AI Gateway / AI 中台
  • 统一治理多场景多模型
  • 支撑工作流与 Agent 体系

建议:

  • 协议层统一收口
  • 路由和治理策略配置化
  • Workflow / Agent Runtime 独立成平台能力
  • 建立完整可观测体系与成本治理体系

10.3 架构师最终建议

如果只允许我给一个核心建议,那就是:

Java AI 项目要先建设 Runtime,再追求 Prompt;先建设治理能力,再追求能力堆叠。

进一步说,真正成熟的生产级 AI 系统,应该具备以下特征:

  • 模型可替换,而不是绑定某一家供应商
  • Tool 可治理,而不是无限堆叠
  • 会话可压缩,而不是上下文无限增长
  • 流程可回放,而不是只看最终结果
  • 成本可量化,而不是月底看账单惊讶
  • 策略可灰度,而不是所有用户同时冒险

当你把这些能力建起来时,框架才真正变成“加速器”;否则,框架只会把 Demo 写得更漂亮。

总结

最后对五大框架给出一句足够务实的判断:

  • Spring AI 适合作为 Java 团队 AI 接入与治理底座
  • LangChain4j 适合作为复杂业务型 AI 服务的主要开发框架
  • Spring AI Alibaba 适合作为企业流程型 AI 编排引擎
  • AgentScope-Java 适合作为多智能体系统运行时
  • Semantic Kernel 更适合插件化、跨语言和微软生态协同

但真正影响生产成败的,从来不是“你选了哪个框架”,而是:

  • 你是否分清了协议层、治理层、状态层
  • 你是否用工程方法管理模型能力
  • 你是否把高并发、可扩展、可审计、可回放、可观测放在系统一开始就考虑

如果你的团队正准备做 Java AI 平台或生产级 AI 应用,推荐的落地顺序是:

  1. 先做统一模型接入与审计
  2. 再做路由、缓存、记忆与 Tool 治理
  3. 然后按场景引入 Workflow 或 Agent Runtime
  4. 最终沉淀成统一 AI Gateway 与 AI 中台

这条路径通常比“一上来就做超级智能体平台”更稳,也更符合企业真实演进规律。

云栈社区将持续关注 Java 在 AI 工程化领域的演进,为技术团队的长期架构决策提供更多一手实践参考。

附录:文章里的关键原则清单

为了方便团队内部评审,这里给出一份可直接复用的检查清单:

  • 是否存在统一 AiCommand / AiResult 契约
  • 是否实现模型路由,而不是业务层写死模型
  • 是否有 Token 预算与成本统计
  • 是否有 Tool 路由与 Tool 数量控制
  • 是否实现会话摘要分层
  • 是否实现供应商级熔断与业务级降级
  • 是否有审计链路与回放能力
  • 是否按场景设计缓存策略
  • 是否把 AI 服务纳入统一监控指标体系
  • 是否为 Workflow/Agent 保留统一消息协议与状态持久化方案

如果以上十项里有一半还没有,那么当前系统大概率仍处于“AI Demo 工程”阶段,还没有真正进入生产级工程阶段。




上一篇:面试官问「异地多活」架构,我画了张分布式架构图逆袭成功
下一篇:Linux文件权限详解:rwx、chmod与最小权限原则
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-6-12 22:58 , Processed in 0.633096 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表