从零开始,手把手教你搭建具备企业级可观测能力的 AI 应用。本文覆盖原理讲解、代码实战、部署运维、问题排查全链路,让你真正理解"可观测性"在 AI 场景下的独特价值。


一、AI 应用可观测性

1.1 传统监控 vs AI 应用监控

在传统的微服务架构中,可观测性主要回答三个问题:系统是否健康?请求有多快?出错在哪里? 这三个问题通过 Metrics、Tracing、Logging 三大支柱就能较好地回答。

但当你引入大模型(LLM)后,事情变得复杂了:

维度 传统 Web 应用 AI 应用(新增)
性能指标 QPS、P99 延迟 Token 消耗速率、模型响应时间
错误类型 HTTP 500、超时 模型幻觉、Prompt 注入、内容审核拒绝
成本维度 服务器资源 API 调用费用(按 Token 计费)
调试难度 看日志即可 需要看 Prompt + Response 才能定位问题
质量评估 接口返回正确即可 需要评估回答相关性、准确性

最核心的一点:AI 应用的"黑盒"特性使得调试极其困难。当模型返回了一个奇怪的回答,你必须知道:我发送了什么 Prompt?模型用了什么参数?消耗了多少 Token?响应耗时多久? 这些信息缺一不可。

1.2 一个真实的场景

假设你的 AI 客服系统突然收到用户投诉:“机器人答非所问”。在传统系统中,你只需要查看应用日志。但在 AI 系统中,你需要:

  1. 找到那条具体的请求链路(TraceId)
  2. 查看当时发送给模型的完整 Prompt(可能包含上下文历史)
  3. 查看模型返回的原始 Response
  4. 确认 Token 消耗是否正常(排除截断导致回答不完整)
  5. 检查模型参数(temperature 是否过高导致随机性太大)

如果没有可观测性体系,这几乎是一个不可能完成的任务。


二、技术架构全景

2.1 整体架构

☁️ 阿里云基础设施

🔭 可观测数据层

📦 Spring Boot 应用层

🧑‍💻 用户层

Span 上下文

TraceId 透传

自动拦截

自动拦截

自动拦截

用户请求

ChatController
/joke 端点

ChatClient
封装 AI 调用

OpenTelemetry
全局实例

ARMS Agent
自动埋点采集

链路追踪 Tracing

性能指标 Metrics

日志采集 Logging

通义千问 DashScope
大模型 API

ARMS 控制台
可视化分析

2.2 数据流向详解

📊 可视化层

💾 数据存储层

⚙️ 数据处理层

📡 数据采集端

HTTP 请求拦截

AI 模型调用拦截

数据库调用拦截

工具调用拦截

Span 组装

Trace 链路构建

指标聚合

日志关联

Trace 存储

Metrics 存储

Log 存储

调用链路图

性能大盘

AI 调用分析

异常告警


三、核心组件解析

3.1 依赖项详解(pom.xml)

<?xml version="1.0" encoding="UTF-8"?>
<project>
    <!-- Spring Boot Web:提供 RESTful API 能力 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Spring Boot Actuator:健康检查、度量端点暴露 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    <!-- Micrometer OpenTelemetry 桥接:将 Micrometer 指标转换为 OTel 格式 -->
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-tracing-bridge-otel</artifactId>
    </dependency>

    <!-- 【核心】Spring AI Alibaba ARMS 可观测性 Starter -->
    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-starter-arms-observation</artifactId>
    </dependency>

    <!-- 【核心】通义千问大模型集成 -->
    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
    </dependency>
</project>

各组件协作关系:

组件 角色定位 为什么需要它
spring-boot-starter-web HTTP 入口 接收用户请求,触发整个链路
spring-boot-starter-actuator 健康探针 暴露 /actuator/health 等端点,K8s 存活检测依赖
micrometer-tracing-bridge-otel 格式转换器 Spring 生态用 Micrometer,ARMS 用 OpenTelemetry,需要"翻译"
spring-ai-alibaba-starter-arms-observation 自动埋点引擎 核心!自动拦截 AI 调用,生成追踪数据
spring-ai-alibaba-starter-dashscope 模型连接器 封装 HTTP 调用,提供 ChatClient API

