AI 工程化第四篇】Spring AI Agent 线上可观测实战:Token 成本、调用链、工具耗时、RAG 命中率怎么监控

【AI 工程化第四篇】Spring AI Agent 线上可观测实战:Token 成本、调用链、工具耗时、RAG 命中率怎么监控

系列定位:

第一篇:搭 Agent 服务。

第二篇:接 RAG 知识库。

第三篇:用 MCP / Tool Calling 让 Agent 调用业务系统。

第四篇:把 Agent 放到线上之后,如何知道它"慢在哪、贵在哪、错在哪"。

技术栈:Java 17 · Spring Boot 4.1.x / 3.5.x · Spring AI 2.0.x · Actuator · Micrometer · Prometheus · Grafana · OpenTelemetry

适用场景:AI 网关、企业知识助手、智能客服、订单 Agent、内部 Copilot

阅读前置:会用 Spring Boot Actuator 即可


为什么 AI 应用比普通后端更需要可观测

普通后端接口出问题,通常看三件事:

text 复制代码
接口耗时
错误日志
数据库 / Redis / MQ 状态

AI Agent 上线后,问题会复杂很多:

text 复制代码
为什么这次回答花了 12 秒?
为什么昨天 Token 成本突然翻倍?
为什么 RAG 明明有资料却没召回?
为什么模型重复调用同一个工具?
为什么用户说 AI 胡说八道,但日志里看不到上下文?

如果没有可观测体系,AI 应用上线后就会变成一个黑盒:

text 复制代码
用户问了什么,不知道
模型用了多少 token,不知道
RAG 召回了什么,不知道
工具调用成功没,不知道
慢在模型、向量库还是 MCP,不知道

这篇文章就解决这个问题。

目标不是"打印几行日志",而是搭一个生产可用的观测闭环:

text 复制代码
日志:能定位单次问题
指标:能看整体趋势
链路:能看一次请求经过哪些环节
审计:能回放 AI 当时为什么这么回答
告警:能在成本、错误、延迟异常时提前发现

一、先看最终效果

上线后,我们希望每次 Agent 请求都有这些数据:

json 复制代码
{
  "traceId": "b7f42f23c9d94b9e8d8a90d0c1f3a110",
  "conversationId": "conv-001",
  "scene": "order-agent",
  "model": "gpt-4.1-mini",
  "promptTokens": 1840,
  "completionTokens": 286,
  "totalTokens": 2126,
  "ragTopK": 6,
  "ragHitCount": 4,
  "toolCallCount": 2,
  "costMillis": 4238,
  "success": true
}

Grafana 面板至少要有这些图:

text 复制代码
QPS / 错误率 / P95 延迟
Token 总量 / 单次平均 Token / 按模型拆分成本
RAG 召回命中率 / 低分召回占比 / 向量检索耗时
工具调用次数 / 工具失败率 / 工具 P95 耗时
模型调用失败率 / 超时率 / 重试次数

这才是 Agent 能上线运营的基础。


二、Spring AI 已经内置了哪些观测能力

Spring AI 2.0.1 已经基于 Micrometer 提供了核心观测能力,覆盖:

组件 观测能力
ChatClient call() / stream() 调用耗时、Advisor、工具名、会话信息
ChatModel 模型调用耗时、输入/输出 Token、模型名
EmbeddingModel embedding 调用耗时、Token、向量维度
VectorStore query / add / remove 操作耗时、向量库信息
Tool Calling 工具名、工具类型、工具调用耗时、trace 上下文

官方文档里有几个关键点要记住:

  1. Spring AI 使用 Micrometer。
  2. ChatModel 提供 gen_ai.client.token.usage 指标,用于统计 Token。
  3. Prompt、Completion、工具参数、工具结果默认不会导出,因为可能包含敏感信息。
  4. spring.ai.tools.observations.include-content=true 可以导出工具入参和结果,但生产环境要非常谨慎。
  5. VectorStore 操作也有观测,名称是 db.vector.client.operation。

换句话说,Spring AI 已经帮我们打好了底座。

但只靠框架内置指标还不够。

业务侧还需要补充:

text 复制代码
conversationId
userId
tenantId
业务场景 scene
RAG 命中情况
工具调用审计
单次请求总成本
业务失败原因

三、整体架构设计

3.1 功能模块图

