文章目标:不是告诉你“怎么把 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 框架做一次完整分析。我们不止比较功能,更聚焦:
- 框架底层原理与抽象边界
- 单 Agent、Workflow、多 Agent 三类系统的架构差异
- 高并发生产场景下的治理能力建设
- 可直接落地的代码组织、配置策略与部署模式
- 从单体 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 系统“为什么这次能答对、下次却答错”的根因。
它包含三类状态:
- 会话状态
- 执行状态
- Tool 调用轨迹
- Workflow 节点结果
- Agent 中间消息
- 重试与回放位点
- 业务状态
- 工单、订单、风控单、推荐任务等领域对象
- 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 更适合企业内复杂场景:不是单次问答,而是多节点处理。
例如一个商品上架审核流程,可能包含:
- 标题风险识别
- 类目判断
- 图片合规检测
- 规则引擎复核
- 人审兜底
这类场景本质上不是 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 统一模型协议与治理
- 用
LangChain4j 或 Spring 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
) {
}
强烈建议从第一天开始记录 model、finishReason、tokenUsage、latency。
因为当线上答非所问、成本飙升或者供应商抖动时,这些字段会是你排障的第一现场。
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 解析前置
- 审计、成本统计异步化
很多团队在做 Tool Calling 时,喜欢把几十个 Tool 一次性注册给模型,这在生产上通常会带来三个问题:
- Token 被 Tool Schema 吃掉
- 模型选错 Tool 的概率上升
- 输出不稳定,排查困难
正确做法是两级路由:
- 先做意图分类
- 再按分类挂载少量 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 直接输出“最终裁决”,而建议采用:
- 规则引擎给出基线结论
- AI 负责补充解释或识别灰区
- 最终由策略聚合器统一裁决
这样做的好处是:
- 保留确定性底座
- 降低大模型幻觉直接影响业务决策的概率
- 方便合规审计
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
- 模型并发
- 流式连接数
因为一次“超长上下文 + 大输出”的请求,资源占用远高于十次短请求。
建议至少做三层限流:
- API 入口限流
- 模型调用限流
- 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 日志不是简单 request 和 response。
建议至少记录:
- 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_requests、streaming_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()
);
}
}
根因
- 没有做意图分层
- 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 应用,推荐的落地顺序是:
- 先做统一模型接入与审计
- 再做路由、缓存、记忆与 Tool 治理
- 然后按场景引入 Workflow 或 Agent Runtime
- 最终沉淀成统一 AI Gateway 与 AI 中台
这条路径通常比“一上来就做超级智能体平台”更稳,也更符合企业真实演进规律。
云栈社区将持续关注 Java 在 AI 工程化领域的演进,为技术团队的长期架构决策提供更多一手实践参考。
附录:文章里的关键原则清单
为了方便团队内部评审,这里给出一份可直接复用的检查清单:
- 是否存在统一
AiCommand / AiResult 契约
- 是否实现模型路由,而不是业务层写死模型
- 是否有 Token 预算与成本统计
- 是否有 Tool 路由与 Tool 数量控制
- 是否实现会话摘要分层
- 是否实现供应商级熔断与业务级降级
- 是否有审计链路与回放能力
- 是否按场景设计缓存策略
- 是否把 AI 服务纳入统一监控指标体系
- 是否为 Workflow/Agent 保留统一消息协议与状态持久化方案
如果以上十项里有一半还没有,那么当前系统大概率仍处于“AI Demo 工程”阶段,还没有真正进入生产级工程阶段。