八、监控与可观测性

项目预览:https://www.joinoai.cloud

项目仓库:https://github.com/vasc-language/ai-code-mother

项目仓库:https://gitee.com/vasc-language/ai-code-mother

46. 什么是可观测性?为什么需要为 AI 项目构建一套可观测性体系?

可观测性的定义

可观测性(Observability) 指通过检查系统的外部输出来了解系统内部状态的能力。它包含三个核心支柱:

  1. 指标(Metrics):数值型的性能数据,如请求次数、响应时间、错误率等
  2. 日志(Logs):系统运行过程中产生的事件记录
  3. 链路追踪(Traces):分布式系统中请求的完整调用链路
AI 项目构建可观测性体系的必要性
  1. AI 模型调用的不确定性

    • AI 模型响应时间波动大,需要实时监控性能指标
    • Token 消耗与成本直接相关,需要精确计量
    • 模型调用失败率影响用户体验,需要及时发现和处理
  2. 业务指标的重要性

    • 用户活跃度分析:监控哪些用户最活跃,使用哪些功能
    • 应用热度统计:了解哪些AI生成的应用最受欢迎
    • 成本控制:监控Token消耗,控制AI调用成本
  3. 系统稳定性保障

    // AI模型监控示例
    public class AiModelMonitorListener implements ChatModelListener {
        @Override
        public void onResponse(ChatModelResponseContext responseContext) {
            // 记录成功请求
            aiModelMetricsCollector.recordRequest(userId, appId, modelName, "success");
    
            // 记录响应时间
            recordResponseTime(attributes, userId, appId, modelName);
    
            // 记录Token消耗
            recordTokenUsage(responseContext, userId, appId, modelName);
        }
    }
    
  4. 问题快速定位

    • 通过多维度指标快速定位性能瓶颈
    • 异常告警机制,第一时间发现问题
    • 历史数据分析,预测系统容量需求

47. 什么是 ARMS?如何利用 ARMS 实现系统监控?它主要监控了哪些指标?

ARMS 简介

**ARMS(Application Real-Time Monitoring Service)**是阿里云提供的一站式应用性能监控服务,提供应用拓扑、调用链查询、异常事务和慢事务监控等功能。

ARMS 的主要特点
  1. 应用性能监控(APM)

    • 自动发现应用拓扑
    • 分布式链路追踪
    • 异常和慢调用监控
  2. 前端监控

    • 页面性能监控
    • JS错误监控
    • 用户行为分析
  3. Prometheus监控

    • 兼容Prometheus生态
    • 自定义指标监控
    • 告警规则配置
ARMS 实现系统监控的方式

注意:本项目实际采用的是自建的Prometheus+Grafana方案,而非ARMS

如果要使用ARMS,监控实现方式如下:

  1. Java应用接入

    <!-- ARMS Agent 依赖 -->
    <dependency>
        <groupId>com.alibaba.arms</groupId>
        <artifactId>arms-agent</artifactId>
        <version>1.7.3</version>
    </dependency>
    
  2. 自动埋点监控

    // ARMS会自动监控以下指标:
    // - HTTP请求响应时间
    // - 数据库查询性能
    // - 外部服务调用链路
    // - JVM性能指标
    
  3. 自定义业务指标

    // 通过ARMS API上报自定义指标
    @Component
    public class ArmsMetricsReporter {
        public void reportAiModelMetrics(String modelName, long responseTime, long tokenCount) {
            // ARMS自定义指标上报
            CustomMetrics.recordGaugeValue("ai_model_response_time", responseTime,
                Tags.of("model", modelName));
            CustomMetrics.recordCounterValue("ai_model_token_usage", tokenCount,
                Tags.of("model", modelName));
        }
    }
    
ARMS 主要监控指标
  1. 基础性能指标

    • 应用QPS(每秒请求数)
    • 平均响应时间
    • 错误率
    • 并发用户数
  2. JVM监控指标

    • 堆内存使用率
    • GC频率和耗时
    • 线程数量
    • CPU使用率
  3. 数据库性能指标

    • SQL执行时间
    • 慢查询监控
    • 连接池状态
    • 事务性能
  4. 外部依赖监控

    • 外部服务调用成功率
    • 第三方API响应时间
    • 缓存命中率

48. 为什么除了 ARMS,你还需要引入 Prometheus 和 Grafana?这两套监控方案有什么不同?

项目实际采用的方案:Prometheus + Grafana

