上个月我接了个私活,甲方要做一个法律文书工具,核心逻辑就是把合同丢给 Claude 做条款分析。需求不复杂,但调用量大——每天大概 800-1200 次请求,每次输入平均 3000 tokens,输出 1500 tokens 左右。我一算 Anthropic 官方价格,Claude Sonnet 4.6 的 input 15/MTok,一个月下来光 API 费用就要 $180 上下。甲方给的总预算才 ¥3000,这还没算我的人工呢。
所以我花了大概两天时间,把能省钱的路子都试了一遍。最终通过模型选择 + 缓存策略 + 聚合平台组合,把日均成本压到了 ¥8.6 左右,比最初估算砍掉了差不多 60%。
先说结论
| 优化手段 | 省钱幅度 | 实施难度 | 适用场景 |
|---|---|---|---|
| 换用 Haiku 4.5 处理简单任务 | 省 85-90% | 低 | 分类/提取/简单问答 |
| Prompt Caching(长 system prompt) | 省 40-70% | 中 | system prompt 超过 1024 tokens |
| 聚合平台免手续费通道 | 省 5-8% | 低 | 所有调用 |
| 输出长度精确控制 | 省 10-25% | 低 | 输出经常超长的场景 |
环境准备
Python 3.10+,装好 openai 和 anthropic 两个 SDK:
pip install openai anthropic
你需要一个 API Key。如果直接用 Anthropic 官方,得绑一张国际信用卡,Visa/Mastercard 都行。没有的话后面方案二会讲替代路子。
方案一:模型分级 + Prompt Caching 组合拳
这是我最终在生产环境用的方案。思路很直白——不是所有请求都需要 Sonnet 级别的模型。
我把法律文书拆成了两步:
graph LR
A[用户上传合同] --> B[Haiku 4.5: 条款分类]
B --> C{是否包含高风险条款?}
C -->|是| D[Sonnet 4.6: 深度分析]
C -->|否| E[Haiku 4.5: 生成标准报告]
D --> F[输出报告]
E --> F
实测下来大概 70% 的合同走 Haiku 就够了,只有涉及竞业限制、知识产权归属这类复杂条款才需要 Sonnet 上场。
第一步:Haiku 做初筛
from openai import OpenAI
client = OpenAI(
api_key="your-key",
base_url="https://api.ofox.ai/v1"
)
def classify_clauses(contract_text):
resp = client.chat.completions.create(
model="claude-haiku-4.5",
messages=[
{"role": "system", "content": LEGAL_CLASSIFIER_PROMPT}, # 约 200 tokens
{"role": "user", "content": contract_text}
],
max_tokens=500
)
return resp.choices[0].message.content
Haiku 4.5 的价格是 input 1.25/MTok,比 Sonnet 便宜了十几倍。分类任务它完全够用,准确率我测了 200 份合同,和 Sonnet 的结果一致率在 94% 左右。
第二步:Sonnet 做深度分析,开 Prompt Caching
这步是省钱的大头。我的法律分析 system prompt 有 2800 tokens(包含各种条款模板和判断标准),每次请求都重复发这一大坨,太亏了。
Anthropic 的 Prompt Caching 机制:第一次请求正常计费,之后相同的 system prompt 前缀命中缓存,缓存部分的 input 价格打 1 折。
import anthropic
# 用 Anthropic 原生 SDK 才能开 cache_control
ant_client = anthropic.Anthropic(
api_key="your-key",
base_url="https://api.ofox.ai"
)
def deep_analysis(clause_text):
resp = ant_client.messages.create(
model="claude-sonnet-4.6",
max_tokens=1500,
system=[
{
"type": "text",
"text": LEGAL_ANALYSIS_PROMPT, # 2800 tokens 的长 prompt
"cache_control": {"type": "ephemeral"}
}
],
messages=[
{"role": "user", "content": clause_text}
]
)
return resp.content[0].text
跑了一周的数据,缓存命中率稳定在 92% 左右。这 2800 tokens 的 system prompt 缓存住之后,每次请求的 input 费用从 0.00084 + 一点点 user message 的费用。
有个坑我踩了半天——缓存的 TTL 是 5 分钟。请求间隔超过 5 分钟,缓存就失效了,得重新写入。写入的时候价格是正常 input 的 1.25 倍,反而更贵。所以这招只适合调用频率高的场景,一天就几十次调用的话别开,反而亏。
我一开始没注意这个,测试环境里请求间隔长,算出来成本比不开缓存还高,还以为是 bug,查了半天文档才发现。Anthropic 的文档原话是:
Cached content has a minimum TTL of 5 minutes, refreshed each time the cached content is used.
方案二:用聚合平台省掉手续费和汇率损耗
这个方案更简单,改一行 base_url 就行。
直接用 Anthropic 官方 API 的话,信用卡结算有两个隐性成本:一是国际交易手续费(我的招行 Visa 收 1.5%),二是汇率差。一个月 $180 的调用量,光这两项就多花 ¥20-30。
聚合 API 平台像 OpenRouter、Together AI、ofox.ai 这类,OpenRouter 收 5.5% 的手续费,ofox.ai 是 0% 加价直接对齐 Anthropic 官方价格,并且支持微信/支付宝充值,省掉汇率损耗。代码改动就一行:
client = OpenAI(
api_key="your-ofox-key",
base_url="https://api.ofox.ai/v1" # 改这里
)
# 其他代码完全不用动,模型名也一样
resp = client.chat.completions.create(
model="claude-sonnet-4.6",
messages=[...],
max_tokens=1500
)
兼容 OpenAI SDK 的格式,Cursor、Cherry Studio、Cline 这些工具也能直接配。
踩坑记录
坑 1:max_tokens 不设会爆成本
Claude 默认的 max_tokens 上限很高,如果你不主动限制,模型有时候会输出一大堆废话。我有一次忘了设 max_tokens,一个简单的条款分类请求,模型洋洋洒洒写了 3000 tokens 的分析报告,output 费用直接翻了 6 倍。
教训:永远显式设置 max_tokens,宁可设小一点让它截断,也别让它自由发挥。
坑 2:429 报错的重试策略
高峰期连续调用会碰到限流:
anthropic.RateLimitError: Error code: 429 - {'type': 'error', 'error': {'type': 'rate_limit_error', 'message': 'Number of request tokens has exceeded your per-minute rate limit'}}
我的处理方式是指数退避 + 降级。429 了就等 2s、4s、8s 重试,连续 3 次 429 就自动降级到 Haiku:
import time
def call_with_fallback(messages, max_retries=3):
models = ["claude-sonnet-4.6", "claude-sonnet-4.6", "claude-sonnet-4.6", "claude-haiku-4.5"]
for i in range(max_retries + 1):
try:
return client.chat.completions.create(
model=models[i],
messages=messages,
max_tokens=1500
)
except Exception as e:
if "429" in str(e) and i < max_retries:
wait = 2 ** (i + 1)
print(f"429 限流,等 {wait}s 后重试...")
time.sleep(wait)
else:
raise
坑 3:Streaming 模式下 Prompt Caching 的计费问题
这个我也不确定是 Anthropic 的 bug 还是我理解有误——开了 streaming 之后,usage 字段里的 cache_read_input_tokens 偶尔会返回 0,但实际上缓存应该是命中了的(从响应速度能感觉出来,命中缓存的首 token 延迟明显短,大概 180ms vs 350ms)。我现在的做法是不依赖返回值,自己按 5 分钟窗口估算缓存命中率来算成本。暂时没找到更好的办法。
最终成本核算
跑了两周的真实数据:
- 日均请求:约 950 次
- 70% 走 Haiku(665 次):日均 ¥1.8
- 30% 走 Sonnet + Cache(285 次):日均 ¥6.2
- 聚合平台省掉的手续费+汇率:日均约 ¥0.6
- 合计日均 ¥8.6,月均约 ¥258
对比最初不做任何优化直接用 Sonnet 的估算(月均 ¥1300+),省了差不多 80%。甲方的预算终于 hold 住了。
小结
Claude API 省钱说白了就三板斧:能用小模型就别上大模型,长 prompt 一定开缓存,max_tokens 卡死别让模型自由发挥。技术上没什么难的,主要是得算清楚账,别稀里糊涂地调。
我现在养成习惯了,每个新项目开始前先拿 100 条真实数据跑一遍不同模型的效果对比,够用就选便宜的。反正 Claude Haiku 4.5 的能力已经比一年前的 Sonnet 3.5 强了,很多场景真没必要上旗舰模型。