Day 56 / 共 68 天 · 阶段 10 可信可观测
成本治理 & 缓存:别让账单吓一跳
昨天(Day 55)学会了「看表」——盯住 token、延迟、错误率。今天解决下一个现实问题:怎么少花钱。大模型是按 token 计费的,一个没管好的 Agent 一个月能烧掉几万块。今天四招:先把账算清(预算归因,搞清谁花的)、把活分级(模型路由,贵活派贵模型、便宜活派便宜模型)、重复的问题直接查缓存(prompt/结果缓存)、能攒一批的用批处理打折。学完你就能把成本砍掉一大半,还能给老板讲清「钱花哪了」;这也是阶段 10 的收官,明天(Day 57)进入部署篇,学 Docker 打包。
📍 你在阶段 10(可信可观测 D53-56)的位置
D53 防幻觉 Critic→
D54 失败闸门&护栏→
D55 可观测→
D56 成本治理&缓存
💡 用一个类比兜住今天(今天全程沿用「过日子管家用钱」的世界观)
运营一个 Agent = 当一个精打细算的家庭管家。token 计费 = 家里的水电费(用多少算多少);预算归因 = 记账本(搞清这个月钱花在谁身上、哪个功能最烧钱);模型路由 = 会持家的智慧(买菜去菜市场、办大事才请专家,不能顿顿下馆子);缓存 = 昨天熬的汤留着今天热一热(同样的问题别花两次钱);批处理 = 超市大包装比零买便宜(能攒一起买就不零买)。今天你从「大手大脚」升级成「会过日子的管家」。
L01
成本为何会悄悄失控
🤔 痛点开发时随便测测没几个钱,一上线用户量一涨,月底账单直接翻十倍。更糟的是你还说不清「这钱到底花哪了」——是某个功能太费,还是有人恶意刷,完全一头雾水。
💡 本质大模型按 token 计费,输入和输出分开算价,越贵的模型单价越高。成本 ≈ 请求量 × 每次 token 数 × 单价。三个数任何一个失控,账单就爆。就像家里水费:用水次数、每次用量、水价,任何一个涨了都心疼。治理成本 = 盯住这三个乘数,逐个压下去。
图注:今天的每一招,都对应砍这三个乘数中的某一个。心里有这个公式,就不会瞎优化。
👶 为什么输入 token 也要钱?我又没让它生成那么多。因为模型每次都要「读一遍」你给它的所有内容(系统提示 + 历史对话 + 检索到的文档),读进去的每个字都算输入 token。所以一个塞了超长 prompt、超长历史的 Agent,哪怕只回一句话,输入这头也很烧钱。Day 18 学的「上下文工程」不只是为了效果,也是为了省钱。
L02
预算归因:先记账,才知道砍谁
🤔 痛点老板说「成本太高,砍一半」。可你连「钱花在哪个功能、哪个用户、哪个模型」都不知道,怎么砍?乱砍可能把最有价值的功能砍没了。
💡 本质预算归因 = 给每一笔 token 花费打上标签(谁花的、哪个功能、哪个模型),这样能按标签汇总,一眼看出「大头在哪」。就像家庭记账本按「买菜/交通/教育」分类,月底一看就知道哪项超支。这一步直接接上昨天的可观测——你已经在日志里记了 token,现在只要加几个标签再汇总。
# 复用 Day55 的日志思路,但多打几个「归因标签」
def log_cost(feature, user_id, model, in_tok, out_tok):
# 各家单价不同,这里用「每百万 token 多少美元」的示意价自己算
price = {"cheap": (0.25, 1.25), "pro": (3.0, 15.0)}[model] # (输入价, 输出价)
cost = in_tok / 1e6 * price[0] + out_tok / 1e6 * price[1]
print({"feature": feature, "user": user_id, "model": model,
"cost_usd": round(cost, 5)}) # 带标签,事后能按 feature/user 汇总
return cost
# 一天下来把所有记录按「功能」汇总,就知道谁最烧钱
log_cost("摘要", "u1", "pro", 3000, 800) # 贵模型 + 长输入 → 最烧
log_cost("闲聊", "u2", "cheap", 200, 100) # 便宜活
📝 举个例子:归因一下就抓到「元凶」
汇总一个月的日志,按功能分类:
结论清晰:优化重点就是「文档摘要」——先做检索只塞相关段落、或换便宜模型。没有归因,你会平均用力;有了归因,你精准打击。
文档摘要功能:占总成本 68% ← 元凶!(因为每次塞整篇长文档进去)问答功能:22% 闲聊:10%结论清晰:优化重点就是「文档摘要」——先做检索只塞相关段落、或换便宜模型。没有归因,你会平均用力;有了归因,你精准打击。
👶 归因标签打哪几个够用?三个最实用:
feature(哪个功能)、user_id 或 tenant(哪个用户/客户,SaaS 里要按客户分摊成本)、model(哪个模型)。再加 trace_id 就能顺藤摸瓜查到具体那一次。L03
模型路由:便宜活别请贵专家
🤔 痛点很多人图省事,所有请求都用最强(最贵)的模型。可「今天天气怎么样」这种简单活,用顶级模型是杀鸡用牛刀,钱哗哗流。
💡 本质模型路由 = 先判断这活难不难,简单活派给便宜/小模型,难活才派给贵/强模型。回顾 Day 15 学的分流思想。就像家里办事:买瓶酱油自己去菜市场(便宜),打官司才请律师(贵)。关键是要有个「分诊台」先判断难度。
图注:分诊本身可以用规则(关键词/长度)或一个便宜小模型来判难度,成本极低,收益很大。
def route(question):
# 最朴素的分诊:用规则判难度(真项目里也可用小模型判)
hard_signals = ["为什么", "分析", "写代码", "对比", "推理"]
is_hard = len(question) > 60 or any(k in question for k in hard_signals)
return "pro" if is_hard else "cheap" # 难→贵模型,简单→便宜模型
print(route("你好呀")) # → cheap(便宜活)
print(route("分析这三个方案的优劣并给建议")) # → pro(难活值得花钱)
👶 小白:那我全用便宜模型不就最省了吗?
👨🏫 老师:省是省,但便宜模型难活会答砸,砸了要么用户跑了、要么你得重试反而更贵。目标不是「最便宜」,是「在满足质量的前提下最便宜」——这就要靠昨天学的可观测:一边路由省钱,一边盯着质量分别掉。省钱和质量是跷跷板,可观测就是那把尺。还有个进阶招叫「便宜模型先试,不行再升级到贵模型」(级联),但要小心别把两次都花了。
L04
缓存:一样的问题别花两次钱
🤔 痛点「你们的退货政策是什么?」这个问题一天被问 800 次,答案几乎一模一样。每次都真的去调一遍模型,等于同一道菜天天从头做——又慢又费钱。
💡 本质缓存 = 把「问过的问题 → 生成的答案」存起来,下次一样的问题直接端出来,不再调模型。省钱又秒回。就像昨天熬好的汤放冰箱,今天热一热就能喝,不用重新熬。两个层次:① 结果缓存(整个答案存起来,命中就 0 花费);② 提示词缓存 prompt caching(很多模型 API 支持:把不变的长前缀——如系统提示、固定文档——缓存起来,重复部分打折计费)。
| 缓存类型 | 存什么 | 省多少 |
|---|---|---|
| 结果缓存 | 「问题 → 完整答案」映射(自己用字典/Redis 存) | 命中就完全不花钱,还秒回 |
| 提示词缓存 | 不变的长前缀(系统提示/固定文档),模型侧缓存 | 重复读的那部分 token 大幅打折 |
cache = {} # 最简单的结果缓存:一个字典(真项目用 Redis,能设过期时间)
def ask_with_cache(question):
key = question.strip().lower() # 归一化:去空格、转小写,提高命中率
if key in cache: # 命中缓存
print("💰 命中缓存,0 花费,秒回")
return cache[key]
answer = call_model(question) # 未命中才真花钱调模型
cache[key] = answer # 存起来,下次直接用
return answer
📝 举个例子:缓存命中率的威力
客服 Agent 上线后统计:
40% 的问题是重复的高频问题。加上结果缓存后,这 40% 请求成本直接归零、响应从 2 秒变 10 毫秒。一行字典就能让账单立减近四成——缓存是性价比最高的一招。👶 缓存有什么坑要小心?三个:①时效——政策改了,旧答案还在缓存里会误导人,所以要设「过期时间」或改动时清缓存;②个性化——「我的订单到哪了」这种因人而异的问题不能缓存;③命中率——问法千变万化(「退货」vs「怎么退」)会降低命中,可用「语义缓存」(问题也 embedding,相似就算命中)提升,但那要多花点检索成本,权衡着用。
L05
批处理:能攒一起买就别零买
🤔 痛点有些活不急着马上要结果——比如「把一万条用户评论都分个类」「给一批文章各写个摘要」。一条一条实时调,又慢又按原价算,没必要。
💡 本质批处理(batch) = 把大量「不着急」的任务攒成一批,一次性提交,模型厂商通常给明显折扣(代价是结果不是实时,可能等几分钟到几小时)。就像超市大包装比零买便宜、批发比零售便宜。关键判断:这活是「用户在等着的」(实时)还是「后台慢慢跑的」(可批)?
图注:一个成熟系统往往「两条腿走路」——实时通道保体验,批处理通道降成本。
各家批处理 API 的用法、折扣、最长等待时间不一样,别背具体数字。记住判断标准:用户在实时等 → 走实时;后台离线任务 → 走批处理省钱。再加一招:把不急的活攒到低峰期跑,也能错开限流。
L06
预算闸 + 组合拳:把四招串起来
🤔 痛点就算前面都做了,万一有人恶意刷接口、或代码 bug 死循环调模型,一夜之间也能烧穿预算。省钱之外,还得有个「保险丝」。
💡 本质预算闸(budget guardrail) = 给花费设上限,快超了就报警、降级或直接拦。回忆 Day 54 的「护栏/闸门」思想——这是它在「钱」这个维度的应用。就像家里设的信用卡限额,刷爆自动停。把「归因 + 路由 + 缓存 + 批处理 + 预算闸」串起来,才是完整的成本治理。
DAILY_BUDGET = 50.0 # 今天最多花 50 美元
spent_today = 0.0
def guarded_call(question):
global spent_today
if spent_today >= DAILY_BUDGET: # 预算闸:超了就拦
return "⚠️ 今日预算已用尽,请稍后或联系管理员"
# 组合拳顺序:先查缓存 → 再路由选模型 → 记账归因
ans = ask_with_cache(question) # 1) 缓存:命中就 0 花费
model = route(question) # 2) 路由:难度决定模型
cost = log_cost("qa", "u1", model, 500, 200) # 3) 归因:记这笔账
spent_today += cost # 累加今日花费
if spent_today > DAILY_BUDGET * 0.8: # 到 80% 先预警
print("🔔 预算已用 80%,注意!")
return ans
📝 举个例子:组合拳能省多少
一个客服 Agent 优化前后对比(示意):
四招叠加,成本降到约四分之一,质量几乎不变。这种「我把成本砍了 70%」的量化结果,写进简历、面试讲出来,极其加分。
🔗 想看成本闸、预算护栏在真实多 Agent 系统里怎么落地?去看《gov-agents 多 Agent 框架教程》→ 学完回来收官 Day 56
优化前:全用贵模型、无缓存 → 月账单 ¥30000加缓存(命中40%) → ¥18000 再加路由(60%走便宜模型) → ¥8000四招叠加,成本降到约四分之一,质量几乎不变。这种「我把成本砍了 70%」的量化结果,写进简历、面试讲出来,极其加分。
L07
今日小结 + 动手 10 分钟
🧠 今天你应该能回答
- 账单的成本公式是什么?(请求量 × 每次 token × 单价)
- 预算归因是什么?该打哪几个标签?为什么先归因再优化?
- 模型路由的思路?为什么「全用便宜模型」不一定最省?
- 结果缓存和提示词缓存分别省什么?缓存有哪三个坑?
- 什么活适合批处理?怎么判断实时还是批处理?
- 预算闸解决什么问题?四招怎么串成组合拳?
✋ 动手 10 分钟:给一个「小管家」加上缓存 + 路由 + 记账
新建 day56.py,把今天几招串起来跑一遍,直观看到「命中缓存 0 花费、便宜活走便宜模型」:
cache = {}
spent = 0.0
PRICE = {"cheap": 0.001, "pro": 0.02} # 示意:每次调用的粗略成本
def route(q): # 分诊:难活走 pro
return "pro" if len(q) > 20 or "分析" in q else "cheap"
def ask(q):
global spent
key = q.strip().lower()
if key in cache: # 命中缓存
print(f"💰 [缓存命中] {q} 本次花费 0")
return cache[key]
model = route(q) # 未命中:选模型
cost = PRICE[model]
spent_before = spent
cache[key] = f"[{model}模型的回答] {q}"
globals()['spent'] += cost
print(f"🛒 [{model}] {q} 本次花费 {cost}")
return cache[key]
# 故意有重复问题、有简单有难,观察花费
for q in ["你好", "你好", "分析下这个方案的优缺点", "你好", "退货政策"]:
ask(q)
print(f"\n总花费 = {round(spent,4)}(比全走 pro、无缓存省了多少?自己算算)")
加分题:把「每次调用」也用 Day55 的结构化日志打出来(带 feature/model/cost 标签),再按 model 汇总——你就同时做完了「可观测 + 成本归因」,这正是线上运维的完整闭环。
明日预告 · Day 57:阶段 10「可信可观测」到此收官——你已经能让 Agent 可信(Critic/护栏)、看得见(可观测)、花得省(成本治理)。明天进入阶段 11 部署篇,第一课是 Docker:把你的 Agent 服务连同它的所有依赖打包成一个「集装箱」,做到「在我电脑能跑,在服务器上也一模一样能跑」,彻底告别「在我这儿是好的呀」这句噩梦。