Skip to content

AI 应用的成本控制与优化

从一个月烧 $500 到 $50——手把手教你把 AI 应用的账单砍下来,同时不牺牲用户体验。


9. 真实案例:从 0 到 1 的成本优化全流程

前 8 章讲了各种省钱技术。但你可能会想:这些技术放在一起,到底能产生多大效果?执行顺序是什么?每一步能省多少?

这一章,我们用一个真实的 RAG 问答系统作为案例,完整走一遍从"能用但烧钱"到"又好又省"的优化全流程。所有数据都基于生产环境的真实统计,前后对比一目了然。


9.1 初始状态:月成本 $500 的 RAG 系统

系统背景

这是一个面向企业内部的 AI 知识库问答系统,核心功能是让员工用自然语言查询公司文档、技术规范和操作手册。

系统概况
═══════════════════════════════════════════
  用途:企业内部知识库问答
  用户:~200 名内部员工
  日均请求:~800 次
  文档库:~3000 篇文档,约 500 万字
  上线时间:2 个月
  当前月成本:~$500
═══════════════════════════════════════════

初始技术架构

用户提问


┌──────────────┐
│  FastAPI 后端  │
└──────┬───────┘


┌──────────────┐    查询 Top 10 文档片段
│  向量数据库    │ ──────────────────────▶ 拼接到 Prompt
│  (Pinecone)   │
└──────────────┘


┌──────────────┐
│   GPT-4o     │ ◀── System Prompt (2000 Token)
│              │ ◀── 用户问题 + 10 段上下文
└──────┬───────┘


   返回回答

成本拆解

python
# 初始成本结构分析
initial_cost = {
    # LLM API 费用(大头)
    "llm_api": {
        "model": "gpt-4o",
        "price_input": 2.50,    # $/1M tokens
        "price_output": 10.00,   # $/1M tokens
        "avg_input_tokens": 3500,  # System Prompt + 10 段上下文 + 问题
        "avg_output_tokens": 800,  # 回答较长,无格式约束
        "daily_requests": 800,
        "monthly_requests": 800 * 30,  # 24,000 次/月
    },

    # Embedding 费用
    "embedding": {
        "model": "text-embedding-3-large",
        "price": 0.13,  # $/1M tokens
        "avg_tokens_per_query": 50,
        "daily_queries": 800,
    },

    # 向量数据库
    "vector_db": {
        "service": "Pinecone",
        "plan": "Starter → Standard",
        "monthly_cost": 70,  # 固定月费
    }
}

# 计算月度 LLM 成本
monthly_requests = 24000
input_cost = monthly_requests * 3500 * 2.50 / 1_000_000    # $210.00
output_cost = monthly_requests * 800 * 10.00 / 1_000_000   # $192.00
embedding_cost = 30 * 800 * 50 * 0.13 / 1_000_000          # $0.16
vector_db_cost = 70

total = input_cost + output_cost + embedding_cost + vector_db_cost
print(f"月度总成本: ${total:.2f}")
# 月度总成本: $472.16 ≈ $500

成本占比可视化

成本占比(月 $500)
──────────────────────────────────────────
  LLM 输入 Token     $210   ████████████████████  42%
  LLM 输出 Token     $192   ██████████████████    38%
  向量数据库          $70    ██████                14%
  Embedding          $0.16  ▏                     ~0%
  其他(服务器等)     $28    ██                     6%
──────────────────────────────────────────
  合计               ~$500

问题诊断

拿到账单后,我们做了一次全面诊断,发现了 5 个核心问题

问题 1:所有请求都用 GPT-4o
────────────────────────────────────────
  → 80% 的问题是简单查询("XX 的报销流程是什么")
  → 这些问题用 GPT-4o-mini 就能回答
  → 但系统里硬编码了 model="gpt-4o"

问题 2:System Prompt 巨长
────────────────────────────────────────
  → 2000 Token 的 System Prompt
  → 包含了完整的公司介绍、行为规范、格式要求
  → 大量信息与回答质量无关,纯属浪费

问题 3:每次检索 Top 10 文档片段
────────────────────────────────────────
  → 平均每个片段 200 Token,10 个就是 2000 Token
  → 其中 5-6 个片段与问题关联度很低
  → 喂给 LLM 的无关内容太多

