🎁 新人 免费注册,送 10 次调用,最高 $1,免绑卡。
把 Claude Fable 5 用在 Agent 上:工具调用中途拒答、与 GLM 5.2 的成本对比

把 Claude Fable 5 用在 Agent 上:工具调用中途拒答、与 GLM 5.2 的成本对比

目录
  1. 执行工具调用前先检查 stop_reason
  2. 五种 agent 形态各自花多少钱
  3. 压低 agent 的账单
  4. 文档不会提醒你的两个成本意外
  5. 请求接口的变化
  6. 结论
  7. 常见问题

在我们的评测里,Claude Fable 5 在 44 个编码 agent 回合中有 11 个出现了工具调用中途拒答,而且拒答的任务简单到只是改个配置默认值。拒答表现为在生成工具参数的过程中返回 stop_reason: "refusal",被截断的参数仍然能解析成合法 JSON,于是那些执行工具调用却不检查 stop reason 的 agent 循环,会毫不犹豫地把一个写了一半的文件落盘。把 Fable 5 放进 agent 时,首先要为这个行为做工程处理,而不是它的价格。

TL;DR

  • Claude Fable 5 会在简单的 agent 任务上(改个配置默认值、订个会议室)中途返回 stop_reason: "refusal";被截断的 write_file 参数仍然能解析,所以不检查 stop reason 的循环会执行写了一半的文件。
  • Fable 5 的思考是自适应的,没有关闭开关:enableddisabled 都会被拒绝;控制项是 output_config.effort
  • Fable 5 的成本溢价取决于任务形态:一个四回合的编码任务花了 $0.045,而 glm-5.2 只要 $0.003(15 倍),但在预热批处理任务上只比 sonnet-5 贵 5 倍。
  • Fable 5 要求 30 天数据保留。

下面的所有数据都是 2026-07-05 通过 Synthorai gateway、用一个小型场景测试框架测得的:五种 agent 工作负载形态(一个用工具的编码循环、RAG 问答、重工具编排、批量分类,以及一个 15 回合的对话),分别跑在 claude-fable-5claude-opus-4-8claude-sonnet-5glm-5.2 上,对波动明显的任务每个跑三次。这些任务是故意设计得很简单的;通过率只是个基本的健全性检查,不是能力基准。成本取自 gateway 计费的 usage.cost

执行工具调用前先检查 stop_reason

这个坑文档不会提醒你,而且它会破坏状态。agent 读了 app.py,决定写入修复代码,开始输出一个 write_file 调用。可就在文件内容写到一半时,流中断了:

{
  "stop_reason": "refusal",
  "content": [{
    "type": "tool_use",
    "name": "write_file",
    "input": {
      "path": "app.py",
      "content": "DEFAULTS = {\n    \"timeout_s\": 30,\n    "
    }
  }]
}

这个 input 对象是完整、可解析的 JSON,看不出任何“提前中断”的迹象。如果你的循环逻辑是“拿到工具调用就执行”,那么你刚刚用一个 38 字符的片段覆盖了 app.py,这段内容停在字典中间,已经不是合法的 Python 了。下一轮同样是拒绝,于是循环结束时工作区被破坏。

从数据里能确定三点:

  • 它在最普通的任务上触发。 引发拒绝的任务包括修复一个配置查找里的 KeyError、实现一个 slugify 函数、预订会议室、生成一张发票草稿。没有任何双重用途的内容,也没有任何敏感内容。
  • 它可复现,不是随机的。 有一个编码任务在三次运行中全部被拒,streaming 和非 streaming 模式都一样。而另一些任务从来没触发过。综合各种条件,我们的这些琐碎编码任务在 Fable 5 上的通过率是 58%–75%,而 claude-opus-4-8、claude-sonnet-5 和 glm-5.2 都是 100%。每一次失败都能追溯到拒绝,而不是代码写错。
  • 一旦对话里出现了拒绝,这个 episode 就结束了。 后续轮次返回 stop_reason: "refusal",输出为空。在同一上下文里重试并不能恢复。

触发原因不是任务内容,数据说得很直白。每次都被拒的那个任务,是修一个配置字典里九行的 KeyError,没有凭证,没有漏洞利用。与此同时,批处理场景对涉及挖矿、泄露的 Stripe 密钥、钓鱼页面的工单做分类,一次拒绝都没有;RAG 场景在满是 AES-256-GCM 密钥和事件响应流程的文档上做问答,同样干净。所有拒绝都落在两个多轮、执行工具的场景里;三个单次调用的场景一次都没拒过,哪怕内容更敏感。规律在于 agent 循环的形态,而不是文字本身,这意味着清洗输入并不能防住它。

修复只需要在执行工具那一步之前加一行:

if response.stop_reason == "refusal":
    # do NOT execute tool calls from this turn: arguments may be truncated
    raise AgentInterrupted("model refused; restart episode or escalate")

