成本问题的本质

LLM 计费公式:成本 = Token 数 × 单价。优化方向只有两个:减少 Token 数、降低单价。

┌──────────────────────────────────────────────┐
│              总 API 成本                      │
│  ┌──────────────────────────────────────┐    │
│  │  Token 优化 (减少输入)                │    │
│  │  - Prompt 压缩                       │    │
│  │  - 历史截断                          │    │
│  │  - Few-shot 精简                     │    │
│  └──────────────────────────────────────┘    │
│  ┌──────────────────────────────────────┐    │
│  │  模型路由 (降低单价)                  │    │
│  │  - 简单 → 小模型 ($0.15/1M)         │    │
│  │  - 复杂 → 大模型 ($10/1M)           │    │
│  └──────────────────────────────────────┘    │
│  ┌──────────────────────────────────────┐    │
│  │  架构优化 (减少调用)                  │    │
│  │  - 缓存 (命中率 60%)                 │    │
│  │  - 批量推理                          │    │
│  │  - 流式输出提前终止                   │    │
│  └──────────────────────────────────────┘    │
└──────────────────────────────────────────────┘

一、Token 优化

1.1 Prompt 压缩

class PromptCompressor:
    """多层 Prompt 压缩"""

    def compress(self, system_prompt: str, history: list, query: str) -> str:
        # 1. 系统提示词精简
        system = self._trim_system(system_prompt)
        # 2. 历史对话压缩
        history = self._compress_history(history)
        # 3. Few-shot 示例选择(只保留最相关的)
        examples = self._select_relevant_examples(query, k=2)
        # 4. 组装
        return f"{system}\n\n{examples}\n\n历史:{history}\n\n问题:{query}"

    def _trim_system(self, prompt: str) -> str:
        """去除冗余描述,保留核心指令"""
        # 去除重复空格和换行
        import re
        prompt = re.sub(r'\n{3,}', '\n\n', prompt)
        prompt = re.sub(r' {2,}', ' ', prompt)
        # 去除注释性文字
        prompt = re.sub(r'#.*\n', '', prompt)
        return prompt.strip()

    def _compress_history(self, history: list, max_turns: int = 5) -> str:
        """压缩对话历史:保留最近 N 轮 + 摘要"""
        if len(history) <= max_turns:
            return "\n".join([f"用户: {h['user']}\n助手: {h['assistant']}"
                            for h in history])
        # 早期对话生成摘要
        old = history[:-max_turns]
        recent = history[-max_turns:]
        summary = self._summarize(old)
        recent_text = "\n".join([f"用户: {h['user']}\n助手: {h['assistant']}"
                                  for h in recent])
        return f"[之前对话摘要:{summary}]\n\n{recent_text}"

1.2 Token 计算与监控

import tiktoken

class TokenMonitor:
    def __init__(self, model="gpt-4"):
        self.encoder = tiktoken.encoding_for_model(model)

    def count(self, text: str) -> int:
        return len(self.encoder.encode(text))

    def estimate_cost(self, input_tokens: int, output_tokens: int,
                      model: str) -> float:
        PRICING = {
            "gpt-4": {"input": 0.03, "output": 0.06},
            "gpt-4o": {"input": 0.005, "output": 0.015},
            "gpt-4o-mini": {"input": 0.00015, "output": 0.0006},
            "claude-3.5-sonnet": {"input": 0.003, "output": 0.015},
        }
        p = PRICING.get(model, PRICING["gpt-4"])
        return (input_tokens * p["input"] + output_tokens * p["output"]) / 1000

1.3 压缩效果对比

优化手段Token 节省质量影响
去除冗余空白5-10%
历史摘要40-60%轻微
Few-shot 精简20-30%可控
输出 max_tokens 限制15-25%
函数调用替代文本解析10-15%正面

二、模型路由

核心思路:80% 的请求用小模型,20% 的请求用大模型。

from enum import Enum

class Complexity(Enum):
    SIMPLE = "simple"
    MODERATE = "moderate"
    COMPLEX = "complex"

MODEL_MAP = {
    Complexity.SIMPLE: "gpt-4o-mini",      # $0.15/$0.60 per 1M
    Complexity.MODERATE: "gpt-4o",          # $5/$15 per 1M
    Complexity.COMPLEX: "gpt-4",            # $30/$60 per 1M
}

class ModelRouter:
    def __init__(self, classifier_model="gpt-4o-mini"):
        self.classifier = classifier_model

    async def classify(self, query: str) -> Complexity:
        """用小模型做分类,成本低"""
        prompt = f"""判断以下查询的复杂度,只返回 simple/moderate/complex:
- simple: 简单问答、翻译、格式转换
- moderate: 代码生成、分析总结、多步推理
- complex: 复杂推理、创意写作、数学证明

查询:{query}"""
        resp = await self._call_model(self.classifier, prompt, max_tokens=5)
        level = resp.strip().lower()
        return Complexity(level) if level in ["simple", "moderate", "complex"] else Complexity.MODERATE

    async def route(self, query: str) -> str:
        complexity = await self.classify(query)
        return MODEL_MAP[complexity]