问题 4:没有任何缓存
────────────────────────────────────────
  → "报销流程" 一天被问了 30 次
  → 每次都调 API,30 次 = 30 份钱
  → 完全相同的问题,重复付费

问题 5:没有限流,没有监控
────────────────────────────────────────
  → 有人写了个脚本批量提问
  → 一个用户一天消耗了全部 Token 的 15%
  → 直到月底看账单才发现

核心洞察:成本不是"贵"本身的问题,而是"浪费"的问题。$500 的账单里,至少 $400 是可以避免的。

9.2 第一刀:模型降级 + Prompt 瘦身(-60%)

第一刀是投入产出比最高的优化——不改架构、不加基础设施,只动两个地方:模型和 Prompt。

优化 A:模型路由——简单问题用小模型

分析了一周的请求日志后,我们发现请求可以分成两类:

请求分类统计(采样 5000 条)
───────────────────────────────────────
  简单查询(80%):
    → "报销流程是什么"
    → "如何申请 VPN 权限"
    → "年假还剩几天怎么查"
    → 答案明确,在文档里有原文

  复杂问题(20%):
    → "对比 A 方案和 B 方案的优劣"
    → "根据这 3 份文档总结项目风险"
    → "帮我基于模板写一份技术评审"
    → 需要推理、对比、生成
───────────────────────────────────────

于是我们实现了一个模型路由器

python
import re

class ModelRouter:
    """根据问题复杂度选择模型"""

    # 复杂问题的特征词
    COMPLEX_PATTERNS = [
        r"对比|比较|区别",
        r"总结|归纳|概括",
        r"分析|评估|评审",
        r"为什么.*|为何.*不",
        r"如果.*那么|假设.*会",
        r"写一[篇份]|帮我[写生]成",
        r"优缺点|优劣|利弊",
    ]

    def route(self, question: str) -> tuple[str, dict]:
        """
        返回 (模型名, 模型参数)
        """
        is_complex = any(
            re.search(p, question) for p in self.COMPLEX_PATTERNS
        )

        if is_complex:
            return "gpt-4o", {
                "max_tokens": 1000,
                "temperature": 0.7,
            }
        else:
            return "gpt-4o-mini", {
                "max_tokens": 500,
                "temperature": 0.3,  # 简单问题,低温度更精确
            }

# 使用
router = ModelRouter()

print(router.route("报销流程是什么"))
# ('gpt-4o-mini', {'max_tokens': 500, 'temperature': 0.3})

print(router.route("对比两种部署方案的优劣"))
# ('gpt-4o', {'max_tokens': 1000, 'temperature': 0.7})

成本影响

模型路由优化前后对比
═══════════════════════════════════════════════════════
                    优化前              优化后
─────────────────────────────────────────────────────
  模型使用      100% GPT-4o         80% GPT-4o-mini
                                    20% GPT-4o

  输入价格      $2.50/1M            mini: $0.15/1M
                                    4o:   $2.50/1M

  输出价格      $10.00/1M           mini: $0.60/1M
                                    4o:   $10.00/1M

  月 LLM 成本   $402                $103
  节省                              -$299(-74%)
═══════════════════════════════════════════════════════
python
# 成本计算验证
monthly_requests = 24000
simple_requests = monthly_requests * 0.8  # 19,200
complex_requests = monthly_requests * 0.2  # 4,800

# GPT-4o-mini 处理简单请求
mini_input = simple_requests * 3500 * 0.15 / 1_000_000   # $10.08
mini_output = simple_requests * 500 * 0.60 / 1_000_000   # $5.76

# GPT-4o 处理复杂请求
gpt4_input = complex_requests * 3500 * 2.50 / 1_000_000  # $42.00
gpt4_output = complex_requests * 800 * 10.00 / 1_000_000 # $38.40

new_llm_cost = mini_input + mini_output + gpt4_input + gpt4_output
print(f"优化后 LLM 成本: ${new_llm_cost:.2f}")
# 优化后 LLM 成本: $96.24

优化 B:System Prompt 瘦身

原始的 System Prompt 有 2000 Token,我们做了一次"断舍离":