3.2 配置层级设计

☁️ 基础设施配置

🔭 观测层配置

📝 应用层配置

spring.application.name

ai.dashscope.api-key

chat.client.observations.*

log-prompt / log-completion

tracing.sampling.probability

include-error-logging

ARMS LicenseKey

ARMS RegionId

ARMS AppName

-javaagent 参数


四、配置文件深度解读

4.1 application.yml 完整配置

spring:
  application:
    name: observability-arms-dashscope  # 应用在 ARMS 控制台显示的名称

  ai:
    dashscope:
      api-key: ${AI_DASHSCOPE_API_KEY}  # 通义千问 API Key,从环境变量读取

# ==========================================
# 观测配置:控制记录哪些数据
# ==========================================
spring:
  ai:
    chat:
      # 全局聊天观测配置
      observations:
        log-prompt: true       # 记录发送给 AI 的 Prompt(调试用)
        log-completion: true   # 记录 AI 返回的 Completion(调试用)
        include-error-logging: true  # 错误时也记录

      client:
        observations:
          log-prompt: true     # ChatClient 级别的 Prompt 记录
          log-completion: true # ChatClient 级别的 Completion 记录

      # 向量存储观测
      vectorstore:
        observations:
          log-query-response: true  # 记录向量检索结果

    # 工具调用观测
    tool:
      observations:
        include-content: true   # 包含工具调用的实际内容

# ==========================================
# 基础设施配置
# ==========================================
management:
  endpoints:
    web:
      exposure:
        include: "*"           # 暴露所有 Actuator 端点(生产环境建议限制)
  endpoint:
    health:
      show-details: always     # 健康检查显示详细信息
  tracing:
    sampling:
      probability: 1.0         # 采样率:1.0 = 100%(开发环境)

# HTTP 客户端超时
http:
  client:
    read-timeout: 60s

4.2 关键配置问答

Q1: log-promptlog-completion 有什么区别?

想象你和 AI 的对话是一次书信往来:

  • log-prompt = 记录你寄出去的信(你问 AI 什么)
  • log-completion = 记录 AI回给你的信(AI 回答什么)

两者都开启后,你可以在 ARMS 控制台完整还原一次对话的上下文,这对调试"AI 为什么这样回答"至关重要。

Q2: 为什么采样率要设成 1.0?

💰 核心业务

sampling: 1.0
+ 条件采样

错误请求 100%
慢请求 100%
正常请求 10%

🏭 生产环境

sampling: 0.1~0.3

10%-30% 采样
降低性能开销
保留问题排查能力

🔍 预发/灰度环境

sampling: 0.5

50% 采样
平衡调试与性能
发现潜在问题

🧪 开发/测试环境

sampling: 1.0

100% 采样
每请求都追踪
便于调试问题


五、核心代码逐行解析

5.1 启动类:为什么要手动提供 OpenTelemetry?

@SpringBootApplication
public class ObservabilityApplication {

    public static void main(String[] args) {
        SpringApplication.run(ObservabilityApplication.class, args);
    }

    /**
     * 关键配置:使用 ARMS Agent 提供的全局 OpenTelemetry 实例
     * 
     * 原理说明:
     * ARMS Java Agent 在 JVM 启动时(premain阶段)就已经初始化了一套完整的
     * OpenTelemetry SDK,包括 TracerProvider、SpanProcessor、Exporter 等。
     * 
     * 如果不配置这个 Bean,Spring AI 会尝试自己创建一套 OTel 实例,
     * 导致两套体系并存,追踪数据无法关联,TraceId 传递中断。
     * 
     * 通过 GlobalOpenTelemetry.get(),我们显式声明:
     * "使用 Agent 已经初始化好的全局实例,不要重复创建"
     */
    @Bean
    public OpenTelemetry openTelemetry() {
        return GlobalOpenTelemetry.get();
    }
}

5.2 控制器:极简设计背后的深意

