---
read_when:
    - การวินิจฉัยการหมุนเวียนโปรไฟล์การยืนยันตัวตน ช่วงพัก หรือพฤติกรรมการสำรองโมเดล
    - การอัปเดตกฎการเปลี่ยนไปใช้ตัวสำรองสำหรับโปรไฟล์การตรวจสอบสิทธิ์หรือโมเดล
    - ทำความเข้าใจว่าการเขียนทับโมเดลของเซสชันโต้ตอบกับการลองใหม่ด้วยทางเลือกสำรองอย่างไร
sidebarTitle: Model failover
summary: OpenClaw หมุนเวียนโปรไฟล์การตรวจสอบสิทธิ์และ fallback ข้ามโมเดลอย่างไร
title: การสลับโมเดลเมื่อเกิดข้อผิดพลาด
x-i18n:
    generated_at: "2026-06-27T17:27:55Z"
    model: gpt-5.5
    postprocess_version: locale-links-v1
    provider: openai
    source_hash: 7be9b2ee7c2c6de42d454248a51219c1917ce9a3a93630dad0af6f67ec030de3
    source_path: concepts/model-failover.md
    workflow: 16
---

OpenClaw จัดการความล้มเหลวในสองขั้นตอน:

1. **การหมุนเวียนโปรไฟล์การยืนยันตัวตน** ภายในผู้ให้บริการปัจจุบัน
2. **การ fallback ของโมเดล** ไปยังโมเดลถัดไปใน `agents.defaults.model.fallbacks`

เอกสารนี้อธิบายกฎขณะรันไทม์และข้อมูลที่รองรับกฎเหล่านั้น

## ลำดับการทำงานขณะรันไทม์

สำหรับการรันข้อความปกติ OpenClaw จะประเมินตัวเลือกตามลำดับนี้:

<Steps>
  <Step title="แก้ไขสถานะเซสชัน">
    แก้ไขโมเดลของเซสชันที่ใช้งานอยู่และค่ากำหนดโปรไฟล์การยืนยันตัวตน
  </Step>
  <Step title="สร้างลำดับตัวเลือก">
    สร้างลำดับตัวเลือกโมเดลจากการเลือกโมเดลปัจจุบันและนโยบาย fallback สำหรับแหล่งที่มาของการเลือกนั้น ค่าเริ่มต้นที่กำหนดไว้ โมเดลหลักของงาน cron และโมเดล fallback ที่เลือกอัตโนมัติสามารถใช้ fallback ที่กำหนดไว้ได้ ส่วนการเลือกเซสชันของผู้ใช้อย่างชัดเจนจะเข้มงวด
  </Step>
  <Step title="ลองผู้ให้บริการปัจจุบัน">
    ลองผู้ให้บริการปัจจุบันด้วยกฎการหมุนเวียน/คูลดาวน์โปรไฟล์การยืนยันตัวตน
  </Step>
  <Step title="ไปต่อเมื่อเกิดข้อผิดพลาดที่ควร failover">
    หากผู้ให้บริการนั้นถูกใช้จนหมดด้วยข้อผิดพลาดที่ควร failover ให้ย้ายไปยังตัวเลือกโมเดลถัดไป
  </Step>
  <Step title="บันทึกการแทนที่ fallback">
    บันทึกการแทนที่ fallback ที่เลือกไว้ก่อนเริ่มลองใหม่ เพื่อให้ตัวอ่านเซสชันอื่นเห็นผู้ให้บริการ/โมเดลเดียวกับที่ runner กำลังจะใช้ การแทนที่โมเดลที่บันทึกไว้จะถูกทำเครื่องหมายเป็น `modelOverrideSource: "auto"`
  </Step>
  <Step title="ย้อนกลับอย่างจำกัดเมื่อเกิดความล้มเหลว">
    หากตัวเลือก fallback ล้มเหลว ให้ย้อนกลับเฉพาะฟิลด์การแทนที่เซสชันที่ fallback เป็นเจ้าของ เมื่อฟิลด์เหล่านั้นยังตรงกับตัวเลือกที่ล้มเหลวนั้น
  </Step>
  <Step title="โยน FallbackSummaryError หากใช้หมดแล้ว">
    หากตัวเลือกทั้งหมดล้มเหลว ให้โยน `FallbackSummaryError` พร้อมรายละเอียดแต่ละครั้งที่ลองและเวลาหมดคูลดาวน์ที่เร็วที่สุดเมื่อทราบ
  </Step>
</Steps>

สิ่งนี้ตั้งใจให้แคบกว่า "บันทึกและกู้คืนทั้งเซสชัน" reply runner จะบันทึกเฉพาะฟิลด์การเลือกโมเดลที่เป็นของตนสำหรับ fallback:

- `providerOverride`
- `modelOverride`
- `modelOverrideSource`
- `authProfileOverride`
- `authProfileOverrideSource`
- `authProfileOverrideCompactionCount`

สิ่งนี้ป้องกันไม่ให้การลอง fallback ที่ล้มเหลวเขียนทับการเปลี่ยนแปลงเซสชันอื่นที่ใหม่กว่าและไม่เกี่ยวข้อง เช่น การเปลี่ยน `/model` ด้วยตนเอง หรือการอัปเดตการหมุนเวียนเซสชันที่เกิดขึ้นขณะที่ความพยายามนั้นกำลังทำงาน

## นโยบายแหล่งที่มาของการเลือก

OpenClaw แยกผู้ให้บริการ/โมเดลที่เลือกออกจากเหตุผลที่เลือก แหล่งที่มานั้นควบคุมว่าอนุญาตให้ใช้ลำดับ fallback หรือไม่:

- **ค่าเริ่มต้นที่กำหนดไว้**: `agents.defaults.model.primary` ใช้ `agents.defaults.model.fallbacks`
- **โมเดลหลักของเอเจนต์**: `agents.list[].model` จะเข้มงวด เว้นแต่ออบเจ็กต์โมเดลของเอเจนต์นั้นจะมี `fallbacks` ของตัวเอง ใช้ `fallbacks: []` เพื่อทำให้พฤติกรรมเข้มงวดชัดเจน หรือระบุรายการที่ไม่ว่างเพื่อให้เอเจนต์นั้นเลือกใช้ model fallback
- **การแทนที่ fallback อัตโนมัติ**: fallback ขณะรันไทม์จะเขียน `providerOverride`, `modelOverride`, `modelOverrideSource: "auto"` และโมเดลต้นทางที่เลือกไว้ก่อนลองใหม่ การแทนที่อัตโนมัตินั้นสามารถเดินต่อในลำดับ fallback ที่กำหนดไว้ได้โดยไม่ต้องทดสอบโมเดลหลักในทุกข้อความ แต่ OpenClaw จะทดสอบต้นทางที่กำหนดไว้อีกครั้งเป็นระยะและล้างการแทนที่อัตโนมัติเมื่อกลับมาใช้งานได้ `/new`, `/reset` และ `sessions.reset` จะล้างการแทนที่ที่มีแหล่งที่มาเป็นอัตโนมัติเช่นกัน การรัน Heartbeat ที่ไม่มีการกำหนด `heartbeat.model` อย่างชัดเจนจะล้างการแทนที่อัตโนมัติโดยตรงเมื่อจุดกำเนิดของการแทนที่ไม่ตรงกับค่าเริ่มต้นที่กำหนดไว้ในปัจจุบันอีกต่อไป
- **การแทนที่เซสชันของผู้ใช้**: `/model`, ตัวเลือกโมเดล, `session_status(model=...)` และ `sessions.patch` จะเขียน `modelOverrideSource: "user"` นี่คือการเลือกเซสชันแบบเจาะจง หากผู้ให้บริการ/โมเดลที่เลือกไว้ล้มเหลวก่อนสร้างคำตอบ OpenClaw จะรายงานความล้มเหลวแทนการตอบจาก fallback ที่กำหนดไว้ซึ่งไม่เกี่ยวข้อง
- **การแทนที่เซสชันแบบเดิม**: รายการเซสชันรุ่นเก่าอาจมี `modelOverride` โดยไม่มี `modelOverrideSource` OpenClaw ถือว่าสิ่งเหล่านั้นเป็นการแทนที่ของผู้ใช้ เพื่อไม่ให้การเลือกเดิมที่ชัดเจนถูกแปลงเป็นพฤติกรรม fallback อย่างเงียบๆ
- **โมเดล payload ของ Cron**: `payload.model` / `--model` ของงาน cron เป็นโมเดลหลักของงาน ไม่ใช่การแทนที่เซสชันของผู้ใช้ โดยจะใช้ fallback ที่กำหนดไว้ เว้นแต่งานจะระบุ `payload.fallbacks`; `payload.fallbacks: []` ทำให้การรัน cron เข้มงวด

ช่วงเวลาการทดสอบโมเดลหลักของ fallback อัตโนมัติคือห้านาทีและไม่สามารถกำหนดค่าได้ OpenClaw จดจำการทดสอบล่าสุดต่อเซสชันและโมเดลหลัก เพื่อไม่ให้ลองโมเดลหลักที่ล้มเหลวซ้ำทุกเทิร์น OpenClaw ส่งประกาศที่มองเห็นได้เมื่อเซสชันย้ายไปใช้ fallback และส่งอีกประกาศเมื่อกลับไปยังโมเดลหลักที่เลือกไว้ โดยจะไม่ส่งประกาศซ้ำในทุกเทิร์น fallback แบบ sticky

## แคชข้ามความล้มเหลวการยืนยันตัวตน

โดยค่าเริ่มต้น ทุกเทิร์นใหม่จะคงพฤติกรรมลอง fallback เดิมไว้: OpenClaw
จะลองตัวเลือก fallback ที่กำหนดไว้แต่ละรายการอีกครั้ง รวมถึงตัวเลือกที่ไม่ใช่โมเดลหลัก
ซึ่งเพิ่งล้มเหลวด้วย `auth` หรือ `auth_permanent`

ผู้ปฏิบัติการที่ต้องการระงับความล้มเหลวการยืนยันตัวตนซ้ำเหล่านั้นสามารถเลือกใช้ได้ด้วย:

```bash
OPENCLAW_FALLBACK_SKIP_TTL_MS=60000
```

เมื่อเปิดใช้ OpenClaw จะบันทึกเครื่องหมายข้ามแบบอยู่ในหน่วยความจำและผูกกับเซสชันสำหรับ
ตัวเลือก fallback ที่ไม่ใช่โมเดลหลักหลังความล้มเหลวประเภท auth เครื่องหมายนี้อ้างอิงคีย์
ด้วยรหัสเซสชัน ผู้ให้บริการ และโมเดล ตัวเลือกโมเดลหลักจะไม่ถูกข้าม ดังนั้น
การเลือกโมเดลของผู้ใช้อย่างชัดเจนยังคงแสดงข้อผิดพลาด auth จริง แคชนี้
เป็นแบบเฉพาะกระบวนการและจะถูกล้างเมื่อ Gateway รีสตาร์ต