原始 System Prompt(2000 Token)
═══════════════════════════════════════════
  ❌ 公司介绍(300 Token)
     → "XX 公司成立于 2015 年,专注于..."
     → 与回答问题无关,删除

  ❌ 行为规范(400 Token)
     → "你不得讨论政治、宗教..."
     → 10 条规范,大部分场景用不到
     → 精简为 2 条核心规则

  ❌ 冗长格式要求(500 Token)
     → "回答应包含标题、正文、参考来源..."
     → 大量示例,可以精简

  ✅ 核心角色定义(200 Token)→ 保留
  ✅ 回答策略(300 Token)→ 精简为 150 Token
  ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
  瘦身后:500 Token(-75%)
═══════════════════════════════════════════
python
# 瘦身前
SYSTEM_PROMPT_OLD = """
你是 XX 公司的智能知识助手。XX 公司成立于 2015 年,是一家专注于
企业数字化转型的科技公司,总部位于上海,在北京、深圳、杭州设有
研发中心...(省略大量公司介绍)

你的行为规范:
1. 不得讨论任何政治话题
2. 不得讨论宗教话题
3. 不得提供法律建议
4. 不得提供医疗建议
...(省略 10 条规范)

回答格式要求:
- 使用 Markdown 格式
- 每个回答包含:标题、正文、注意事项、参考来源
- 标题使用 ## 级别
- 正文使用清晰的分点描述
- 在回答末尾列出参考的文档来源
...(省略大量格式说明和示例)
"""

# 瘦身后
SYSTEM_PROMPT_NEW = """
你是企业知识库助手。根据提供的参考资料回答问题。
规则:1) 只基于参考资料回答,不确定就说"未找到相关信息";2) 简洁、准确、分点。
"""

第一刀总结

第一刀优化效果
═══════════════════════════════════════════
  优化项            成本变化       节省
─────────────────────────────────────────
  模型路由          $402 → $96     -$306
  Prompt 瘦身       输入 Token -75%  包含在上面
  合计 LLM 成本     $402 → $96     -$306(-76%)
─────────────────────────────────────────
  月总成本          $500 → $194    -$306(-61%)
  耗时              1 天
  代码改动          ~50 行
═══════════════════════════════════════════

经验法则:模型路由 + Prompt 瘦身是所有优化的起点。它不需要额外基础设施,30 分钟就能上线,却能砍掉 50-70% 的成本。如果你只做一件事,就做这个。

9.3 第二刀:缓存 + 限流(-50%)

第一刀砍掉了模型和 Prompt 的浪费。第二刀要解决的是重复请求异常流量——这两个问题在第一刀之后变得更加突出。

优化 C:语义缓存

分析请求日志后,我们发现一个惊人的数据:

请求重复率分析(30 天数据)
═══════════════════════════════════════════
  完全相同的问题:        18%
  语义相似的问题:        25%
  (相似度 > 0.92)
───────────────────────────────────────
  总可缓存请求:          43%
  → 也就是说,43% 的 API 调用本可以不花钱
═══════════════════════════════════════════

我们用 Redis + 语义相似度实现了双层缓存:

python
import hashlib
import numpy as np
from openai import OpenAI

class SemanticCache:
    """精确缓存 + 语义缓存的双层方案"""

    def __init__(self, redis_client, openai_client: OpenAI):
        self.redis = redis_client
        self.openai = openai_client
        self.ttl = 3600 * 24  # 缓存 24 小时

    def _hash(self, text: str) -> str:
        return hashlib.md5(text.strip().lower().encode()).hexdigest()

    def _get_embedding(self, text: str) -> list[float]:
        """用小模型算 embedding(成本极低)"""
        resp = self.openai.embeddings.create(
            model="text-embedding-3-small",  # 比 large 便宜 5 倍
            input=text
        )
        return resp.data[0].embedding

    def get(self, question: str) -> dict | None:
        """查缓存:先精确匹配,再语义匹配"""
        # 第一层:精确匹配
        key = f"cache:exact:{self._hash(question)}"
        result = self.redis.get(key)
        if result:
            return {"answer": result, "cache_type": "exact"}

        # 第二层:语义匹配
        query_emb = self._get_embedding(question)
        # 从最近的缓存条目中找相似的
        for cached_key in self.redis.scan_iter("cache:semantic:*"):
            cached = self.redis.hgetall(cached_key)
            cached_emb = np.frombuffer(
                cached["embedding"], dtype=np.float32
            )
            similarity = np.dot(query_emb, cached_emb) / (
                np.linalg.norm(query_emb) * np.linalg.norm(cached_emb)
            )
            if similarity > 0.92:  # 阈值
                return {
                    "answer": cached["answer"],
                    "cache_type": "semantic",
                    "similarity": f"{similarity:.4f}"
                }

        return None

    def set(self, question: str, answer: str):
        """写入双层缓存"""
        # 精确缓存
        exact_key = f"cache:exact:{self._hash(question)}"
        self.redis.setex(exact_key, self.ttl, answer)

        # 语义缓存
        embedding = self._get_embedding(question)
        semantic_key = f"cache:semantic:{self._hash(question)}"
        self.redis.hset(semantic_key, mapping={
            "question": question,
            "answer": answer,
            "embedding": np.array(embedding, dtype=np.float32).tobytes()
        })
        self.redis.expire(semantic_key, self.ttl)

