Claude Fable 5 包含可以拒绝请求的安全分类器。当发生这种情况时,您会收到一个正常的响应(而非错误),其中包含 stop_reason: "refusal"。通常,您仍然可以通过将相同的请求发送到另一个 Claude 模型来获得答案。本页将向您展示如何识别拒绝以及如何设置该重试。
当您基于 Claude Fable 5 进行构建,并希望被拒绝的请求自动回退到另一个模型时,请阅读本页。当您刚刚在响应中看到 "refusal" 并想知道下一步该怎么做时,本页同样适用。
stop_reason 值的完整列表请参阅停止原因与回退。有关被拒绝请求的计费方式,以及如何避免在重试时为提示缓存重复付费的详细信息,请参阅回退额度。封装所有这些功能的 SDK 辅助工具请参阅 SDK 中间件。如需完整的端到端示例,请参阅回退与计费 Cookbook。
最简单的设置:在请求中指定一个回退模型,API 会处理重试。
await client.beta.messages.create({
model: "claude-fable-5",
max_tokens: 1024,
messages,
betas: ["server-side-fallback-2026-06-01"],
fallbacks: [{ model: "claude-opus-4-8" }]
});以下各节将介绍拒绝响应包含的内容、何时使用服务器端或客户端回退,以及各自的计费方式。
拒绝是一个成功的 HTTP 200 响应,其中包含 stop_reason: "refusal":
{
"id": "msg_01XFUDYJgAACzvnptvVoYEL",
"type": "message",
"role": "assistant",
"model": "claude-fable-5",
"content": [],
"stop_reason": "refusal",
"stop_details": {
"type": "refusal",
"category": "cyber",
"explanation": "This request was declined because it could enable cyber harm."
},
"usage": {
"input_tokens": 412,
"output_tokens": 0
}
}stop_details 对象解释了拒绝的原因。其 category 字段指明触发分类器的策略领域。其 explanation 字段是人类可读的描述;该文本并不稳定,因此请将其用于显示而非解析。当拒绝未映射到已命名的类别时,这两个字段均为 null,且 null 是正常的永久值,而非占位符。对于除 refusal 之外的所有停止原因,stop_details 本身为 null。
category | 含义 |
|---|---|
"cyber" | 该请求可能导致网络危害,例如恶意软件或漏洞利用开发。良性的网络安全工作也可能触发此类别。 |
"bio" | 该请求可能导致生物危害,例如危险的实验室方法。有益的生命科学工作也可能触发此类别。 |
"reasoning_extraction" | 该请求要求模型在响应文本中重现其内部推理。如需以结构化形式获取推理内容,请改用自适应思考。 |
拒绝可能在任何输出之前到达,也可能在部分输出之后的流式传输过程中到达。无论哪种情况,都应将任何部分输出视为不完整并予以丢弃。
**拒绝的计费方式:**在任何输出之前发生的拒绝会使 content 为空,您不会被计费(令牌计数会出现在 usage 中但不会收费,且该请求不计入速率限制)。流式传输中途的拒绝会按正常费率对输入令牌和已流式传输的输出进行计费。
有三种方法可以在另一个模型上重试被拒绝的请求。正确的选择取决于您的运行环境以及所需的控制程度。
| 您的情况 | 使用 | 原因 |
|---|---|---|
| Claude API 或 AWS 上的 Claude Platform,最简单的设置 | 服务器端回退 | 一个请求,一个响应。API 处理重试。 |
| 任何平台,使用 TypeScript、Python、Go、Java 或 C# SDK | SDK 中间件 | 在客户端配置一次。重试自动进行。 |
| Ruby、PHP、原始 HTTP 或自定义重试逻辑 | 使用回退额度手动重试 | 完全控制。回退额度可降低成本。 |
服务器端回退和 SDK 中间件会为您应用回退额度,因此只有在自行构建重试时才需要参阅该页面。
服务器端回退在单个 API 调用内重试被拒绝的请求。您最多可以指定三个回退模型,当 Claude Fable 5 拒绝时,API 会对同一请求运行链中的下一个模型。您会收到一个响应,其中指明了作出回答的模型,因此您的用户可以在一次往返中获得答案。
在 fallbacks 参数中指定回退模型,并发送 server-side-fallback-2026-06-01 测试版标头。
client = Anthropic()
response = client.beta.messages.create(
model="claude-fable-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello, Claude"}],
fallbacks=[{"model": "claude-opus-4-8"}],
betas=["server-side-fallback-2026-06-01"],
)
# usage.iterations 中出现 fallback_message 条目表示回退模型已运行;
# 将其与 stop_reason 结合查看,以确认该响应由回退模型提供。
fallback_ran = any(
iteration.type == "fallback_message"
for iteration in response.usage.iterations or []
)
served_by_fallback = fallback_ran and response.stop_reason != "refusal"
print(
json.dumps(
{
"stop_reason": response.stop_reason,
"model": response.model,
"served_by_fallback": served_by_fallback,
}
)
)fallbacks 列表适用以下几条规则:
allowed_fallback_models 发布在模型 API 中该模型的条目上。model,并且可以仅针对该次尝试覆盖 max_tokens 和 thinking。测试版标头必须精确携带日期 2026-06-01。在任何其他 server-side-fallback-* 值下,fallbacks 参数会被拒绝并返回 400 错误。如果您是基于此功能的早期预览版进行构建的,请将测试版标头以及请求和响应的结构一并更新为本页所示的版本。
响应看起来与任何其他消息一样,但有两处新增内容:
model 字段报告生成返回消息的模型,无论是所请求的模型还是回退模型。fallback 内容块标记 content 中一个模型的输出让位于下一个模型的每个位置:{"type": "fallback", "from": {"model": ...}, "to": {"model": ...}}。当拒绝的跳转是所请求的模型时,from.model 会回显您发送的模型字符串。to.model 始终是继续处理的模型的解析后 ID。在任何输出之前发生拒绝时,fallback 块是第一个内容块:
{
"id": "msg_01XFUDYJgAACzvnptvVoYEL",
"type": "message",
"role": "assistant",
"model": "claude-opus-4-8",
"content": [
{
"type": "fallback",
"from": { "model": "claude-fable-5" },
"to": { "model": "claude-opus-4-8" }
},
{ "type": "text", "text": "Hi! How can I help you today?" }
],
"stop_reason": "end_turn",
"stop_details": null,
"usage": {
"input_tokens": 412,
"output_tokens": 264,
"cache_read_input_tokens": 0,
"cache_creation_input_tokens": 0,
"iterations": [
{
"type": "message",
"model": "claude-fable-5",
"input_tokens": 535,
"output_tokens": 0,
"cache_read_input_tokens": 0,
"cache_creation_input_tokens": 0
},
{
"type": "fallback_message",
"model": "claude-opus-4-8",
"input_tokens": 412,
"output_tokens": 264,
"cache_read_input_tokens": 0,
"cache_creation_input_tokens": 0
}
]
}
}usage.iterations 数组记录每次尝试。拒绝的模型显示为普通的 message 条目,而处理该轮次的模型显示为 fallback_message 条目。如果链中的每个模型都拒绝,则响应是最后一个模型的拒绝,其中每个较早的跳转都有一个 message 条目,最后一个有一个 fallback_message 条目。
在下一轮次中,按原样发回您收到的助手内容。在输出中途回退后,content 可能包含拒绝模型在交接前生成的块类型;下表说明了在回显该轮次时应保留哪些、丢弃哪些。
| 块类型 | 在下一轮次中 |
|---|---|
fallback | 保留在其原本出现的位置。API 使用其位置来验证其周围的思考块,因此如果省略或移动该块,回显边界两侧思考块的请求会被拒绝。 |
text | 保留。 |
最后一个 fallback 块之后的任何块 | 保留。 |
最后一个 fallback 块之前的 thinking、redacted_thinking 或 connector_text | 丢弃。 |
最后一个 fallback 块之前的客户端 tool_use | 丢弃。 |
最后一个 fallback 块之前的 server_tool_use | 与其结果配对时保留。没有匹配结果时丢弃。 |
connector_text 块承载某些使用工具的响应在工具调用之间包含的叙述文本。
在流式传输请求中,重试发生在同一个流上,您已经收到的任何内容都不会失效。当拒绝发生在任何输出之前时,message_start 会指明回退模型,且 fallback 块是第一个内容块;由于 message_start 会等待回退尝试开始,首字节时间包含被拒绝的尝试。当拒绝发生在输出中途时,打开的内容块会关闭,fallback 块(一对普通的 content_block_start 和 content_block_stop,没有增量)标记边界,回退模型从部分输出继续。只有部分输出的 text 块会作为上下文传递给回退模型;其他块类型保留在 content 中。在输出中途的情况下,message_start 已经指明了所请求的模型,因此请从 fallback 块的 to.model 以及最终 message_delta 的 usage.iterations 中的 fallback_message 条目读取服务模型。
在非流式传输请求中,输出中途的拒绝行为不同:响应会省略被拒绝模型的部分输出,回退模型从头开始回答。结果看起来像是在任何输出之前的拒绝,fallback 块位于首位。被拒绝的尝试及其输出令牌仍会出现在 usage.iterations 中。
当服务器工具(例如网络搜索或代码执行)已在请求内执行后触发拒绝时,API 会返回拒绝而不是推进到回退模型。如果同时设置了 fallback-credit-2026-06-01 标头,该拒绝会携带一个可通过继续部分响应来兑换的额度令牌,因此已完成的工具工作不会丢失。这仅适用于在单个请求内迭代的服务器工具;使用客户端工具的对话会正常回退。
TypeScript、Python、Go、Java 和 C# SDK 包含一个拒绝回退中间件。您在客户端上使用回退模型列表配置一次。之后通过 client.beta.messages 的调用会在任何平台上自动重试被拒绝的请求。该中间件还会在其处理的每个请求上发送 fallback-credit-2026-06-01 测试版标头,因此重试会被重新定价,无需逐个请求设置。
拒绝回退中间件辅助工具目前在 Ruby 和 PHP SDK 中尚不可用。在这些 SDK 上,请直接实现检测并重试的模式。
将中间件传递给客户端构造函数,并在对话的各个请求之间共享一个 BetaFallbackState 实例。
# 遇到拒绝时,中间件会在列出的回退模型上重试,并
# 在其处理的每个请求上自动发送 fallback-credit beta 标头。
client = Anthropic(
middleware=[BetaRefusalFallbackMiddleware([{"model": "claude-opus-4-8"}])],
)
state = BetaFallbackState() # pins follow-ups to the model that accepted
# 流式传输:遇到拒绝时,中间件会在回退模型上重试,并
# 将其事件拼接到已打开的流中。
with (
state,
client.beta.messages.stream(
max_tokens=1024,
model="claude-fable-5",
messages=[{"role": "user", "content": "Hello, Claude"}],
) as stream,
):
for event in stream:
if event.type == "text":
print(event.text, end="", flush=True)
final_message = stream.get_final_message()
print(f"\nserved by: {final_message.model}")
# 非流式传输:复用状态可使对话保持固定。
with state:
message = client.beta.messages.create(
max_tokens=1024,
model="claude-fable-5",
messages=[{"role": "user", "content": "Hello, Claude"}],
)
print(f"served by: {message.model}")fallback 内容块,与服务器端回退响应相同。中间件会在后续请求中为您管理这些块。BetaFallbackState 中,因此共享该状态的后续请求会固定在该模型上,而不是重新询问已拒绝的模型。中间件和服务器端 fallbacks 参数执行相同的工作。请配置其中之一,切勿在同一请求上同时使用两者。如需从安装了中间件的应用程序发送服务器端 fallbacks 请求,请使用不带中间件的单独客户端实例。
消息批处理中被拒绝的请求会以 result.type: "succeeded" 和 stop_reason: "refusal" 的形式返回。批处理结果中的 stop_details 字段可能为 null,因此请通过直接检查 stop_reason 来检测拒绝。
服务器端回退不适用于批处理(包含 fallbacks 的批处理请求会产生逐项错误结果)。要重试被拒绝的批处理项:
fallbacks 参数不会传播到工具执行内部发起的模型调用中。usage.iterations 中的 fallback_message 条目标记后者),然后对这两个计数之间的差距设置告警。stop_reason 进行分支,而非基于 stop_details 或 content。stop_details 是信息性的,在拒绝时可能为 null。请直接检查 stop_reason 是否等于 "refusal"。在自行构建重试时避免为提示缓存成本重复付费。
每个 stop_reason 值及其处理方式。
SDK 中间件的工作原理,包括拒绝回退辅助工具。
将现有应用程序迁移到 Claude Fable 5。
Was this page helpful?