返回AI笔记
AI Day 59

AI Day 59: 实战(9):性能调优与成本实战 — 从能跑到跑得好

AI Day 59: 实战(9):性能调优与成本实战 — 从能跑到跑得好

2026-05-30

日期: 2026-05-30 | 阶段: 第五阶段 · 动手实战 (Day 51-60) | 主题: Performance Tuning & Cost Optimization in Practice

学习路径 / Learning Path

AI/LLM 深度技术学习 60天计划
├── 第一阶段:模型基础 (Day 1-15) ✅
│   ├── Day 1: Transformer与LLM基础 ✅
│   ├── Day 2: 量化与本地部署 ✅
│   ├── Day 3: 训练全流程 ✅
│   ├── Day 4: Prompt Engineering ✅
│   ├── Day 5: RAG架构 ✅
│   ├── Day 6: 向量数据库与Embedding ✅
│   ├── Day 7: 微调技术 ✅
│   ├── Day 8: 推理优化 ✅
│   ├── Day 9: 长上下文技术 ✅
│   ├── Day 10: 多模态模型 ✅
│   ├── Day 11: 推理模型 ✅
│   ├── Day 12: Agent框架 ✅
│   ├── Day 13: MCP协议 ✅
│   ├── Day 14: 模型评估 ✅
│   └── Day 15: 阶段一总结 ✅
├── 第二阶段:工程实践 (Day 16-30) ✅
│   ├── Day 16: LLM应用架构 ✅
│   ├── Day 17: 安全与护栏 ✅
│   ├── Day 18: 可观测性 ✅
│   ├── Day 19: 生产RAG·解析与分块 ✅
│   ├── Day 20: 生产RAG·检索与重排 ✅
│   ├── Day 21: 生产RAG·评估与迭代 ✅
│   ├── Day 22: Agent状态与恢复 ✅
│   ├── Day 23: Agent成本优化 ✅
│   ├── Day 24: 多Agent系统 ✅
│   ├── Day 25: Agent测试部署 ✅
│   ├── Day 26: LLM成本工程 ✅
│   ├── Day 27: 多模型编排 ✅
│   ├── Day 28: LLM应用测试 ✅
│   ├── Day 29: 企业LLM平台 ✅
│   └── Day 30: 阶段二总结 ✅
├── 第三阶段:金融零售AI应用 (Day 31-42) ✅
│   ├── Day 31: 金融AI风控 ✅
│   ├── Day 32: 智能投顾与量化 ✅
│   ├── Day 33: 合规与RegTech ✅
│   ├── Day 34: 信贷AI全链路 ✅
│   ├── Day 35: 金融AI总结 ✅
│   ├── Day 36: 零售AI推荐 ✅
│   ├── Day 37: 智能客服 ✅
│   ├── Day 38: 供应链AI ✅
│   ├── Day 39: 智能营销 ✅
│   ├── Day 40: 零售AI总结 ✅
│   ├── Day 41: CeFi×DeFi×AI融合 ✅
│   └── Day 42: AI融合案例与职业 ✅
├── 第四阶段:面试冲刺 (Day 43-50) ✅
│   ├── Day 43: 系统设计·LLM平台 ✅
│   ├── Day 44: 系统设计·RAG系统 ✅
│   ├── Day 45: 系统设计·Agent系统 ✅
│   ├── Day 46: 系统设计·推荐系统 ✅
│   ├── Day 47: 面试·产品AI ✅
│   ├── Day 48: 面试·架构AI ✅
│   ├── Day 49: 面试·行为AI ✅
│   └── Day 50: 学习总结 ✅
└── 第五阶段:动手实战 (Day 51-60)
    ├── Day 51: 本地大模型部署全流程 ✅
    ├── Day 52: RAG系统实战:从文档到问答 ✅
    ├── Day 53: RAG进阶:评估优化与生产化 ✅
    ├── Day 54: LoRA微调实战:训练你的专属模型 ✅
    ├── Day 55: Agent开发实战:构建工具调用Agent ✅
    ├── Day 56: MCP Server开发:扩展AI能力边界 ✅
    ├── Day 57: 多模态应用:图文理解与文档分析 ✅
    ├── Day 58: AI应用全栈开发:前后端集成 ✅
    ├── Day 59: 性能调优与成本实战 ← 你在这里
    └── Day 60: 总结与作品集

核心概念 / Core Concepts

性能和成本是产品能否上线的最后一关 / Performance & Cost: The Final Gate