缓存效果

缓存上线 7 天后的数据
═══════════════════════════════════════════
  精确缓存命中率:     22%
  语义缓存命中率:     16%
  总缓存命中率:       38%
───────────────────────────────────────
  每月避免 API 调用:  24000 × 38% = 9,120 次
  节省 LLM 成本:      $96 × 38% = $36.48/月
═══════════════════════════════════════════

优化 D:用户级限流与 Token 预算

缓存解决了"重复付费",限流解决了"异常消耗":

python
class TokenBudget:
    """用户级 Token 预算控制"""

    def __init__(self, redis_client):
        self.redis = redis_client
        # 每个用户每天的预算
        self.daily_limits = {
            "default": 50000,     # 普通用户:5 万 Token/天
            "power_user": 200000, # 高级用户:20 万 Token/天
            "admin": 500000,      # 管理员:50 万 Token/天
        }

    def check_budget(self, user_id: str, estimated_tokens: int,
                     role: str = "default") -> dict:
        """检查用户是否还有预算"""
        today = datetime.now().strftime("%Y%m%d")
        key = f"budget:{today}:{user_id}"

        used = int(self.redis.get(key) or 0)
        limit = self.daily_limits.get(role, self.daily_limits["default"])
        remaining = limit - used

        if estimated_tokens > remaining:
            return {
                "allowed": False,
                "used": used,
                "limit": limit,
                "remaining": remaining,
                "message": f"今日 Token 额度已用 {used}/{limit},"
                          f"剩余 {remaining},请明天再试。"
            }

        return {"allowed": True, "remaining": remaining}

    def consume(self, user_id: str, tokens_used: int):
        """消耗预算"""
        today = datetime.now().strftime("%Y%m%d")
        key = f"budget:{today}:{user_id}"
        self.redis.incrby(key, tokens_used)
        self.redis.expire(key, 86400 * 2)  # 保留 2 天

# 在 API 层面集成
budget = TokenBudget(redis_client)

def handle_question(user_id: str, question: str):
    # 1. 先查缓存
    cached = cache.get(question)
    if cached:
        return cached["answer"]

    # 2. 检查预算
    check = budget.check_budget(user_id, estimated_tokens=2000)
    if not check["allowed"]:
        return check["message"]

    # 3. 调用 LLM
    result = call_llm(question)

    # 4. 记录消耗
    budget.consume(user_id, result["total_tokens"])

    return result["answer"]

限流效果

限流上线后的变化
═══════════════════════════════════════════
  异常用户消耗:     从 15% → 3%
  日均请求量:       800 → 720(-10%)
  减少的请求大多是:
    → 脚本批量提问(被限流拦截)
    → 同一用户重复提问(被预算限制)
───────────────────────────────────────
  额外成本节省:     ~$6/月
═══════════════════════════════════════════

第二刀总结

第二刀优化效果(基于第一刀后的 $194)
═══════════════════════════════════════════
  优化项            成本变化          节省
─────────────────────────────────────────
  语义缓存          38% 请求免调用    -$37
  用户限流          异常流量 -80%     -$6
  合计节省                           -$43
─────────────────────────────────────────
  月总成本          $194 → $151      -$43(-22%)
  累计节省          $500 → $151      -$349(-70%)
  耗时              2 天
  新增依赖          Redis
═══════════════════════════════════════════

经验法则:缓存的投入产出比取决于你的请求重复率。如果重复率超过 20%,语义缓存就值得做。限流不是省钱的主力,但它是防止意外账单爆炸的安全网

9.4 第三刀:RAG 优化 + 监控(-30%)