@RestController
public class ChatController {

    private final ChatClient chatClient;

    public ChatController(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    @GetMapping("/joke")
    public Map<String, String> joke() {
        // 1. 调用 AI 模型(这一行会被 ARMS 自动拦截并生成 Span)
        var reply = chatClient
            .prompt()
            .user("Tell me a joke. be concise.")
            .call()
            .content();

        // 2. 获取当前追踪上下文中的 TraceId
        //    这个 TraceId 贯穿了整个请求链路:HTTP -> ChatClient -> DashScope API
        Span currentSpan = Span.current();
        String traceId = currentSpan.getSpanContext().getTraceId();

        // 3. 将 TraceId 返回给客户端
        //    价值:当用户反馈"某个回答有问题"时,你只需要问用户要这个 traceId,
        //    就能在 ARMS 控制台精准定位到那条调用链路
        return Map.of(
            "joke", reply,
            "traceId", traceId
        );
    }
}

5.3 调用链路时序图

ARMS 控制台 通义千问 API Spring AI ChatClient ARMS Agent 自动埋点 Spring Boot 8080端口 用户 ARMS 控制台 通义千问 API Spring AI ChatClient ARMS Agent 自动埋点 Spring Boot 8080端口 用户 整个过程:业务代码零侵入, 只需在返回时手动提取 traceId GET /joke 1 [自动] 创建 Root Span traceId: abc123 2 chatClient.prompt().call() 3 [自动] 创建 AI Span parent: abc123 4 HTTP POST /api/v1/services/aigc/... 5 返回 joke 内容 6 [自动] 结束 AI Span 记录 latency、token 用量 7 [手动] 获取当前 Span 提取 traceId 8 {"joke":"...","traceId":"abc123"} 9 异步上报 Trace 数据 10

5.4 扩展示例:带参数的笑话生成

@GetMapping("/joke")
public Map<String, String> joke(@RequestParam(defaultValue = "funny") String type) {

    // 根据类型构造不同提示词
    String prompt = switch (type) {
        case "dad" -> "Tell me a dad joke. be concise.";
        case "tech" -> "Tell me a programming joke. be concise.";
        case "dark" -> "Tell me a dark humor joke. be concise.";
        default -> "Tell me a joke. be concise.";
    };

    var reply = chatClient
        .prompt()
        .user(prompt)
        .call()
        .content();

    Span currentSpan = Span.current();

    // 将类型参数也加入返回,便于在 ARMS 中按类型筛选分析
    return Map.of(
        "joke", reply,
        "traceId", currentSpan.getSpanContext().getTraceId(),
        "type", type,
        "timestamp", Instant.now().toString()
    );
}

六、Java Agent 原理:为什么能做到零代码侵入?

6.1 Java Agent 技术本质

ARMS 云端 业务应用 字节码增强引擎 ARMS Java Agent JVM 启动 ARMS 云端 业务应用 字节码增强引擎 ARMS Java Agent JVM 启动 在 main 方法执行前完成 在方法前后插入 span.start() / span.end() loop [类加载时] 无需修改任何业务代码! 1. 加载 -javaagent 参数指定的 JAR 1 2. 执行 premain() 方法 2 3. 注册 ClassFileTransformer 3 4. 启动应用 main() 4 5. 加载类(如 ChatController) 5 6. 匹配目标方法 6 7. 注入追踪代码 7 8. 执行业务逻辑 8 9. 上报追踪数据 9

6.2 字节码增强具体做了什么?

ChatClient.call() 方法为例,Agent 会在运行时将其字节码从:

// 原始方法(你写的)
public String call() {
    // 发送 HTTP 请求到 DashScope
    // 返回 AI 响应
}

增强为:

// 增强后的方法(运行时自动生成,你看不到)
public String call() {
    Span span = tracer.spanBuilder("ai.chat").startSpan();  // Agent 插入
    try {
        // 发送 HTTP 请求到 DashScope
        // 返回 AI 响应
        span.setStatus(StatusCode.OK);  // Agent 插入
    } catch (Exception e) {
        span.recordException(e);        // Agent 插入
        throw e;
    } finally {
        span.end();                     // Agent 插入
    }
}

6.3 ARMS Agent 的覆盖范围

拦截目标 采集内容 价值
HTTP 请求 请求方法、URL、状态码、耗时 了解接口整体健康度
AI 模型调用 Prompt、Completion、Token 数、模型名 核心!调试 AI 行为
数据库访问 SQL 语句、执行耗时、返回行数 定位慢查询
Redis 操作 命令类型、Key 模式、耗时 发现缓存问题
工具调用 工具名、参数、返回结果 调试 Function Calling
异常抛出 异常类型、堆栈、上下文 快速定位根因

七、部署实操指南

7.1 环境准备检查清单

# 快速检查环境
java -version && mvn -version

# 预期输出:
# openjdk version "17.0.x" 202x-xx-xx
# Apache Maven 3.8.x

7.2 阿里云账号准备