Day 51-58 解决了"能不能做":
  ✅ 模型能跑
  ✅ RAG能检索
  ✅ Agent能调工具
  ✅ 前后端能联通

Day 59 解决"能不能上线":
  ❓ 每次请求要等多久?(用户体验)
  ❓ 能同时服务多少人?(并发能力)
  ❓ 每月运行费用多少?(商业可行性)
  ❓ 出了问题怎么发现?(监控告警)

真实案例:
  某公司做了一个AI客服,Demo阶段效果很好
  上线后:
    平均响应 8 秒 → 用户放弃率 60%
    每月 API 费用 $12,000 → 预算只有 $3,000
    并发 5 人就开始超时 → 实际需要支撑 50 人

  结果:下线重做,浪费3个月

Day 59 = 避免这个悲剧的最后防线

Day 8 理论(推理优化) + Day 26 理论(成本工程) → Day 59 全部实战验证

知识点1:延迟分析 / Latency Analysis

端到端延迟拆解 / End-to-End Latency Breakdown

一次 AI 请求的完整延迟路径:

用户 ──→ 前端 ──→ 后端API ──→ Ollama ──→ 生成 ──→ 返回
 │        │        │          │          │        │
 ├ 网络   ├ 渲染   ├ 路由     ├ Prefill  ├ Decode ├ 后处理
 │ ~50ms  │ ~10ms  │ ~5ms    │ ~200ms   │ ~2-5s  │ ~10ms
 │        │        │          │          │        │
 └────────┴────────┴──────────┴──────────┴────────┘
                    总延迟: 2-6 秒

各阶段详解:

1. 网络延迟 (Network) ~50ms
   客户端 → 服务器的RTT
   本地部署几乎为0,云端取决于距离

2. API路由 (Routing) ~5ms
   FastAPI路由匹配、中间件处理
   通常可以忽略

3. Prefill (预填充) ~200-500ms
   处理输入 prompt 的所有 token
   = 理解"你问了什么"
   与输入长度成正比
   长 prompt → 长 prefill

4. Decode (解码/生成) ~2-5s ← 最大瓶颈
   逐个生成输出 token
   200 tokens × 15ms/token = 3s
   这是用户等待的主要部分

5. 后处理 (Post-processing) ~10ms
   格式化、过滤、缓存写入

瓶颈定位方法 / Bottleneck Identification

"""
latency_profiler.py — 延迟分析工具
"""
import time
import ollama
import json
from dataclasses import dataclass, asdict


@dataclass
class LatencyProfile:
    """延迟剖析结果"""
    total_ms: float
    prefill_ms: float
    decode_ms: float
    tokens_generated: int
    tokens_per_second: float
    input_tokens: int
    time_to_first_token_ms: float  # TTFT


def profile_request(
    prompt: str,
    model: str = "qwen2.5:7b",
    max_tokens: int = 200,
) -> LatencyProfile:
    """
    精确剖析一次LLM请求的延迟分布
    """
    start = time.perf_counter()
    first_token_time = None
    token_count = 0

    stream = ollama.chat(
        model=model,
        messages=[{"role": "user", "content": prompt}],
        stream=True,
        options={"num_predict": max_tokens},
    )

    for chunk in stream:
        if first_token_time is None and chunk["message"]["content"]:
            first_token_time = time.perf_counter()
        token_count += 1

    end = time.perf_counter()

    total_ms = (end - start) * 1000
    ttft_ms = (first_token_time - start) * 1000 if first_token_time else total_ms
    decode_ms = (end - first_token_time) * 1000 if first_token_time else 0
    tps = token_count / (decode_ms / 1000) if decode_ms > 0 else 0

    return LatencyProfile(
        total_ms=round(total_ms, 1),
        prefill_ms=round(ttft_ms, 1),
        decode_ms=round(decode_ms, 1),
        tokens_generated=token_count,
        tokens_per_second=round(tps, 1),
        input_tokens=len(prompt.split()),  # 粗略估计
        time_to_first_token_ms=round(ttft_ms, 1),
    )