前两刀砍掉了"模型浪费"和"重复浪费"。第三刀要解决的是检索层的浪费——喂给 LLM 太多无关内容,以及缺乏数据驱动的持续优化能力。

优化 E:检索结果精简

原来每次查询都取 Top 10 文档片段,但分析发现大部分时候只有 3-4 个片段真正相关:

Top 10 检索结果的相关性分析
═══════════════════════════════════════════
  排名 1-3:    平均相关性 0.85    → 高度相关
  排名 4-5:    平均相关性 0.72    → 部分相关
  排名 6-10:   平均相关性 0.55    → 大多不相关
───────────────────────────────────────
  结论:Top 6-10 的片段是"噪音"
  → 白白增加了 1000 Token 输入
  → 还可能干扰 LLM 的回答质量
═══════════════════════════════════════════

优化方案:动态截断 + 重排序

python
class SmartRetriever:
    """智能检索:动态数量 + 相关性过滤"""

    def __init__(self, vector_store, reranker=None):
        self.vector_store = vector_store
        self.reranker = reranker
        self.min_score = 0.70    # 最低相关性阈值
        self.max_chunks = 5      # 最多返回 5 个片段
        self.target_tokens = 1000  # 目标 Token 数

    def retrieve(self, query: str) -> list[dict]:
        """检索并过滤"""
        # 1. 先取 Top 10 候选
        candidates = self.vector_store.similarity_search(
            query, k=10
        )

        # 2. 过滤低相关性结果
        filtered = [
            c for c in candidates
            if c["score"] >= self.min_score
        ]

        # 3. 重排序(如果有 reranker)
        if self.reranker:
            filtered = self.reranker.rerank(query, filtered)

        # 4. 按 Token 预算截断
        selected = []
        total_tokens = 0
        for chunk in filtered[:self.max_chunks]:
            chunk_tokens = len(chunk["text"]) // 2  # 粗估
            if total_tokens + chunk_tokens > self.target_tokens:
                break
            selected.append(chunk)
            total_tokens += chunk_tokens

        return selected

# 效果对比
# 优化前:每次 10 个片段 × 200 Token = 2000 Token 上下文
# 优化后:每次 3-5 个片段 × 200 Token = 600-1000 Token 上下文

优化 F:分块策略调整

原来的分块策略太粗暴——固定 500 字一块,经常把一段完整的内容切断:

分块策略优化
═══════════════════════════════════════════
  优化前                      优化后
─────────────────────────────────────────
  固定 500 字切割             按标题/段落切割
  经常切断一段话的中间         每个块是完整的语义单元
  块之间没有重叠              块之间 50 字重叠
  平均块大小:500 字          平均块大小:300 字
─────────────────────────────────────────
  效果:
  → 检索精度提升(块更精准)
  → 单块更短,Token 消耗更低
  → 回答质量反而提高了
═══════════════════════════════════════════
python
from langchain.text_splitter import RecursiveCharacterTextSplitter

# 优化前
old_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=0,  # 无重叠
)

# 优化后
new_splitter = RecursiveCharacterTextSplitter(
    chunk_size=300,           # 更小的块
    chunk_overlap=50,          # 50 字重叠
    separators=[              # 按语义边界切割
        "\n## ",              # H2 标题
        "\n### ",             # H3 标题
        "\n\n",               # 段落
        "\n",                 # 换行
        "。",                 # 句号
    ],
)

# 重新索引文档库
# 文档数:3000 篇
# 优化前块数:~50,000
# 优化后块数:~75,000(块更小但更多)
# 重新 embedding 成本:一次性 ~$2(可忽略)

优化 G:监控体系搭建

前两刀都是"凭感觉"优化。第三刀我们搭建了监控体系,让后续优化有数据支撑

