第2461篇:AI辅助的架构评审——用LLM检查架构设计中的潜在问题
第2461篇:AI辅助的架构评审——用LLM检查架构设计中的潜在问题
适读人群:架构师、技术负责人、高级工程师 | 阅读时长:约16分钟 | 核心价值:把架构评审的经验工程化,用LLM在设计阶段发现潜在风险
我参加过很多次架构评审,有些评审开了3个小时,最后的结论是"这个方案可以"。但其实大家都知道,那个方案里有几个隐患,只是没人说出来。
架构评审的问题在于:参与者有时候碍于情面,不想正面质疑提案者的设计;有时候是因为评审材料太长,没人仔细读;有时候是因为专业方向不同,数据库专家不懂网络,网络专家不懂存储。
我在想,如果有一个不讲情面、懂各个领域、又肯仔细读材料的"评审员",会不会比现行流程好?
架构评审的常见盲区
根据我的观察,架构评审最容易遗漏的问题类型:
1. 单点故障:设计图上画着两个服务中间有个Redis,但没说Redis是单节点还是集群,也没说挂了之后降级策略是什么。
2. 级联故障传播:A调B,B调C,C响应慢了,没有超时和熔断,A最终把线程池打满,连带A也挂了。
3. 数据一致性问题:分布式场景下,两个服务同时写了两个不同的数据库,失败了怎么回滚,部分成功怎么处理。
4. 容量预估缺失:设计文档里写"支持高并发",但没有给数字,也没有说明为什么这个设计能支持这个并发量。
5. 安全问题:API没有鉴权,数据库连接用了root账号,敏感数据明文存储。
这五类问题,有的是架构经验不足,有的是写文档的时候想当然,都可以用结构化的Checklist来检查——而LLM特别擅长做这种结构化检查。
AI架构评审系统设计
核心实现
@Service
public class ArchitectureReviewService {
private final ChatClient chatClient;
private final DocumentParser documentParser;
private static final List<ReviewDomain> REVIEW_DOMAINS = List.of(
ReviewDomain.AVAILABILITY, // 可用性和容错
ReviewDomain.PERFORMANCE, // 性能和扩展性
ReviewDomain.SECURITY, // 安全
ReviewDomain.DATA_CONSISTENCY, // 数据一致性
ReviewDomain.OBSERVABILITY, // 可观测性
ReviewDomain.OPERATIONAL // 运维和部署
);
public ArchitectureReviewReport review(ArchitectureDocument document) {
// 解析架构文档
ParsedArchitecture arch = documentParser.parse(document);
// 并行执行各领域评审(互相独立,可并行)
List<DomainReviewResult> domainResults = REVIEW_DOMAINS.parallelStream()
.map(domain -> reviewDomain(arch, domain))
.collect(toList());
// 汇总并生成综合建议
return generateReport(arch, domainResults);
}
private DomainReviewResult reviewDomain(ParsedArchitecture arch, ReviewDomain domain) {
String systemPrompt = getDomainSystemPrompt(domain);
String userPrompt = buildDomainReviewPrompt(arch, domain);
ChatResponse response = chatClient.call(new Prompt(
List.of(
new SystemMessage(systemPrompt),
new UserMessage(userPrompt)
),
OpenAiChatOptions.builder()
.withModel("gpt-4o")
.withTemperature(0.2f)
.withResponseFormat(new ResponseFormat(ResponseFormat.Type.JSON_OBJECT))
.build()
));
return parseDomainResult(response.getResult().getOutput().getContent(), domain);
}
private String getDomainSystemPrompt(ReviewDomain domain) {
return switch (domain) {
case AVAILABILITY -> """
你是一个专注于高可用架构设计的专家,曾经历过多次大规模故障处置。
评审时重点关注:
- 是否存在单点故障(SPOF)
- 故障隔离和熔断机制是否完备
- 服务降级策略是否定义清晰
- 超时和重试策略是否合理
- 数据中心或可用区级别的容灾设计
返回JSON格式:
{
"issues": [{"severity": "CRITICAL/HIGH/MEDIUM/LOW", "title": "...", "description": "...", "recommendation": "..."}],
"missingElements": ["..."],
"overallScore": 1-10
}
""";
case PERFORMANCE -> """
你是一个专注于系统性能和可扩展性的专家。
评审时重点关注:
- 关键链路的性能瓶颈
- 缓存策略是否合理(缓存穿透/击穿/雪崩)
- 数据库访问模式(N+1查询、全表扫描)
- 扩缩容机制(水平扩展的可行性)
- 容量规划是否有数字支撑
返回JSON格式同上。
""";
case SECURITY -> """
你是一个专注于系统安全的专家,熟悉OWASP Top 10和常见安全漏洞。
评审时重点关注:
- 认证和授权机制
- 敏感数据的存储和传输加密
- API安全(速率限制、输入验证)
- 内部服务间的通信安全
- 日志中的敏感信息泄露
返回JSON格式同上。
""";
case DATA_CONSISTENCY -> """
你是一个专注于分布式数据一致性的专家。
评审时重点关注:
- 跨服务事务的处理方式(Saga/TCC/2PC)
- 幂等性设计
- 消息队列的重复消费处理
- 缓存和数据库的一致性
- 数据补偿和对账机制
返回JSON格式同上。
""";
default -> buildGenericPrompt(domain);
};
}
private String buildDomainReviewPrompt(ParsedArchitecture arch, ReviewDomain domain) {
StringBuilder sb = new StringBuilder();
sb.append("请评审以下架构设计:\n\n");
sb.append("## 系统概述\n").append(arch.getOverview()).append("\n\n");
if (!arch.getComponents().isEmpty()) {
sb.append("## 组件列表\n");
arch.getComponents().forEach(c ->
sb.append("- ").append(c.getName()).append(": ").append(c.getDescription()).append("\n")
);
sb.append("\n");
}
if (!arch.getDataFlows().isEmpty()) {
sb.append("## 数据流\n");
arch.getDataFlows().forEach(flow ->
sb.append("- ").append(flow.getFrom()).append(" -> ").append(flow.getTo())
.append(": ").append(flow.getDescription()).append("\n")
);
sb.append("\n");
}
if (arch.getDiagramDescription() != null) {
sb.append("## 架构图描述\n").append(arch.getDiagramDescription()).append("\n\n");
}
if (!arch.getTechnicalDecisions().isEmpty()) {
sb.append("## 技术选型\n");
arch.getTechnicalDecisions().forEach((k, v) ->
sb.append("- ").append(k).append(": ").append(v).append("\n")
);
}
return sb.toString();
}
}问题严重程度分级
public enum IssueSeverity {
CRITICAL("严重", "必须解决,可能导致数据丢失或服务不可用", 1),
HIGH("高", "强烈建议解决,在压力下或特定场景下会出问题", 2),
MEDIUM("中", "建议解决,提升系统健壮性", 3),
LOW("低", "优化建议,不影响核心功能", 4);
private final String label;
private final String description;
private final int priority;
public static IssueSeverity fromString(String s) {
return switch (s.toUpperCase()) {
case "CRITICAL" -> CRITICAL;
case "HIGH" -> HIGH;
case "MEDIUM" -> MEDIUM;
default -> LOW;
};
}
}
// 汇总报告生成
@Service
public class ReviewReportGenerator {
public ArchitectureReviewReport generate(
ParsedArchitecture arch,
List<DomainReviewResult> domainResults) {
// 收集所有问题,按严重程度排序
List<ArchitectureIssue> allIssues = domainResults.stream()
.flatMap(r -> r.getIssues().stream())
.sorted(Comparator.comparingInt(i -> i.getSeverity().getPriority()))
.collect(toList());
// 统计各严重程度的问题数量
Map<IssueSeverity, Long> issueCounts = allIssues.stream()
.collect(groupingBy(ArchitectureIssue::getSeverity, counting()));
// 计算综合评分
double overallScore = domainResults.stream()
.mapToDouble(DomainReviewResult::getScore)
.average()
.orElse(5.0);
// 生成执行摘要
String executiveSummary = generateExecutiveSummary(arch, allIssues, overallScore);
return ArchitectureReviewReport.builder()
.systemName(arch.getSystemName())
.reviewTime(Instant.now())
.overallScore(overallScore)
.issueSummary(issueCounts)
.issues(allIssues)
.domainResults(domainResults)
.executiveSummary(executiveSummary)
.build();
}
private String generateExecutiveSummary(
ParsedArchitecture arch,
List<ArchitectureIssue> issues,
double score) {
long criticalCount = issues.stream()
.filter(i -> i.getSeverity() == IssueSeverity.CRITICAL)
.count();
long highCount = issues.stream()
.filter(i -> i.getSeverity() == IssueSeverity.HIGH)
.count();
if (criticalCount > 0) {
return String.format(
"架构存在%d个严重问题,需要在上线前解决。主要集中在:%s。建议暂缓上线,优先解决严重问题。",
criticalCount,
issues.stream()
.filter(i -> i.getSeverity() == IssueSeverity.CRITICAL)
.map(ArchitectureIssue::getTitle)
.collect(joining("、"))
);
} else if (highCount > 0) {
return String.format(
"架构整体可行(评分%.1f/10),但有%d个高优先级问题需要关注。建议在迭代1中解决这些问题。",
score, highCount
);
} else {
return String.format(
"架构设计合理(评分%.1f/10),共发现%d个优化建议,可在后续迭代中逐步改进。",
score, issues.size()
);
}
}
}真实评审案例
我拿这套工具评审了一个消息通知系统的架构,AI发现了这几个问题:
CRITICAL: 消息发送服务直接写数据库,没有队列缓冲。用户并发发消息时,数据库会成为瓶颈,且没有背压机制。一旦数据库慢,消息发送会大量超时。
HIGH: Push通知使用了第三方服务(APNs/FCM),但没有设置超时。如果第三方接口响应慢,会占用线程池,最终导致整个通知服务挂掉。
HIGH: 消息的幂等性处理不完整。如果消息因为网络问题重试,接收方可能收到重复消息,但架构文档里没有说明如何处理。
MEDIUM: 没有消息发送的监控和告警。用户反馈"没收到消息"时,无法快速判断是哪个环节出了问题。
这些问题,架构评审会上可能真的被跳过了——不是因为大家不知道,而是评审时间有限,大家关注的是更宏观的设计,细节容易遗漏。
工程落地的注意事项
LLM的分析不是终点,是起点。AI评审的输出是"待讨论清单",而不是"通过/不通过"的最终结论。有些问题AI认为是隐患,但提案者有充分的理由说明为什么已经考虑过了,这时候AI的意见要让步。
要建立Issue的跟踪机制。AI发现的问题记录下来了,但之后有没有被解决,要有闭环。我们用JIRA创建对应的Story,每个问题对应一个ticket,这样在架构落地过程中可以逐一追踪。
