千人级 AI 平台的可观测性:如何看清谁在用、用得好不好

2026-05-27 27 预计阅读时间:1 分钟
来源:aws.amazon.com AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:8 分钟

当企业 AI 平台从几十人试点扩展到上千人日常使用时,平台 owner 面对的核心问题变了——不再是"能不能跑起来",而是"谁在用、用得怎样、哪些能力最被需要"。这些数据散落在 CloudTrail 日志、CloudWatch 指标、S3 对话记录和 QuickSight 报表里,没有统一的视角,决策就只能靠猜。

这篇文章拆解一套面向 Amazon Q 企业版的可观测方案:从数据采集、指标定义到可视化呈现,给出可以直接落地的配置和代码。

数据从哪里来

Amazon Q 的用户交互天然产生三类数据:

  • 调用日志——每次问答请求的元信息(用户 ID、时间、调用的能力类型),通过 CloudTrail 或 VPC Flow Logs 记录。
  • 对话内容——用户提问与 AI 回答的完整文本,存储在 S3(需开启对话日志功能)。
  • 反馈信号——用户对回答的点赞/点踩,嵌入在 QuickSight 或自定义前端中。

关键一步是把这些异构数据汇到同一管道。下面用一个 Kinesis Data Firehose + Lambda 的组合做实时清洗和路由:

# lambda/transform_q_logs.py — Firehose 内嵌转换 Lambda
import base64, json, datetime

def handler(event, context):
    records_out = []
    for rec in event["records"]:
        # Firehose 传入的是 base64 编码的原始记录
        payload = json.loads(base64.b64decode(rec["data"]))

        # 只保留可观测需要的字段,脱敏敏感内容
        cleaned = {
            "user_id": payload.get("userId", "unknown"),
            "session_id": payload.get("sessionId"),
            "capability": payload.get("pluginId", "general"),
            "timestamp": payload.get("eventTime", 
                          datetime.datetime.utcnow().isoformat()),
            "feedback": payload.get("feedback", None),  # thumbs_up / thumbs_down
            "response_latency_ms": payload.get("latencyMs"),
        }

        out_data = json.dumps(cleaned) + "\n"
        records_out.append({
            "recordId": rec["recordId"],
            "result": "Ok",
            "data": base64.b64encode(out_data.encode()).decode()
        })
    return {"records": records_out}

部署时把此 Lambda 挂到 Firehose 的 ProcessingConfiguration,Firehose 会自动调用。输出格式选 JSON newline-delimited,方便后续 Athena 或 Redshift 直接查询。

指标定义:从原始数据到业务信号

原始日志只是"发生了什么",可观测要回答"意味着什么"。建议聚焦四个核心指标族:

指标族 具体指标 计算方式 业务含义
活跃度 DAU / WAU COUNT(DISTINCT user_id) 按日/周 平台是否真的被用起来
满意度 Positive Feedback Rate COUNT(feedback='thumbs_up') / COUNT(feedback IS NOT NULL) 回答质量是否达标
能力热度 Top Capabilities GROUP BY capability ORDER BY COUNT(*) DESC 哪些插件/能力最值得投入
响应体验 P50 / P95 Latency APPROX_PERCENTILE(response_latency_ms, 0.95) 用户是否在等太久

这些指标用 Athena SQL 即可实时计算,不需要额外建数仓:

-- athena_queries/daily_observation.sql
-- 数据源:Firehose 写入 S3 的清洗后日志
SELECT
  date_trunc('day', timestamp)            AS usage_date,
  count(distinct user_id)                 AS dau,
  count_if(feedback = 'thumbs_up')
    / nullifcount_if(feedback IS NOT NULL) AS positive_rate,
  approx_percentile(response_latency_ms, 0.50) AS p50_ms,
  approx_percentile(response_latency_ms, 0.95) AS p95_ms,
  capability,
  count(*)                                AS interactions
FROM q_observation_logs
WHERE timestamp >= date('now') - interval '7' day
GROUP BY 1, capability
ORDER BY usage_date DESC, interactions DESC

nullif 防止分母为零;Athena 的 approx_percentile 对大数据量比精确 percentile 实用得多。

可视化:一个 CloudWatch Dashboard 就够起步

不需要一开始就搭 QuickSight 大屏。CloudWatch Dashboard 可以用 YAML 声明式定义,CI/CD 直接部署:

# dashboard/q-observability.yaml
DashboardName: QEnterpriseObservability
DashboardBody:
  widgets:
    - type: metric
      x: 0
      y: 0
      width: 12
      height: 6
      properties:
        title: "Daily Active Users (7d)"
        metrics:
          - [AWS/Lambda, Invocations, FunctionName, q-log-transformer,
             { stat: Sum, period: 86400, label: "DAU proxy (Lambda calls)" }]
        view: timeSeries
        stacked: false

    - type: metric
      x: 0
      y: 6
      width: 12
      height: 6
      properties:
        title: "Response Latency P50 / P95"
        metrics:
          - [QObservability, ResponseLatency, stat: p50, label: "P50" ]
          - [QObservability, ResponseLatency, stat: p95, label: "P95" ]
        view: timeSeries

    - type: log
      x: 0
      y: 12
      width: 24
      height: 6
      properties:
        title: "Recent Negative Feedback Sessions"
        logGroupName: /aws/lambda/q-log-transformer
        filterPattern: '{ $.feedback = "thumbs_down" }'

部署命令:

# 一行部署 Dashboard
aws cloudwatch put-dashboard \
  --dashboard-name QEnterpriseObservability \
  --dashboard-body file://dashboard/q-observability.yaml

# 验证
aws cloudwatch get-dashboard \
  --dashboard-name QEnterpriseObservability \
  --query 'DashboardBody' --output text | head -20

这里 DAU 用 Lambda 调用次数做代理指标——更精确的做法是从 Athena 查询结果写回 CloudWatch Custom Metric,但起步阶段代理指标足够发现趋势。

把反馈闭环做进前端

可观测不只是"看数据",还要让数据产生行动。最直接的做法:在 Amazon Q 的自定义前端里嵌入反馈按钮,点击后写入 S3 或 Firehose。

// frontend/feedback-hook.js — 嵌入 Q Web Client 的反馈采集
async function sendFeedback(sessionId, feedbackType) {
  const payload = {
    sessionId,
    feedback: feedbackType,   // 'thumbs_up' | 'thumbs_down'
    timestamp: new Date().toISOString(),
    userId: getCurrentUser(),  // 从 IAM 或 IdP 获取
  };

  // 方案 A:直接写 S3(简单,适合低频场景)
  await fetch(
    `https://your-bucket.s3.amazonaws.com/feedback/${sessionId}.json`,
    {
      method: "PUT",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(payload),
    }
  );

  // 方案 B:写 Firehose(实时,适合高频场景)
  // await fetch("https://your-firehose-endpoint/", {
  //   method: "POST",
  //   body: JSON.stringify(payload),
  // });
}

S3 PUT 需要配置 Bucket Policy 允许前端写入指定前缀,且只允许 PUT 不允许 DELETE,防止用户篡改历史反馈。

落地时的取舍和风险

先做最小闭环,再补精度。 DAU 代理指标 + CloudWatch Dashboard 可以在一天内上线;Athena 精确查询和 QuickSight 大屏是第二阶段的事。

注意数据合规边界。 对话内容含业务敏感信息,清洗 Lambda 必须在入湖前脱敏——只保留元信息,不保留完整问答文本,除非合规团队明确允许。

反馈数据天然稀疏。 大多数用户不会主动点赞/点踩,positive_rate 的分母可能很小,导致指标波动剧烈。应对方式:设置最低样本量阈值(如 COUNT(feedback) >= 50 才显示比率),或用贝叶斯平滑补充小样本区间。

成本控制。 Firehose + S3 + Athena 的组合在千用户量级月成本通常在 $50–$150;上万用户时 Athena 扫描量会上升,建议用 Parquet 分区存储并开启压缩,把单次查询扫描量压到 GB 级以下。


上线检查清单:

  • [ ] CloudTrail / 对话日志已开启,写入指定 S3 前缀
  • [ ] Firehose + 清洗 Lambda 已部署,输出 Parquet 或 JSON newline
  • [ ] Athena 表已注册,daily_observation.sql 可跑通
  • [ ] CloudWatch Dashboard 已部署,至少覆盖 DAU 和 Latency
  • [ ] 前端反馈按钮已接入,数据能写入 S3/Firehose
  • [ ] S3 Bucket Policy 已锁定:只允许前端 PUT 反馈,不允许 DELETE
  • [ ] 对话内容脱敏策略已与合规团队确认

相关推荐