text 复制代码
┌────────────────────────────────────────────────────────────────────┐
│                         前端 / 调用方                                │
│            Web · 企业微信 · 钉钉 · 内部客服系统                        │
└─────────────────────────────┬──────────────────────────────────────┘
                              │
┌─────────────────────────────▼──────────────────────────────────────┐
│                         AI Agent 应用                               │
│                                                                    │
│  Controller                                                        │
│    - 生成 traceId                                                   │
│    - 参数校验                                                       │
│    - MDC 日志上下文                                                  │
│                                                                    │
│  AgentService                                                      │
│    - ChatClient                                                     │
│    - RAG Advisor / VectorStore                                      │
│    - Tool Calling / MCP                                             │
│    - AI 调用日志                                                     │
│                                                                    │
│  Observability Layer                                               │
│    - Micrometer Metrics                                             │
│    - Observation / Tracing                                          │
│    - Tool Audit                                                     │
│    - RAG Hit Log                                                    │
└───────────────┬────────────────────┬───────────────────────────────┘
                │                    │
┌───────────────▼────────────┐ ┌─────▼──────────────────────────────┐
│      Prometheus             │ │          OpenTelemetry / Tempo      │
│  拉取 /actuator/prometheus   │ │          Trace 链路追踪             │
└───────────────┬────────────┘ └─────┬──────────────────────────────┘
                │                    │
┌───────────────▼────────────────────▼──────────────────────────────┐
│                         Grafana Dashboard                          │
│       延迟 · 错误率 · Token 成本 · RAG 命中 · 工具耗时 · 告警         │
└────────────────────────────────────────────────────────────────────┘

3.2 单次请求链路

text 复制代码
用户请求
  -> Controller 生成 traceId
  -> ChatClient observation
  -> RAG Advisor observation
  -> VectorStore query observation
  -> ChatModel observation
  -> Tool Calling observation
  -> MCP / 业务工具
  -> Usage 汇总
  -> 业务日志表落库
  -> Micrometer 指标上报

这条链路里,至少要能回答三个问题:

text 复制代码
慢在哪:ChatModel / VectorStore / Tool / DB
贵在哪:哪个模型、哪个场景、哪个租户 token 高
错在哪:RAG 召回错、工具调用错、模型输出错、业务权限错

四、依赖配置

4.1 Maven 依赖

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webmvc</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-prometheus</artifactId>
    </dependency>

    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-tracing-bridge-otel</artifactId>
    </dependency>

    <dependency>
        <groupId>io.opentelemetry</groupId>
        <artifactId>opentelemetry-exporter-otlp</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-openai</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-vector-store-pgvector</artifactId>
    </dependency>
</dependencies>

4.2 application.yml

