通过tool_choice强制、严格输出Schema、thinking_effort和max_tokens调优,使Sonnet模型达到Opus精度并显著降低成本,提供可复用的调优框架。
我们的 AI Pipeline 包含三类步骤(ai.generate、ai.extract、ai.classify),每个步骤都会在运行时独立解析自己使用的 provider、model 和 prompt revision。默认模型是 Sonnet,而不是 Opus——有一段时间,这看起来像是一种妥协:Opus 昂贵但可靠,而 Sonnet 需要投入更多精力反复调校,才能达到同样的通过率。
最终弥合差距的并不是更聪明的 prompt,而是 tool_choice 加上更严格的输出 schema:强制模型明确给出符合既定结构的答案,而不是消耗 token 一路犹豫、保留余地。在我们的 eval 中,单凭这一项改动,Sonnet 就达到了与 Opus 之前输出结果相同的通过率,而成本大约只有后者的四分之一。第二个独立的优化手段是:Anthropic 官方推荐用于 Agent 任务的 effort "xhigh",在通过率相同的情况下,产生的 thinking token 大约是 "high" 的两倍——thinking token 与 output token 采用相同的计费方式,因此这相当于成本直接翻倍,准确率却毫无提升。而且,只有通过显式 override 使用 Opus 时,这一点才会产生影响(Sonnet 根本不支持 adaptive thinking)。第三个同样独立的优化手段是:出于谨慎考虑,max_tokens 的默认值原本设为 16000;将其降至 4000 后——这个额度依然远高于任何实际步骤的需要——有效输出成本再次下降,因为在某些失败路径中,Anthropic 会以 token 上限作为计费边界,而不只是按照模型实际输出的 token 数量计费。
这三项改动都没有触碰 prompt 内容,也没有更换 provider。它们全部源于对每个步骤 token 用量的观察。之所以能够做到这一点,是因为每个步骤完成时都会写入一条不可变的 provenance 记录,其中包括 prompt revision、provider、model 和 token usage。这与 event sourcing 的思路相同,只不过应用对象从领域数据写入变成了 LLM 调用。你不会再依赖“这个 Pipeline 大概使用了 prompt v3,模型则是当时配置的某一个”这种猜测,因为数据库中有一行记录会明确告诉你答案——而且,你可以审计过去六个月里“哪个 prompt 接触过这个租户”,完全不需要加载实际的 LLM payload(这种结构也更符合 DSGVO:provenance 记录不包含任何用户内容,只有调用元数据)。
另一个真正的陷阱,是我们踩坑之后才发现的:adaptive thinking 与强制使用工具不能同时启用。只要两者同时设置,Anthropic 就会立即返回 400 错误:Thinking may not be enabled when tool_choice forces tool use。事后看来,这似乎显而易见;但当初同时设置它们时并不是这么想的,因为二者单独看起来都像是在“让模型更努力地完成任务”。这个问题必须自动处理——检测到强制性的 tool_choice 后,在请求发出前禁用 adaptive thinking。因为如果依赖每个调用方自己记住这条规则,那么所有通过 Opus override、并使用 toolChoice: { type: "any" } 的 eval 运行都会以同样的方式同时崩溃。
另外,只有将 cache_control breakpoint 放在最后一个静态 block 上,并把 tools 与 system prompt 组成一个可缓存的前缀,prompt caching 才真正划算。如果不这么做,当请求规模超过大约 16k token 后,往往还没等响应流返回足够多的内容,请求就已经触发 SDK 的 HTTP timeout。如果把 breakpoint 放在每次请求都会变化的内容上,就会出现无声的 cache miss:它在日志里看起来与 cache hit 完全一样,但你仍然在支付全额费用。
包含 Pipeline 架构(附图)、provider 解析代码以及 provenance 数据结构的完整文章:docs.kumiko.rocks/en/guides/ai-pipeline-provenance。
如需采取进一步措施,你可以考虑屏蔽此人和/或举报滥用行为。