ค่านี้เป็น TTL หน่วยมิลลิวินาที `0` หรือค่าที่ไม่ได้ตั้งไว้จะปิดใช้งานแคช
ค่าบวกจะถูกจำกัดให้อยู่ระหว่าง 1 วินาทีถึง 10 นาที

## ประกาศ fallback ที่ผู้ใช้มองเห็นได้

เมื่อเซสชันย้ายไปยัง fallback ที่เลือกอัตโนมัติ OpenClaw จะส่งประกาศสถานะในพื้นผิวคำตอบเดียวกัน:

```text
↪️ Model Fallback: <fallback> (selected <primary>; <reason>)
```

เมื่อการทดสอบภายหลังสำเร็จและเซสชันกลับไปยังโมเดลหลักที่เลือกไว้ OpenClaw จะส่ง:

```text
↪️ Model Fallback cleared: <primary> (was <fallback>)
```

ประกาศเหล่านี้เป็นข้อความปฏิบัติการ ไม่ใช่เนื้อหาของผู้ช่วย ประกาศจะถูกส่งหนึ่งครั้งต่อการเปลี่ยนสถานะ รวมถึงเทิร์นที่มีเฉพาะผลข้างเคียงเมื่อทำได้ แต่เทิร์น fallback แบบ sticky จะไม่ส่งซ้ำ การส่งจะข้ามการระงับ source-reply ปกติ ประกาศจะไม่ใช้สล็อตคำตอบแรกของผู้ช่วยสำหรับช่องทางแบบเธรด และจะถูกแยกออกจาก text-to-speech และการแยก commitment

## ที่จัดเก็บการยืนยันตัวตน (คีย์ + OAuth)

OpenClaw ใช้ **โปรไฟล์การยืนยันตัวตน** สำหรับทั้ง API key และโทเค็น OAuth

- ความลับและสถานะการกำหนดเส้นทางการยืนยันตัวตนขณะรันไทม์อยู่ใน `~/.openclaw/agents/<agentId>/agent/openclaw-agent.sqlite`
- Config `auth.profiles` / `auth.order` เป็น **metadata + routing เท่านั้น** (ไม่มีความลับ)
- ไฟล์ OAuth แบบเดิมสำหรับนำเข้าเท่านั้น: `~/.openclaw/credentials/oauth.json` (นำเข้าไปยังที่จัดเก็บการยืนยันตัวตนรายเอเจนต์เมื่อใช้งานครั้งแรก)
- ไฟล์ `auth-profiles.json`, `auth-state.json` และ `auth.json` รายเอเจนต์แบบเดิมจะถูกนำเข้าโดย `openclaw doctor --fix`

รายละเอียดเพิ่มเติม: [OAuth](/th/concepts/oauth)

ประเภทข้อมูลรับรอง:

- `type: "api_key"` → `{ provider, key }`
- `type: "oauth"` → `{ provider, access, refresh, expires, email? }` (+ `projectId`/`enterpriseUrl` สำหรับผู้ให้บริการบางราย)

## รหัสโปรไฟล์

การเข้าสู่ระบบ OAuth จะสร้างโปรไฟล์แยกกันเพื่อให้หลายบัญชีอยู่ร่วมกันได้

- ค่าเริ่มต้น: `provider:default` เมื่อไม่มีอีเมล
- OAuth พร้อมอีเมล: `provider:<email>` (เช่น `google-antigravity:user@gmail.com`)

โปรไฟล์อยู่ในที่จัดเก็บโปรไฟล์การยืนยันตัวตน `openclaw-agent.sqlite` รายเอเจนต์

## ลำดับการหมุนเวียน

เมื่อผู้ให้บริการมีหลายโปรไฟล์ OpenClaw จะเลือกลำดับดังนี้:

<Steps>
  <Step title="Config ที่ชัดเจน">
    `auth.order[provider]` (หากตั้งไว้)
  </Step>
  <Step title="โปรไฟล์ที่กำหนดไว้">
    `auth.profiles` ที่กรองตามผู้ให้บริการ
  </Step>
  <Step title="โปรไฟล์ที่จัดเก็บไว้">
    รายการโปรไฟล์การยืนยันตัวตน SQLite รายเอเจนต์สำหรับผู้ให้บริการ
  </Step>
</Steps>

หากไม่ได้กำหนดลำดับอย่างชัดเจน OpenClaw จะใช้ลำดับแบบ round-robin:

- **คีย์หลัก:** ประเภทโปรไฟล์ (**OAuth ก่อน API key**)
- **คีย์รอง:** `usageStats.lastUsed` (เก่าที่สุดก่อน ภายในแต่ละประเภท)
- **โปรไฟล์ที่อยู่ในคูลดาวน์/ถูกปิดใช้งาน** จะถูกย้ายไปไว้ท้ายสุด โดยเรียงตามเวลาหมดอายุที่เร็วที่สุด

### การยึดติดกับเซสชัน (เป็นมิตรกับแคช)

OpenClaw **ตรึงโปรไฟล์การยืนยันตัวตนที่เลือกไว้ต่อเซสชัน** เพื่อให้แคชของผู้ให้บริการยังอุ่นอยู่ ระบบจะ **ไม่** หมุนเวียนทุกคำขอ โปรไฟล์ที่ตรึงไว้จะถูกใช้ซ้ำจนกว่า:

- เซสชันจะถูกรีเซ็ต (`/new` / `/reset`)
- Compaction เสร็จสมบูรณ์ (จำนวน compaction เพิ่มขึ้น)
- โปรไฟล์อยู่ในคูลดาวน์/ถูกปิดใช้งาน