本项目实际使用的是Prometheus + Grafana组合,而非ARMS。以下是两种方案的对比:

Prometheus + Grafana 的优势
  1. 完全开源免费

    # prometheus.yml 配置
    scrape_configs:
      - job_name: 'ai-code-mother'
        metrics_path: '/api/actuator/prometheus'
        static_configs:
          - targets: ['localhost:8123']
        scrape_interval: 10s
    
  2. 高度可定制化

    // 自定义AI业务指标
    @Component
    public class AiModelMetricsCollector {
        public void recordTokenUsage(String userId, String appId, String modelName,
                                    String tokenType, long tokenCount) {
            Counter counter = tokenCountersCache.computeIfAbsent(key, k ->
                Counter.builder("ai_model_tokens_total")
                    .tag("user_id", userId)
                    .tag("app_id", appId)
                    .tag("model_name", modelName)
                    .tag("token_type", tokenType)
                    .register(meterRegistry)
            );
            counter.increment(tokenCount);
        }
    }
    
  3. 丰富的生态系统

    • 支持多种Exporter
    • 强大的查询语言PromQL
    • 灵活的告警规则配置
两套方案的详细对比
特性Prometheus + GrafanaARMS
成本开源免费商业付费
部署需要自主部署和维护托管服务,开箱即用
可定制性高度可定制相对固定的模板
数据存储本地存储,数据可控云端存储
查询语言PromQL,学习成本高但功能强大图形化界面,易用性好
告警AlertManager配置复杂但灵活内置告警,配置简单
链路追踪需集成Jaeger/Zipkin内置APM链路追踪
前端监控需要额外方案内置前端监控
项目选择 Prometheus + Grafana 的原因
  1. AI业务指标的特殊性

    // Grafana中的AI模型监控面板配置
    {
      "title": "AI模型监控看板",
      "panels": [
        {
          "title": "总成功请求数",
          "targets": [{"expr": "sum(ai_model_requests_total{status=\"success\"})"}]
        },
        {
          "title": "Token消耗排行",
          "targets": [{"expr": "topk(10, sum by (app_id) (ai_model_tokens_total))"}]
        }
      ]
    }
    
  2. 成本控制需求

    • 开源方案无额外费用
    • 完全控制数据存储和查询
    • 可根据业务需求定制监控指标
  3. 技术栈统一

    • 与Spring Boot Actuator完美集成
    • 使用Micrometer标准指标格式
    • 便于开发团队维护

49. 你如何在 AI 项目中实现自定义业务指标的监控?

自定义业务指标架构设计
// 监控架构的核心组件
@Component
public class AiModelMetricsCollector {
    @Resource
    private MeterRegistry meterRegistry;

    // 线程安全的指标缓存
    private final ConcurrentMap<String, Counter> requestCountersCache = new ConcurrentHashMap<>();
    private final ConcurrentMap<String, Counter> errorCountersCache = new ConcurrentHashMap<>();
    private final ConcurrentMap<String, Counter> tokenCountersCache = new ConcurrentHashMap<>();
    private final ConcurrentMap<String, Timer> responseTimersCache = new ConcurrentHashMap<>();
}
1. 自定义指标类型设计

请求次数指标

public void recordRequest(String userId, String appId, String modelName, String status) {
    String key = String.format("%s_%s_%s_%s", userId, appId, modelName, status);
    Counter counter = requestCountersCache.computeIfAbsent(key, k ->
        Counter.builder("ai_model_requests_total")
            .description("AI模型总请求次数")
            .tag("user_id", userId)
            .tag("app_id", appId)
            .tag("model_name", modelName)
            .tag("status", status)
            .register(meterRegistry)
    );
    counter.increment();
}

Token消耗指标

public void recordTokenUsage(String userId, String appId, String modelName,
                           String tokenType, long tokenCount) {
    String key = String.format("%s_%s_%s_%s", userId, appId, modelName, tokenType);
    Counter counter = tokenCountersCache.computeIfAbsent(key, k ->
        Counter.builder("ai_model_tokens_total")
            .description("AI模型Token消耗总数")
            .tag("user_id", userId)
            .tag("app_id", appId)
            .tag("model_name", modelName)
            .tag("token_type", tokenType)
            .register(meterRegistry)
    );
    counter.increment(tokenCount);
}

响应时间指标

