第1959篇:智能运维平台的构建——用AI监控AI的自指涉工程
第1959篇:智能运维平台的构建——用AI监控AI的自指涉工程
这篇文章的标题"自指涉"这个词,在逻辑学里是悖论的来源,在工程里却是一个可以落地的有趣实践。
用AI来监控AI系统,听起来像在制造"理发师悖论"。但仔细想想,这其实是很自然的选择:AI系统产生的是语义数据(Prompt、Response、质量指标),这种数据用传统的数值阈值规则处理效果有限,但AI本身非常擅长处理语义数据。
简单举个例子:你的AI客服最近开始给用户的回答质量下降了,但你不知道是哪类问题出了问题。传统监控只能告诉你"平均质量分从0.85降到了0.78",但无法告诉你"最近用户在问关于退款政策的问题,模型总是给出模糊的答案"。
如果你用一个分析AI来扫描最近的低质量回答,它可以直接给你这样的分析:"近48小时内,有37%的低质量回答集中在退款相关话题,主要问题是:1) 回答没有明确的金额信息;2) 回答存在前后矛盾。建议检查退款政策文档是否有更新,以及对应的Prompt是否覆盖了这些边界情况。"
这就是AI监控AI的价值:它能把数字指标翻译成人类可以直接行动的洞察。
系统架构
注意:这里的"智能分析引擎"本身也是一个AI系统,它监控的是另一个AI系统。这里的自指涉要小心处理:分析引擎不能依赖被监控系统,否则被监控系统崩了,分析引擎也跟着崩了。
数据收集与预处理
@Service
public class MonitoringDataCollector {
private final AIRequestLogRepository logRepo;
private final MetricsRepository metricsRepo;
/**
* 为分析引擎准备数据摘要
* 不能把原始数据直接喂给分析AI(太多),需要先做摘要
*/
public AnalysisContext buildAnalysisContext(AnalysisTimeWindow window) {
LocalDateTime from = window.getFrom();
LocalDateTime to = window.getTo();
// 1. 基础统计摘要
SystemStatsSummary stats = buildStatsSummary(from, to);
// 2. 异常样本采样(质量最差的那些)
List<RequestSample> lowQualitySamples = sampleLowQualityRequests(from, to, 20);
// 3. 趋势数据(和上周同期对比)
TrendComparison trends = compareToPreviousPeriod(from, to);
// 4. 最近的系统变更(Prompt版本、模型版本等)
List<SystemChange> recentChanges = getRecentChanges(from, to);
// 5. 用户反馈摘要(如果有)
UserFeedbackSummary feedbackSummary = summarizeUserFeedback(from, to);
return AnalysisContext.builder()
.timeWindow(window)
.stats(stats)
.lowQualitySamples(lowQualitySamples)
.trends(trends)
.recentChanges(recentChanges)
.feedbackSummary(feedbackSummary)
.build();
}
private SystemStatsSummary buildStatsSummary(LocalDateTime from, LocalDateTime to) {
return SystemStatsSummary.builder()
.totalRequests(logRepo.countByTimeRange(from, to))
.successRate(logRepo.getSuccessRate(from, to))
.avgQualityScore(logRepo.getAvgQualityScore(from, to))
.hallucinationRate(logRepo.getHallucinationRate(from, to))
.formatComplianceRate(logRepo.getFormatComplianceRate(from, to))
.avgLatencyMs(logRepo.getAvgLatencyMs(from, to))
.p95LatencyMs(logRepo.getP95LatencyMs(from, to))
.totalTokensConsumed(logRepo.getTotalTokens(from, to))
.degradationRate(logRepo.getDegradationRate(from, to))
// 按话题分类的质量分布
.qualityByCategory(logRepo.getQualityByCategory(from, to))
// 按Prompt版本的质量分布
.qualityByPromptVersion(logRepo.getQualityByPromptVersion(from, to))
.build();
}
private List<RequestSample> sampleLowQualityRequests(LocalDateTime from,
LocalDateTime to,
int count) {
return logRepo.findLowQualityRequests(from, to, count).stream()
.map(log -> RequestSample.builder()
.requestId(log.getRequestId())
.userMessage(log.getUserMessage()) // 已脱敏
.promptKey(log.getPromptKey())
.promptVersion(log.getPromptVersion())
.retrievedDocTitles(log.getRetrievedDocs().stream()
.map(RetrievedDocInfo::getDocTitle)
.collect(Collectors.toList()))
.response(truncate(log.getResponse(), 500)) // 截断
.qualityScore(log.getHallucinationRiskScore())
.issues(log.getQualityFlags())
.build())
.collect(Collectors.toList());
}
}智能分析引擎
这是核心组件,用LLM来分析另一个LLM系统的状态。
@Service
public class IntelligentAnalysisEngine {
// 注意:这里用的是和被监控系统不同的LLM提供商
// 如果被监控系统用的是OpenAI,分析引擎可以用Claude或者本地部署的模型
// 这样依赖隔离更彻底
private final AnalysisLLMClient analysisLlm;
private final MonitoringDataCollector dataCollector;
private static final String ANALYSIS_PROMPT = """
你是一个AI系统运维专家。我将提供一个AI应用系统的近期运行数据,请帮我分析以下几个方面:
1. **异常模式识别**:从低质量样本中识别主要的问题模式(按类型和频率)
2. **根因推断**:基于数据推断最可能的根本原因
3. **影响评估**:这些问题对用户体验和业务的影响程度
4. **改进建议**:具体可操作的改进建议,按优先级排列
5. **需要人工确认的事项**:哪些推断需要人工进一步确认
以下是系统数据摘要:
=== 基础统计 ===
{{stats_summary}}
=== 与上周对比趋势 ===
{{trends}}
=== 最近系统变更 ===
{{recent_changes}}
=== 低质量请求样本({{sample_count}}条)===
{{low_quality_samples}}
=== 用户反馈摘要 ===
{{feedback_summary}}
请用结构化格式回答,每个部分要有具体的数据支撑,不要泛泛而谈。
重要:如果你认为某个问题有超过70%的把握,请明确标注置信度;如果不确定,也要说明。
""";
/**
* 执行智能分析并生成运维报告
*/
public IntelligentAnalysisReport analyze(AnalysisTimeWindow window) {
log.info("开始智能分析: window={}", window);
// 收集数据
AnalysisContext context = dataCollector.buildAnalysisContext(window);
// 构建Prompt
String analysisPrompt = buildAnalysisPrompt(context);
// 调用分析LLM
String rawAnalysis;
try {
rawAnalysis = analysisLlm.complete(analysisPrompt,
AnalysisConfig.builder()
.maxTokens(2000)
.temperature(0.1) // 低温,保证分析的一致性
.build());
} catch (Exception e) {
log.error("智能分析LLM调用失败", e);
return IntelligentAnalysisReport.fallback(window, context.getStats());
}
// 解析分析结果
AnalysisResult parsedResult = parseAnalysisResult(rawAnalysis);
// 构建报告
return IntelligentAnalysisReport.builder()
.window(window)
.stats(context.getStats())
.rawAnalysis(rawAnalysis)
.anomalyPatterns(parsedResult.getAnomalyPatterns())
.rootCauses(parsedResult.getRootCauses())
.recommendations(parsedResult.getRecommendations())
.itemsNeedingHumanReview(parsedResult.getHumanReviewItems())
.confidence(parsedResult.getOverallConfidence())
.generatedAt(LocalDateTime.now())
.build();
}
private String buildAnalysisPrompt(AnalysisContext context) {
String statsSummary = formatStatsSummary(context.getStats());
String trends = formatTrends(context.getTrends());
String changes = formatChanges(context.getRecentChanges());
String samples = formatSamples(context.getLowQualitySamples());
String feedback = formatFeedback(context.getFeedbackSummary());
return ANALYSIS_PROMPT
.replace("{{stats_summary}}", statsSummary)
.replace("{{trends}}", trends)
.replace("{{recent_changes}}", changes)
.replace("{{sample_count}}", String.valueOf(context.getLowQualitySamples().size()))
.replace("{{low_quality_samples}}", samples)
.replace("{{feedback_summary}}", feedback);
}
private String formatSamples(List<RequestSample> samples) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < samples.size(); i++) {
RequestSample s = samples.get(i);
sb.append(String.format("样本%d [%s v%s]:\n",
i + 1, s.getPromptKey(), s.getPromptVersion()));
sb.append("用户问:").append(s.getUserMessage()).append("\n");
sb.append("检索文档:").append(String.join(", ", s.getRetrievedDocTitles())).append("\n");
sb.append("AI回答:").append(s.getResponse()).append("\n");
sb.append("问题标记:").append(s.getIssues()).append("\n\n");
}
return sb.toString();
}
}自动化运维建议的执行引擎
分析出问题之后,某些建议可以自动执行,某些需要人工确认。
@Service
public class AutomatedRemediationExecutor {
private final IntelligentAnalysisEngine analysisEngine;
private final PromptVersionManager promptManager;
private final AlertService alertService;
/**
* 自动执行置信度高、风险低的改进建议
*/
public RemediationReport executeRecommendations(
IntelligentAnalysisReport report) {
List<RemediationAction> executed = new ArrayList<>();
List<RemediationAction> pendingHumanApproval = new ArrayList<>();
for (Recommendation rec : report.getRecommendations()) {
RemediationAction action = classifyAndExecute(rec, report);
if (action.isAutoExecuted()) {
executed.add(action);
} else {
pendingHumanApproval.add(action);
}
}
// 需要人工审核的,发通知
if (!pendingHumanApproval.isEmpty()) {
alertService.sendReviewRequest(pendingHumanApproval, report);
}
return RemediationReport.builder()
.analysisReportId(report.getId())
.autoExecuted(executed)
.pendingApproval(pendingHumanApproval)
.build();
}
private RemediationAction classifyAndExecute(Recommendation rec,
IntelligentAnalysisReport report) {
// 判断是否可以自动执行
boolean canAutoExecute = rec.getConfidence() >= 0.85 &&
rec.getRiskLevel() == RiskLevel.LOW &&
rec.getType().isAutoExecutable();
if (!canAutoExecute) {
return RemediationAction.pendingApproval(rec,
"置信度不足或风险较高,需要人工确认");
}
return switch (rec.getType()) {
case ROLLBACK_PROMPT_VERSION -> {
// 自动回滚Prompt版本(只有当回滚有对应记录时才自动执行)
String targetVersion = (String) rec.getParameters().get("target_version");
if (targetVersion != null) {
promptManager.rollback(rec.getPromptKey(), targetVersion);
yield RemediationAction.executed(rec,
"已自动回滚Prompt到版本" + targetVersion);
} else {
yield RemediationAction.pendingApproval(rec, "缺少目标版本信息");
}
}
case INCREASE_RETRIEVAL_TOP_K -> {
// 增加RAG检索文档数量
int newTopK = (int) rec.getParameters().get("new_top_k");
ragConfigManager.updateTopK(rec.getApplicationId(), newTopK);
yield RemediationAction.executed(rec,
"已将检索文档数量调整为" + newTopK);
}
case ADD_DOCUMENT_TO_KNOWLEDGE_BASE -> {
// 自动添加文档到知识库需要人工审核
yield RemediationAction.pendingApproval(rec,
"知识库变更需要人工确认内容准确性");
}
default -> RemediationAction.pendingApproval(rec, "此类操作需要人工确认");
};
}
}日报/周报的自动生成
@Service
public class AutoReportGenerator {
private final IntelligentAnalysisEngine analysisEngine;
private final ReportNotifier notifier;
/**
* 每天早上8点生成昨天的AI系统日报
*/
@Scheduled(cron = "0 0 8 * * *")
public void generateDailyReport() {
AnalysisTimeWindow yesterday = AnalysisTimeWindow.yesterday();
IntelligentAnalysisReport analysis = analysisEngine.analyze(yesterday);
DailyReport report = buildDailyReport(analysis);
notifier.sendDailyReport(report);
}
private DailyReport buildDailyReport(IntelligentAnalysisReport analysis) {
SystemStatsSummary stats = analysis.getStats();
// 和前一天对比,计算变化
SystemStatsSummary previousDay = getPreviousDayStats();
return DailyReport.builder()
.date(LocalDate.now().minusDays(1))
// 核心指标
.totalRequests(stats.getTotalRequests())
.successRate(stats.getSuccessRate())
.avgQualityScore(stats.getAvgQualityScore())
// 与前日对比
.qualityScoreChange(stats.getAvgQualityScore() -
previousDay.getAvgQualityScore())
.requestCountChange(stats.getTotalRequests() -
previousDay.getTotalRequests())
// AI分析洞察
.keyInsights(analysis.getAnomalyPatterns())
.topRecommendation(analysis.getRecommendations().isEmpty() ? null :
analysis.getRecommendations().get(0))
// Token成本
.tokenCost(estimateCost(stats.getTotalTokensConsumed()))
// 需要关注的事项
.attentionItems(analysis.getItemsNeedingHumanReview())
.build();
}
}自指涉的几个陷阱
这个架构有几个地方需要特别小心:
陷阱1:分析引擎和被监控系统耦合
最开始我们把分析引擎和主系统部署在一起,共用同一个LLM API。结果LLM API限流时,主系统和分析引擎同时崩,没有任何告警出来——因为分析引擎本身也崩了。
现在的做法:分析引擎用独立的LLM API账号和密钥,甚至用不同的LLM提供商。资源隔离是第一原则。
陷阱2:分析AI的输出缺乏确定性
同一组数据,分析AI每次给出的分析可能稍有不同。在运维场景里,这会导致"上次分析说是问题A,这次分析说是问题B,我到底该信哪个?"
解决方法:强制分析AI附带置信度评分,只对高置信度(>80%)的结论做自动处理,低置信度的结论只作为参考展示给人工。
陷阱3:分析结果的行动闭环缺失
分析引擎给出了建议,但建议没有人执行,下次分析还是给出同样的建议,就变成了"系统在反复说同样的废话"。
解决方法:建立"建议追踪"机制,每个建议都有状态(待处理/已执行/已忽略/已失效),分析引擎在下次分析时会参考上次建议的执行情况,不重复已处理的建议。
陷阱4:自分析的成本失控
我们的分析引擎每5分钟跑一次,每次分析要消耗大量Token。结果分析引擎的成本比被监控的主系统还高,本末倒置了。后来改成:普通情况下每小时分析一次,检测到异常信号时触发即时分析,每天出一份深度日报。
// 自适应分析频率
@Component
public class AdaptiveAnalysisScheduler {
private final MetricsRepository metricsRepo;
private final IntelligentAnalysisEngine analysisEngine;
// 异常信号检测:快速、轻量
@Scheduled(fixedRate = 300_000) // 每5分钟
public void checkForAnomalySignals() {
QuickHealthSnapshot snapshot = metricsRepo.getQuickSnapshot(Duration.ofMinutes(10));
if (isAnomalySignalDetected(snapshot)) {
log.info("检测到异常信号,触发即时分析");
// 异步触发分析,不阻塞当前线程
CompletableFuture.runAsync(() ->
analysisEngine.analyze(AnalysisTimeWindow.lastHour()));
}
}
private boolean isAnomalySignalDetected(QuickHealthSnapshot snapshot) {
return snapshot.getQualityScoreDrop() > 0.10 || // 质量下降10%
snapshot.getErrorRateSpike() > 0.05 || // 错误率超5%
snapshot.getHallucinationSpike() > 0.20 || // 幻觉率上升20%
snapshot.isRefusalRateAbnormal(); // 拒绝率异常
}
}实际效果
这套系统在我参与的一个项目里运行了大约四个月,几个有意思的真实案例:
案例1:有一天分析引擎发现用户在问"如何申请退款"这类问题时,回答质量分连续低于0.6。分析认为可能是知识库里的退款政策文档有更新但RAG没有及时索引。运维人员确认后,发现确实是文档更新了但再索引任务失败了,修复后问题消失。这个问题如果靠传统监控,可能要等用户大量投诉才发现。
案例2:某次Prompt版本升级后,分析引擎在两小时内就识别出"新版Prompt对技术类问题的回答格式合规性明显下降",并自动触发了回滚。这个反馈速度比人工审查快了大约一个工作日。
案例3:分析引擎连续三天报告说"检索质量在下午3-5点明显下降"。人工排查发现是向量数据库在高峰期索引重建任务会占用大量I/O资源。这是一个只有做长期趋势分析才能发现的隐藏问题,传统阈值告警完全发现不了。
用AI监控AI,是工具在解决工具自身的问题。
听起来很酷,但更重要的是它真的管用——它让AI系统的运维从"人工巡检+靠感觉"变成了"数据驱动+有洞察"。
当然,这套系统本身也需要被监控。如果有一天我把监控分析引擎的AI再接进来,我们就真的进入"无限自指涉"了,那就是另一个故事了。