การเลือกด้วยตนเองผ่าน `/model …@<profileId>` ตั้งค่า **การแทนที่ของผู้ใช้** สำหรับเซสชันนั้นและจะไม่ถูกหมุนเวียนอัตโนมัติจนกว่าจะเริ่มเซสชันใหม่

<Note>
โปรไฟล์ที่ตรึงอัตโนมัติ (เลือกโดยตัวกำหนดเส้นทางเซสชัน) จะถูกถือเป็น **ค่ากำหนด**: จะถูกลองก่อน แต่ OpenClaw อาจหมุนเวียนไปยังโปรไฟล์อื่นเมื่อเกิด rate limit/timeout เมื่อโปรไฟล์เดิมกลับมาใช้งานได้อีกครั้ง การรันใหม่สามารถเลือกใช้โปรไฟล์นั้นก่อนอีกครั้งโดยไม่เปลี่ยนโมเดลที่เลือกหรือรันไทม์ โปรไฟล์ที่ผู้ใช้ตรึงไว้จะถูกล็อกไว้กับโปรไฟล์นั้น หากล้มเหลวและมีการกำหนด model fallback ไว้ OpenClaw จะย้ายไปยังโมเดลถัดไปแทนการสลับโปรไฟล์
</Note>

### การสมัครใช้งาน OpenAI Codex พร้อม API-key สำรอง

สำหรับโมเดลเอเจนต์ OpenAI การยืนยันตัวตนและรันไทม์แยกจากกัน `openai/gpt-*` ยังคงอยู่บน
Codex harness ขณะที่การยืนยันตัวตนสามารถหมุนเวียนระหว่างโปรไฟล์การสมัครใช้งาน Codex และ
API-key สำรองของ OpenAI ได้

ใช้ `auth.order.openai` สำหรับลำดับที่ผู้ใช้เห็น:

```json5
{
  auth: {
    order: {
      openai: ["openai:user@example.com", "openai:api-key-backup"],
    },
  },
}
```

ใช้ `openai:*` สำหรับทั้งโปรไฟล์ OAuth ของ ChatGPT/Codex และโปรไฟล์ API-key
ของ OpenAI เมื่อการสมัครใช้งานชนขีดจำกัดการใช้งาน Codex
OpenClaw จะบันทึกเวลารีเซ็ตที่แน่นอนเมื่อ Codex ให้มา ลองโปรไฟล์การยืนยันตัวตนถัดไป
ตามลำดับ และคงการรันไว้ภายใน Codex harness เมื่อเวลารีเซ็ตผ่านไป
โปรไฟล์การสมัครใช้งานจะกลับมาเข้าเกณฑ์อีกครั้ง และการเลือกอัตโนมัติครั้งถัดไป
สามารถกลับไปใช้โปรไฟล์นั้นได้

ใช้โปรไฟล์ที่ผู้ใช้ตรึงไว้เฉพาะเมื่อคุณต้องการบังคับใช้บัญชี/คีย์เดียวสำหรับ
เซสชันนั้น โปรไฟล์ที่ผู้ใช้ตรึงไว้ตั้งใจให้เข้มงวดและจะไม่กระโดด
ไปยังโปรไฟล์อื่นอย่างเงียบๆ

## คูลดาวน์

เมื่อโปรไฟล์ล้มเหลวเนื่องจากข้อผิดพลาดการยืนยันตัวตน/rate-limit (หรือ timeout ที่ดูเหมือน rate limiting) OpenClaw จะทำเครื่องหมายโปรไฟล์นั้นว่าอยู่ในคูลดาวน์และย้ายไปยังโปรไฟล์ถัดไป