def run_latency_benchmark():
    """运行不同场景的延迟基准测试"""

    scenarios = [
        {"name": "短问题", "prompt": "Hello", "max_tokens": 50},
        {"name": "中等问题", "prompt": "请解释区块链的工作原理", "max_tokens": 200},
        {"name": "长问题", "prompt": "请详细分析2024年DeFi市场的发展趋势,包括TVL变化、新协议、监管影响。" * 3, "max_tokens": 500},
        {"name": "代码生成", "prompt": "用Python实现一个简单的HTTP服务器", "max_tokens": 300},
    ]

    print("=" * 70)
    print(f"{'场景':<12} {'总延迟':>8} {'TTFT':>8} {'Decode':>8} {'Token数':>8} {'TPS':>6}")
    print("=" * 70)

    for s in scenarios:
        profile = profile_request(s["prompt"], max_tokens=s["max_tokens"])
        print(
            f"{s['name']:<12} "
            f"{profile.total_ms:>7.0f}ms "
            f"{profile.prefill_ms:>7.0f}ms "
            f"{profile.decode_ms:>7.0f}ms "
            f"{profile.tokens_generated:>7} "
            f"{profile.tokens_per_second:>5.1f}"
        )

    print("=" * 70)


if __name__ == "__main__":
    run_latency_benchmark()

# 预期输出:
# ====================================================================
# 场景           总延迟     TTFT   Decode   Token数    TPS
# ====================================================================
# 短问题          892ms    185ms    707ms      48    67.9
# 中等问题       3245ms    210ms   3035ms     198    65.2
# 长问题         8012ms    520ms   7492ms     487    65.0
# 代码生成       4567ms    198ms   4369ms     289    66.1
# ====================================================================

知识点2:吞吐量优化 / Throughput Optimization

Continuous Batching 配置 / Continuous Batching Setup

Ollama 默认是串行处理:
  请求1 → 处理中... → 完成 → 请求2 → 处理中... → 完成

  10个请求串行 = 10 × 3s = 30s 总等待

Continuous Batching(连续批处理):
  请求1 ─┐
  请求2 ─┤──→ GPU 同时处理 ──→ 并行完成
  请求3 ─┘

  10个请求并行 ≈ 4-5s 总等待(取决于GPU显存)

Ollama 配置:
  OLLAMA_NUM_PARALLEL=4    # 最大并行请求数
  OLLAMA_MAX_LOADED_MODELS=2  # 最多加载的模型数

并发测试 / Concurrency Testing

"""
concurrency_test.py — 并发测试
"""
import asyncio
import aiohttp
import time
import statistics


async def single_request(session, url, payload):
    """发送单个请求并计时"""
    start = time.perf_counter()
    async with session.post(url, json=payload) as resp:
        result = await resp.json()
    elapsed = (time.perf_counter() - start) * 1000
    return elapsed


