第2288篇:微服务中的AI模块化——如何把AI能力设计成独立的微服务
第2288篇:微服务中的AI模块化——如何把AI能力设计成独立的微服务
适读人群:微服务架构师和有一定AI工程经验的后端工程师 | 阅读时长:约16分钟 | 核心价值:掌握AI能力服务化的接口设计、隔离策略与版本管理方法
我见过两种极端做法,都不好。
第一种:所有业务服务都直接调AI API。订单服务自己调、用户服务自己调、客服服务自己调。表面上每个服务都"有AI能力了",实际上是API Key散落各处、成本统计乱七八糟、提示词维护没人负责、模型升级要改十几个地方。
第二种:搞一个"AI大中台",所有AI能力统一在一个服务里,业务服务统一来这里调。听起来很对,但这个大中台越长越胖,变成了一个包揽一切的单体,反而成了新的瓶颈。
正确的做法在这两者之间:把AI能力按领域拆成有边界的微服务,每个服务专注一类能力,接口清晰,独立部署,独立扩展。
AI能力拆分的原则
拆分AI微服务不能按技术特征拆(比如"文本处理服务"),要按业务能力领域拆。几个具体的判断依据:
1. 不同的模型需求:内容审核需要快速的分类模型,代码生成需要强大的推理模型,图像描述需要多模态模型。这些天然属于不同服务。
2. 不同的SLA要求:实时客服对话要求P99 < 3秒,批量报告生成可以接受几分钟。不同SLA要求混在一起,高优先级任务会被低优先级任务拖慢。
3. 不同的提示词生命周期:客服话术提示词每周都要迭代,内容审核规则提示词可能几个月不变。生命周期不同的东西放一起,变更影响范围难以控制。
4. 不同的安全边界:处理用户隐私数据的AI能力,和处理公开信息的AI能力,安全审计要求不同,应该在不同服务里隔离。
典型的AI微服务拆分:
接口契约设计
AI微服务的接口设计有个常见陷阱:把"提示词"暴露在接口里。这是绝对要避免的。
错误做法:
// 错误:让调用方传提示词
POST /ai/complete
{
"prompt": "你是一个客服助手,请回答以下问题:...",
"question": "我的订单在哪里"
}这样做有几个严重问题:
- 提示词分散在所有调用方的代码里,根本无法统一管理
- 调用方可以注入任意提示词,造成安全风险
- 模型升级时,提示词可能需要跟着改,但改在调用方里,改不过来
正确做法——面向业务意图设计接口,隐藏提示词细节:
// 对话服务接口
public interface ConversationService {
/**
* 发送客服对话消息
* 内部封装了客服提示词和上下文管理
*/
ConversationResponse sendMessage(ConversationRequest request);
/**
* 生成对话摘要
*/
String summarizeConversation(String conversationId);
}
// 内容理解服务接口
public interface ContentIntelligenceService {
/**
* 检测内容是否违规
*/
ContentSafetyResult checkContentSafety(String content, ContentType type);
/**
* 提取实体和关键信息
*/
EntityExtractionResult extractEntities(String text, List<EntityType> targetTypes);
/**
* 分类意图
*/
IntentClassificationResult classifyIntent(String text, String domain);
}// 接口的具体实现(在AI微服务内部)
@RestController
@RequestMapping("/api/v1/content-intelligence")
public class ContentIntelligenceController {
private final ContentSafetyAnalyzer safetyAnalyzer;
private final EntityExtractor entityExtractor;
private final IntentClassifier intentClassifier;
@PostMapping("/safety-check")
public ResponseEntity<ContentSafetyResult> checkSafety(
@RequestBody ContentSafetyRequest request,
@RequestHeader("X-Service-Token") String serviceToken) {
// 验证调用方身份(服务间认证)
serviceAuthValidator.validate(serviceToken);
ContentSafetyResult result = safetyAnalyzer.check(
request.getContent(),
request.getContentType()
);
return ResponseEntity.ok(result);
}
}版本管理:如何不停服地升级AI能力
AI微服务的一个独特挑战是:模型升级或提示词修改可能改变输出格式,影响调用方。
解决方案是严格的API版本化 + 金丝雀发布:
@RestController
public class VersionedAiController {
private final Map<String, ContentIntelligenceService> serviceVersions;
@PostMapping("/api/{version}/content-intelligence/classify-intent")
public ResponseEntity<IntentClassificationResult> classifyIntent(
@PathVariable String version,
@RequestBody IntentClassificationRequest request) {
ContentIntelligenceService service = serviceVersions.get(version);
if (service == null) {
return ResponseEntity.badRequest()
.body(null); // 或者返回错误信息
}
return ResponseEntity.ok(service.classifyIntent(
request.getText(), request.getDomain()
));
}
}
// v1版本的实现(保持稳定)
@Service("v1ContentIntelligence")
public class ContentIntelligenceV1 implements ContentIntelligenceService {
private static final String INTENT_PROMPT_V1 = """
分析以下文本的用户意图,从这些类别中选择最匹配的一个:
[咨询/投诉/购买/退款/其他]
文本:{text}
只返回类别名称,不要解释。
""";
@Override
public IntentClassificationResult classifyIntent(String text, String domain) {
String prompt = INTENT_PROMPT_V1.replace("{text}", text);
String rawResult = llmClient.complete(prompt);
return IntentClassificationResult.v1Parse(rawResult);
}
}
// v2版本(改用新模型和更精细的意图分类)
@Service("v2ContentIntelligence")
public class ContentIntelligenceV2 implements ContentIntelligenceService {
private static final String INTENT_PROMPT_V2 = """
分析用户文本的意图,以JSON格式返回:
{
"primary_intent": "主要意图",
"confidence": 0.0-1.0,
"sub_intents": ["次要意图列表"]
}
意图类别:咨询/投诉/购买/退款/比较/推荐/其他
文本:{text}
""";
@Override
public IntentClassificationResult classifyIntent(String text, String domain) {
String prompt = INTENT_PROMPT_V2.replace("{text}", text);
String rawResult = llmClient.completeWithJson(prompt);
return IntentClassificationResult.v2Parse(rawResult);
}
}服务间调用的容错设计
AI微服务调用不同于普通服务调用,有几个特殊的容错需求:
@Service
public class ResilientAiServiceClient {
private final ContentIntelligenceService primaryService;
private final ContentIntelligenceService fallbackService; // 降级服务(用简单规则代替AI)
private final CircuitBreakerRegistry circuitBreakerRegistry;
/**
* 带熔断、降级、重试的AI服务调用
*/
public IntentClassificationResult classifyIntentResilient(
String text, String domain) {
CircuitBreaker cb = circuitBreakerRegistry.circuitBreaker("content-intelligence");
// 尝试主服务(带熔断)
Try<IntentClassificationResult> result = Try.ofSupplier(
CircuitBreaker.decorateSupplier(cb, () ->
primaryService.classifyIntent(text, domain)
)
)
// 超时降级
.recover(TimeoutException.class, e -> {
log.warn("AI意图分类超时,使用规则降级", e);
return fallbackService.classifyIntent(text, domain);
})
// 熔断降级
.recover(CallNotPermittedException.class, e -> {
log.warn("AI服务熔断,使用规则降级", e);
return fallbackService.classifyIntent(text, domain);
});
return result.getOrElseThrow();
}
}
// 降级服务:用简单规则代替AI,保证基本可用性
@Service
@Primary
@ConditionalOnProperty("ai.fallback.enabled")
public class RuleBasedFallbackService implements ContentIntelligenceService {
private static final Map<String, String> KEYWORD_INTENT_MAP = Map.of(
"退款", "退款",
"投诉", "投诉",
"价格", "咨询",
"怎么买", "购买"
// ... 更多规则
);
@Override
public IntentClassificationResult classifyIntent(String text, String domain) {
// 简单关键词匹配
for (Map.Entry<String, String> entry : KEYWORD_INTENT_MAP.entrySet()) {
if (text.contains(entry.getKey())) {
return IntentClassificationResult.fromFallback(entry.getValue(), 0.6);
}
}
return IntentClassificationResult.fromFallback("其他", 0.5);
}
}提示词版本管理与A/B测试
AI微服务内部需要管理提示词的版本,支持A/B测试:
@Service
public class PromptManager {
private final PromptRepository promptRepository;
private final ExperimentService experimentService;
/**
* 根据实验配置获取提示词
* 支持A/B测试:不同用户看到不同版本的提示词
*/
public String getPrompt(String promptKey, String userId, Map<String, String> variables) {
// 查看用户是否在实验组
String variant = experimentService.getVariant(userId, promptKey);
// 获取对应版本的提示词模板
PromptTemplate template = promptRepository.findByKeyAndVariant(promptKey, variant)
.orElseThrow(() -> new PromptNotFoundException(promptKey, variant));
// 填充变量
return fillVariables(template.getContent(), variables);
}
private String fillVariables(String template, Map<String, String> variables) {
String result = template;
for (Map.Entry<String, String> entry : variables.entrySet()) {
result = result.replace("{" + entry.getKey() + "}", entry.getValue());
}
return result;
}
}把AI能力拆分成独立微服务,短期看是增加了复杂度,但长期来看带来了:独立扩展(AI服务可以单独横向扩展)、独立迭代(提示词升级不影响业务服务)、统一观测(成本、延迟、质量都在一个地方监控)。这是企业AI平台走向成熟的必经之路。