<AccordionGroup>
  <Accordion title="สิ่งที่อยู่ในกลุ่ม rate-limit / timeout">
    กลุ่ม rate-limit นั้นกว้างกว่า `429` ธรรมดา: ยังรวมข้อความจากผู้ให้บริการ เช่น `Too many concurrent requests`, `ThrottlingException`, `concurrency limit reached`, `workers_ai ... quota limit exceeded`, `throttled`, `resource exhausted` และขีดจำกัดหน้าต่างการใช้งานเป็นระยะ เช่น `weekly/monthly limit reached`

    ข้อผิดพลาดรูปแบบ/คำขอไม่ถูกต้องมักเป็นข้อผิดพลาดปลายทาง เพราะการลอง payload เดิมซ้ำจะล้มเหลวแบบเดิม ดังนั้น OpenClaw จะแสดงข้อผิดพลาดเหล่านั้นแทนการหมุนเวียนโปรไฟล์การยืนยันตัวตน เส้นทาง retry-repair ที่รู้จักสามารถเลือกใช้ได้อย่างชัดเจน: เช่น ความล้มเหลวในการตรวจสอบ ID ของ tool call ของ Cloud Code Assist จะถูกทำให้ปลอดภัยและลองใหม่หนึ่งครั้งผ่านนโยบาย `allowFormatRetry` ข้อผิดพลาด stop-reason ที่เข้ากันได้กับ OpenAI เช่น `Unhandled stop reason: error`, `stop reason: error` และ `reason: error` จะถูกจัดประเภทเป็นสัญญาณ timeout/failover

    ข้อความเซิร์ฟเวอร์ทั่วไปอาจอยู่ในกลุ่ม timeout นั้นได้เช่นกันเมื่อแหล่งที่มาตรงกับรูปแบบ transient ที่รู้จัก ตัวอย่างเช่น ข้อความ stream-wrapper ของรันไทม์โมเดลเปล่าๆ `An unknown error occurred` จะถูกถือว่าควร failover สำหรับทุกผู้ให้บริการ เพราะรันไทม์โมเดลที่ใช้ร่วมกันจะปล่อยข้อความนี้เมื่อสตรีมของผู้ให้บริการจบด้วย `stopReason: "aborted"` หรือ `stopReason: "error"` โดยไม่มีรายละเอียดเฉพาะ payload JSON `api_error` ที่มีข้อความเซิร์ฟเวอร์ transient เช่น `internal server error`, `unknown error, 520`, `upstream error` หรือ `backend error` จะถูกถือเป็น timeout ที่ควร failover เช่นกัน

    ข้อความ upstream ทั่วไปเฉพาะ OpenRouter เช่น `Provider returned error` เปล่าๆ จะถูกถือเป็น timeout เฉพาะเมื่อบริบทผู้ให้บริการเป็น OpenRouter จริงเท่านั้น ข้อความ fallback ภายในทั่วไป เช่น `LLM request failed with an unknown error.` จะยังคงใช้แนวทางอนุรักษ์นิยมและไม่กระตุ้น failover ด้วยตัวเอง

  </Accordion>
  <Accordion title="SDK retry-after caps">
    SDK ของผู้ให้บริการบางรายอาจพักการทำงานตามช่วงเวลา `Retry-After` ที่ยาวนานก่อนส่งการควบคุมกลับมายัง OpenClaw สำหรับ SDK ที่ใช้ Stainless เช่น Anthropic และ OpenAI โดยค่าเริ่มต้น OpenClaw จะจำกัดการรอ `retry-after-ms` / `retry-after` ภายใน SDK ไว้ที่ 60 วินาที และแสดงผลการตอบกลับที่ลองใหม่ได้ซึ่งนานกว่านั้นทันที เพื่อให้เส้นทาง failover นี้ทำงานได้ ปรับแต่งหรือปิดใช้งานขีดจำกัดด้วย `OPENCLAW_SDK_RETRY_MAX_WAIT_SECONDS`; ดู [พฤติกรรมการลองใหม่](/th/concepts/retry)
  </Accordion>
  <Accordion title="Model-scoped cooldowns">
    คูลดาวน์จากการจำกัดอัตราสามารถจำกัดขอบเขตตามโมเดลได้เช่นกัน:

    - OpenClaw บันทึก `cooldownModel` สำหรับความล้มเหลวจากการจำกัดอัตราเมื่อทราบ id ของโมเดลที่ล้มเหลว
    - โมเดลพี่น้องบนผู้ให้บริการเดียวกันยังสามารถถูกลองได้เมื่อคูลดาวน์จำกัดขอบเขตอยู่ที่โมเดลอื่น
    - ช่วงเวลาการเรียกเก็บเงิน/การปิดใช้งานยังคงบล็อกทั้งโปรไฟล์ข้ามโมเดล

  </Accordion>
</AccordionGroup>

คูลดาวน์ใช้ exponential backoff:

- 1 นาที
- 5 นาที
- 25 นาที
- 1 ชั่วโมง (ขีดจำกัดสูงสุด)

สถานะถูกเก็บไว้ในสถานะ auth ของ SQLite ต่อเอเจนต์ภายใต้ `usageStats`:

```json
{
  "usageStats": {
    "provider:profile": {
      "lastUsed": 1736160000000,
      "cooldownUntil": 1736160600000,
      "errorCount": 2
    }
  }
}
```

## การปิดใช้งานจากการเรียกเก็บเงิน

ความล้มเหลวด้านการเรียกเก็บเงิน/เครดิต (เช่น "insufficient credits" / "credit balance too low") ถือว่าควรทำ failover แต่โดยปกติไม่ใช่ปัญหาชั่วคราว แทนที่จะใช้คูลดาวน์สั้น OpenClaw จะทำเครื่องหมายโปรไฟล์เป็น **ปิดใช้งาน** (พร้อม backoff ที่นานกว่า) และหมุนไปยังโปรไฟล์/ผู้ให้บริการถัดไป

<Note>
ไม่ใช่ทุกการตอบกลับที่มีลักษณะเกี่ยวกับการเรียกเก็บเงินจะเป็น `402` และไม่ใช่ HTTP `402` ทุกกรณีจะมาถึงเส้นทางนี้ OpenClaw เก็บข้อความการเรียกเก็บเงินที่ชัดเจนไว้ในเลนการเรียกเก็บเงิน แม้ผู้ให้บริการจะส่งคืน `401` หรือ `403` แทน แต่ matcher เฉพาะผู้ให้บริการยังคงจำกัดขอบเขตอยู่ที่ผู้ให้บริการที่เป็นเจ้าของมัน (เช่น OpenRouter `403 Key limit exceeded`)

ในขณะเดียวกัน ข้อผิดพลาด `402` ชั่วคราวจากกรอบเวลาการใช้งานและขีดจำกัดค่าใช้จ่ายขององค์กร/เวิร์กสเปซจะถูกจัดประเภทเป็น `rate_limit` เมื่อข้อความดูเหมือนลองใหม่ได้ (เช่น `weekly usage limit exhausted`, `daily limit reached, resets tomorrow` หรือ `organization spending limit exceeded`) รายการเหล่านี้จะยังอยู่บนเส้นทางคูลดาวน์สั้น/failover แทนเส้นทางปิดใช้งานจากการเรียกเก็บเงินที่ยาวกว่า
</Note>

สถานะถูกเก็บไว้ในสถานะ auth ของ SQLite ต่อเอเจนต์:

```json
{
  "usageStats": {
    "provider:profile": {
      "disabledUntil": 1736178000000,
      "disabledReason": "billing"
    }
  }
}
```

ค่าเริ่มต้น:

- Backoff จากการเรียกเก็บเงินเริ่มที่ **5 ชั่วโมง**, เพิ่มเป็นสองเท่าต่อความล้มเหลวด้านการเรียกเก็บเงินแต่ละครั้ง และจำกัดสูงสุดที่ **24 ชั่วโมง**
- ตัวนับ backoff จะรีเซ็ตหากโปรไฟล์ไม่ล้มเหลวเป็นเวลา **24 ชั่วโมง** (กำหนดค่าได้)
- การลองใหม่เมื่อโอเวอร์โหลดอนุญาตให้ **หมุนโปรไฟล์ผู้ให้บริการเดียวกัน 1 ครั้ง** ก่อน fallback โมเดล
- การลองใหม่เมื่อโอเวอร์โหลดใช้ **backoff 0 ms** โดยค่าเริ่มต้น

## Fallback ของโมเดล

หากโปรไฟล์ทั้งหมดสำหรับผู้ให้บริการล้มเหลว OpenClaw จะย้ายไปยังโมเดลถัดไปใน `agents.defaults.model.fallbacks` สิ่งนี้ใช้กับความล้มเหลวด้าน auth, การจำกัดอัตรา และ timeout ที่ใช้การหมุนโปรไฟล์จนหมดแล้ว (ข้อผิดพลาดอื่นจะไม่เลื่อน fallback) ข้อผิดพลาดของผู้ให้บริการที่ไม่เปิดเผยรายละเอียดเพียงพอยังคงถูกติดป้ายอย่างแม่นยำในสถานะ fallback: `empty_response` หมายถึงผู้ให้บริการไม่ส่งคืนข้อความหรือสถานะที่ใช้งานได้, `no_error_details` หมายถึงผู้ให้บริการส่งคืน `Unknown error (no error details in response)` อย่างชัดเจน และ `unclassified` หมายถึง OpenClaw เก็บตัวอย่างดิบไว้แต่ยังไม่มี classifier ใดตรงกับมัน

ข้อผิดพลาดโอเวอร์โหลดและการจำกัดอัตราจะถูกจัดการอย่างเข้มงวดกว่าคูลดาวน์จากการเรียกเก็บเงิน โดยค่าเริ่มต้น OpenClaw อนุญาตให้ลอง auth-profile ผู้ให้บริการเดียวกันหนึ่งครั้ง แล้วสลับไปยัง fallback โมเดลที่กำหนดค่าถัดไปโดยไม่รอ สัญญาณผู้ให้บริการยุ่ง เช่น `ModelNotReadyException` จะอยู่ในกลุ่มโอเวอร์โหลดนั้น ปรับแต่งสิ่งนี้ด้วย `auth.cooldowns.overloadedProfileRotations`, `auth.cooldowns.overloadedBackoffMs` และ `auth.cooldowns.rateLimitedProfileRotations`

เมื่อการรันเริ่มจาก primary เริ่มต้นที่กำหนดค่าไว้, primary ของงาน Cron, primary ของเอเจนต์ที่มี fallback ชัดเจน หรือ override fallback ที่เลือกอัตโนมัติ OpenClaw สามารถเดินตามเชน fallback ที่กำหนดค่าไว้ซึ่งตรงกันได้ Primary ของเอเจนต์ที่ไม่มี fallback ชัดเจนและการเลือกโดยผู้ใช้อย่างชัดเจน (เช่น `/model ollama/qwen3.5:27b`, ตัวเลือกโมเดล, `sessions.patch` หรือ override ผู้ให้บริการ/โมเดลแบบครั้งเดียวของ CLI) จะเข้มงวด: หากผู้ให้บริการ/โมเดลนั้นเข้าถึงไม่ได้หรือล้มเหลวก่อนสร้างคำตอบ OpenClaw จะรายงานความล้มเหลวแทนการตอบจาก fallback ที่ไม่เกี่ยวข้อง

### กฎของเชนตัวเลือก

OpenClaw สร้างรายการตัวเลือกจาก `provider/model` ที่ร้องขออยู่ในปัจจุบันบวกกับ fallback ที่กำหนดค่าไว้

<AccordionGroup>
  <Accordion title="Rules">
    - โมเดลที่ร้องขอจะอยู่ลำดับแรกเสมอ
    - Fallback ที่กำหนดค่าไว้อย่างชัดเจนจะถูกลบรายการซ้ำ แต่ไม่ถูกกรองด้วย allowlist ของโมเดล รายการเหล่านี้ถือเป็นเจตนาชัดเจนของผู้ปฏิบัติงาน
    - หากการรันปัจจุบันอยู่บน fallback ที่กำหนดค่าไว้แล้วใน family ผู้ให้บริการเดียวกัน OpenClaw จะใช้เชนที่กำหนดค่าไว้เต็มต่อไป
    - เมื่อไม่ได้ระบุ override fallback อย่างชัดเจน fallback ที่กำหนดค่าไว้จะถูกลองก่อน primary ที่กำหนดค่าไว้ แม้โมเดลที่ร้องขอจะใช้ผู้ให้บริการอื่น
    - เมื่อไม่ได้ระบุ override fallback อย่างชัดเจนให้ runner ของ fallback primary ที่กำหนดค่าไว้จะถูกต่อท้าย เพื่อให้เชนกลับไปลงที่ค่าเริ่มต้นปกติได้หลังจากตัวเลือกก่อนหน้าถูกใช้จนหมด
    - เมื่อผู้เรียกระบุ `fallbacksOverride` runner จะใช้เฉพาะโมเดลที่ร้องขอบวกกับรายการ override นั้นเท่านั้น รายการว่างจะปิด fallback โมเดลและป้องกันไม่ให้ primary ที่กำหนดค่าไว้ถูกต่อท้ายเป็นเป้าหมายลองใหม่แบบซ่อน

  </Accordion>
