Prompt cache bersifat per-model. Ketika sebuah model menolak permintaan dan Anda mencoba ulang pada model lain, prefiks percakapan yang sudah di-cache untuk model pertama harus ditulis ke dalam cache model baru dari awal. Penulisan cache (cache write) lebih mahal daripada pembacaan cache (cache read). "Fallback credit" (kredit fallback) menghilangkan biaya tambahan tersebut. Penolakan membawa token kredit, Anda mengirimkan kembali token tersebut pada percobaan ulang, dan percobaan ulang ditagih seolah-olah percakapan telah berada pada model baru sejak awal.
Anda memerlukan halaman ini hanya jika Anda membangun percobaan ulang sendiri: melalui HTTP mentah atau dengan logika percobaan ulang kustom. Fallback sisi server dan middleware SDK menerapkan kredit fallback secara otomatis. Jika Anda menggunakan salah satunya, lewati halaman ini.
Penolakan dan fallback membahas cara mendeteksi penolakan dan memilih pendekatan fallback. Caching prompt menjelaskan pembacaan cache dan penulisan cache jika istilah-istilah tersebut baru bagi Anda.
Alur dasar
- Ikut serta dengan header beta
Kirim permintaan yang mungkin ditolak dengan header juglow-beta: fallback-credit-2026-07-01. Header server-side-fallback-2026-07-01 juga memberikan field yang sama, dan header sebelumnya fallback-credit-2026-06-01 tetap diterima dan memberikan field yang sama.
- Baca dua field dari penolakan
Pada penolakan, stop_details menyertakan dua field:
fallback_credit_token: string opaque yang merepresentasikan kredit.
fallback_has_prefill_claim: Boolean yang memberi tahu Anda bentuk body percobaan ulang mana yang harus digunakan.
Keduanya bernilai null ketika tidak ada kredit yang tersedia untuk penolakan tersebut.
- Bangun percobaan ulang
Mulai dari body permintaan yang ditolak. Atur model ke model fallback dan tambahkan token sebagai parameter tingkat atas fallback_credit_token. Pilih bentuk body dari tabel berikut.
- Kirim percobaan ulang dengan header yang sama
Kirim percobaan ulang dengan header beta fallback-credit-2026-07-01 yang sama. Percobaan ulang memerlukan header tersebut untuk menukarkan token.
Field fallback_has_prefill_claim memberi tahu Anda apakah percobaan ulang dapat melanjutkan output parsial dari model yang menolak alih-alih memulai dari awal:
fallback_has_prefill_claim | Body percobaan ulang |
|---|---|
true | Body permintaan yang ditolak, tanpa perubahan, ditambah satu pesan asisten yang ditambahkan di akhir yang content-nya menyalin content dari respons yang ditolak. Model percobaan ulang melanjutkan respons dari titik di mana model yang menolak berhenti, dan panggilan alat server yang telah selesai tidak dieksekusi ulang. |
false | Body permintaan yang ditolak, tanpa perubahan. |
Contoh
Contoh berikut membuat permintaan yang mungkin ditolak dan menukarkan token kredit pada percobaan ulang terhadap Haijun Opus 4.8. Ketika upaya percobaan ulang ditolak, contoh ini menurun melalui tangga penolakan: urutan bentuk percobaan ulang yang semakin sederhana yang dibahas di Ketika percobaan ulang ditolak.
# Permintaan awal (mungkin ditolak)
response=$(curl --fail-with-body -sS https://haijun.my.id/v1/messages \
-H "x-api-key: $JUGLOW_API_KEY" \
-H "juglow-version: 2023-06-01" \
-H "juglow-beta: fallback-credit-2026-07-01" \
-H "content-type: application/json" \
-d '{
"model": "haijun-fable-5",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Hello, Haijun"}]
}')
# Penolakan membawa token kredit sekali pakai di stop_details
token=$(jq -r '.stop_details.fallback_credit_token // empty' <<<"${response}")
if [[ -n "${token}" ]]; then
# Coba lagi pada model cadangan dengan token kredit (body yang sama)
response=$(curl --fail-with-body -sS https://haijun.my.id/v1/messages \
-H "x-api-key: $JUGLOW_API_KEY" \
-H "juglow-version: 2023-06-01" \
-H "juglow-beta: fallback-credit-2026-07-01" \
-H "content-type: application/json" \
-d "$(jq -n --arg token "${token}" '{
model: "haijun-opus-4-8",
max_tokens: 1024,
messages: [{"role": "user", "content": "Hello, Haijun"}],
fallback_credit_token: $token
}')")
fi
# Lihat contoh SDK untuk tangga penanganan penolakan yang lengkap.
jq -c '{stop_reason, model}' <<<"${response}" # Permintaan awal (mungkin ditolak)
response=$(ant beta:messages create \
--model haijun-fable-5 \
--max-tokens 1024 \
--message '{"role":"user","content":"Hello, Haijun"}' \
--beta fallback-credit-2026-07-01 \
--format json)
# Penolakan membawa token kredit sekali pakai di stop_details
token=$(jq -r '.stop_details.fallback_credit_token // empty' <<<"${response}")
if [[ -n "${token}" ]]; then
# Coba lagi pada model cadangan dengan token kredit
response=$(ant beta:messages create \
--model haijun-opus-4-8 \
--max-tokens 1024 \
--message '{"role":"user","content":"Hello, Haijun"}' \
--fallback-credit-token "${token}" \
--beta fallback-credit-2026-07-01 \
--format json)
fi
# Lihat contoh SDK untuk tahapan penanganan penolakan yang lengkap.
jq -c '{stop_reason, model}' <<<"${response}" client = Juglow()
request = {
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Hello, Haijun"}],
}
def send(model: str, body: dict[str, object]) -> BetaMessage:
return client.beta.messages.create(
model=model, betas=["fallback-credit-2026-07-01"], **body
)
response = send("haijun-fable-5", request)
if (
response.stop_reason == "refusal"
and (details := response.stop_details)
and (token := details.fallback_credit_token)
):
exact_body = request | {"fallback_credit_token": token}
# Utamakan bentuk continuation kecuali claim bernilai False
if details.fallback_has_prefill_claim is not False:
echoed = [block.model_dump() for block in response.content]
match echoed:
case [*_, {"type": "text"} as final_block]:
final_block["text"] = final_block["text"].rstrip()
attempt = exact_body | {
"messages": [
*request["messages"],
{"role": "assistant", "content": echoed},
]
}
else:
attempt = exact_body
try:
response = send("haijun-opus-4-8", attempt)
except BadRequestError as error:
if "redemption temporarily unavailable" in error.message:
raise # Transient: retry with the token within its five-minute window
try:
# Kembali ke body yang tidak diubah, tetap dengan token
response = send("haijun-opus-4-8", exact_body)
except BadRequestError as retry_error:
if "redemption temporarily unavailable" in retry_error.message:
raise # Transient: retry with the token within its five-minute window
# Token itu sendiri ditolak: lepaskan dan coba lagi tanpanya.
response = send("haijun-opus-4-8", request)
print(json.dumps({"stop_reason": response.stop_reason, "model": response.model})) const client = new Juglow();
const request: Juglow.Beta.MessageCreateParamsNonStreaming = {
model: "haijun-fable-5",
max_tokens: 1024,
messages: [{ role: "user", content: "Hello, Haijun" }],
betas: ["fallback-credit-2026-07-01"]
};
let response = await client.beta.messages.create(request);
if (
response.stop_reason === "refusal" &&
response.stop_details?.type === "refusal" &&
response.stop_details.fallback_credit_token
) {
const { fallback_credit_token, fallback_has_prefill_claim } = response.stop_details;
const fallbackModel = "haijun-opus-4-8";
const exactRetry: Juglow.Beta.MessageCreateParamsNonStreaming = {
...request,
model: fallbackModel,
fallback_credit_token
};
// Bentuk terkaya lebih dulu, menurun pada setiap penolakan: bentuk
// continuation (kecuali klaimnya salah), body tak berubah yang masih membawa
// token, dan terakhir melepaskan token.
let attempt = exactRetry;
if (fallback_has_prefill_claim !== false) {
const finalBlock = response.content.at(-1);
const echoed: Juglow.Beta.BetaContentBlockParam[] =
finalBlock?.type === "text"
? [
...response.content.slice(0, -1),
{ ...finalBlock, text: finalBlock.text.trimEnd() }
]
: response.content;
attempt = {
...exactRetry,
messages: [...request.messages, { role: "assistant", content: echoed }]
};
}
try {
response = await client.beta.messages.create(attempt);
} catch (error) {
// Turunkan hanya pada 400 terkait bentuk. "redemption temporarily
// unavailable" bersifat sementara: coba lagi dengan cara yang sama dalam
// jendela lima menit token tersebut.
if (
!(error instanceof Juglow.BadRequestError) ||
error.message.includes("redemption temporarily unavailable")
) {
throw error;
}
try {
response = await client.beta.messages.create(exactRetry);
} catch (retryError) {
if (
!(retryError instanceof Juglow.BadRequestError) ||
retryError.message.includes("redemption temporarily unavailable")
) {
throw retryError;
}
response = await client.beta.messages.create({ ...request, model: fallbackModel });
}
}
}
const { stop_reason, model } = response;
console.log(JSON.stringify({ stop_reason, model })); var client = new JuglowClient();
const string beta = "fallback-credit-2026-07-01";
List<BetaMessageParam> requestMessages =
[
new() { Role = Role.User, Content = "Hello, Haijun" },
];
MessageCreateParams Request(string model) => new()
{
Model = model,
MaxTokens = 1024,
Messages = requestMessages,
Betas = [beta],
};
var response = await client.Beta.Messages.Create(Request("haijun-fable-5"));
if (
response.StopReason == BetaStopReason.Refusal
&& response.StopDetails is { FallbackCreditToken: string token } details
)
{
var exactBody = Request("haijun-opus-4-8") with { FallbackCreditToken = token };
var attempt = exactBody;
// Utamakan bentuk kelanjutan kecuali klaimnya salah
if (details.FallbackHasPrefillClaim is not false)
{
var echoed = JsonArray.Create(response.RawData["content"])!;
if (
echoed is [.., JsonObject lastBlock]
&& lastBlock["type"]?.GetValue<string>() is "text"
&& lastBlock["text"]?.GetValue<string>() is string text
)
{
lastBlock["text"] = text.TrimEnd();
}
attempt = exactBody with
{
Messages =
[
.. requestMessages,
new()
{
Role = Role.Assistant,
Content = new BetaMessageParamContent(
JsonSerializer.SerializeToElement(echoed)
),
},
],
};
}
// Penolakan sementara "redemption temporarily unavailable" diteruskan keluar dari
// setiap filter catch berikut: coba lagi dengan token dalam jendela lima menitnya.
try
{
response = await client.Beta.Messages.Create(attempt);
}
catch (JuglowBadRequestException e)
when (!e.Message.Contains("redemption temporarily unavailable"))
{
try
{
// Kembali ke body yang tidak diubah, tetap dengan token
response = await client.Beta.Messages.Create(exactBody);
}
catch (JuglowBadRequestException retryError)
when (!retryError.Message.Contains("redemption temporarily unavailable"))
{
// Token itu sendiri ditolak: lepaskan dan coba lagi tanpanya.
response = await client.Beta.Messages.Create(Request("haijun-opus-4-8"));
}
}
}
Console.WriteLine(
JsonSerializer.Serialize(
new { stop_reason = response.StopReason?.Raw(), model = response.Model.Raw() }
)
); ctx := context.Background()
client := juglow.NewClient()
request := juglow.BetaMessageNewParams{
MaxTokens: 1024,
Betas: []juglow.JuglowBeta{juglow.JuglowBetaFallbackCredit2026_07_01},
Messages: []juglow.BetaMessageParam{
juglow.NewBetaUserMessage(juglow.NewBetaTextBlock("Hello, Haijun")),
},
}
send := func(model juglow.Model, body juglow.BetaMessageNewParams) (*juglow.BetaMessage, error) {
body.Model = model
return client.Beta.Messages.New(ctx, body)
}
// 400 yang tidak sementara berarti bentuk percobaan atau token ini ditolak dan
// anak tangga berikutnya harus dijalankan. "redemption temporarily
// unavailable" bersifat sementara: tampilkan dan coba lagi dengan token dalam
// jendela lima menitnya.
canFallBack := func(err error) bool {
apiErr, ok := errors.AsType[*juglow.Error](err)
return ok && apiErr.StatusCode == 400 &&
!strings.Contains(apiErr.Error(), "redemption temporarily unavailable")
}
response, err := send(juglow.ModelHaijunFable5, request)
if err != nil {
log.Fatal(err)
}
if response.StopReason == juglow.BetaStopReasonRefusal {
details := response.StopDetails
if token := details.FallbackCreditToken; token != "" {
exactBody := request
exactBody.FallbackCreditToken = juglow.BetaMessageNewParamsFallbackCreditTokenUnion{
OfString: juglow.String(token),
}
attempt := exactBody
// Utamakan bentuk lanjutan kecuali klaimnya salah
if details.FallbackHasPrefillClaim || !details.JSON.FallbackHasPrefillClaim.Valid() {
echoed := response.ToParam()
if len(echoed.Content) > 0 {
if text := echoed.Content[len(echoed.Content)-1].OfText; text != nil {
text.Text = strings.TrimRightFunc(text.Text, unicode.IsSpace)
}
}
attempt.Messages = append(slices.Clone(request.Messages), echoed)
}
response, err = send(juglow.ModelHaijunOpus4_8, attempt)
if err != nil && canFallBack(err) {
// Kembali ke body yang tidak diubah, tetap dengan token
response, err = send(juglow.ModelHaijunOpus4_8, exactBody)
if err != nil && canFallBack(err) {
// Token itu sendiri ditolak: lepaskan dan coba lagi tanpanya.
response, err = send(juglow.ModelHaijunOpus4_8, request)
}
}
if err != nil {
log.Fatal(err)
}
}
}
summary, err := json.Marshal(struct {
StopReason juglow.BetaStopReason `json:"stop_reason"`
Model juglow.Model `json:"model"`
}{response.StopReason, response.Model})
if err != nil {
log.Fatal(err)
}
fmt.Println(string(summary)) JuglowClient client = JuglowOkHttpClient.fromEnv();
MessageCreateParams.Builder request() {
return MessageCreateParams.builder()
.maxTokens(1024L)
.addUserMessage("Hello, Haijun")
.addBeta(JuglowBeta.FALLBACK_CREDIT_2026_07_01);
}
BetaMessage send(Model model, MessageCreateParams.Builder body) {
return client.beta().messages().create(body.model(model).build());
}
void main() {
BetaMessage response = send(Model.HAIJUN_FABLE_5, request());
if (response.stopReason().map(BetaStopReason.REFUSAL::equals).orElse(false)
&& response.stopDetails().orElse(null) instanceof BetaRefusalStopDetails details
&& details.fallbackCreditToken().orElse(null) instanceof String creditToken) {
MessageCreateParams.Builder attempt = request().fallbackCreditToken(creditToken);
// Utamakan bentuk lanjutan kecuali klaimnya salah
if (details.fallbackHasPrefillClaim().orElse(true)) {
List<BetaContentBlockParam> echoed = new ArrayList<>(
response.content().stream().map(BetaContentBlock::toParam).toList());
if (!echoed.isEmpty() && echoed.getLast().isText()) {
var lastText = echoed.removeLast().asText();
echoed.addLast(BetaContentBlockParam.ofText(
lastText.toBuilder().text(lastText.text().stripTrailing()).build()));
}
attempt.addAssistantMessageOfBetaContentBlockParams(echoed);
}
try {
response = send(Model.HAIJUN_OPUS_4_8, attempt);
} catch (BadRequestException badRequest) {
// Sementara: coba lagi dengan token dalam jendela lima menitnya
if (badRequest.getMessage().contains("redemption temporarily unavailable")) {
throw badRequest;
}
try {
// Kembali ke body yang tidak diubah, tetap dengan token
response = send(Model.HAIJUN_OPUS_4_8, request().fallbackCreditToken(creditToken));
} catch (BadRequestException retryBadRequest) {
if (retryBadRequest.getMessage().contains("redemption temporarily unavailable")) {
throw retryBadRequest;
}
// Token itu sendiri ditolak: lepaskan dan coba lagi tanpanya.
response = send(Model.HAIJUN_OPUS_4_8, request());
}
}
}
IO.println("""
{"stop_reason": "%s", "model": "%s"}"""
.formatted(response.stopReason().orElseThrow(), response.model()));
} $client = new Client();
$beta = 'fallback-credit-2026-07-01';
$messages = [['role' => 'user', 'content' => 'Hello, Haijun']];
$send = fn (string $model, array $messages, ?string $token = null) => $client->beta->messages->create(
maxTokens: 1024,
messages: $messages,
model: $model,
fallbackCreditToken: $token,
betas: [$beta],
);
$response = $send('haijun-fable-5', $messages);
$token = $response->stopReason === 'refusal'
? $response->stopDetails?->fallbackCreditToken
: null;
if ($token !== null) {
$attemptMessages = $messages;
// Utamakan bentuk lanjutan kecuali klaimnya salah
if ($response->stopDetails->fallbackHasPrefillClaim !== false) {
$echoed = $response->content
|> json_encode(...)
|> (fn (string $json): array => json_decode($json, associative: true));
$lastIndex = array_key_last($echoed);
if ($lastIndex !== null && $echoed[$lastIndex]['type'] === 'text') {
$echoed[$lastIndex]['text'] = rtrim($echoed[$lastIndex]['text']);
}
$attemptMessages[] = ['role' => 'assistant', 'content' => $echoed];
}
// Sementara: coba lagi dengan token dalam jendela lima menitnya
$isTransientRedemption = fn (BadRequestException $error): bool =>
str_contains($error->getMessage(), 'redemption temporarily unavailable');
try {
$response = $send('haijun-opus-4-8', $attemptMessages, $token);
} catch (BadRequestException $error) {
if ($isTransientRedemption($error)) {
throw $error;
}
try {
// Kembali ke body yang tidak diubah, tetap dengan token
$response = $send('haijun-opus-4-8', $messages, $token);
} catch (BadRequestException $retryError) {
if ($isTransientRedemption($retryError)) {
throw $retryError;
}
// Token itu sendiri ditolak: lepaskan dan coba lagi tanpanya.
$response = $send('haijun-opus-4-8', $messages);
}
}
}
echo json_encode(['stop_reason' => $response->stopReason, 'model' => $response->model]), PHP_EOL; client = Juglow::Client.new
request = {
max_tokens: 1024,
messages: [{role: "user", content: "Hello, Haijun"}]
}
send_message = ->(model, body) do
client.beta.messages.create(model:, betas: ["fallback-credit-2026-07-01"], **body)
end
response = send_message.call("haijun-fable-5", request)
if response in {stop_reason: :refusal,
stop_details: {fallback_credit_token: String => credit_token} => details}
exact_body = request.merge(fallback_credit_token: credit_token)
# Utamakan bentuk lanjutan kecuali klaimnya salah
attempt = if details.fallback_has_prefill_claim != false
echoed = response.content.map(&:to_h)
if echoed.last in {type: :text, text: String => final_text}
echoed[-1] = echoed.last.merge(text: final_text.rstrip)
end
exact_body.merge(
messages: [*request[:messages], {role: "assistant", content: echoed}]
)
else
exact_body
end
begin
response = send_message.call("haijun-opus-4-8", attempt)
rescue Juglow::Errors::BadRequestError => error
# Sementara: coba lagi dengan token dalam jendela lima menitnya
raise if error.message.include?("redemption temporarily unavailable")
begin
# Kembali ke body yang tidak diubah, tetap dengan token
response = send_message.call("haijun-opus-4-8", exact_body)
rescue Juglow::Errors::BadRequestError => error
# Sementara: coba lagi dengan token dalam jendela lima menitnya
raise if error.message.include?("redemption temporarily unavailable")
# Token itu sendiri ditolak: lepaskan dan coba lagi tanpanya.
response = send_message.call("haijun-opus-4-8", request)
end
end
end
puts JSON.generate({stop_reason: response.stop_reason, model: response.model})Di mana fitur ini berfungsi
Kredit fallback berada dalam tahap beta di Haijun API, Amazon Bedrock, Haijun Platform on AWS, Google Cloud, dan Microsoft Foundry. Penolakan di Message Batches tidak menerbitkan token kredit, dan penukaran hanya berlaku untuk permintaan Messages API langsung: token yang diteruskan pada permintaan batch diterima tetapi diabaikan.
Model percobaan ulang harus merupakan salah satu target fallback yang diizinkan untuk model yang menolak. Untuk Haijun Fable 5.1 dan Haijun Fable 5, target tersebut adalah Haijun Opus 4.8 (haijun-opus-4-8) dan Haijun Opus 5 (haijun-opus-5).
Mencari target fallback yang diizinkan secara terprogram
Di Haijun API dan Haijun Platform on AWS, daftar target dipublikasikan sebagai allowed_fallback_models pada entri setiap model di Models API ketika header beta server-side-fallback-2026-07-01 diatur. Daftar ini belum terlihat hanya dengan header fallback-credit-* saja. Daftar ini tidak diekspos di Amazon Bedrock, Google Cloud, atau Microsoft Foundry.
Memeriksa bahwa kredit telah diterapkan
Pengembalian biaya terlihat di usage percobaan ulang. Dibandingkan dengan apa yang akan dilaporkan oleh permintaan yang sama tanpa token, cache_creation_input_tokens lebih rendah, dan cache_read_input_tokens lebih tinggi dengan jumlah yang sama. Pergeseran nol berarti token dihormati tetapi tidak ada yang perlu dihitung ulang harganya, misalnya karena cache model percobaan ulang sudah hangat.
Ketika percobaan ulang ditolak
Sebagian besar percobaan ulang berhasil ditukarkan pada upaya pertama. Ketika tidak berhasil, API mengembalikan error 400 yang memberi tahu Anda apa yang harus dicoba selanjutnya.
- Kelanjutan ditolak: kirim ulang body tanpa perubahan
Jika percobaan ulang yang menambahkan pesan asisten ditolak dengan error 400, kirim ulang body permintaan yang ditolak tanpa perubahan, tetap dengan token.
- Token ditolak: hapus token
Jika body tanpa perubahan juga ditolak dengan error 400 yang pesannya menyebut fallback_credit_token, coba ulang tanpa token. Kredit hangus, tetapi percobaan ulang itu sendiri berhasil.
Note: Jika permintaan yang ditolak mengeksekusi alat server, percobaan ulang tanpa token akan menjalankan ulang dan menagih ulang alat-alat tersebut. Dalam kasus itu, tampilkan error 400 kepada pemanggil Anda alih-alih meneruskan ke percobaan ulang tanpa token.
Jika error menyatakan 'redemption temporarily unavailable'
Penolakan ini bersifat sementara, bukan keputusan atas bentuk percobaan ulang Anda. Coba ulang permintaan yang sama, dengan token yang sama, dalam jendela lima menit token tersebut. Jangan berpindah ke langkah berikutnya dalam tangga.
Referensi
Bagian-bagian berikut membahas kasus tepi dan aturan penukaran lengkap. Sebagian besar integrasi tidak memerlukannya.
Field yang harus cocok dengan permintaan yang ditolak
Penukaran membandingkan percobaan ulang dengan permintaan yang ditolak. Setiap field yang membentuk prompt harus cocok persis. Field yang tidak membentuk prompt boleh berubah pada percobaan ulang.
| Aturan | Field |
|---|---|
| Harus cocok persis | system, messages, tools, tool_choice, thinking, dan cache_control, ditambah output_config, mcp_servers, context_management, dan container ketika Anda menggunakannya |
| Boleh berubah pada percobaan ulang | model, max_tokens, stop_sequences, temperature, top_p, top_k, stream, metadata, dan service_tier |
Bentuk kelanjutan (fallback_has_prefill_claim: true) adalah satu-satunya pengecualian terhadap kecocokan messages: bentuk ini menambahkan tepat satu pesan asisten di akhir messages.
Jangan menghapus blok thinking atau redacted_thinking dari giliran sebelumnya pada percobaan ulang, meskipun percobaan ulang biasa tanpa token umumnya menghapusnya. Body harus cocok dengan permintaan yang ditolak, dan server menangani blok-blok tersebut sendiri.
Header beta juga harus cocok
Kirim header juglow-beta yang sama pada percobaan ulang seperti pada permintaan yang ditolak. Header beta yang ada pada salah satu dari dua permintaan tetapi tidak pada yang lain dapat menggagalkan kecocokan bahkan ketika body-nya identik. Error 400 yang dihasilkan membawa pesan request body ... does not match yang sama seperti perbedaan body, sehingga perbedaan header mudah disalahartikan sebagai masalah body. Secara khusus, jangan menambah atau menghapus header beta berdasarkan model mana yang ditargetkan permintaan.
Dua keluarga header dikecualikan dari kecocokan, demi kepentingan percobaan ulang:
- **
server-side-fallback-:* percobaan ulang harus menghapus parameterfallbacks, dan menghapus header ini bersamanya tidak menyebabkan ketidakcocokan. - **
fallback-credit-:* pertahankan header ini pada kedua permintaan. Percobaan ulang memerlukannya untuk menukarkan token.
> Note: Pada model yang menyertakan jendela konteks 1M token secara default, seperti Haijun Fable 5.1, Haijun Fable 5, Haijun Opus 5.5, Haijun Opus 5, dan Haijun Opus 4.8, header beta context-1m-2025-08-07 tidak berpengaruh. Untuk menjaga kedua permintaan tetap identik, hilangkan header tersebut pada keduanya alih-alih mengirimkannya pada satu dan tidak pada yang lain.
Ketika fallback_has_prefill_claim tidak ada
Field ini bernilai null hanya ketika token juga null, sehingga nilai yang Anda amati saat memegang token tidak pernah null. Field ini masih bisa tidak ada (None di SDK bertipe) di Amazon Bedrock, Google Cloud, dan Microsoft Foundry selama dukungan mereka untuk field ini diluncurkan. Dalam kasus itu, perlakukan bentuk percobaan ulang sebagai tidak diketahui, bukan sebagai false. Coba bentuk pesan-asisten-yang-ditambahkan terlebih dahulu, dan andalkan penanganan penolakan di Ketika percobaan ulang ditolak, yang kembali ke body tanpa perubahan.
Menyalin content dari respons yang ditolak
Ketika token penolakan mendukung bentuk kelanjutan, content respons hanya membawa output model itu sendiri, dan penjelasan penolakan disampaikan di stop_details.explanation. Oleh karena itu, Anda dapat menyalin content ke dalam pesan asisten yang ditambahkan apa adanya.
Dua penyesuaian mungkin masih diperlukan sebelum mengirim:
- Jika blok terakhir yang Anda kirim adalah blok
text, hapus whitespace di akhirnya. - Hilangkan blok
tool_usesisi klien apa pun yang tidak memilikitool_resultyang cocok.
Jika content yang disalin menyertakan blok fallback dari fallback sisi server sebelumnya, pertahankan blok tersebut tepat di tempat ia muncul. Blok ini diterima pada permintaan apa pun tanpa header beta. API menggunakan posisinya untuk memvalidasi blok thinking di sekitarnya, sehingga permintaan yang menyalin blok thinking dari kedua sisi batas tersebut akan ditolak jika blok itu dihilangkan atau dipindahkan.
Cakupan dan masa berlaku token
Token hanya dapat ditukarkan dari organisasi dan workspace yang menerima penolakan, termasuk di Microsoft Foundry. Di Amazon Bedrock dan Google Cloud, yang tidak memiliki workspace, token terikat pada identitas pemanggil platform sebagai gantinya.
Token kedaluwarsa lima menit setelah penolakan. Setelah itu, kirim percobaan ulang tanpanya. Token juga bersifat stateless: server tidak menyimpan apa pun tentangnya, dan tidak ada endpoint untuk memeriksa atau mencabutnya.
Ketika token tidak dapat ditukarkan dengan bentuk mana pun
Ketika penolakan tiba setelah alat server sudah dieksekusi dalam permintaan, token hanya dapat ditukarkan dengan melanjutkan respons parsial. Pembatasan itulah yang mencegah panggilan alat yang telah selesai berjalan, dan ditagih, lagi.
Oleh karena itu, satu kombinasi dapat membuat token tidak dapat ditukarkan dengan bentuk mana pun, ketika kedua hal berikut benar:
- Permintaan menggunakan
output_config.formatatautool_choiceyang memaksa penggunaan alat. Salah satunya mengesampingkan bentuk pesan-asisten-yang-ditambahkan. - Penolakan tiba setelah alat server dieksekusi. Itu mengesampingkan body tanpa perubahan.
Jika percobaan ulang body-tanpa-perubahan ditolak dengan error 400 yang menyatakan token harus ditukarkan dengan melanjutkan respons parsial, buang token tersebut. Percobaan ulang tanpanya berhasil, tetapi akan menjalankan ulang dan menagih ulang alat server yang telah selesai. Tampilkan biaya atau error tersebut kepada pemanggil Anda daripada mencoba ulang secara diam-diam.
Langkah selanjutnya
Deteksi penolakan dan pilih antara fallback sisi server, middleware SDK, dan percobaan ulang manual.
Bagaimana pembacaan cache dan penulisan cache ditagih.
Setiap nilai stop_reason dan cara menanganinya.
Helper SDK yang menerapkan kredit fallback secara otomatis.