public void recordResponseTime(String userId, String appId, String modelName, Duration duration) {
    String key = String.format("%s_%s_%s", userId, appId, modelName);
    Timer timer = responseTimersCache.computeIfAbsent(key, k ->
        Timer.builder("ai_model_response_duration_seconds")
            .description("AI模型响应时间")
            .tag("user_id", userId)
            .tag("app_id", appId)
            .tag("model_name", modelName)
            .register(meterRegistry)
    );
    timer.record(duration);
}
2. 监听器集成
@Component
public class AiModelMonitorListener implements ChatModelListener {

    @Override
    public void onRequest(ChatModelRequestContext requestContext) {
        // 记录请求开始时间和上下文
        requestContext.attributes().put("request_start_time", Instant.now());
        MonitorContext context = MonitorContextHolder.getContext();
        requestContext.attributes().put("monitor_context", context);

        // 记录请求开始指标
        aiModelMetricsCollector.recordRequest(
            context.getUserId(),
            context.getAppId(),
            requestContext.chatRequest().modelName(),
            "started"
        );
    }

    @Override
    public void onResponse(ChatModelResponseContext responseContext) {
        MonitorContext context = (MonitorContext)
            responseContext.attributes().get("monitor_context");

        // 记录成功请求
        aiModelMetricsCollector.recordRequest(
            context.getUserId(),
            context.getAppId(),
            responseContext.chatResponse().modelName(),
            "success"
        );

        // 记录响应时间和Token使用
        recordResponseTime(responseContext.attributes(), context);
        recordTokenUsage(responseContext, context);
    }
}
3. 上下文传递机制
// 监控上下文
@Data
@Builder
public class MonitorContext implements Serializable {
    private String userId;
    private String appId;
}

// 上下文持有者
public class MonitorContextHolder {
    private static final ThreadLocal<MonitorContext> CONTEXT_THREAD = new ThreadLocal<>();

    public static void setContext(MonitorContext context) {
        CONTEXT_THREAD.set(context);
    }

    public static MonitorContext getContext() {
        return CONTEXT_THREAD.get();
    }

    public static void clearContext() {
        CONTEXT_THREAD.remove();
    }
}
4. Grafana 可视化配置

概览指标面板

{
  "title": "概览指标",
  "panels": [
    {
      "title": "总成功请求数",
      "targets": [{
        "expr": "sum(ai_model_requests_total{status=\"success\"})"
      }]
    },
    {
      "title": "总Token消耗",
      "targets": [{
        "expr": "sum(ai_model_tokens_total{token_type=\"total\"})"
      }]
    },
    {
      "title": "平均响应时间",
      "targets": [{
        "expr": "sum(ai_model_response_duration_seconds_sum) / sum(ai_model_response_duration_seconds_count)"
      }]
    }
  ]
}

排行榜面板

{
  "title": "热门应用排行",
  "targets": [{
    "expr": "topk(10, sum by (app_id) (ai_model_requests_total{status=\"success\"}))",
    "format": "table"
  }]
}
5. 关键技术实现要点
  1. 性能优化

    • 使用ConcurrentHashMapcomputeIfAbsent避免重复创建指标
    • 指标缓存按类型分离,提高并发性能
    • 使用线程安全的缓存容器
  2. 标签设计原则

    • 多维度标签:用户ID、应用ID、模型名称、状态等
    • 避免高基数标签,防止指标爆炸
    • 标签值统一格式,便于查询和聚合
  3. 内存管理

    // 定期清理无效指标,防止内存泄漏
    @Scheduled(fixedRate = 300000) // 5分钟执行一次
    public void cleanupMetrics() {
        // 清理长时间未使用的指标缓存
    }
    
  4. 告警配置

    # Prometheus告警规则
    groups:
      - name: ai_model_alerts
        rules:
          - alert: HighErrorRate
            expr: rate(ai_model_requests_total{status="error"}[5m]) > 0.1
            for: 2m
            labels:
              severity: warning
            annotations:
              summary: "AI模型错误率过高"
    

通过这套自定义监控体系,我们能够:

  • 实时监控AI模型的调用性能和成本
  • 分析用户使用行为和应用热度
  • 快速定位和解决系统问题
  • 为业务决策提供数据支撑

📞 联系我们

如果您有任何问题或建议,请随时联系我们:

📧 邮箱: zrt3ljnygz@163.com
💬 微信: Join2049
🐛 问题反馈: 提交Issue


扫码添加微信好友

扫码添加微信好友

⭐ Star History ⭐

如果这个项目对你有帮助,请给我们一个 Star!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