AI应用架构演进:从单体到微服务到云原生AI的完整路径
2026/4/30大约 7 分钟
AI应用架构演进:从单体到微服务到云原生AI的完整路径
适读人群:有1-5年Java开发经验,想向AI工程师方向转型的开发者 阅读时长:约18分钟 文章价值:① 建立AI应用架构演进的完整认知框架 ② 掌握每个阶段的核心技术选型逻辑 ③ 理解什么时候该升级架构、什么时候不该
上周五,老周来找我喝咖啡,聊他们公司AI产品的架构问题。
老周所在的公司是一家做法律SaaS的,去年开始往AI方向转,一开始就几个人,现在用户涨到了两万多,系统开始出问题了。
"老张,我们当时为了快,直接把AI功能加到了原有的法律文书系统里,现在一个AI请求慢了,整个系统都卡。"
"一个大Jar包,AI、文书、用户、计费都在里面?"
"对,都在一起。"
"这是架构演进没跟上业务增长的典型案例。"我说,"你现在面临的不是修bug,是架构升级决策。"
接下来我们聊了两个多小时。这篇文章,把那次对话的核心整理出来。
三个演进阶段
AI应用的架构演进,基本上会经历三个阶段:
阶段一:AI单体
适用场景
- 团队规模:1-5人
- 用户规模:<5000 DAU
- AI功能:1-3个场景
- 验证期,快速迭代
典型架构
// 阶段一:AI功能直接集成在主服务里
@Service
@RequiredArgsConstructor
public class LegalDocumentService {
// 业务依赖
private final DocumentRepository documentRepository;
private final UserRepository userRepository;
// AI依赖:直接注入ChatClient
private final ChatClient chatClient;
/**
* 法律文书AI审查(单体风格:业务+AI混在一起)
*/
public ReviewResult reviewDocument(Long documentId, String userId) {
// 1. 业务逻辑:查文书
Document doc = documentRepository.findById(documentId)
.orElseThrow(() -> new NotFoundException("文书不存在"));
// 2. 业务逻辑:权限检查
User user = userRepository.findById(userId)
.orElseThrow(() -> new UnauthorizedException("用户不存在"));
checkPermission(user, doc);
// 3. AI逻辑:调用LLM
String aiReview = chatClient.prompt()
.system("你是一名专业律师,请审查以下法律文书,找出潜在的法律风险。")
.user(doc.getContent())
.call()
.content();
// 4. 保存结果
doc.setAiReview(aiReview);
documentRepository.save(doc);
return ReviewResult.of(aiReview);
}
}单体的优点是简单,一个进程里所有东西都有,部署一个Jar就行。缺点是AI慢了,整个应用都慢——因为它们共享线程池和资源。
单体阶段的优化:隔离AI线程池
即使在单体阶段,也要做一件事:给AI调用配置独立线程池,不让它影响业务接口响应。
@Configuration
public class AiIsolationConfig {
/**
* AI专用线程池:即使AI慢,不影响业务接口
*/
@Bean("aiTaskExecutor")
public Executor aiTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setMaxPoolSize(50);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("ai-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
// 使用@Async隔离AI调用
@Async("aiTaskExecutor")
public CompletableFuture<String> reviewDocumentAsync(String content) {
String result = chatClient.prompt()
.user(content)
.call()
.content();
return CompletableFuture.completedFuture(result);
}阶段二:AI微服务拆分
触发条件
- AI接口响应慢,开始影响核心业务
- 需要独立扩容AI处理能力
- AI功能增多,代码耦合严重
- 需要灵活切换不同LLM Provider
拆分策略
AI微服务的核心实现
// AI服务:独立的Spring Boot应用
@SpringBootApplication
public class AiServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AiServiceApplication.class, args);
}
}
@RestController
@RequestMapping("/internal/ai") // internal表示只供内部服务调用
@RequiredArgsConstructor
@Slf4j
public class AiInternalController {
private final LegalAiService legalAiService;
/**
* 同步审查接口(短文书)
*/
@PostMapping("/review/sync")
public ResponseEntity<ReviewResponse> syncReview(@RequestBody ReviewRequest request) {
// 限制同步接口只处理短文书
if (request.getContent().length() > 3000) {
return ResponseEntity.badRequest()
.body(ReviewResponse.error("内容超长,请使用异步接口"));
}
String result = legalAiService.reviewDocument(request.getContent());
return ResponseEntity.ok(ReviewResponse.success(result));
}
/**
* 异步审查接口(长文书):提交任务,返回taskId
*/
@PostMapping("/review/async")
public ResponseEntity<AsyncTaskResponse> asyncReview(@RequestBody ReviewRequest request) {
String taskId = legalAiService.submitReviewTask(
request.getContent(),
request.getDocumentId(),
request.getUserId()
);
return ResponseEntity.ok(AsyncTaskResponse.of(taskId));
}
}
// 文书服务通过Feign调用AI服务
@FeignClient(name = "ai-service", url = "${services.ai.url}",
fallbackFactory = AiClientFallbackFactory.class)
public interface AiServiceClient {
@PostMapping("/internal/ai/review/sync")
ReviewResponse syncReview(@RequestBody ReviewRequest request);
@PostMapping("/internal/ai/review/async")
AsyncTaskResponse asyncReview(@RequestBody ReviewRequest request);
}
// Fallback:AI服务不可用时的降级
@Component
public class AiClientFallbackFactory implements FallbackFactory<AiServiceClient> {
@Override
public AiServiceClient create(Throwable cause) {
return new AiServiceClient() {
@Override
public ReviewResponse syncReview(ReviewRequest request) {
log.warn("AI服务不可用,走降级", cause);
return ReviewResponse.degraded("AI服务暂时不可用,请稍后查看审查结果");
}
@Override
public AsyncTaskResponse asyncReview(ReviewRequest request) {
return AsyncTaskResponse.error("AI服务暂时不可用");
}
};
}
}阶段三:云原生AI
触发条件
- 用户超过10万,AI流量波动剧烈(高峰低峰相差10倍+)
- 运维成本高,手动扩缩容跟不上
- 需要多模型/多Provider支持(成本优化、能力互补)
- 需要精细的可观测性(知道每次AI调用的成本/延迟/质量)
Kubernetes部署配置
# ai-service deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ai-service
spec:
replicas: 2 # 初始2个副本
selector:
matchLabels:
app: ai-service
template:
metadata:
labels:
app: ai-service
annotations:
# Prometheus抓取配置
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/actuator/prometheus"
spec:
containers:
- name: ai-service
image: laozhang/ai-service:latest
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "2"
memory: "2Gi"
env:
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: ai-secrets
key: openai-api-key
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 30
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
---
# HPA:基于CPU或自定义指标自动扩缩容
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: ai-service-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: ai-service
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
# 也可以基于Kafka消费延迟扩缩容
- type: External
external:
metric:
name: kafka_consumer_lag
target:
type: Value
value: "1000"AI Gateway:多模型路由
/**
* AI网关:根据任务类型、成本、可用性动态路由到不同模型
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class AiGateway {
// 多个ChatClient,对应不同模型
@Qualifier("gpt4oChatClient")
private final ChatClient gpt4oClient;
@Qualifier("gpt4oMiniChatClient")
private final ChatClient gpt4oMiniClient;
@Qualifier("tongYiChatClient")
private final ChatClient tongYiClient;
private final ModelHealthChecker healthChecker;
private final CostTracker costTracker;
/**
* 智能路由:根据任务复杂度和模型可用性选择最合适的模型
*/
public String route(AiTask task) {
ModelChoice choice = selectModel(task);
log.info("AI路由决策:task={}, model={}, reason={}",
task.getType(), choice.getModelName(), choice.getReason());
ChatClient client = getClient(choice.getModelName());
String result = client.prompt()
.user(task.getPrompt())
.call()
.content();
// 记录成本
costTracker.track(task.getUserId(), choice.getModelName(), task.estimatedTokens());
return result;
}
private ModelChoice selectModel(AiTask task) {
// 规则1:复杂推理任务用GPT-4o
if (task.requiresComplexReasoning() && healthChecker.isHealthy("gpt4o")) {
return ModelChoice.of("gpt4o", "复杂推理任务");
}
// 规则2:简单问答、高频任务用更便宜的模型
if (task.isSimple() && healthChecker.isHealthy("gpt4o-mini")) {
return ModelChoice.of("gpt4o-mini", "简单任务省成本");
}
// 规则3:主模型不可用,切国内模型
if (healthChecker.isHealthy("tongyi")) {
return ModelChoice.of("tongyi", "主模型不可用,切备用");
}
throw new AllModelsUnavailableException("所有模型均不可用");
}
}三个阶段的演进决策矩阵
| 指标 | 单体 | 微服务 | 云原生 |
|---|---|---|---|
| 团队规模 | 1-5人 | 5-20人 | 20人+ |
| 日活用户 | <5000 | 5000-50万 | 50万+ |
| AI场景数量 | 1-3个 | 3-10个 | 10个+ |
| 运维复杂度 | 低 | 中 | 高 |
| 基础设施成本 | 低 | 中 | 高 |
| 开发效率 | 高 | 中 | 低(初期) |
| 扩展性 | 差 | 好 | 极好 |
老周的情况怎么选?
两万用户,AI功能有3-4个,团队8个人——应该从单体迁移到微服务,把AI服务独立拆出去。暂时不需要K8s,用Docker Compose部署微服务足够了。等用户再涨10倍,再考虑云原生。
过度设计是AI架构最常见的陷阱。你两万用户就搞K8s多集群,团队精力全耗在运维上,业务没空迭代。
