我把大模型API月账单从5000砍到800的踩坑实录

上个月帮一个做跨境电商的朋友看了他们的大模型API账单,真吓人——五月底的时候月消费已经飙到5000多块,但他们的业务量跟年初比也就翻了一倍不到。他们主要用大模型干两件事:批量生成商品listing描述,以及一个半自动的客服机器人。我当时翻了下他们的调用日志,好家伙,一个月两三百万次API调用,其中将近40%是重复的或者几乎重复的请求。朋友说"你先帮我把成本压下来,下个月业务要上一个新站点,再涨就扛不住了"。行,那就干。

先搞清楚钱到底花在哪了

说实话我第一反应是"调轻量模型就行了吧",但真翻日志之后发现没那么简单。他们调的全是旗舰级模型,单次调用确实贵,但更离谱的是缓存几乎等于没有。

我拉了一周的数据做了个简单统计:同一条商品标题+属性组合,平均被调用了7次。为什么?因为他们的前端有个"重新生成"按钮,用户多点两下就重新发请求,后端毫无拦截。再加上他们有个定时任务,每天凌晨把全量商品数据重新过一遍模型,哪怕内容压根没变。

我给他们加了一层响应缓存,key用商品ID+属性哈希+prompt版本来做:

```python
import hashlib
import redis

def build_cache_key(product_id: str, attrs: dict, prompt_version: str) -> str:
raw = f"{product_id}:{hashlib.md5(str(sorted(attrs.items())).encode()).hexdigest()}:{prompt_version}"
return f"llm_resp:{raw}"

def get_or_call_model(prompt: str, product_id: str, attrs: dict, version: str):
key = build_cache_key(product_id, attrs, version)
cache = redis.from_url("redis://cache-node:6379/2")
cached = cache.get(key)
if cached:
return json.loads(cached)

result = call_flagship_model(prompt)
cache.set(key, json.dumps(result, ensure_ascii=False), ex=86400 * 3)
return result
```

当时我觉得这样就行了,命中率应该能到60%以上。结果上线第二天一看,命中率才22%。坑死了。排查了一下午才发现,他们的属性字段里有几个是浮点型的评分,每次请求传的精度不一样(有时候3.7,有时候3.70),哈希结果就全对不上了。后来统一做了精度截断,命中率才稳定到65%左右。光这一步,月调用量直接砍掉了将近三分之一。

模型分级:不是每个请求都得用旗舰模型

缓存解决的是"重复调用"的问题,但还有一大块成本在于:他们所有场景全用的同一个旗舰模型。客服机器人里70%的问题其实是"我的包裹到哪了""能退货吗"这种模板化内容,根本不需要旗舰模型理解复杂语境。

这里当时有两个方案。方案A是全部切到轻量模型,成本直接降到原来的1/5,但朋友担心listing描述质量会掉,毕竟那些是直接影响转化的东西。方案B是按场景分级:listing生成和复杂客服对话走旗舰模型,简单FAQ和物流查询走轻量模型。我选了方案B,核心原因就是——不能一刀切。

实现上挺直接的,在他们网关层加了个路由:

```python
MODEL_ROUTES = {
"listing_generate": "flagship-v3",
"customer_complex": "flagship-v3",
"customer_faq": "lite-v2",
"logistics_query": "lite-v2",
"tag_classification": "micro-v1", # 纯分类任务
}

def route_model(scene: str, user_query: str = "") -> str:
base = MODEL_ROUTES.get(scene, "flagship-v3")

简单客服问题降级:问句长度<20字且命中FAQ知识库则走lite

if scene == "customer_complex" and len(user_query) < 20:
if faq_knowledge.hit(user_query, threshold=0.85):
return "lite-v2"
return base
```

有意思的是,上线后客服那边的用户满意度基本没掉,因为FAQ命中率其实很高,用户问的都是那几个问题。但listing那边朋友还是坚持用了旗舰,这个我尊重,毕竟那是直接产生收入的环节。

Token层面还能再抠一点

模型分级做完之后月成本大概降到2200左右了,离800还差得远。我接着看prompt,发现他们系统提示词有将近800个token,里面塞了一堆"你是专业电商文案专家,擅长……"之类的角色描述,还有五六条互斥的格式要求。我帮他们把系统prompt压到了250个token左右,把格式约束直接放进了JSON schema里让模型自己遵循,省掉了一大段自然语言描述。

另外他们客服场景的上下文管理也很粗糙,把最近20轮对话全部塞进去。我改成只保留最近5轮,更早的对话压缩成一段摘要放在system里。这一条在token层面又省了大约15%。

还有一个小细节:他们之前用模型生成的是纯文本,前端自己再做一次格式化。我改成让模型直接输出结构化JSON,省掉了后续一次"把文本转JSON"的额外调用。这个看起来不起眼,但一天几千次客服对话累积起来,一个月少了一万多块钱。

最终三个手段叠加,月账单稳定在800出头。朋友下个月要开新站点,按现在的成本结构多开一个站点也就多200块,完全可接受。

我复盘的时候其实有点犹豫,缓存那一层如果当时用更激进的策略(比如直接按商品ID做24小时硬缓存,不管属性变没变),成本还能再压一截,但风险是商品改个价格描述就过期了。最后选择了属性哈希做key,牺牲了一点缓存命中率换准确性,我觉得这个trade-off对电商场景是合理的。

本文基于实际项目经验整理,欢迎在评论区交流技术问题。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