  1. 开通 ARMS 服务

    • 访问 ARMS 控制台
    • 首次进入按提示开通(有免费额度)
    • 进入「应用监控」→「接入中心」获取 LicenseKey
  2. 开通 DashScope

7.3 本地启动完整流程

# 1. 进入项目目录
cd /home/tht/examples-main/spring-ai-alibaba-observability-example/observability-arms-example

# 2. 配置环境变量(替换成你的真实 Key)
export AI_DASHSCOPE_API_KEY="sk-xxxxxxxxxxxxxxxx"
export ARMS_LICENSE_KEY="xxxx-xxxx-xxxx-xxxx"
export ARMS_APP_NAME="my-ai-demo"
export ARMS_REGION_ID="cn-hangzhou"

# 3. 构建项目
mvn clean package -Dmvn.test.skip=true

# 4. 启动应用(关键:必须挂载 Java Agent)
java   -javaagent:./src/javaagent/AliyunJavaAgent/aliyun-java-agent.jar   -Darms.licenseKey=${ARMS_LICENSE_KEY}   -Darms.appName=${ARMS_APP_NAME}   -Daliyun.javaagent.regionId=${ARMS_REGION_ID}   -jar ./target/observability-arms-example-1.0.0.jar

7.4 验证服务

# 测试接口
curl http://localhost:8080/joke

# 预期返回:
# {
#   "joke": "Why don't scientists trust atoms? Because they make up everything!",
#   "traceId": "abc123def4567890abc123def4567890"
# }

# 健康检查
curl http://localhost:8080/actuator/health

八、Docker 部署(生产推荐)

8.1 多阶段构建 Dockerfile

# 阶段一:构建
FROM eclipse-temurin:17-jdk-alpine AS builder

WORKDIR /app
COPY pom.xml .
COPY src ./src

RUN apk add --no-cache maven &&     mvn clean package -Dmvn.test.skip=true

# 阶段二:运行
FROM eclipse-temurin:17-jre-alpine

WORKDIR /app

# 复制构建产物
COPY --from=builder /app/target/observability-arms-example-1.0.0.jar app.jar

# 复制 ARMS Agent(关键!)
COPY --from=builder /app/src/javaagent ./javaagent

# 环境变量(生产环境建议用 K8s Secret 注入)
ENV AI_DASHSCOPE_API_KEY=""
ENV ARMS_LICENSE_KEY=""
ENV ARMS_APP_NAME="docker-ai-demo"
ENV ARMS_REGION_ID="cn-hangzhou"

EXPOSE 8080

# 启动命令
ENTRYPOINT ["sh", "-c", "java   -javaagent:./javaagent/AliyunJavaAgent/aliyun-java-agent.jar   -Darms.licenseKey=${ARMS_LICENSE_KEY}   -Darms.appName=${ARMS_APP_NAME}   -Daliyun.javaagent.regionId=${ARMS_REGION_ID}   -jar app.jar"]

8.2 构建与运行

# 构建镜像
docker build -t my-ai-observability:latest .

# 运行容器
docker run -d   -p 8080:8080   -e AI_DASHSCOPE_API_KEY=sk-xxxxxxxx   -e ARMS_LICENSE_KEY=xxxx-xxxx   -e ARMS_APP_NAME=my-docker-demo   -e ARMS_REGION_ID=cn-hangzhou   --name my-ai-app   my-ai-observability:latest

九、Kubernetes 部署(企业级)

9.1 完整 Deployment 配置

apiVersion: apps/v1
kind: Deployment
metadata:
  name: arms-observability-demo
  labels:
    app: arms-observability-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: arms-observability-demo
  template:
    metadata:
      labels:
        app: arms-observability-demo
    spec:
      containers:
      - name: app
        image: my-ai-observability:latest
        ports:
        - containerPort: 8080
        env:
        # API Key 通过 Secret 注入(安全最佳实践)
        - name: AI_DASHSCOPE_API_KEY
          valueFrom:
            secretKeyRef:
              name: ai-secrets
              key: dashscope-api-key
        # ARMS 配置
        - name: ARMS_LICENSE_KEY
          valueFrom:
            secretKeyRef:
              name: arms-secrets
              key: license-key
        - name: ARMS_APP_NAME
          value: "k8s-ai-demo"
        - name: ARMS_REGION_ID
          value: "cn-hangzhou"
        # 资源限制
        resources:
          requests:
            memory: "512Mi"
            cpu: "500m"
          limits:
            memory: "1Gi"
            cpu: "1000m"
        # 存活探针
        livenessProbe:
          httpGet:
            path: /actuator/health/liveness
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
        # 就绪探针
        readinessProbe:
          httpGet:
            path: /actuator/health/readiness
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
  name: ai-observability-service
spec:
  selector:
    app: arms-observability-demo
  ports:
  - port: 80
    targetPort: 8080
  type: ClusterIP

9.2 创建 Secret

# 创建 API Key Secret
kubectl create secret generic ai-secrets   --from-literal=dashscope-api-key=sk-xxxxxxxxxxxxxxxx

# 创建 ARMS License Secret
kubectl create secret generic arms-secrets   --from-literal=license-key=xxxx-xxxx-xxxx-xxxx

# 部署
kubectl apply -f deployment.yaml

# 查看状态
kubectl get pods -w

十、问题排查完全手册

10.1 问题排查决策树

遇到问题?

ARMS 控制台
能看到应用?

应用启动日志
有 ARMS 字样?

能看到
调用链路?

检查 -javaagent
参数是否正确

检查 LicenseKey
和网络连通性

请求是否
到达应用?

TraceId
是否为空?

检查端口和
防火墙配置

检查采样率
是否为 0

ARMS Agent
未正确挂载

AI 调用
是否成功?

检查 API Key
和 DashScope 额度

一切正常!
🎉

重新配置
启动参数

确认 RegionId
和 LicenseKey

curl 测试
连通性

修改采样率
为 1.0

重启应用
挂载 Agent

充值或更换
API Key

10.2 常见问题速查表

现象 根因 解决方案
启动报 Agent jar not found -javaagent 路径错误 使用绝对路径或确认相对路径正确
控制台无应用数据 LicenseKey 错误或网络不通 telnet arms-apm-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com 443
有应用但无链路 采样率为 0 检查 tracing.sampling.probability
TraceId 为空 Agent 未挂载 `ps aux
AI 返回 401 API Key 无效 在 DashScope 控制台重新生成
启动端口冲突 8080 被占用 server.port=8081 或杀掉占用进程
构建失败 Maven 版本过低 升级至 3.8+

10.3 日志排查命令

# 1. 确认 Agent 是否加载
grep -i "arms\|agent" logs/application.log

# 2. 查看 JVM 参数确认 Agent 挂载
jps -lvm | grep javaagent

# 3. 测试网络连通性
curl -v https://arms-apm-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com

# 4. 查看应用实时日志
tail -f logs/application.log | grep -E "(ARMS|traceId|ERROR)"

十一、Token 成本监控与优化

11.1 为什么 Token 监控是 AI 应用特有的?

🔧 成本优化手段

🚨 成本告警策略

📐 计费维度

💰 Token 成本采集

Input Tokens
输入提示词

Output Tokens
模型生成内容

Total Tokens
总消耗

按模型区分
qwen-turbo vs qwen-plus

按接口区分
/joke vs /chat

按用户区分
用户级别成本

按时间区分
小时/日/月趋势

单请求 Token 超限
> 4000 tokens

日消耗超预算
> 1000元/天

QPS 异常突增
可能是循环调用

错误率上升
无效 Token 浪费

Prompt 压缩
减少输入长度

模型降级
turbo 替代 plus

缓存命中
相似请求复用

流式响应
减少等待超时

11.2 Prometheus 告警规则示例

groups:
  - name: ai-application-alerts
    rules:
      # 告警一:Token 消耗突增(可能是异常循环或攻击)
      - alert: AiTokenUsageSpike
        expr: |
          rate(gen_ai_client_token_usage_tokens_total[5m]) > 10000
        for: 2m
        labels:
          severity: warning
        annotations:
          summary: "AI Token 消耗速率异常"
          description: "过去5分钟 Token 消耗速率超过10000/min"

      # 告警二:AI 服务响应超时(P99 > 30秒)
      - alert: AiResponseLatencyHigh
        expr: |
          histogram_quantile(0.99,
            rate(gen_ai_client_operation_duration_seconds_bucket[5m])) > 30
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "AI 服务响应延迟过高"

      # 告警三:AI 服务错误率超阈值
      - alert: AiErrorRateHigh
        expr: |
          rate(gen_ai_client_operation_error_total[5m]) /
          rate(gen_ai_client_operation_duration_seconds_count[5m]) > 0.05
        for: 3m
        labels:
          severity: critical
        annotations:
          summary: "AI 服务错误率超过 5%"

十二、扩展:开源方案 vs 阿里云 ARMS

12.1 方案对比

🎯 选型建议

🔓 开源组合方案

✅ 完全免费
无商业依赖

✅ 可私有化
数据自主可控

✅ 社区活跃
生态丰富

❌ 需自行搭建
Prometheus + Grafana + Jaeger

❌ 配置复杂
需手动埋点

❌ 无 AI 专属
需自定义大盘

☁️ 阿里云 ARMS 方案

✅ 零代码侵入
Agent 自动埋点

✅ 开箱即用
无需搭建存储

✅ AI 专属视图
LLM 调用分析

✅ 智能告警
自动异常检测

❌ 商业服务
按量付费

❌ 阿里云绑定
无法私有化

快速验证 / POC
→ ARMS

生产环境 / 大规模
→ ARMS

成本敏感 / 私有化
→ 开源方案

学习目的 / 个人项目
→ 开源方案

12.2 开源替代方案依赖

如果你选择开源路线,需要引入以下依赖:

<!-- Prometheus 指标暴露 -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

<!-- OTLP 协议导出 -->
<dependency>
    <groupId>io.opentelemetry</groupId>
    <artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>

然后自己搭建:

  • Prometheus:指标存储与查询
  • Grafana:可视化大盘
  • Jaeger/Zipkin:链路追踪存储与展示

十三、一键启动脚本

#!/bin/bash
set -e

# ==========================================
# Spring AI Alibaba + ARMS 一键启动脚本
# ==========================================

PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)"

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# 请修改以下配置!
export AI_DASHSCOPE_API_KEY="${AI_DASHSCOPE_API_KEY:-sk-你的通义千问Key}"
export ARMS_LICENSE_KEY="${ARMS_LICENSE_KEY:-你的ARMS许可证Key}"
export ARMS_APP_NAME="${ARMS_APP_NAME:-my-arms-demo}"
export ARMS_REGION_ID="${ARMS_REGION_ID:-cn-hangzhou}"

echo -e "${GREEN}🚀 Spring AI Alibaba + ARMS 可观测性演示${NC}"
echo "================================================"

# 检查环境
echo -e "${YELLOW}📋 检查环境...${NC}"
if ! command -v java &> /dev/null; then
    echo -e "${RED}❌ Java 未安装${NC}"; exit 1
fi
if ! command -v mvn &> /dev/null; then
    echo -e "${RED}❌ Maven 未安装${NC}"; exit 1
fi

java -version 2>&1 | head -1
mvn -version 2>&1 | head -1

# 检查环境变量
if [ -z "$AI_DASHSCOPE_API_KEY" ] || [ "$AI_DASHSCOPE_API_KEY" = "sk-你的通义千问Key" ]; then
    echo -e "${RED}❌ 请设置 AI_DASHSCOPE_API_KEY 环境变量${NC}"
    exit 1
fi

if [ -z "$ARMS_LICENSE_KEY" ] || [ "$ARMS_LICENSE_KEY" = "你的ARMS许可证Key" ]; then
    echo -e "${RED}❌ 请设置 ARMS_LICENSE_KEY 环境变量${NC}"
    exit 1
fi

echo -e "${GREEN}✅ 环境检查通过${NC}"

# 构建项目
echo -e "${YELLOW}🔨 构建项目...${NC}"
cd "$PROJECT_DIR"
mvn clean package -Dmvn.test.skip=true -q

if [ ! -f "./target/observability-arms-example-1.0.0.jar" ]; then
    echo -e "${RED}❌ 构建失败,JAR 文件未生成${NC}"
    exit 1
fi

echo -e "${GREEN}✅ 构建成功${NC}"

# 检查 Agent
AGENT_JAR="./src/javaagent/AliyunJavaAgent/aliyun-java-agent.jar"
if [ ! -f "$AGENT_JAR" ]; then
    echo -e "${RED}❌ ARMS Agent 未找到: $AGENT_JAR${NC}"
    exit 1
fi

echo -e "${GREEN}✅ Agent 文件存在${NC}"

# 启动应用
echo -e "${YELLOW}🚀 启动应用...${NC}"
echo -e "${YELLOW}   应用名称: $ARMS_APP_NAME${NC}"
echo -e "${YELLOW}   地域: $ARMS_REGION_ID${NC}"
echo "================================================"

java   -javaagent:"$AGENT_JAR"   -Darms.licenseKey="$ARMS_LICENSE_KEY"   -Darms.appName="$ARMS_APP_NAME"   -Daliyun.javaagent.regionId="$ARMS_REGION_ID"   -jar ./target/observability-arms-example-1.0.0.jar

保存为 start.sh,执行:

chmod +x start.sh
./start.sh

十四、总结与进阶路径

14.1 本项目核心价值

🧠 关联分析能力

🔭 可观测性三大支柱

📝 Logging
日志

Prompt 内容

Completion 内容

异常堆栈

业务日志

🔗 Tracing
链路

请求链路图

Span 耗时分析

跨服务追踪

AI 调用详情

📊 Metrics
指标

QPS / 延迟

Token 消耗

错误率

JVM 内存/CPU

通过 TraceId 串联
Metrics + Traces + Logs

AI 调用成本核算

异常根因定位

14.2 你已经掌握了什么?

零代码侵入的可观测性:通过 Java Agent 实现,业务代码完全无感知
AI 调用全链路追踪:从 HTTP 请求到模型响应,每个环节清晰可见
Prompt/Completion 审计:完整记录 AI 对话内容,满足合规要求
Token 成本监控:精细化追踪每个请求的 Token 消耗,控制成本
多环境部署:本地、Docker、K8s 全覆盖

14.3 下一步进阶方向

  1. 接入 Spring AI Alibaba Graph:构建多 Agent 工作流,观测更复杂的编排场景
  2. 集成 Nacos MCP Registry:实现 MCP 工具的分布式注册与可观测
  3. 自定义业务埋点:在关键业务节点手动添加 Span,细化追踪粒度
  4. 配置 ARMS 告警:设置 Token 消耗、延迟、错误率的自动告警规则
  5. 接入 Higress AI 网关:在网关层实现统一的 AI 流量治理与观测

📚 参考资源

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