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 段上下文
└──────┬───────┘
│
▼
返回回答成本拆解
# 初始成本结构分析
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 份文档总结项目风险"
→ "帮我基于模板写一份技术评审"
→ 需要推理、对比、生成
───────────────────────────────────────于是我们实现了一个模型路由器:
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%)
═══════════════════════════════════════════════════════# 成本计算验证
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%)
═══════════════════════════════════════════# 瘦身前
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 + 语义相似度实现了双层缓存:
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 预算
缓存解决了"重复付费",限流解决了"异常消耗":
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 的回答质量
═══════════════════════════════════════════优化方案:动态截断 + 重排序。
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 消耗更低
→ 回答质量反而提高了
═══════════════════════════════════════════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:监控体系搭建
前两刀都是"凭感觉"优化。第三刀我们搭建了监控体系,让后续优化有数据支撑:
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%
═══════════════════════════════════════════最终成本拆解
# 最终成本计算
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 是浪费。掌握了本书的技术,你就有能力把每一分钱都花在刀刃上。