yaml 复制代码
spring:
  application:
    name: ai-agent-app

  ai:
    model:
      chat: openai
      embedding: openai

    openai:
      api-key: ${OPENAI_API_KEY}
      base-url: ${OPENAI_BASE_URL:https://api.openai.com}
      chat:
        model: gpt-4.1-mini
        temperature: 0.2

    # 生产环境不建议打开 prompt / completion 全量日志
    chat:
      observations:
        log-prompt: false
        log-completion: false
        include-error-logging: true
      client:
        observations:
          log-prompt: false
          log-completion: false

    tools:
      observations:
        include-content: false
      limits:
        max-calls-per-tool-default: 3
        max-total-tool-calls: 8
        on-limit-exceeded: RETURN_ERROR_RESPONSE

management:
  endpoints:
    web:
      exposure:
        include: health,info,prometheus,metrics
  endpoint:
    health:
      probes:
        enabled: true
  metrics:
    tags:
      application: ${spring.application.name}
  tracing:
    sampling:
      probability: 1.0
  otlp:
    tracing:
      endpoint: http://localhost:4318/v1/traces

注意:如果你的 Prompt 里可能包含手机号、订单号、客户资料、合同内容,不要在生产环境开启 log-prompt 和 include-content。调试环境也建议脱敏后再打开。


五、核心表结构

内置 Micrometer 指标适合看趋势,业务表适合追溯单次请求。

这两个都要有。

5.1 AI 调用日志表

sql 复制代码
CREATE TABLE t_ai_call_log (
    id                 BIGSERIAL PRIMARY KEY,
    trace_id           VARCHAR(64)  NOT NULL,
    conversation_id    VARCHAR(64),
    tenant_id          VARCHAR(64)  NOT NULL DEFAULT 'default',
    user_id            VARCHAR(64),
    scene              VARCHAR(64)  NOT NULL,
    model              VARCHAR(64),
    prompt_tokens      INT          DEFAULT 0,
    completion_tokens  INT          DEFAULT 0,
    total_tokens       INT          DEFAULT 0,
    rag_hit_count      INT          DEFAULT 0,
    tool_call_count    INT          DEFAULT 0,
    cost_millis        BIGINT       DEFAULT 0,
    success            BOOLEAN      DEFAULT TRUE,
    error_type         VARCHAR(64),
    error_msg          VARCHAR(500),
    create_time        TIMESTAMP    DEFAULT now()
);

CREATE INDEX idx_ai_call_trace ON t_ai_call_log(trace_id);
CREATE INDEX idx_ai_call_scene_time ON t_ai_call_log(scene, create_time DESC);

5.2 RAG 命中日志表

sql 复制代码
CREATE TABLE t_ai_rag_hit_log (
    id              BIGSERIAL PRIMARY KEY,
    trace_id        VARCHAR(64) NOT NULL,
    conversation_id VARCHAR(64),
    kb_code         VARCHAR(64) NOT NULL,
    user_query      TEXT        NOT NULL,
    chunk_id        VARCHAR(64) NOT NULL,
    document_id     VARCHAR(64) NOT NULL,
    score           NUMERIC(8, 6),
    rank_no         INT         NOT NULL,
    create_time     TIMESTAMP   NOT NULL DEFAULT now()
);

CREATE INDEX idx_rag_hit_trace ON t_ai_rag_hit_log(trace_id);

5.3 工具调用日志表

sql 复制代码
CREATE TABLE t_ai_tool_call_log (
    id              BIGSERIAL PRIMARY KEY,
    trace_id        VARCHAR(64)  NOT NULL,
    conversation_id VARCHAR(64),
    tenant_id       VARCHAR(64)  NOT NULL,
    user_id         VARCHAR(64)  NOT NULL,
    tool_name       VARCHAR(128) NOT NULL,
    success         BOOLEAN      NOT NULL DEFAULT TRUE,
    error_msg       VARCHAR(500),
    cost_millis     BIGINT       NOT NULL DEFAULT 0,
    create_time     TIMESTAMP    NOT NULL DEFAULT now()
);

CREATE INDEX idx_tool_log_trace ON t_ai_tool_call_log(trace_id);
CREATE INDEX idx_tool_log_name_time ON t_ai_tool_call_log(tool_name, create_time DESC);

六、TraceId 过滤器

所有日志、指标、数据库记录都要能通过 traceId 串起来。

java 复制代码
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.UUID;

@Component
public class TraceIdFilter extends OncePerRequestFilter {

    public static final String TRACE_ID = "traceId";

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain)
            throws ServletException, IOException {
        String traceId = request.getHeader("X-Trace-Id");
        if (traceId == null || traceId.isBlank()) {
            traceId = UUID.randomUUID().toString().replace("-", "");
        }

        try {
            MDC.put(TRACE_ID, traceId);
            response.setHeader("X-Trace-Id", traceId);
            filterChain.doFilter(request, response);
        } finally {
            MDC.remove(TRACE_ID);
        }
    }
}

日志格式建议带上 traceId:

yaml 复制代码
logging:
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%X{traceId}] [%thread] %logger{36} - %msg%n"

七、业务指标 Recorder

不要把所有维度都塞进 Prometheus 标签。

低基数标签可以放:

text 复制代码
scene
model
result
toolName
kbCode

高基数字段不要放:

text 复制代码
userId
conversationId
traceId
orderNo
message

这些应该进日志或数据库。

java 复制代码
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.DistributionSummary;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.stereotype.Component;

import java.time.Duration;

@Component
public class AiMetricsRecorder {

    private final MeterRegistry meterRegistry;

    public AiMetricsRecorder(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }

    public void recordCall(String scene,
                           String model,
                           boolean success,
                           int totalTokens,
                           Duration cost) {
        String result = success ? "success" : "fail";

        Counter.builder("ai_agent_requests_total")
                .tag("scene", scene)
                .tag("model", model)
                .tag("result", result)
                .register(meterRegistry)
                .increment();

        DistributionSummary.builder("ai_agent_tokens_total")
                .tag("scene", scene)
                .tag("model", model)
                .register(meterRegistry)
                .record(totalTokens);

        Timer.builder("ai_agent_request_duration")
                .tag("scene", scene)
                .tag("model", model)
                .tag("result", result)
                .publishPercentileHistogram()
                .register(meterRegistry)
                .record(cost);
    }