async def concurrency_test(
    url: str,
    payload: dict,
    concurrency: int,
    total_requests: int,
):
    """并发压测"""
    semaphore = asyncio.Semaphore(concurrency)
    latencies = []
    errors = 0

    async def bounded_request(session):
        nonlocal errors
        async with semaphore:
            try:
                latency = await single_request(session, url, payload)
                latencies.append(latency)
            except Exception:
                errors += 1

    start = time.perf_counter()
    async with aiohttp.ClientSession() as session:
        tasks = [bounded_request(session) for _ in range(total_requests)]
        await asyncio.gather(*tasks)
    total_time = time.perf_counter() - start

    # 统计
    latencies.sort()
    results = {
        "concurrency": concurrency,
        "total_requests": total_requests,
        "total_time_s": round(total_time, 2),
        "qps": round(total_requests / total_time, 2),
        "errors": errors,
        "latency_p50_ms": round(latencies[len(latencies)//2], 0),
        "latency_p90_ms": round(latencies[int(len(latencies)*0.9)], 0),
        "latency_p99_ms": round(latencies[int(len(latencies)*0.99)], 0),
        "latency_avg_ms": round(statistics.mean(latencies), 0),
    }

    return results


async def run_qps_test():
    """QPS递增测试"""
    url = "http://localhost:8000/chat/"
    payload = {
        "message": "What is DeFi?",
        "model": "qwen2.5:7b",
        "stream": False,
    }

    print("=" * 70)
    print("QPS 递增测试 / QPS Ramp-Up Test")
    print("=" * 70)
    print(f"{'并发':>6} {'总请求':>8} {'QPS':>8} {'P50':>8} {'P90':>8} {'P99':>8} {'错误':>6}")
    print("-" * 70)

    for concurrency in [1, 2, 4, 8, 16]:
        result = await concurrency_test(url, payload, concurrency, concurrency * 5)
        print(
            f"{result['concurrency']:>6} "
            f"{result['total_requests']:>8} "
            f"{result['qps']:>7.1f} "
            f"{result['latency_p50_ms']:>7.0f}ms "
            f"{result['latency_p90_ms']:>7.0f}ms "
            f"{result['latency_p99_ms']:>7.0f}ms "
            f"{result['errors']:>6}"
        )

    print("=" * 70)


# asyncio.run(run_qps_test())

# 预期输出:
# ======================================================================
# QPS 递增测试 / QPS Ramp-Up Test
# ======================================================================
#   并发     总请求      QPS      P50      P90      P99     错误
# ----------------------------------------------------------------------
#      1        5      0.3    3102ms   3205ms   3205ms      0
#      2       10      0.6    3312ms   3580ms   3620ms      0
#      4       20      1.0    3890ms   4521ms   4800ms      0
#      8       40      1.5    5200ms   7100ms   8200ms      0
#     16       80      1.2    9800ms  14200ms  18500ms      3  ← 开始超时
# ======================================================================

QPS 提升策略 / QPS Improvement Strategies

提升策略(按效果排序):

策略1: 缓存 (命中时: 延迟从3s→<10ms)
  热门问题缓存 → 大部分请求不需要跑模型
  详见知识点3

策略2: 更小的模型 (延迟降50%)
  7B → 3B: 速度提升2倍,质量下降15%
  策略: 简单问题用3B,复杂问题用7B
  Day 27 学的"模型路由"在这里用上

策略3: 量化 (延迟降20-30%)
  FP16 → INT4: 速度提升30%,质量下降5%
  Day 2 学的量化知识在这里用上

策略4: 限制输出长度 (延迟可控)
  max_tokens=200 而不是无限制
  大部分场景不需要生成1000个token

策略5: GPU升级 (线性提升)
  RTX 3060 → RTX 4090: 吞吐量提升3-4倍
  但成本也提升3-4倍

投入产出比: 缓存 > 小模型路由 > 量化 > 限制长度 > GPU升级

知识点3:缓存实战 / Caching in Practice

三层缓存实现 / Three-Layer Cache Implementation

"""
cache_system.py — 三层缓存系统
Layer 1: 精确匹配 — 相同问题直接返回
Layer 2: 语义匹配 — 相似问题返回缓存
Layer 3: Prompt Cache — 相同前缀加速推理
"""
import hashlib
import json
import time
from typing import Optional
import chromadb


class ThreeLayerCache:
    """三层AI缓存系统"""

    def __init__(self):
        # Layer 1: 精确匹配(内存字典/Redis)
        self.exact_cache: dict[str, dict] = {}

        # Layer 2: 语义缓存(向量数据库)
        self.semantic_client = chromadb.PersistentClient(path="./cache_db")
        self.semantic_cache = self.semantic_client.get_or_create_collection(
            name="semantic_cache",
            metadata={"hnsw:space": "cosine"},
        )

        # 统计
        self.stats = {
            "total_requests": 0,
            "exact_hits": 0,
            "semantic_hits": 0,
            "misses": 0,
        }

    def _hash_key(self, query: str, model: str) -> str:
        """生成精确匹配的key"""
        raw = f"{model}:{query.strip().lower()}"
        return hashlib.md5(raw.encode()).hexdigest()

    def get(self, query: str, model: str = "qwen2.5:7b") -> Optional[dict]:
        """
        查询缓存(三层依次查找)
        Returns: 缓存结果或None
        """
        self.stats["total_requests"] += 1

        # === Layer 1: 精确匹配 ===
        key = self._hash_key(query, model)
        if key in self.exact_cache:
            cached = self.exact_cache[key]
            # 检查过期(默认1小时)
            if time.time() - cached["timestamp"] < 3600:
                self.stats["exact_hits"] += 1
                return {**cached, "cache_layer": "exact"}

        # === Layer 2: 语义匹配 ===
        results = self.semantic_cache.query(
            query_texts=[query],
            n_results=1,
        )

        if results["distances"] and results["distances"][0]:
            distance = results["distances"][0][0]
            # 余弦相似度 > 0.92 认为是相似问题
            if distance < 0.08:  # 1 - 0.92 = 0.08
                self.stats["semantic_hits"] += 1
                cached_response = json.loads(results["metadatas"][0][0]["response"])
                return {**cached_response, "cache_layer": "semantic"}

        # === Layer 3: Prompt Cache ===
        # Ollama 原生支持 KV Cache
        # 相同前缀的请求会复用 prefill 结果
        # 无需手动实现,但可以通过设计 prompt 模板来利用

        self.stats["misses"] += 1
        return None

    def set(self, query: str, response: dict, model: str = "qwen2.5:7b"):
        """写入缓存"""
        key = self._hash_key(query, model)

        # Layer 1: 精确缓存
        self.exact_cache[key] = {
            **response,
            "timestamp": time.time(),
        }

        # Layer 2: 语义缓存
        self.semantic_cache.add(
            ids=[key],
            documents=[query],
            metadatas=[{
                "response": json.dumps(response, ensure_ascii=False),
                "model": model,
                "timestamp": str(time.time()),
            }],
        )

    def get_stats(self) -> dict:
        """缓存统计"""
        total = self.stats["total_requests"]
        if total == 0:
            return {**self.stats, "hit_rate": 0}

        hits = self.stats["exact_hits"] + self.stats["semantic_hits"]
        return {
            **self.stats,
            "hit_rate": round(hits / total * 100, 1),
            "exact_hit_rate": round(self.stats["exact_hits"] / total * 100, 1),
            "semantic_hit_rate": round(self.stats["semantic_hits"] / total * 100, 1),
        }


# === 集成到API ===
cache = ThreeLayerCache()


async def cached_chat(message: str, model: str = "qwen2.5:7b") -> dict:
    """带缓存的Chat接口"""
    # 查缓存
    cached = cache.get(message, model)
    if cached:
        return {
            **cached,
            "from_cache": True,
            "latency_ms": 1,  # 缓存命中几乎无延迟
        }

    # 缓存未命中,调用模型
    start = time.perf_counter()
    import ollama
    response = ollama.chat(
        model=model,
        messages=[{"role": "user", "content": message}],
    )
    latency = (time.perf_counter() - start) * 1000

    result = {
        "response": response["message"]["content"],
        "model": model,
        "latency_ms": round(latency, 0),
    }

    # 写入缓存
    cache.set(message, result, model)

    return {**result, "from_cache": False}

缓存命中率监控与ROI / Cache Hit Rate & ROI

缓存ROI计算:

假设每天1000次请求,无缓存:
  每次请求延迟: ~3000ms
  每次请求成本: ~$0.003 (本地GPU电费) 或 ~$0.01 (云API)
  日成本: $3-10

加入三层缓存后(假设命中率60%):
  600次命中: ~5ms × 600 = 3s 总耗时, 接近$0成本
  400次未命中: ~3000ms × 400 = 1200s 总耗时

  延迟改善: 平均 3000ms → 1205ms (↓60%)
  成本改善: $3-10/天 → $1.2-4/天 (↓60%)

  缓存数据库成本: ~$0.01/天 (本地ChromaDB)

ROI: 缓存带来的收益远超投入

实际监控指标:
  ┌─────────────────────────────────────────┐
  │        Cache Performance Dashboard      │
  ├─────────────────────────────────────────┤
  │                                         │
  │  Total Requests:  1,247                 │
  │  Cache Hit Rate:  63.2%                 │
  │    ├ Exact Hits:  45.1%                 │
  │    └ Semantic:    18.1%                 │
  │                                         │
  │  Avg Latency:                           │
  │    Cache Hit:     4ms                   │
  │    Cache Miss:    3,124ms               │
  │    Overall:       1,154ms  (↓62%)       │
  │                                         │
  │  Est. Cost Saved: $6.21/day             │
  └─────────────────────────────────────────┘

知识点4:成本实战 / Cost Analysis in Practice

实际项目成本核算 / Real Project Cost Breakdown

场景: Day 58 构建的AI全栈应用,日活100人,每人每天10次请求

=== 方案A: 全部本地 (Ollama + 自有GPU) ===

硬件成本:
  GPU: RTX 3060 12GB (已有)     $0/月
  电费: 200W × 24h × 30天       ~$15/月
  网络: 家用宽带 (已有)          $0/月

软件成本:
  Ollama: 免费
  ChromaDB: 免费
  Next.js: 免费

总成本: ~$15/月
单次请求成本: $15 / (100×10×30) = $0.0005

限制: 无法24/7保证可用,单GPU并发有限

=== 方案B: 云端GPU实例 ===

基础设施:
  AWS g5.xlarge (A10G GPU): $1.006/hr × 730h  $734/月
  或 按需开关: $1.006/hr × 12h × 30天         $362/月
  存储 (100GB EBS): $10/月
  网络: ~$5/月

软件: 全部免费/开源

总成本: $377-749/月
单次请求成本: $0.013-0.025

=== 方案C: 云API (OpenAI/Anthropic) ===

调用成本 (以 GPT-4o-mini 为例):
  输入: 1000 requests × 500 tokens = 500K tokens/天
  输出: 1000 requests × 200 tokens = 200K tokens/天
  日成本: 500K × $0.15/1M + 200K × $0.60/1M = $0.195/天
  月成本: $5.85

RAG Embedding:
  月新增文档: 10万 tokens
  $0.02/1M tokens ≈ $0.002/月

总成本: ~$6/月
单次请求成本: $0.0002

限制: 数据发送到第三方,延迟更高(网络RTT)

=== 方案D: 混合方案(推荐)===

热门/简单请求 → 本地 Ollama (70% 流量)  $15/月
复杂/长文本请求 → 云API (30% 流量)       $2/月
前端 → Vercel Free Tier                  $0/月

总成本: ~$17/月
最佳性价比!

优化前后成本对比表 / Before vs After Optimization

优化措施成本影响对比表:

措施                  实施难度  延迟改善  成本改善  推荐度
──────────────────────────────────────────────────────────
三层缓存(知识点3)       中      ↓60%     ↓60%     ★★★★★
模型路由(小/大模型)     中      ↓30%     ↓40%     ★★★★★
INT4量化               低      ↓20%     ↓15%     ★★★★
限制max_tokens         低      ↓15%     ↓20%     ★★★★
Prompt优化(更短)       低      ↓10%     ↓15%     ★★★★
GPU升级                高      ↓50%     ↑200%    ★★
云API迁移              中      ↑50%     ↓80%     ★★★
Batch请求合并          高      ↓5%      ↓30%     ★★★

组合优化效果(全部实施):
  优化前: 平均延迟 3000ms, 月成本 $200
  优化后: 平均延迟 800ms,  月成本 $40
  改善:   延迟 ↓73%, 成本 ↓80%

最关键的3个优化(80/20法则):
  1. 缓存 — 大部分请求不需要跑模型
  2. 模型路由 — 简单问题用小模型
  3. Prompt优化 — 减少不必要的输入token

知识点5:压测与基准 / Load Testing & Benchmarking

Locust 压测配置 / Locust Load Testing

"""
locustfile.py — AI应用压测脚本
使用: locust -f locustfile.py --host=http://localhost:8000
"""
from locust import HttpUser, task, between, events
import json
import time


class AIAppUser(HttpUser):
    """模拟AI应用用户行为"""

    # 请求间隔: 5-15秒(模拟真实用户思考时间)
    wait_time = between(5, 15)

    def on_start(self):
        """用户启动时"""
        self.headers = {
            "Content-Type": "application/json",
            "X-API-Key": "demo-key-12345",
        }

    @task(5)  # 权重5: 最常见的操作
    def chat_simple(self):
        """简单对话"""
        payload = {
            "message": "什么是DeFi?",
            "model": "qwen2.5:7b",
            "stream": False,
        }
        with self.client.post(
            "/chat/",
            json=payload,
            headers=self.headers,
            catch_response=True,
            name="/chat (simple)",
        ) as response:
            if response.status_code == 200:
                data = response.json()
                if len(data.get("response", "")) < 10:
                    response.failure("Response too short")
            else:
                response.failure(f"Status {response.status_code}")

    @task(3)  # 权重3
    def rag_query(self):
        """RAG问答"""
        payload = {
            "question": "如何设计空投方案?",
            "n_results": 3,
        }
        self.client.post(
            "/rag/query",
            json=payload,
            headers=self.headers,
            name="/rag/query",
        )

    @task(1)  # 权重1: 较少使用
    def health_check(self):
        """健康检查"""
        self.client.get("/health", name="/health")


# === 自定义统计输出 ===
@events.request.add_listener
def on_request(request_type, name, response_time, response_length, **kwargs):
    """记录每个请求的详细信息(可选)"""
    pass  # 可以写入文件或数据库

SLA 定义 / SLA Definition

AI应用的SLA标准(参考业界):

指标              目标值           告警阈值          严重阈值
──────────────────────────────────────────────────────────
可用性            99.5%           99.0%            98.0%
P50 延迟          < 2s            > 3s             > 5s
P99 延迟          < 8s            > 12s            > 20s
TTFT             < 500ms         > 1s             > 2s
错误率            < 1%            > 2%             > 5%
QPS (Chat)        > 2 req/s      < 1.5            < 1.0
缓存命中率        > 50%           < 40%            < 20%

不同场景的SLA差异:

内部工具:
  可用性 99%, P50 < 5s, 错误率 < 5%
  要求较低,但不能经常挂

B2C 产品:
  可用性 99.9%, P50 < 2s, 错误率 < 1%
  用户体验关键,超过3秒用户就流失

金融场景:
  可用性 99.99%, P50 < 1s, 错误率 < 0.1%
  合规要求高,错误可能导致资金损失

知识点6:监控仪表盘 / Monitoring Dashboard

Prometheus 指标收集 / Prometheus Metrics Collection

"""
backend/metrics.py — 监控指标收集
"""
from prometheus_client import (
    Counter,
    Histogram,
    Gauge,
    generate_latest,
    CONTENT_TYPE_LATEST,
)
from fastapi import Response
import time


# === 定义指标 ===

# 请求计数
REQUEST_COUNT = Counter(
    "ai_request_total",
    "Total AI requests",
    ["endpoint", "model", "cache_hit"],
)

# 延迟直方图
REQUEST_LATENCY = Histogram(
    "ai_request_duration_seconds",
    "AI request latency in seconds",
    ["endpoint", "model"],
    buckets=[0.1, 0.5, 1.0, 2.0, 3.0, 5.0, 8.0, 12.0, 20.0],
)

# Token使用量
TOKENS_USED = Counter(
    "ai_tokens_total",
    "Total tokens used",
    ["model", "direction"],  # direction: input/output
)

# 活跃请求数
ACTIVE_REQUESTS = Gauge(
    "ai_active_requests",
    "Currently processing requests",
    ["endpoint"],
)

# 模型加载状态
MODEL_LOADED = Gauge(
    "ai_model_loaded",
    "Whether model is loaded",
    ["model"],
)

# 缓存命中率
CACHE_HIT_RATE = Gauge(
    "ai_cache_hit_rate",
    "Cache hit rate (percentage)",
)

# 估算成本
ESTIMATED_COST = Counter(
    "ai_estimated_cost_usd",
    "Estimated cost in USD",
    ["model"],
)


# === 使用示例 ===

def track_request(endpoint: str, model: str, cache_hit: bool, latency_s: float,
                  input_tokens: int, output_tokens: int):
    """记录一次请求的所有指标"""

    REQUEST_COUNT.labels(
        endpoint=endpoint,
        model=model,
        cache_hit=str(cache_hit),
    ).inc()

    REQUEST_LATENCY.labels(
        endpoint=endpoint,
        model=model,
    ).observe(latency_s)

    if not cache_hit:
        TOKENS_USED.labels(model=model, direction="input").inc(input_tokens)
        TOKENS_USED.labels(model=model, direction="output").inc(output_tokens)

        # 估算成本(本地GPU电费)
        cost_per_token = 0.000001  # $0.001 per 1K tokens
        cost = (input_tokens + output_tokens) * cost_per_token
        ESTIMATED_COST.labels(model=model).inc(cost)


# === Prometheus 端点 ===
async def metrics_endpoint():
    """Prometheus 指标端点"""
    return Response(
        content=generate_latest(),
        media_type=CONTENT_TYPE_LATEST,
    )

Grafana Dashboard 配置 / Grafana Dashboard

关键监控面板:

┌─────────────────────────────────────────────────────────────┐
│                    AI Application Dashboard                  │
├─────────────────┬─────────────────┬─────────────────────────┤
│   QPS           │   Error Rate    │   Active Requests       │
│   ████████ 2.3  │   ░░░░░░ 0.8%  │   ██░░░░ 3/10          │
├─────────────────┴─────────────────┴─────────────────────────┤
│                                                             │
│   Latency Distribution (P50 / P90 / P99)                   │
│   ┌──────────────────────────────────────────────┐          │
│   │    P50: 1.2s    P90: 3.4s    P99: 8.1s      │          │
│   │    ■■■■■■■──────■■■──────────■               │          │
│   └──────────────────────────────────────────────┘          │
│                                                             │
├─────────────────┬─────────────────┬─────────────────────────┤
│  Cache Hit Rate │  Token Usage    │  Est. Daily Cost        │
│  ████████ 63%   │  In: 125K/hr   │  $0.45                  │
│  exact: 45%     │  Out: 52K/hr   │  Budget: $1.00          │
│  semantic: 18%  │                 │  ████████░░             │
├─────────────────┴─────────────────┴─────────────────────────┤
│                                                             │
│   Request Latency Over Time (24h)                           │
│   5s │         ╱╲                                           │
│   4s │        ╱  ╲    ╱╲                                    │
│   3s │───────╱────╲──╱──╲─────────────────                  │
│   2s │ ╱╲  ╱       ╲╱                                       │
│   1s │╱  ╲╱                                                 │
│   0s └──────────────────────────────────────                │
│      00:00  04:00  08:00  12:00  16:00  20:00               │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Grafana + Prometheus 配置:

prometheus.yml:
  scrape_configs:
    - job_name: 'ai-backend'
      scrape_interval: 15s
      static_configs:
        - targets: ['backend:8000']
      metrics_path: '/metrics'

告警规则:
  - alert: HighLatency
    expr: histogram_quantile(0.95, ai_request_duration_seconds) > 8
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "AI请求P95延迟超过8秒"

  - alert: HighErrorRate
    expr: rate(ai_request_total{status="error"}[5m]) > 0.05
    for: 2m
    labels:
      severity: critical
    annotations:
      summary: "AI请求错误率超过5%"

  - alert: LowCacheHitRate
    expr: ai_cache_hit_rate < 20
    for: 15m
    labels:
      severity: warning
    annotations:
      summary: "缓存命中率低于20%,检查缓存策略"

今日思考 / Today's Reflections

思考1:性能优化的80/20法则 / The 80/20 Rule of Performance

今天测下来的结论:

3个优化覆盖了80%的收益:
  1. 缓存 (命中率60% → 延迟↓60%, 成本↓60%)
  2. 模型路由 (简单→小模型 → 延迟↓30%, 成本↓40%)
  3. Prompt精简 (减少输入token → Prefill↓30%)

其余优化收益递减:
  量化: ↓20%延迟(但已经在用INT4了)
  GPU升级: 钱的问题
  框架优化: 边际收益小

这给PM的启示:
  不要追求"极致优化"
  先把最有效的3个做了
  剩下的看ROI再决定

  就像产品功能:
    20%的功能覆盖80%的用户需求
    先做这20%,做好

思考2:缓存是AI应用的生命线 / Cache is AI's Lifeline

没有缓存的AI应用 = 没有CDN的网站

Day 26 学的缓存理论,今天实测验证:

  相同问题不同用户问 → 完全不需要重新推理
  相似问题 → 语义缓存命中,也不需要重新推理
  只有真正新的问题 → 才需要跑模型

实际应用中,大量请求是重复的:
  "什么是DeFi" "DeFi是什么" "defi的定义"
  → 这三个问题,只有第一个需要跑模型
  → 其他两个语义缓存命中

缓存的设计决策:
  TTL多长?太短→命中率低,太长→答案过时
  语义阈值多少?太低→误命中,太高→命中率低

  我的经验值:
    TTL=1小时(大多数知识不会1小时就变)
    语义相似度阈值=0.92(实测最佳平衡点)

思考3:监控是AI应用的必需品而非可选项 / Monitoring is Non-Negotiable

传统应用监控:
  知道请求是否成功就够了
  HTTP 200 = 成功
  HTTP 500 = 失败

AI应用监控更复杂:
  HTTP 200 但答案是垃圾 = 质量问题
  HTTP 200 但花了15秒 = 体验问题
  HTTP 200 但花了$0.50 = 成本问题
  HTTP 200 但缓存全部miss = 效率问题

必须监控的5个指标:
  1. 延迟分布 (不是平均值,要看P50/P90/P99)
  2. 缓存命中率 (低于40%就要调查)
  3. Token消耗 (防止成本失控)
  4. 错误率 (含超时和质量问题)
  5. QPS (了解容量余量)

Day 18 学的可观测性三支柱(Logging/Tracing/Metrics)
在今天全部落地实现了

学习资源 / Resources

性能测试

监控

LLM 性能优化

成本优化


明日预告 / Tomorrow's Preview

Day 60: 60天总结 — AI深度学习完整复盘

明天是最后一天!

60天旅程即将画上句号:
  Day 1:  "Attention is All You Need" — 什么是Transformer?
  Day 60: 构建了完整的AI应用并完成了性能调优

明天将回顾:
1. 60天全景回顾 — 每天一句话总结
2. 完整知识地图 — 从理论到实战
3. 实战产出统计 — 代码、笔记、系统
4. 能力自评 — 10个维度雷达图
5. 三大计划融合 — Web3 + 架构 + AI
6. Top 10 核心洞察
7. 下一步 — 持续学习和求职策略

准备工作:
  回顾所有60篇笔记的标题
  整理代码和产出清单

最后一天,画一个完美的句号!

Day 59 完成! 从延迟分析、三层缓存、成本核算到压测和监控。 缓存命中率60%让平均延迟从3秒降到1.2秒,成本下降60%。 明天是最后一天,60天AI深度学习的完整复盘!