Claude Fable 5(model id claude-fable-5)是 Anthropic 目前广泛发布中能力最强的模型,思考默认且始终开启、不可关闭。在能力之外,它在「思维链如何对外暴露」和「请求被安全机制拒绝时如何返回」这两件事上做了相当明确的工程约束。对接入方而言,这两点都直接影响代码该怎么写——尤其是处理多轮对话和异常分支的那部分。这篇文章把受保护思维链(protected thinking)与 refusal 拒答这两块讲清楚。
受保护思维链:原始链永不返回,只给摘要
很多人对「思维链」的第一反应是:模型把推理过程吐出来给我看。Fable 5 在这件事上划了一条清晰的线:原始思维链(raw chain of thought)永远不会出现在响应里。 你能拿到的,是 thinking 类型的内容块(注意是常规 thinking 块,不是加密的 redacted_thinking),其可见性由 display 字段控制:
display: "summarized":返回一段可读的推理摘要;display: "omitted"(默认值,与 Opus 4.8 / 4.7 一致):响应里仍然带thinking块,但其中的thinking文本是空字符串。
关键在于:display 只控制「可见性」,不控制「是否思考」。无论哪种设置,模型都照常思考、照常按思考计费,原始链都不会暴露。如果你的产品要把推理过程流式呈现给用户,记得显式设成 summarized,否则默认的 omitted 看起来就像「输出前长时间无响应的卡顿」。
1 | resp = client.messages.create( |
还有一个相关的边界:如果请求试图诱导模型把内部推理写进回答正文,可能会被拒(stop_details.category: "reasoning_extraction")。需要推理可见性的场景,正确姿势是去读 summarized 的 thinking 块,而不是用提示词去套出推理。
多轮回传的硬规矩:原样回传,换模型则丢弃
受保护思维链真正会「坑」到人的地方在多轮对话的回传规则上。当你在同一个模型上继续一段对话时,必须把收到的 thinking 块原样回传——包括那些 thinking 文本为空的块。API 拒绝的是被修改过的块,而不是你读过、展示过的块。换句话说:把摘要显示给用户没问题,但你不能去编辑、重构、或凭记忆重建这些块,回传时要逐字带回去。
而当你切换到另一个模型时,规则反过来:Fable 5 的受保护 thinking 块会在拼 prompt 时被丢弃——通常是静默丢弃,不报错。这个丢弃发生在计价之前,所以被丢的块不计费,你也没有什么需要手动剥离的。
这条规则配合下一节的 refusal 回退非常关键:当你因为拒答想换个模型重试时,可以把对话历史原样发过去,无需担心 Fable 5 的 thinking 块会污染目标模型——它们会被自动忽略且不计费。
refusal:HTTP 200 但 stop_reason 是拒答
Fable 5 会对入站请求跑安全分类器,主要针对研究型生物学和大部分网络安全领域(这两个领域本就不是 Fable 5 的目标场景)。被拒绝的请求不是 4xx 错误,而是一个成功的 HTTP 200,但 stop_reason 为 "refusal",并附带一个 stop_details 对象说明策略类别("cyber" / "bio" / "reasoning_extraction" 或 null)。
这里有一条铁律:先判 stop_reason,再读 content。 因为:
- 分类器可能在任何输出之前就触发:此时
content是空数组,且完全不计费(输入输出 token 都不算,也不占限流额度); - 也可能在流式输出中途触发:此时已经流出的部分按正常价计费——你应当把这段半成品丢弃,而不是当成完整结果。
任何无条件 response.content[0] 的代码,碰到拒答都会直接抛索引错误。正确写法是先分支:
1 | resp = client.messages.create(model="claude-fable-5", max_tokens=1024, messages=[...]) |
另外注意:判分支只看 stop_reason,不要看 stop_details。stop_details 是信息性的,即便在拒答时也可能是 null,explanation 也不保证存在。安全分类器拦截和模型自身的常规拒绝都表现为 stop_reason: "refusal",靠 stop_details.category 区分是哪一类、进而决定要不要回退到别的模型。
fallback 到 Opus 4.8:让良性请求别被误伤
安全领域工具、生命科学任务这类良性但相邻的工作,偶尔会触发误判(false positive)。这正是回退机制的价值所在。Fable 5 提供了从服务端到客户端的多套 fallback 能力,最常见的目标是退回到 claude-opus-4-8:
- 服务端
fallbacks参数(beta,Claude API 与 Claude Platform on AWS):在一次往返里由服务端自动用下一个模型重试,并自动做 fallback credit 重定价。最简,客户端无需自己写重试逻辑。 - GA SDK 的客户端中间件:
BetaRefusalFallbackMiddleware+BetaFallbackState,在任何环境下(含 Bedrock / Vertex)做客户端重试;fallback credit 会退还客户端重试中因换模型导致的缓存切换成本。
无论走哪条路,前面那条「换模型时 Fable 5 的 thinking 块被静默丢弃且不计费」的规则都保证了你可以把历史原样回传去重试,不用做任何剥离。
其他约束
最后两条迁移时容易忽略的硬约束:Fable 5 不支持 assistant prefill(最后一轮 assistant 预填会报 400,用结构化输出或系统提示替代);并且它要求 30 天数据保留,不在零数据保留(ZDR)下提供——如果迁移后每个请求都莫名其妙地 400,先去检查组织的数据保留配置,而不是反复 debug 请求体。
结语
Fable 5 的安全设计可以归结为两条工程契约:思维链只给摘要、原始链永不返回,且多轮要原样回传、换模型则自动丢弃;拒答走 HTTP 200 + stop_reason: "refusal",必须先判 stop_reason 再读 content,并可在误伤时优雅回退到 Opus 4.8——把这两条吃透,接入代码就能既安全又稳健。