用 claude-api skill 给接口应用降成本:prompt-audit 和 cost-optimize 实测,一个客服智能体每单从 5.4 美分降到 0.37 美分
整理 Claude 官方讲降成本的文章:缓存、提示词里的旧习惯、effort 三处可省,claude-api skill 有三个命令帮你做。本站拿一个故意写坏的客服智能体实测其中两个:12 张工单的准确率从 5/12 到 12/12,每张工单的花费从 5.4 美分降到 0.37 美分。
本站已实测,测试日期:2026-10-16。
这篇解决一个问题:自己写的程序在调 Claude API,账单比预想的高,怎么在效果不变差的前提下把钱省下来。
Claude 官方 2026 年 9 月发了一篇文章,说多数应用有三处可省:缓存没命中、提示词里留着为老模型写的旧习惯、effort 没调对。官方把这些经验写进了 Claude Code 自带的 claude-api skill,给了三个命令。本文先整理文章,再拿一个故意写坏的客服智能体,在服务器上把其中两个命令跑了一遍:
| 阶段 | 准确率 | 每张工单的花费 |
|---|---|---|
| 起点 | 5/12(另一次跑是 6/12) | 5.40 美分 |
照 /claude-api prompt-audit 的建议改完 |
11/12 | 2.33 美分 |
从起点重来,交给 /claude-api cost-optimize |
12/12 | 0.37 美分 |
花费按官方价估算。省下来的钱近九成在输入这一侧:开了缓存,又把常见问题挪出了提示词;其余是输出变短了。准确率上来,主要是因为删掉了两条互相矛盾的规则。下面细说。
一、官方说的三处可省
缓存
接口处理输入时,最贵的是把提示词算成内部状态的那一步。缓存把这个状态存下来,下一次请求开头一模一样时直接读出来,按输入价的零头计费。要命中,有三个前提:同一个模型;从头开始逐字节一致;在有效期内(默认 5 分钟)。
文章列的几个常见的坑:
- 提示词开头放了每次都变的东西。 系统提示里写当前时间、会话号,每个请求的开头都不一样,缓存永远对不上。
- 工具的顺序不固定。 工具定义排在缓存前缀的最前面,换个顺序后面全部失效。
- 中途改 effort 或思考的设置。 这些设置也算在前缀里。
- 一个工具调用或子代理跑得比缓存有效期还久。 结果回来时缓存已经过期,下一轮要重新写一遍,按 1.25 倍输入价(1 小时缓存是 2 倍)计,而不是零头。
对应的办法:
- 在 Claude Console 看缓存的命中率,命中掉了用缓存诊断找出两个请求从哪里开始不一样。
- 不常用的工具标成延迟加载,用工具搜索按需加进来,不进缓存前缀。
- 要改系统提示时,用对话中途的系统消息,不去改开头的系统提示。
- 固定的内容(工具定义、系统提示)放前面,变化的对话放后面。
- 要换模型或 effort,挑缓存本来就要重写的时候换,比如刚做完压缩。
- 用户还在打字时,先发一个
max_tokens: 0带缓存断点的请求预热缓存,第一个真正的请求就能命中。 - 一轮要等超过 5 分钟的,前缀改用 1 小时的缓存。
本站另有一篇专讲缓存的《提示词缓存怎么用》。
提示词里的旧习惯
为老模型写的提示词,在新模型上会变成浪费。文章列了六种:
| 写法 | 新模型上会怎样 |
|---|---|
| 核对仪式:“回答前再检查一遍”“核对两遍” | 照字面执行,白白多调工具 |
| 加重语气:“务必详尽”“CRITICAL: YOU MUST ALWAYS……” | 写得更长、多调工具 |
| 固定流程和让它先写草稿的格式 | 和模型自带的思考叠在一起,白费 token |
| 为老模型的毛病挑的示例 | 教会它在不需要的请求上也长篇推理 |
| 互相矛盾的规则 | 新模型更照字面执行,左右为难,效果变差 |
| 老一代的配置,比如手写的思考预算 | 换到新模型后,接口可能直接拒绝 |
官方的例子:一个客服测试集从 Opus 4.8 换到 Opus 5.5,只改模型 ID,花费降了约 18%,因为 5.5 的输入价和缓存读取更便宜;再跑一遍 /claude-api prompt-audit 去掉旧习惯,又降了 9%,准确率还高了约 2 个百分点。准确率上来的原因:老的思考设置让接口直接拒绝了所有分派工单的请求;两条矛盾的退款规则让模型扣下了四笔该退的钱;让它先写草稿的格式和自带的思考冲突,三张工单上它把工具调用写在了思考里,没有真的执行。
effort
effort 告诉 Claude 这件事要多用心。文章的意思是两头都会错:
- 以为越高越好。 想得比任务需要的多,又贵又慢,答案还可能更差。官方给的一组数:Fable 5.1 做一个不带工具的考试题集,low 档约 53 分、每题约 0.30 美元,max 档约 61 分、约 2.23 美元,最后一档只多半分,花费多 46%,还在测量误差以内。
- 压得太低。 证据还没找够就停了:工具调得少,拿第一条搜索结果就作答,难的地方不多想,平时会做的检查也跳过。
办法是先试更强的模型配更低的 effort:一个编程测试集上,Fable 5.1 的 low 档和 Fable 5 的 high 档一样好,花费是三分之一。然后在自己的评测上把几档都跑一遍:曲线是平的,说明这个任务不缺思考,调高没用。effort 怎么设,见《思考和 effort》。
二、claude-api skill 的三个命令
claude-api skill 随 Claude Code 一起发布,先 claude update 到最新版,在项目目录里运行:
| 命令 | 做什么 | 什么时候用 |
|---|---|---|
/claude-api prompt-audit |
检查工作目录里的提示词、skill、工具说明,包括调接口的程序和 Claude Code 自己的 CLAUDE.md,找出上面那些旧习惯 |
刚换到新一代模型,想看老提示词有没有问题 |
/claude-api cost-optimize |
先查钱花在哪里,再按缓存、精简每个请求带的内容(含一遍 prompt-audit)、限制输出长度、把不用等结果的活改成批处理的顺序试;给了评测的话,还会比较不同 effort 和模型 | 程序在调接口,想做一次全面的降成本 |
/claude-api hillclimb |
把评测分成训练集和测试集,一轮改一处,读失败的样例找原因,最后用没见过的测试集打分 | 有评测,想反复迭代 |
cost-optimize 查钱花在哪里有三个来源,按顺序用:有 Admin API key 就读组织的用量和花费报表;程序记了每个响应里的 usage 就读日志;两样都没有,就读构造请求的代码估算。官方在四个公开测试集上跑过:法律问答省了约 67%(缓存一部分、low 档、批处理)、零售客服省了约 73%(约 93% 的提示词能缓存)、办公文档问答省了约 72%(批处理、把过长的文档裁到相关的段落)、SWE-bench Verified 省了约 24%(缓存本来就有,靠 medium 档和限制输出)。前三个的分数基本不变,第四个文章没有给出分数的变化。
hillclimb 和建评测的 build-eval,本站在《用 Claude Code 自动建评测并逐步提分》里写过,这次没有测。
三、本站实测
| 实测环境 | |
|---|---|
| 日期 | 2026-10-16 |
| 被优化的程序 | 一个 Python 写的客服智能体:Messages 接口,Python SDK,自己写的工具循环,模型 Sonnet 5.5(claude-sonnet-5-5),四个工具(查订单、搜知识库、退款、转人工),订单和知识库全是虚构的 |
| 评测 | 12 张工单,每张有标准结果:该退多少钱、要不要转人工。打印准确率、token 用量和按官方价估算的花费(Sonnet 5.5:输入每百万 token 2 美元,5 分钟缓存写入 2.50 美元,缓存读取 0.10 美元,输出 10 美元) |
| Claude Code | 2.1.300,用不带界面的 claude -p 跑,模型 Opus 5.5 |
| 接口 | 直连官方接口:客服智能体和 Claude Code 都是。没有经中转站测 |
被测的程序:故意写坏的客服智能体
我们照着文章列的旧习惯,写了一个“从老模型时代一路改过来的”客服智能体。系统提示是这样的(节选):
SYSTEM = f"""Current time: {{now}}
Session id: {{session}}
你是“好物商城”的客服智能体。
CRITICAL: YOU MUST ALWAYS VERIFY TWICE. 每次调用 issue_refund 之前,必须再调用一次 lookup_order 核对订单,确认两遍无误再退款。
Be maximally thorough. 回答之前把知识库里所有可能相关的条目都搜一遍。
处理流程(必须按顺序):
1. 问候客户
2. 复述问题
3. 查询订单
4. 搜索知识库
5. 给出方案
6. 询问是否还有其他问题
退款规则:
- 符合政策的退款,一律直接办理,不要让客户等。
- 任何退款都不能自己办理,必须先转人工确认。
{POLICY}
# 常见问题
{KB_TEXT}
"""
一共埋了这些问题:开头的时间和随机会话号;每张工单都把工具顺序打乱一次;“核对两遍”“务必详尽”;六步固定流程;两条矛盾的退款规则;80 条常见问题整段贴进提示词,同时又给了一个搜知识库的工具;没有开缓存。
最早的版本里还有一条要求模型在回答里写出推理过程的指令。Sonnet 5.5 把 12 张工单的请求全部拒答了:stop_reason 是 refusal,类别是 reasoning_extraction,一个工具都没调,输入照样计费。这类拒答见《报错、限流和停止原因》。我们先删掉这一句,把删掉之后的版本当作起点。
起点跑了两次,一次 6/12、一次 5/12,同样的代码差一张,说明 12 张工单的结果本身就有起伏。错的几乎都是同一种:该直接退款的单子转了人工,两条矛盾的规则里它选了后一条。每张工单调 3 到 6 次工具,12 张工单的输入二十七八万 token,一点缓存都没有。
第一步:/claude-api prompt-audit
claude -p "/claude-api prompt-audit" --permission-mode acceptEdits --max-budget-usd 4 --output-format json
它读了三个文件和 git 历史,出了一份报告:13 条,按把握从高到低排,每条写了位置、原文、属于哪种旧习惯、为什么过时、怎么改。排在最前面的三条:
- 退款规则自相矛盾,而且错的那一半和评测对不上。 它对照了政策和评测里的标准答案,判断应该保留“符合政策的直接办理”。
- 缓存不可能命中。 开头的时间和会话号、每次打乱的工具顺序,让每个请求的前缀都不一样;而且根本没开缓存。
- 加重语气和固定流程在逼它多调工具。 订单在一张工单里不会变,查第二遍没有意义;知识库已经整段贴在提示词里,还要求再搜一遍。
其余几条:工具说明太简略(退款工具没说调用即生效、不可撤销,金额是什么单位);没检查 stop_reason,拒答和截断会被当成正常回复;max_tokens 和 effort 没按 Sonnet 5.5 设。另有两条它只提醒、不建议直接改:知识库同时在提示词里和工具里,留哪一个是产品决定;退款金额要模型自己算,可以改成代码算,但金额算错了再说。
它默认不改代码,只给报告和一份拟改的 diff。它本来想把仓库复制一份先试一下,这一步要跑命令,在 acceptEdits 模式下被拒,于是手写了 diff。
报告也会错:它说 Sonnet 5.5 的缓存读取是每百万 token 0.20 美元,要把评测里的价格改掉。官方价格页写的是 0.10 美元。我们让它照建议改代码时说明了这一点,它撤回了这一条,评测脚本没有动:
claude -p --resume <上一次的会话 ID> "按你的建议直接改好 support_agent.py,第 12、13 条先不动。eval.py 里的价格不要改:官方价格页写明……Sonnet 5.5 是每百万 token 0.10 美元。改完不用跑评测。" --permission-mode acceptEdits
改完的结果:11/12,每张工单 2.33 美分,比起点便宜了一半多。每张工单只调 1 到 2 次工具,输出从 1 万 token 降到 3 千多。没过的一张是“耳机拆开试了不喜欢”:政策写的是数码类拆封后只换货、换货要转人工,它既没退也没转。
钱为什么只省了一半?看 usage:缓存写入 92,274 token,差不多是每张工单把 7 千多 token 的共用前缀重写了一遍。原因在下面单独说。
第二步:/claude-api cost-optimize
从起点重来,这次交给 cost-optimize。提示词里写清楚评测怎么跑、一次大概花多少、最多跑几次、哪些不能动:
claude -p "/claude-api cost-optimize 这个客服智能体。评测是 eval.py,用 python eval.py 结果文件.json 运行,会打印准确率和按官方价估算的花费,每次大约 0.3 到 0.7 美元,最多跑 4 次。目标是在准确率不下降的前提下降低每张工单的花费。eval.py 里的价格和标准答案不要改。改完直接改到文件里。" \
--permission-mode acceptEdits \
--allowedTools "Bash(python eval.py *)" "Bash(git diff*)" "Bash(git status*)" \
--max-budget-usd 6 --output-format json
--allowedTools 只放行了跑评测和看 diff 的命令,--max-budget-usd 给这次会话封了顶。它跑了 21 轮、6 分钟,用了 4 次评测里的 3 次,自己列了一张表:
| 轮次 | 改了什么 | 准确率 | 请求 | 不走缓存的输入 | 缓存写入 | 缓存读取 | 输出 | 每张工单 |
|---|---|---|---|---|---|---|---|---|
| 0 | 不改,先量一遍 | 5/12 | 34 | 274,046 | 0 | 0 | 10,005 | 5.40 美分 |
| 1 | 清理提示词,开缓存 | 12/12 | 34 | 92 | 10,782 | 237,319 | 2,804 | 0.66 美分 |
| 2 | 再把常见问题从提示词里拿掉 | 12/12 | 34 | 92 | 4,860 | 41,827 | 2,799 | 0.37 美分 |
它做的改动:
- 缓存。 去掉开头的时间和会话号,工具顺序固定,在系统提示的末尾加一个缓存断点,再在请求最外层开自动缓存,让每张工单越来越长的对话也走缓存。
- 提示词。 两条矛盾的规则留了前一条,它算出这一条造成了起点 7 张错单里的 6 张;删掉“核对两遍”“务必详尽”和六步流程;工具说明补上返回什么、金额按政策算、单位是元。
- 耳机那一单。 它在政策里补了一句:数码类拆封后,客户没主动提换货也要转人工。
- 常见问题。 80 条常见问题每个请求都带着,但判断退款用不上。改成客户问清洁、保修、配送、发票时再用搜知识库的工具查。每个请求缓存的前缀从约 7 千 token 降到约 1.2 千。
改完的请求是这样的:
SYSTEM_BLOCKS = [{"type": "text", "text": SYSTEM, "cache_control": {"type": "ephemeral"}}]
resp = client.messages.create(model=MODEL, max_tokens=4000, system=SYSTEM_BLOCKS, tools=TOOLS,
messages=messages, cache_control={"type": "ephemeral"})
它没做、留作建议的:effort 从默认的 high 降到 medium。输出已经占了花费的六成多,降一档可能还能省,但也可能掉准确率;12 张工单跑一次分不清是真变化还是起伏,要每档跑 3 次左右才能定,所以它没有拿最后一次评测去试。换更便宜的模型,它建议等 effort 试完再一步一步来。批处理(客户在等回复)、裁剪长对话(每张工单只有两三个请求)、工具搜索(工具定义很短),它判断这里用不上。
它自己指出的局限,也都在理:评测里没有问常见问题的工单,常见问题挪出提示词之后答得好不好,这套评测测不出来;每项改动只量了一次,用的是同样的 12 张工单;流量少时缓存 5 分钟就过期,每张工单都可能重写共用的前缀,好在前缀现在只有一千来个 token。
我们按它改好的代码自己又跑了一遍评测:12/12,每张工单 0.38 美分,和它报的一致。审核时(同一天晚些时候)再跑一次,是 12/12、0.37 美分。
为什么只开自动缓存还是贵
prompt-audit 那一版和 cost-optimize 那一版都开了缓存,花费却差了 3 倍多。差别在缓存断点放在哪:
| 断点 | 缓存写入 | 每张工单 | |
|---|---|---|---|
| prompt-audit 改的 | 只在最外层开自动缓存 | 92,274 | 2.33 美分 |
| cost-optimize 改的 | 系统提示末尾一个,外加自动缓存 | 10,782 | 0.66 美分(常见问题还在提示词里时) |
官方文档里有一句关键的话:缓存只在断点的位置写入,往前回看时也只能找到以前的请求在它们自己的断点上写下的内容。自动缓存把断点放在最后一个块上,也就是客户这次说的话后面。每张新工单的第一个请求,开头的工具和系统提示和上一张一样,但上一张只在它自己那句话后面写过缓存,系统提示的末尾从来没有写过,于是一次也命中不了,只能整段重写,按 1.25 倍输入价计。
一张工单之内的几轮对话,自动缓存是管用的:后一轮的开头就是前一轮的全部内容。要让不同的对话共用同一段前缀,就要在这段前缀的最后一块上自己放一个断点。官方的原话是把断点放在“要共用缓存的那些请求里,前缀完全相同的最后一块”上。
花费
花费都按官方价估算,Claude Code 的会话用的是 Opus 5.5:
| 项目 | 花费 |
|---|---|
| prompt-audit 出报告(10 轮,约 2 分钟) | 0.78 美元 |
| 照报告改代码(4 轮,约 35 秒) | 约 0.19 美元 |
| cost-optimize(21 轮,约 6 分钟) | 0.90 美元 |
| cost-optimize 自己跑的 3 次评测 | 0.77 美元 |
| 我们自己跑的评测(起点、prompt-audit 之后、复跑) | 约 1 美元 |
cost-optimize 这一趟连评测花了约 1.7 美元,每张工单省 5 美分,处理三十几张工单就回本。
有一处容易看错:用 claude -p --resume 接着上一个会话问时,--output-format json 输出里的 total_cost_usd 是整个会话累计的。改代码那一步的 JSON 里写的是 0.96 美元,减去出报告那一步的 0.78,才是它自己花的约 0.19 美元。
要注意的几件事
- 它会改业务规则。 耳机那一单,cost-optimize 是在退款政策里加了一句话解决的。这句话和原政策的意思一致,但改政策应该由定政策的人点头,合并之前要看 diff。
- 评测覆盖不到的地方,它也不知道改坏了没有。 常见问题挪出提示词,是这次省钱的第二大来源,而评测里一张问常见问题的工单都没有。先把评测补全,再让它优化。
- 12 张工单太少。 起点两次跑出 5/12 和 6/12,一张的差别就在起伏以内。上线之前换成更多的真实工单再量一遍。
- 仓库的 git 历史里留着会被拒的提示词时,Claude Code 也可能被拒。 第一次我们在原来的仓库里跑 cost-optimize,跑到第 13 轮被拒(
stop_reason: refusal),花了 0.63 美元。这个仓库的历史里还有那条要求写出推理过程的指令,它多半是翻历史时读到了。我们换了一个只提交了修好版本的新仓库,第二次正常跑完。 - 给它划好边界。
claude -p加--permission-mode acceptEdits,它能改文件,但不能随便跑命令;要它跑评测,用--allowedTools只放行评测那一条;再用--max-budget-usd封住这次会话的花费。评测的价格和标准答案写明不许改,免得它通过改评测来“提分”。
四、该用哪个
- 刚把模型换到 5.5 这一代,先跑 prompt-audit,看老提示词里有没有矛盾的规则和旧习惯。它只出报告,改不改你来定。
- 程序已经在线上、想降账单,跑 cost-optimize,并且给它一个评测和跑评测的命令。没有评测,它只能估算,也没法证明省钱没有伤到效果。还没有评测的话,先看《给智能体建评测》。
- 评测够大、想反复迭代模型、effort 和提示词,用 hillclimb。
- 不管用哪个,先自己看一眼
usage:cache_read_input_tokens是零,或者缓存写入和读取差不多一样多,钱多半就漏在缓存上。
参考
- Lance Martin:Reducing cost and improving performance with Claude Platform(Claude 博客,2026-09-08)
- Claude 开发平台文档:Prompt caching