路由策略效果

假设月调用 1M 次,平均 2000 input + 500 output tokens:

策略模型分布月成本vs 全 GPT-4
全 GPT-4100% GPT-4$90,000baseline
简单路由70% mini / 20% 4o / 10% GPT-4$16,800-81%
智能路由60% mini / 30% 4o / 10% GPT-4$19,200-79%

三、批量推理

import asyncio

class BatchInference:
    """批量推理:合并多请求,利用 batch API 折扣"""

    def __init__(self, batch_size=100, max_wait=5.0):
        self.batch_size = batch_size
        self.max_wait = max_wait
        self.queue = asyncio.Queue()
        self.results = {}

    async def submit(self, query: str) -> str:
        task_id = id(query)
        await self.queue.put((task_id, query))
        # 等待结果
        while task_id not in self.results:
            await asyncio.sleep(0.01)
        return self.results.pop(task_id)

    async def process_batches(self, llm_client):
        while True:
            batch = []
            try:
                # 等待第一个请求
                first = await asyncio.wait_for(
                    self.queue.get(), timeout=self.max_wait
                )
                batch.append(first)
                # 非阻塞收集更多
                while len(batch) < self.batch_size:
                    try:
                        item = self.queue.get_nowait()
                        batch.append(item)
                    except asyncio.QueueEmpty:
                        break
                # 批量调用
                results = await self._batch_call(llm_client, batch)
                for task_id, result in results:
                    self.results[task_id] = result
            except asyncio.TimeoutError:
                continue

四、缓存策略

class TieredCache:
    """三级缓存 + 成本追踪"""

    def __init__(self):
        self.stats = {"hit_l1": 0, "hit_l2": 0, "miss": 0, "saved_cost": 0.0}

    async def get_or_call(self, query: str, llm_call, cache):
        # L1 精确缓存
        exact = cache.exact_get(query)
        if exact:
            self.stats["hit_l1"] += 1
            self.stats["saved_cost"] += self._estimate_cost(query)
            return exact

        # L2 语义缓存
        semantic = cache.semantic_get(query)
        if semantic:
            self.stats["hit_l2"] += 1
            self.stats["saved_cost"] += self._estimate_cost(query)
            return semantic

        # 未命中 → LLM 调用
        self.stats["miss"] += 1
        response = await llm_call(query)
        cache.set(query, response)
        return response

    def report(self) -> dict:
        total = sum(self.stats.values())
        hit_rate = (self.stats["hit_l1"] + self.stats["hit_l2"]) / max(total, 1)
        return {"hit_rate": hit_rate, "saved_cost": self.stats["saved_cost"]}

五、自部署 vs API TCO 分析

维度API 调用自部署 (7B 模型)自部署 (70B 模型)
初始成本$0$15,000 (GPU)$80,000 (GPU)
月运营成本$0.03/1K tokens$2,000 (服务器)$8,000 (服务器)
月调用量10M tokens10M tokens10M tokens
月成本$300$2,000$8,000
月调用量100M tokens100M tokens100M tokens
月成本$3,000$2,000$8,000
月调用量1B tokens1B tokens1B tokens
月成本$30,000$2,000$8,000
延迟 P500.5-2s0.3-1s1-3s
运维复杂度很高
模型质量GPT-4 级别Llama 7B 级别Llama 70B 级别

盈亏平衡点:月 Token 量 > 500M 时,自部署 7B 模型开始比 API 便宜。

def tco_analysis(monthly_tokens_millions: float, api_price_per_1k: float,
                 server_monthly_cost: float, gpu_cost: float,
                 gpu_lifetime_months: int = 36):
    """TCO 对比分析"""
    api_monthly = monthly_tokens_millions * 1000 * api_price_per_1k
    self_deploy_monthly = server_monthly_cost + gpu_cost / gpu_lifetime_months

    break_even = server_monthly_cost / (api_price_per_1k * 1000)  # 百万 tokens
    cheaper = "self-deploy" if self_deploy_monthly < api_monthly else "api"

    return {
        "api_monthly_cost": api_monthly,
        "self_deploy_monthly_cost": self_deploy_monthly,
        "break_even_tokens_millions": break_even,
        "cheaper_option": cheaper,
        "monthly_savings": abs(api_monthly - self_deploy_monthly),
    }

六、综合优化策略

优化手段成本降低实施难度质量影响
Prompt 压缩20-30%轻微
模型路由60-80%可控
缓存40-70%
批量推理10-20%
自部署50-90%取决于模型
输出限制15-25%
流式提前终止5-10%

实施优先级:模型路由 > 缓存 > Prompt 压缩 > 批量推理 > 自部署

总结

省 80% 费用不是单一手段实现的,而是组合拳:模型路由解决单价问题(-60%),缓存减少调用次数(-30%),Prompt 压缩减少单次 Token(-25%),三者叠加效果:1 × 0.4 × 0.7 × 0.75 = 0.21,即节省 79%。自部署是终极方案但需要足够的规模和运维能力。

加入讨论

这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。

碳基与硅基的智慧碰撞,认知差异创造无限可能。