python
class CostMonitor:
    """轻量级成本监控"""

    def __init__(self, redis_client):
        self.redis = redis_client

    def record(self, event: dict):
        """记录每次调用"""
        today = datetime.now().strftime("%Y%m%d")
        pipe = self.redis.pipeline()

        # 按功能统计成本
        pipe.incrbyfloat(
            f"monitor:{today}:cost:{event['feature']}",
            event["cost"]
        )
        # 缓存命中统计
        if event.get("cached"):
            pipe.hincrby(f"monitor:{today}:cache", "hit", 1)
        else:
            pipe.hincrby(f"monitor:{today}:cache", "miss", 1)

        # 模型使用统计
        pipe.hincrby(
            f"monitor:{today}:model",
            event["model"], 1
        )

        # 检索统计
        if "chunks_used" in event:
            pipe.lpush(
                f"monitor:{today}:chunks",
                event["chunks_used"]
            )

        pipe.execute()

    def daily_report(self, date: str = None) -> str:
        """生成每日报告"""
        if not date:
            date = datetime.now().strftime("%Y%m%d")

        # 汇总数据
        cache_stats = self.redis.hgetall(f"monitor:{date}:cache")
        model_stats = self.redis.hgetall(f"monitor:{date}:model")

        hit = int(cache_stats.get("hit", 0))
        miss = int(cache_stats.get("miss", 0))
        total = hit + miss

        report = f"""
📊 成本日报 ({date})
─────────────────────────
  总请求:{total}
  缓存命中:{hit} ({hit/total*100:.1f}%)
  模型分布:{dict(model_stats)}
  """
        return report.strip()

# 每天自动发送日报
monitor = CostMonitor(redis_client)
print(monitor.daily_report())
# 📊 成本日报 (20250315)
# ─────────────────────────
#   总请求:756
#   缓存命中:287 (38.0%)
#   模型分布:{'gpt-4o-mini': '480', 'gpt-4o': '120'}

第三刀的成本影响

第三刀优化效果(基于第二刀后的 $151)
═══════════════════════════════════════════
  优化项               成本变化         节省
─────────────────────────────────────────
  检索精简(10→5 片段) 输入 Token -40%  -$15
  分块优化              单块 Token -30%  包含在上面
  向量数据库降级        Pinecone → pgvector  -$65
  监控体系              成本 ~$0        持续优化基础
─────────────────────────────────────────
  月总成本              $151 → $71      -$80(-53%)
  累计节省              $500 → $71      -$429(-86%)
  耗时                  3 天
═══════════════════════════════════════════

  向量数据库说明:
  ──────────────────────────────────────
  Pinecone Standard:$70/月
  pgvector(自建 PostgreSQL):$5/月(服务器成本分摊)
  → 数据量 75,000 条,pgvector 完全够用
  → 省了 $65/月,这是第三刀最大的单项节省

经验法则:RAG 优化是"精细活",单项节省不如前两刀明显,但向量数据库的选型可能是一个大的成本因子。如果你的数据量在百万级以下,pgvector 几乎是免费的。

9.5 最终效果:$500 → $50,质量不降

三刀砍完,我们再做最后一轮微调——利用监控数据发现了几个额外的优化点:

最终微调
═══════════════════════════════════════════
  1. Embedding 模型降级
     text-embedding-3-large → text-embedding-3-small
     精度影响可忽略,成本 -80%
     $0.16 → $0.03/月(本来就很少)

  2. 输出 max_tokens 精调
     简单问题:max_tokens 500 → 300
     → 分析发现 90% 的简单回答不超过 200 Token
     → 设 300 足够,减少极端情况的输出浪费

  3. 缓存 TTL 优化
     从 24 小时 → 72 小时
     → 知识库更新频率低,缓存可以更久
     → 缓存命中率从 38% 提升到 45%
═══════════════════════════════════════════

最终成本拆解

python
# 最终成本计算
final_cost = {
    # LLM API(含模型路由 + Prompt 瘦身)
    "llm_api": {
        "base_cost": 96.24,           # 模型路由后
        "cache_saving": 96.24 * 0.45, # 45% 缓存命中
        "rag_saving": 96.24 * 0.55 * 0.40,  # 非缓存请求,输入 Token -40%
        "actual": 96.24 * (1 - 0.45) * 0.60, # ≈ $31.76
    },

    # 向量数据库
    "vector_db": {
        "service": "pgvector on PostgreSQL",
        "monthly": 5.0,  # 服务器成本分摊
    },

    # Embedding(极低)
    "embedding": 0.03,

    # Redis(缓存 + 监控)
    "redis": 5.0,  # 小实例

    # 服务器
    "server": 8.0,  # FastAPI 小实例
}

total = 31.76 + 5.0 + 0.03 + 5.0 + 8.0
print(f"最终月成本: ${total:.2f}")
# 最终月成本: $49.79 ≈ $50

前后对比全景图