</AccordionGroup>

### ข้อผิดพลาดใดที่เลื่อน fallback

<Tabs>
  <Tab title="Continues on">
    - ความล้มเหลวด้าน auth
    - การจำกัดอัตราและการใช้คูลดาวน์จนหมด
    - ข้อผิดพลาดโอเวอร์โหลด/ผู้ให้บริการยุ่ง
    - ข้อผิดพลาด failover ที่มีลักษณะเป็น timeout
    - การปิดใช้งานจากการเรียกเก็บเงิน
    - `LiveSessionModelSwitchError` ซึ่งถูก normalize เข้าสู่เส้นทาง failover เพื่อไม่ให้โมเดลที่ persisted ไว้เก่าสร้างลูปลองใหม่ชั้นนอก
    - ข้อผิดพลาดอื่นที่ไม่รู้จักเมื่อยังมีตัวเลือกเหลืออยู่

  </Tab>
  <Tab title="Does not continue on">
    - การ abort อย่างชัดเจนที่ไม่มีลักษณะเป็น timeout/failover
    - ข้อผิดพลาด context overflow ที่ควรอยู่ภายในตรรกะ compaction/retry (เช่น `request_too_large`, `INVALID_ARGUMENT: input exceeds the maximum number of tokens`, `input token count exceeds the maximum number of input tokens`, `The input is too long for the model` หรือ `ollama error: context length exceeded`)
    - ข้อผิดพลาด unknown สุดท้ายเมื่อไม่มีตัวเลือกเหลืออยู่

  </Tab>
</Tabs>

### พฤติกรรมการข้ามคูลดาวน์เทียบกับการ probe

เมื่อ auth profile ทุกโปรไฟล์สำหรับผู้ให้บริการอยู่ในคูลดาวน์แล้ว OpenClaw จะไม่ข้ามผู้ให้บริการนั้นตลอดไปโดยอัตโนมัติ แต่จะตัดสินใจต่อหนึ่งตัวเลือก:

<AccordionGroup>
  <Accordion title="Per-candidate decisions">
    - ความล้มเหลวด้าน auth แบบถาวรจะข้ามทั้งผู้ให้บริการทันที
    - การปิดใช้งานจากการเรียกเก็บเงินมักจะข้าม แต่ตัวเลือก primary ยังสามารถถูก probe ตาม throttle เพื่อให้กู้คืนได้โดยไม่ต้องรีสตาร์ท
    - ตัวเลือก primary อาจถูก probe ใกล้เวลาหมดอายุคูลดาวน์ พร้อม throttle ต่อผู้ให้บริการ
    - Fallback พี่น้องจากผู้ให้บริการเดียวกันสามารถถูกลองได้แม้มีคูลดาวน์เมื่อความล้มเหลวดูเป็นชั่วคราว (`rate_limit`, `overloaded` หรือ unknown) สิ่งนี้สำคัญเป็นพิเศษเมื่อการจำกัดอัตราจำกัดขอบเขตตามโมเดล และโมเดลพี่น้องอาจยังฟื้นตัวได้ทันที
    - Probe คูลดาวน์ชั่วคราวถูกจำกัดไว้ที่หนึ่งครั้งต่อผู้ให้บริการต่อการรัน fallback เพื่อไม่ให้ผู้ให้บริการเดียวทำให้ fallback ข้ามผู้ให้บริการหยุดชะงัก

  </Accordion>
</AccordionGroup>

## Override ของเซสชันและการสลับโมเดลสด

การเปลี่ยนโมเดลของเซสชันเป็นสถานะที่ใช้ร่วมกัน Runner ที่ใช้งานอยู่, คำสั่ง `/model`, การอัปเดต compaction/เซสชัน และการ reconcile live-session ล้วนอ่านหรือเขียนบางส่วนของ entry เซสชันเดียวกัน

นั่นหมายความว่าการลองใหม่ของ fallback ต้องประสานงานกับการสลับโมเดลสด:

- เฉพาะการเปลี่ยนโมเดลที่ผู้ใช้ขับเคลื่อนอย่างชัดเจนเท่านั้นที่จะทำเครื่องหมาย live switch ที่รอดำเนินการ ซึ่งรวมถึง `/model`, `session_status(model=...)` และ `sessions.patch`
- การเปลี่ยนโมเดลที่ระบบขับเคลื่อน เช่น การหมุน fallback, override ของ Heartbeat หรือ compaction จะไม่ทำเครื่องหมาย live switch ที่รอดำเนินการด้วยตัวเอง
- Override โมเดลที่ผู้ใช้ขับเคลื่อนถือเป็นการเลือกที่แน่นอนสำหรับนโยบาย fallback ดังนั้นผู้ให้บริการที่เลือกซึ่งเข้าถึงไม่ได้จะแสดงเป็นความล้มเหลวแทนที่จะถูกซ่อนด้วย `agents.defaults.model.fallbacks`
- ก่อนเริ่มลอง fallback ใหม่ reply runner จะ persist ฟิลด์ override fallback ที่เลือกไว้ไปยัง entry เซสชัน
- Override fallback อัตโนมัติจะยังคงถูกเลือกใน turn ถัดไป เพื่อให้ OpenClaw ไม่ probe primary ที่ทราบว่าเสียทุกข้อความ OpenClaw จะ probe origin ที่กำหนดค่าไว้อีกครั้งเป็นระยะ และล้าง override อัตโนมัติเมื่อฟื้นตัว; `/new`, `/reset` และ `sessions.reset` จะล้าง override ที่มาจากอัตโนมัติทันที
- การตอบกลับของผู้ใช้จะแจ้งการเปลี่ยนผ่าน fallback และการกู้คืนเมื่อ fallback ถูกล้างหนึ่งครั้งต่อการเปลี่ยนสถานะ Turn ของ fallback แบบ sticky จะไม่แจ้งซ้ำ
- `/status` แสดงโมเดลที่เลือก และเมื่อสถานะ fallback แตกต่าง จะแสดงโมเดล fallback ที่ใช้งานอยู่และเหตุผล
- การ reconcile live-session ให้ความสำคัญกับ override ของเซสชันที่ persisted ไว้มากกว่าฟิลด์โมเดล runtime ที่เก่า
- หากข้อผิดพลาด live-switch ชี้ไปยังตัวเลือกถัดไปในเชน fallback ที่ใช้งานอยู่ OpenClaw จะกระโดดตรงไปยังโมเดลที่เลือกนั้นแทนการเดินผ่านตัวเลือกที่ไม่เกี่ยวข้องก่อน
- หากความพยายาม fallback ล้มเหลว runner จะ rollback เฉพาะฟิลด์ override ที่เขียนไว้ และเฉพาะเมื่อยังตรงกับตัวเลือกที่ล้มเหลวนั้น