    public void recordRag(String kbCode, int hitCount, Duration cost) {
        DistributionSummary.builder("ai_rag_hit_count")
                .tag("kbCode", kbCode)
                .register(meterRegistry)
                .record(hitCount);

        Timer.builder("ai_rag_retrieve_duration")
                .tag("kbCode", kbCode)
                .publishPercentileHistogram()
                .register(meterRegistry)
                .record(cost);
    }

    public void recordTool(String toolName, boolean success, Duration cost) {
        Timer.builder("ai_tool_call_duration")
                .tag("toolName", toolName)
                .tag("result", success ? "success" : "fail")
                .publishPercentileHistogram()
                .register(meterRegistry)
                .record(cost);

        Counter.builder("ai_tool_calls_total")
                .tag("toolName", toolName)
                .tag("result", success ? "success" : "fail")
                .register(meterRegistry)
                .increment();
    }
}

八、AgentService 中记录 Token、耗时、RAG、工具

Spring AI 的 ChatResponse 可以拿到 Usage。

官方文档里有一个关键点:如果一次 ChatClient 请求触发了工具调用 loop,getUsage() 返回的是整个多步流程累计 Token,而不只是最后一次模型调用。

这对成本统计非常有用。

java 复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.metadata.Usage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.Instant;

@Service
public class ObservableAgentService {

    private static final Logger log = LoggerFactory.getLogger(ObservableAgentService.class);

    private final ChatClient chatClient;
    private final JdbcTemplate jdbcTemplate;
    private final AiMetricsRecorder metricsRecorder;

    public ObservableAgentService(ChatClient.Builder chatClientBuilder,
                                  JdbcTemplate jdbcTemplate,
                                  AiMetricsRecorder metricsRecorder) {
        this.chatClient = chatClientBuilder.build();
        this.jdbcTemplate = jdbcTemplate;
        this.metricsRecorder = metricsRecorder;
    }

    public String chat(String scene, String conversationId, String userId, String message) {
        String traceId = MDC.get("traceId");
        Instant start = Instant.now();
        Usage usage = null;
        boolean success = false;
        String errorType = null;
        String errorMsg = null;

        try {
            ChatResponse response = chatClient.prompt()
                    .system("你是企业 AI Agent,请基于知识库和工具结果回答。")
                    .user(message)
                    .call()
                    .chatResponse();

            usage = response.getMetadata().getUsage();
            success = true;
            return response.getResult().getOutput().getText();
        } catch (Exception ex) {
            errorType = ex.getClass().getSimpleName();
            errorMsg = ex.getMessage();
            log.error("Agent调用失败 traceId={}, scene={}, conversationId={}",
                    traceId, scene, conversationId, ex);
            throw new BizException("AI 服务暂时不可用,请稍后重试");
        } finally {
            long costMillis = Duration.between(start, Instant.now()).toMillis();
            int promptTokens = usage == null ? 0 : usage.getPromptTokens();
            int completionTokens = usage == null ? 0 : usage.getCompletionTokens();
            int totalTokens = usage == null ? 0 : usage.getTotalTokens();

            jdbcTemplate.update("""
                    INSERT INTO t_ai_call_log
                    (trace_id, conversation_id, tenant_id, user_id, scene, model,
                     prompt_tokens, completion_tokens, total_tokens,
                     cost_millis, success, error_type, error_msg)
                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                    """,
                    traceId,
                    conversationId,
                    "default",
                    userId,
                    scene,
                    "gpt-4.1-mini",
                    promptTokens,
                    completionTokens,
                    totalTokens,
                    costMillis,
                    success,
                    errorType,
                    errorMsg
            );

            metricsRecorder.recordCall(
                    scene,
                    "gpt-4.1-mini",
                    success,
                    totalTokens,
                    Duration.ofMillis(costMillis)
            );

            log.info("Agent调用完成 traceId={}, scene={}, conversationId={}, promptTokens={}, completionTokens={}, totalTokens={}, costMillis={}, success={}",
                    traceId, scene, conversationId, promptTokens, completionTokens, totalTokens, costMillis, success);
        }
    }
}

九、RAG 命中率怎么监控

RAG 的观测不能只看向量库耗时。

还要看:

text 复制代码
topK 召回了几条
平均 score
最低 score
低于阈值的比例
最终引用了几条
用户是否追问"你答错了"

示例代码:

java 复制代码
import org.springframework.ai.document.Document;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.Instant;
import java.util.List;

@Service
public class RagObserveService {

    private final JdbcTemplate jdbcTemplate;
    private final AiMetricsRecorder metricsRecorder;

    public RagObserveService(JdbcTemplate jdbcTemplate,
                             AiMetricsRecorder metricsRecorder) {
        this.jdbcTemplate = jdbcTemplate;
        this.metricsRecorder = metricsRecorder;
    }

    public void record(String traceId,
                       String conversationId,
                       String kbCode,
                       String userQuery,
                       List<Document> docs,
                       Instant start) {
        int rank = 1;
        for (Document doc : docs) {
            jdbcTemplate.update("""
                    INSERT INTO t_ai_rag_hit_log
                    (trace_id, conversation_id, kb_code, user_query, chunk_id, document_id, score, rank_no)
                    VALUES (?, ?, ?, ?, ?, ?, ?, ?)
                    """,
                    traceId,
                    conversationId,
                    kbCode,
                    userQuery,
                    String.valueOf(doc.getMetadata().get("chunkId")),
                    String.valueOf(doc.getMetadata().get("documentId")),
                    doc.getScore() == null ? BigDecimal.ZERO : BigDecimal.valueOf(doc.getScore()),
                    rank++
            );
        }

        metricsRecorder.recordRag(kbCode, docs.size(), Duration.between(start, Instant.now()));
    }
}

推荐告警:

text 复制代码
RAG 命中数连续 10 分钟低于 1
RAG P95 检索耗时 > 1s
某知识库低分召回比例 > 30%
向量入库失败数 > 0

十、工具调用怎么监控

工具调用是 Agent 最危险的部分。

至少要监控:

text 复制代码
工具调用次数
工具失败率
工具耗时
写操作次数
重复调用次数
工具调用限制触发次数

示例:

java 复制代码
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.Instant;

@Service
public class ToolObserveService {

    private final AiMetricsRecorder metricsRecorder;
    private final ToolAuditRepository toolAuditRepository;

    public ToolObserveService(AiMetricsRecorder metricsRecorder,
                              ToolAuditRepository toolAuditRepository) {
        this.metricsRecorder = metricsRecorder;
        this.toolAuditRepository = toolAuditRepository;
    }

    public <T> T observe(String traceId,
                         String toolName,
                         ToolSupplier<T> supplier) {
        Instant start = Instant.now();
        boolean success = false;
        String errorMsg = null;
        try {
            T result = supplier.get();
            success = true;
            return result;
        } catch (Exception ex) {
            errorMsg = ex.getMessage();
            throw ex;
        } finally {
            Duration cost = Duration.between(start, Instant.now());
            metricsRecorder.recordTool(toolName, success, cost);
            toolAuditRepository.save(traceId, toolName, success, errorMsg, cost.toMillis());
        }
    }

    @FunctionalInterface
    public interface ToolSupplier<T> {
        T get();
    }
}

十一、Grafana 面板建议

11.1 总览面板

text 复制代码
AI 请求 QPS
AI 请求错误率
AI 请求 P95 / P99 延迟
Token 总消耗
平均每次 Token
模型调用成功率

11.2 RAG 面板

text 复制代码
VectorStore query P95
RAG 平均命中数
RAG 低分召回比例
Top 知识库 Token 消耗
Top 文档命中次数

11.3 Tool 面板

text 复制代码
工具调用总数
工具失败率
Top 慢工具
Top 失败工具
写操作工具调用次数
工具调用限制触发次数

11.4 成本面板

text 复制代码
按模型统计 Token
按租户统计 Token
按场景统计 Token
按用户统计 Token(只在数据库里查,不做 Prometheus 标签)
每日预估成本

十二、PromQL 示例

12.1 Agent P95 延迟

promql 复制代码
histogram_quantile(
  0.95,
  sum(rate(ai_agent_request_duration_seconds_bucket[5m])) by (le, scene)
)

12.2 Agent 错误率

promql 复制代码
sum(rate(ai_agent_requests_total{result="fail"}[5m]))
/
sum(rate(ai_agent_requests_total[5m]))

12.3 Token 消耗趋势

promql 复制代码
sum(rate(ai_agent_tokens_total_sum[5m])) by (scene, model)

12.4 工具失败率