Anthropic 的文档说明了机制:如果拒绝在任何输出产生之前触发,content 数组为空,且不计费;如果在流的中途触发,已经流式输出的部分会计费,官方建议丢弃这段片段。响应里还带一个 stop_details 对象,包含类别(比如 cyberbio,或者 null),你可以据此区分是分类器拦截还是普通拒答。文档没讲清楚的,是上面遇到的与工具调用的交互:拒绝可能落在参数生成过程中,而这些不完整的参数和完整参数看起来完全一样。

官方还提供了一条恢复路径。在 Claude API 上,beta 版的 fallbacks 参数(betas: ["server-side-fallback-2026-06-01"]fallbacks: [{"model": "claude-opus-4-8"}])会在同一次调用内用 fallback 模型重跑被拒的请求,且拒答本身如果发生在输出前不计费。这个参数在 Amazon Bedrock、Vertex AI 或 Microsoft Foundry 上不可用,那里的 SDK 改为提供客户端 fallback 中间件。不管走哪条路径,上面那道防护都得放在最前面:绝不执行 stop reason 是拒绝的那一轮里的工具调用。

五种 agent 形态各自花多少钱

同样的 prompt,同一天,每完成一个单位(任务、查询、条目或一段对话)的中位成本:

场景fable-5opus-4-8sonnet-5glm-5.2
编码循环(每任务,中位 4 轮)$0.045$0.012$0.0059$0.0031
RAG 回答(每查询)$0.024$0.0075$0.0036$0.0031
工具编排(每任务)$0.048$0.011$0.0045$0.0027
批量分类(每条目,热缓存)$0.0024$0.0012$0.00046$0.00057
15 轮对话(整段)$0.94$0.34$0.26$0.083

这张表里有两点结论,比任何单个数字都更重要:

  • 最便宜的模型会随形态变化。 glm-5.2 在循环和长对话里胜出,但在这几个模型里,claude-sonnet-5 是最便宜的批量分类器,比 glm-5.2 还低。原因是它的 introductory price 建立在 97% 的 cache-read 占比之上——只要脚手架 prompt 处于热缓存状态。
  • Fable 5 的溢价同样取决于形态:编码循环上是 glm-5.2 的 15 倍,对话上 11 倍,但在热缓存的批量条目上只有 sonnet-5 的 5 倍,因为缓存吸收了 prompt 的大部分。

成本的其余部分,一是如何控制这些数字,二是有两样东西会悄悄把它们又推高。

压低 agent 的账单

缓存是最大的一根杠杆,而在 Fable 5 上它的契约没有变。agent 数据显示了它值多少钱:去掉 cache_control 标记后,同一个编码任务贵了 2.0 倍,热缓存批量条目贵了 6.8 倍。在 opus-4-8 上,同样的消融实验读数是 3.8 倍和 6.9 倍。在循环里,滑动标记的模式不是优化,而是账单能不能扛得住的分界线。

prompt 顺序是第二根杠杆,在我们跑过的每个模型上都成立。把稳定的规则放在每次查询的上下文之前(而不是之后),让四个模型的 RAG 查询都便宜了 26-37%;在 Claude 系列上,顺序放错还会在每次调用上额外付出 1.25 倍的 cache-write 溢价。机制在 LangChain caching 文章里;这里的数字只是确认它们原样适用于 Fable 5。

Fable 5 还多出两根自己的杠杆。第一根是缓存资格门槛降到了 2,048 个 token,是 Opus 4.8 的 4,096 的一半。这听起来像冷知识,但想想 agent 的节省从哪来:重复的脚手架(system prompt、工具定义、滑动的对话前缀)才是被缓存的部分,而且只有过了门槛才行。一个工具密集的 agent,如果每轮前缀落在 2,048 到 4,096 个 token 之间,在 Opus 4.8 上完全没有缓存,到了 Fable 5 上开始缓存,把一个全价前缀变成后续每一轮约为全价 10% 的 cache read。反过来也一样:为了越过旧的 4,096 门槛而填充的前缀,现在可能是在背死重量。别靠假设,直接从实时响应里读 cache_read_input_tokens,因为在 Fable 5 上折扣开始得更早。

第二根是任务预算(beta,header task-budgets-2026-03-13),它正好解决这个对比反复暴露出来的问题:Fable 5 的循环会很快堆起一笔账,而 max_tokens 帮不上忙。max_tokens 是一个模型看不见的每响应硬上限,所以模型会当作自己有无限空间来规划,然后在想到一半时被切断。任务预算不一样。你给循环一个 token 上限(最低 20,000),模型能看到它像倒计时一样递减,并据此自己把握节奏,从容收尾而不是被截断。它统计的是模型生成的部分,加上当轮读取的工具结果,而不是你每次请求都重发的完整历史。在一个编码循环单轮成本是 glm-5.2 的 15 倍的模型上,让模型自我约束的预算是你能加上的最便宜的护栏。