สิ่งนี้ป้องกัน race แบบคลาสสิก:

<Steps>
  <Step title="Primary fails">
    โมเดล primary ที่เลือกไว้ล้มเหลว
  </Step>
  <Step title="Fallback chosen in memory">
    ตัวเลือก fallback ถูกเลือกในหน่วยความจำ
  </Step>
  <Step title="Session store still says old primary">
    ที่เก็บเซสชันยังคงสะท้อน primary เก่า
  </Step>
  <Step title="Live reconciliation reads stale state">
    การ reconcile live-session อ่านสถานะเซสชันที่เก่า
  </Step>
  <Step title="Retry snapped back">
    การลองใหม่ถูกดึงกลับไปยังโมเดลเก่าก่อนความพยายาม fallback จะเริ่ม
  </Step>
</Steps>

Override fallback ที่ persisted ไว้จะปิดช่องว่างนั้น และ rollback ที่แคบจะคงการเปลี่ยนแปลงเซสชันแบบ manual หรือ runtime ที่ใหม่กว่าไว้ครบถ้วน

## Observability และสรุปความล้มเหลว

`runWithModelFallback(...)` บันทึกรายละเอียดต่อความพยายามซึ่งป้อนให้ log และข้อความคูลดาวน์ที่ผู้ใช้เห็น:

- ผู้ให้บริการ/โมเดลที่ลอง
- เหตุผล (`rate_limit`, `overloaded`, `billing`, `auth`, `model_not_found` และเหตุผล failover ที่คล้ายกัน)
- status/code แบบไม่บังคับ
- สรุปข้อผิดพลาดที่มนุษย์อ่านได้

Log `model_fallback_decision` แบบมีโครงสร้างยังรวมฟิลด์ `fallbackStep*` แบบ flat เมื่อ candidate ล้มเหลว ถูกข้าม หรือ fallback ถัดไปสำเร็จ ฟิลด์เหล่านี้ทำให้การเปลี่ยนผ่านที่ลองชัดเจน (`fallbackStepFromModel`, `fallbackStepToModel`, `fallbackStepFromFailureReason`, `fallbackStepFromFailureDetail`, `fallbackStepFinalOutcome`) เพื่อให้ตัวส่งออก log และ diagnostics สามารถสร้างความล้มเหลวของ primary กลับมาได้ แม้ fallback ปลายทางจะล้มเหลวด้วย

เมื่อทุกตัวเลือกล้มเหลว OpenClaw จะ throw `FallbackSummaryError` reply runner ชั้นนอกสามารถใช้สิ่งนั้นเพื่อสร้างข้อความที่เฉพาะเจาะจงกว่า เช่น "all models are temporarily rate-limited" และรวมเวลาหมดอายุคูลดาวน์ที่เร็วที่สุดเมื่อทราบ

สรุปคูลดาวน์นั้นรับรู้ตามโมเดล:

- การจำกัดอัตราที่จำกัดขอบเขตตามโมเดลที่ไม่เกี่ยวข้องจะถูกละเว้นสำหรับเชนผู้ให้บริการ/โมเดลที่ลอง
- หากบล็อกที่เหลือเป็นการจำกัดอัตราที่จำกัดขอบเขตตามโมเดลซึ่งตรงกัน OpenClaw จะรายงานเวลาหมดอายุล่าสุดที่ตรงกันซึ่งยังคงบล็อกโมเดลนั้น

## การกำหนดค่าที่เกี่ยวข้อง

ดู [การกำหนดค่า Gateway](/th/gateway/configuration) สำหรับ:

- `auth.profiles` / `auth.order`
- `auth.cooldowns.billingBackoffHours` / `auth.cooldowns.billingBackoffHoursByProvider`
- `auth.cooldowns.billingMaxHours` / `auth.cooldowns.failureWindowHours`
- `auth.cooldowns.overloadedProfileRotations` / `auth.cooldowns.overloadedBackoffMs`
- `auth.cooldowns.rateLimitedProfileRotations`
- การกำหนดเส้นทาง `agents.defaults.model.primary` / `agents.defaults.model.fallbacks`
- การกำหนดเส้นทาง `agents.defaults.imageModel`

ดู [โมเดล](/th/concepts/models) สำหรับภาพรวมที่กว้างขึ้นเกี่ยวกับการเลือกโมเดลและการใช้ตัวสำรอง