promql 复制代码
sum(rate(ai_tool_calls_total{result="fail"}[5m])) by (toolName)
/
sum(rate(ai_tool_calls_total[5m])) by (toolName)

十三、生产环境告警规则

建议第一版先做这些:

告警项 阈值
Agent 错误率 5 分钟内 > 5%
Agent P95 延迟 5 分钟内 > 8s
Token 消耗突增 当前小时 > 过去 7 天同小时均值 2 倍
工具失败率 5 分钟内 > 10%
RAG 无命中率 10 分钟内 > 30%
模型超时 5 分钟内 > 20 次
MCP Server 不可用 health check 失败

AI 应用最容易被忽略的是成本告警。

建议每天有一条成本日报:

text 复制代码
昨日请求数:128,420
昨日 Token:1.82B
预估成本:xxx 元
Top 场景:客服问答、订单助手、研发文档
Top 用户/租户:xxx
异常增长:RAG 文档助手 +86%

十四、哪些内容不要进入观测系统

不要把这些作为 Prometheus 标签:

text 复制代码
用户原始问题
手机号
身份证
订单号
邮箱
合同号
conversationId
traceId

原因:

  1. 基数太高,会打爆指标系统。
  2. 涉及隐私和合规。
  3. 查询性能会变差。

正确做法:

text 复制代码
指标系统:低基数聚合趋势
日志系统:脱敏后的排查信息
数据库审计表:必要字段,按权限查询
对象存储:极少数问题样本,严格脱敏

十五、总结

这篇文章我们把 AI Agent 从"能跑"推进到了"可运营"。

核心结论:

  1. Spring AI 已经内置 Micrometer 观测,覆盖 ChatClient、ChatModel、Tool、VectorStore。
  2. Token 指标可以用 gen_ai.client.token.usage,业务侧还要记录单次调用 Usage。
  3. Prompt、Completion、工具参数默认不导出,生产环境不要轻易打开。
  4. RAG 观测重点是命中数、score、向量检索耗时和引用质量。
  5. Tool 观测重点是失败率、耗时、重复调用和写操作审计。
  6. Prometheus 看趋势,数据库审计表做追溯,两者缺一不可。

下一篇我准备写:

Spring AI Agent 生产治理实战:限流、熔断、降级、灰度、多模型路由

如果你想要完整工程骨架,可以在评论区留一句:

text 复制代码
观测

我会继续把这个系列写完整。


可选标题

  1. Spring AI Agent 线上可观测实战:Token 成本、RAG 命中率、工具耗时一次讲透
  2. AI 应用别裸奔上线:Spring AI + Micrometer 监控体系实战
  3. Java AI Agent 第四篇:Prometheus + Grafana 监控 Token、RAG、MCP 工具调用
  4. Spring Boot 企业 AI 应用:从日志到链路追踪的生产级可观测方案

推荐标签

Spring AI Micrometer Prometheus Grafana AI Agent RAG Spring Boot

参考资料

相关推荐
吴建旭 智宅焕1 小时前
AI时代智能家居交付知识资产架构:非业务内容作为可信信息源的系统设计
人工智能·架构·智能家居
m0_734172421 小时前
Python列表切片为什么不改变原列表
java
土星云SaturnCloud1 小时前
边缘计算 + AI 视频存管一体机:快递末端网点分拣提效与安全管控实战方案
服务器·人工智能·ai·边缘计算
kiss strong1 小时前
idea显示前进后退按钮
java·ide·intellij-idea
起个名字费劲死了1 小时前
VisionMaster集成深度学习算法(基础狗)
人工智能·深度学习·算法
制造业的搬运工1 小时前
车载 PCB 打样周期与选型指南:从 IATF 16949 到 IPC-6012 的 5 个硬指标
大数据·网络·人工智能·制造·pcb工艺
55873 生态系统1 小时前
55873 正和博弈经济模型:重构数字时代商业价值体系
大数据·人工智能·重构·全域文明操作系统·55873 操作系统·55873全域文明生态体系
法狗狗技术团队1 小时前
2026年标书审查工具测评:AI标书检查软件怎么选?
人工智能·招投标·投标·标书检查·标书审查·标书制作·投标全流程
“AI国潮设计-小江”2 小时前
【SDXL实战】用AI生成“财神爷蛋糕×英歌舞人物”潮汕国潮甜品IP,附Prompt与批量生成思路
开发语言·人工智能·python·aigc