文档不会提醒你的两个成本意外

主要的调节手段都设好之后,还有两个不太起眼的因素在往文档没提过的方向影响我们的账单。

「低」档并不更便宜。 Fable 5 的思考深度由 output_config.effort 控制,直觉上 low 应该更省钱。结果并没有。设成 effort: "low" 后,我们的编码循环每个任务花 $0.0478,而默认值只要 $0.0451,输出 token 反而更多而不是更少。GLM 5.2 上也是同样的情况,那里的 effort 档位名字也和 token 数量对不上。这两个模型系列都一样:别假设「低」就等于「更少」,先拿自己的负载测一下这个旋钮。数字难以预测的一个原因是,adaptive thinking 在输出 token 里的占比波动很大——编码循环里是 2%,RAG 问答是 30%,批量分类是 52%,同一个模型,同一天。输出 token 的预算要按负载形态来算,而不是按模型来算。

绝不要回传 reasoning_content 在 OpenAI 兼容的模型上,reasoning 字段不是对话历史。DeepSeek 的 API 要求把它剥掉;GLM 5.2 上回传它是允许的,但会计费。把它塞回消息历史让我们的 GLM 循环成本涨了约 28%,直到我们把它剥掉。Anthropic 自家的 thinking 块则不一样:同一个模型上你必须原样回传,但如果一个 Fable 5 的 thinking 块被路由到另一个模型(比如回退到 Opus),它会自动从 prompt 里丢弃,也不计费,所以没什么可剥的。

请求接口的变化

Fable 5 的请求接口和 Opus 4.7/4.8、Sonnet 5 大部分一致。按文档说明,以下这些没了:

  • thinking: {type: "enabled", budget_tokens: N} 会返回 400。带 token 预算的扩展思考——从 Claude 3.7 Sonnet 到 4.5 系列一直用的那套机制——在 4.7+ 系列里已被弃用,换成了 adaptive thinking
  • thinking: {type: "disabled"} 会返回 400,这一点是 Fable 5 独有的。Opus 4.7/4.8 和 Sonnet 5 仍然允许你关闭思考,Fable 5 不行。
  • temperaturetop_ptop_k 只要取非默认值就会被拒绝。
  • Assistant 消息的 prefill(末尾带一个 assistant 轮次)会返回 400。

temperature/top_p/top_k 和 prefill 这两处删改,最容易在迁移请求时坑到人;思考和保留方面的变化在前面以及保留期那篇里讲过了。

结论

在 agent 里用 Fable 5,先是个工程问题,然后才是预算问题。在执行 tool call 之前先处理好 stop_reason: "refusal",否则哪怕是改个配置这么无聊的任务,一次被截断的写入也会把状态搞坏。成本这块要当成可以自己塑造的东西来对待:缓存是最大的调节杠杆,命中门槛现在是 2048 个 token,所以要重新检查你的前缀;给任务设预算能防止一个循环把这次对比里最高的单轮账单跑出来;而 effort: "low" 并不是它名字暗示的那种折扣。预算也要按负载形态来定:同一个模型在编码循环上是 glm-5.2 的 15 倍成本,在热批处理上是 sonnet-5 的 5 倍。这些都不是在说该用还是不该用,而是说默认值并不中立,账单和故障模式都取决于你的 agent 是怎么搭的。

常见问题

Fable 5 是不是经常拒绝 tool call? 它集中在特定任务上:有一个 config-fix 任务每次都拒绝,其他任务从不拒绝,而且同样的任务在 streaming 和非 streaming 调用下都能复现。所以这不是重试几次就能绕过去的偶发抖动。你自己的负载上比例会不一样,但工程上的结论是一样的:执行 tool call 之前先检查 stop_reason

能不能关掉 Fable 5 的 thinking? 不能。thinking.type.disabledenabled 都会被拒绝。thinking 默认是自适应的,output_config.effort 是唯一的开关。在我们的循环里,low effort 并没有降低成本。

Fable 5 有没有便宜的时候? 在这组测试里没有。它溢价最小的场景是缓存命中率高的 batch 任务,大约是 sonnet-5 的 5 倍,因为 warm cache 吸收了大部分 prompt。在循环任务和长对话上,它是我们跑过的所有模型里最贵的。


验证说明:所有数据于 2026-07-05 针对 https://synthorai.io/ 测得(Claude 系列走 Anthropic 原生 /v1/messages,glm-5.2 走 /v1/chat/completions),覆盖五种场景形态下的 505 个 episode、1,022 次调用,对方差敏感的任务每个跑三次。成本取自 gateway 上报的 usage.cost,展示的是中位数。任务是故意设计得很简单的,所以通过率只是一道健全性检查,不是能力基准;我们不发布没测过的能力结论。拒绝行为在 streaming 和非 streaming 两种模式下都能复现。你的数字会随 prompt、region 和负载而变化。

← 返回博客