成本优化全流程对比
╔════════════════════════════════════════════════════════════╗
║  阶段          月成本    节省      累计降幅    耗时         ║
╠════════════════════════════════════════════════════════════╣
║  初始状态      $500      --        --          --          ║
║  第一刀        $194      -$306     -61%        1 天        ║
║   模型路由                                                ║
║   Prompt 瘦身                                             ║
║  第二刀        $151      -$43      -70%        2 天        ║
║   语义缓存                                                ║
║   用户限流                                                ║
║  第三刀        $71       -$80      -86%        3 天        ║
║   RAG 优化                                                ║
║   数据库降级                                               ║
║   监控体系                                                ║
║  最终微调      $50       -$21      -90%        0.5 天      ║
║   缓存 TTL                                                ║
║   输出限制                                                ║
╠════════════════════════════════════════════════════════════╣
║  总计          $50       -$450     -90%        6.5 天      ║
╚════════════════════════════════════════════════════════════╝

质量影响评估

成本砍了 90%,质量有没有下降?我们做了对比测试:

质量指标对比(200 道测试题)
═══════════════════════════════════════════════════
  指标                优化前        优化后        变化
─────────────────────────────────────────────────
  回答准确率          87%           85%           -2%
  回答完整度          82%           80%           -2%
  用户满意度          4.2/5         4.1/5         -0.1
  平均响应时间        3.2s          2.1s          -34% ✨
  幻觉率(胡说率)    8%            5%            -3% ✨
═══════════════════════════════════════════════════

分析:
  → 准确率下降 2%:GPT-4o-mini 处理简单问题的准确率略低
    但考虑到成本降 90%,这是完全可接受的权衡
  → 响应时间变快:缓存命中 + 更小的模型 = 更快
  → 幻觉率降低:检索结果更精准,LLM 收到的噪音更少

优化路线图总结

如果你也要做成本优化,建议按这个顺序执行:

成本优化执行路线图
═══════════════════════════════════════════════════════════

  周期 1(Day 1-2):快速见效
  ─────────────────────────────────────
  → 模型路由器(简单问题用小模型)     预期 -50~70%
  → System Prompt 瘦身
  → 输出格式约束(max_tokens)
  → 投入:半天开发,0 额外成本

  周期 2(Day 3-5):构建基础设施
  ─────────────────────────────────────
  → Redis 缓存(精确 + 语义)           预期 -20~40%
  → 用户限流 + Token 预算
  → 监控埋点
  → 投入:2 天开发,Redis 实例 $5/月

  周期 3(Day 6-10):精细优化
  ─────────────────────────────────────
  → RAG 检索精简(Top K 调优)          预期 -10~30%
  → 分块策略优化
  → 向量数据库选型评估
  → 投入:3 天开发 + 测试

  周期 4(持续):数据驱动
  ─────────────────────────────────────
  → 基于监控数据持续微调
  → 缓存 TTL 调优
  → 模型路由规则迭代
  → ROI 评估,下线低价值功能

═══════════════════════════════════════════════════════════

最重要的经验:成本优化不是一次性工程,但第一刀的 ROI 是最高的。80% 的节省来自 20% 的改动(模型路由 + Prompt 瘦身)。先把这 20% 做好,剩下的再慢慢迭代。


本章小结

知识点要点
案例背景企业 RAG 问答系统,200 用户,800 次/天,月成本 $500
问题诊断5 个核心问题:全用 GPT-4o、Prompt 巨长、检索太多、无缓存、无限流
第一刀模型路由 + Prompt 瘦身,$500 → $194(-61%),1 天搞定
第二刀语义缓存 + 用户限流,$194 → $151(-70%),需要 Redis
第三刀RAG 优化 + 向量数据库降级 + 监控,$151 → $71(-86%)
最终微调缓存 TTL + 输出限制,$71 → $50(-90%)
质量影响准确率 -2%,响应时间 -34%,幻觉率 -3%,整体可接受
执行顺序模型/Prompt → 缓存/限流 → RAG/监控 → 持续微调
核心经验80% 的节省来自 20% 的改动,先做模型路由和 Prompt 瘦身

全书总结:AI 应用的成本控制不是"抠门",而是"工程能力"。一个月 $500 的账单里可能有 $450 是浪费。掌握了本书的技术,你就有能力把每一分钱都花在刀刃上。

坚持是一种品格