33 KiB
| read_when | sidebarTitle | summary | title | x-i18n | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Model failover | OpenClaw چگونه از نمایههای احراز هویت بهصورت چرخشی استفاده میکند و بین مدلها به گزینههای جایگزین میرود | جابهجایی خودکار مدل هنگام خرابی |
|
OpenClaw خرابیها را در دو مرحله مدیریت میکند:
- چرخش پروفایل احراز هویت در ارائهدهندهٔ فعلی.
- fallback مدل به مدل بعدی در
agents.defaults.model.fallbacks.
این سند قواعد زمان اجرا و دادههایی را توضیح میدهد که پشتوانهٔ آنها هستند.
جریان زمان اجرا
برای یک اجرای متنی عادی، OpenClaw نامزدها را به این ترتیب ارزیابی میکند:
مدل فعال نشست و ترجیح پروفایل احراز هویت را resolve میکند. زنجیرهٔ نامزدهای مدل را از انتخاب مدل فعلی و سیاست fallback برای منبع آن انتخاب میسازد. پیشفرضهای پیکربندیشده، مدلهای اصلی Cron job و مدلهای fallback انتخابشده بهصورت خودکار میتوانند از fallbackهای پیکربندیشده استفاده کنند؛ انتخابهای صریح نشست کاربر سختگیرانه هستند. ارائهدهندهٔ فعلی را با قواعد چرخش/دورهٔ انتظار پروفایل احراز هویت امتحان میکند. اگر آن ارائهدهنده با خطایی که شایستهٔ failover است تمام شود، به نامزد مدل بعدی میرود. پیش از شروع تلاش مجدد، override انتخابشدهٔ fallback را پایدار میکند تا خوانندههای دیگر نشست همان ارائهدهنده/مدلی را ببینند که runner در آستانهٔ استفاده از آن است. override پایدارشدهٔ مدل با `modelOverrideSource: "auto"` علامتگذاری میشود. اگر نامزد fallback شکست بخورد، فقط فیلدهای override نشست متعلق به fallback را، هنگامی که هنوز با همان نامزد شکستخورده مطابقت دارند، برمیگرداند. اگر همهٔ نامزدها شکست بخورند، یک `FallbackSummaryError` با جزئیات هر تلاش و نزدیکترین زمان پایان دورهٔ انتظار، وقتی معلوم باشد، پرتاب میکند.این عمداً محدودتر از «ذخیره و بازیابی کل نشست» است. reply runner فقط فیلدهای انتخاب مدل را که برای fallback مالک آنهاست پایدار میکند:
providerOverridemodelOverridemodelOverrideSourceauthProfileOverrideauthProfileOverrideSourceauthProfileOverrideCompactionCount
این کار از این جلوگیری میکند که یک تلاش مجدد fallback ناموفق، جهشهای نامرتبط و جدیدتر نشست مثل تغییرات دستی /model یا بهروزرسانیهای چرخش نشست را که هنگام اجرای تلاش رخ دادهاند، بازنویسی کند.
سیاست منبع انتخاب
OpenClaw ارائهدهنده/مدل انتخابشده را از دلیل انتخاب آن جدا میکند. آن منبع تعیین میکند که آیا زنجیرهٔ fallback مجاز است یا نه:
- پیشفرض پیکربندیشده:
agents.defaults.model.primaryازagents.defaults.model.fallbacksاستفاده میکند. - مدل اصلی Agent:
agents.list[].modelسختگیرانه است مگر اینکه شیء مدل آن agent شاملfallbacksخودش باشد. برای صریح کردن رفتار سختگیرانه ازfallbacks: []استفاده کنید، یا برای فعال کردن model fallback برای آن agent یک فهرست غیرخالی ارائه کنید. - override خودکار fallback: یک fallback زمان اجرا پیش از تلاش مجدد،
providerOverride،modelOverrideوmodelOverrideSource: "auto"را مینویسد. آن override خودکار میتواند به پیمایش زنجیرهٔ fallback پیکربندیشده ادامه دهد و با/new،/resetوsessions.resetپاک میشود. - override نشست کاربر:
/model، انتخابگر مدل،session_status(model=...)وsessions.patchمقدارmodelOverrideSource: "user"را مینویسند. این یک انتخاب دقیق نشست است. اگر ارائهدهنده/مدل انتخابشده پیش از تولید پاسخ شکست بخورد، OpenClaw بهجای پاسخ دادن از یک fallback پیکربندیشدهٔ نامرتبط، خرابی را گزارش میکند. - override نشست legacy: ورودیهای نشست قدیمیتر ممکن است
modelOverrideرا بدونmodelOverrideSourceداشته باشند. OpenClaw با آنها مثل overrideهای کاربر رفتار میکند تا یک انتخاب صریح قدیمی بیسروصدا به رفتار fallback تبدیل نشود. - مدل payload در Cron: یک Cron job با
payload.model/--modelمدل اصلی job است، نه override نشست کاربر. مگر اینکه job مقدارpayload.fallbacksرا ارائه کند، از fallbackهای پیکربندیشده استفاده میکند؛payload.fallbacks: []اجرای Cron را سختگیرانه میکند.
ذخیرهسازی احراز هویت (کلیدها + OAuth)
OpenClaw برای هر دو نوع کلیدهای API و توکنهای OAuth از پروفایلهای احراز هویت استفاده میکند.
- Secretها در
~/.openclaw/agents/<agentId>/agent/auth-profiles.jsonقرار دارند (legacy:~/.openclaw/agent/auth-profiles.json). - وضعیت مسیریابی احراز هویت زمان اجرا در
~/.openclaw/agents/<agentId>/agent/auth-state.jsonقرار دارد. - پیکربندی
auth.profiles/auth.orderفقط فراداده + مسیریابی است (بدون secret). - فایل OAuth فقط برای import در حالت legacy:
~/.openclaw/credentials/oauth.json(در اولین استفاده بهauth-profiles.jsonimport میشود).
جزئیات بیشتر: OAuth
انواع credential:
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/agents/<agentId>/agent/auth-profiles.json زیر profiles قرار دارند.
ترتیب چرخش
وقتی یک ارائهدهنده چندین پروفایل دارد، OpenClaw ترتیب را به این شکل انتخاب میکند:
`auth.order[provider]` (اگر تنظیم شده باشد). `auth.profiles` که بر اساس ارائهدهنده فیلتر شده است. ورودیهای `auth-profiles.json` برای ارائهدهنده.اگر ترتیب صریحی پیکربندی نشده باشد، OpenClaw از ترتیب round‑robin استفاده میکند:
- کلید اصلی: نوع پروفایل (OAuth پیش از کلیدهای API).
- کلید ثانویه:
usageStats.lastUsed(قدیمیترین ابتدا، درون هر نوع). - پروفایلهای در دورهٔ انتظار/غیرفعال به انتها منتقل میشوند و بر اساس نزدیکترین زمان پایان مرتب میشوند.
چسبندگی نشست (سازگار با cache)
OpenClaw برای گرم نگه داشتن cacheهای ارائهدهنده، پروفایل احراز هویت انتخابشده را به ازای هر نشست pin میکند. در هر درخواست نمیچرخد. پروفایل pinشده تا زمانی دوباره استفاده میشود که:
- نشست reset شود (
/new//reset) - یک Compaction کامل شود (شمارندهٔ Compaction افزایش یابد)
- پروفایل در دورهٔ انتظار/غیرفعال باشد
انتخاب دستی از طریق /model …@<profileId> یک override کاربر برای آن نشست تنظیم میکند و تا شروع یک نشست جدید بهصورت خودکار چرخانده نمیشود.
چرا OAuth میتواند «گمشده به نظر برسد»
اگر برای یک ارائهدهنده هم پروفایل OAuth و هم پروفایل کلید API داشته باشید، round‑robin میتواند بین پیامها میان آنها جابهجا شود، مگر اینکه pin شده باشند. برای اجبار به یک پروفایل واحد:
- با
auth.order[provider] = ["provider:profileId"]pin کنید، یا - از یک override به ازای نشست از طریق
/model …همراه با override پروفایل استفاده کنید (وقتی توسط سطح UI/چت شما پشتیبانی میشود).
دورههای انتظار
وقتی یک پروفایل بهدلیل خطاهای احراز هویت/rate-limit شکست میخورد (یا timeoutی که شبیه rate limiting است)، OpenClaw آن را در دورهٔ انتظار علامتگذاری میکند و به پروفایل بعدی میرود.
آن bucket مربوط به rate-limit گستردهتر از `429` ساده است: پیامهای ارائهدهنده مثل `Too many concurrent requests`، `ThrottlingException`، `concurrency limit reached`، `workers_ai ... quota limit exceeded`، `throttled`، `resource exhausted` و محدودیتهای دورهای پنجرهٔ مصرف مثل `weekly/monthly limit reached` را هم شامل میشود.خطاهای format/invalid-request (برای مثال خرابیهای اعتبارسنجی شناسهٔ tool call در Cloud Code Assist) بهعنوان شایستهٔ failover در نظر گرفته میشوند و از همان دورههای انتظار استفاده میکنند. خطاهای stop-reason سازگار با OpenAI مثل `Unhandled stop reason: error`، `stop reason: error` و `reason: error` بهعنوان سیگنالهای timeout/failover طبقهبندی میشوند.
متن عمومی server هم وقتی منبع با یک الگوی گذرای شناختهشده مطابق باشد میتواند در آن bucket مربوط به timeout قرار بگیرد. برای مثال، پیام bare stream-wrapper مربوط به pi-ai یعنی `An unknown error occurred` برای هر ارائهدهندهای شایستهٔ failover در نظر گرفته میشود، چون pi-ai وقتی streamهای ارائهدهنده بدون جزئیات مشخص با `stopReason: "aborted"` یا `stopReason: "error"` پایان مییابند آن را emit میکند. payloadهای JSON با `api_error` و متن server گذرا مثل `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 را فعال نمیکند.
برخی SDKهای ارائهدهنده ممکن است در غیر این صورت پیش از برگرداندن کنترل به OpenClaw برای یک پنجرهٔ طولانی `Retry-After` sleep کنند. برای SDKهای مبتنی بر Stainless مثل Anthropic و OpenAI، OpenClaw بهصورت پیشفرض انتظارهای داخلی SDK مربوط به `retry-after-ms` / `retry-after` را روی ۶۰ ثانیه cap میکند و پاسخهای retryable طولانیتر را فوراً نمایان میکند تا این مسیر failover بتواند اجرا شود. cap را با `OPENCLAW_SDK_RETRY_MAX_WAIT_SECONDS` تنظیم یا غیرفعال کنید؛ [رفتار retry](/fa/concepts/retry) را ببینید.
دورههای انتظار rate-limit میتوانند scoped به مدل هم باشند:
- OpenClaw برای خرابیهای rate-limit وقتی شناسهٔ مدل شکستخورده معلوم باشد، `cooldownModel` را ثبت میکند.
- یک مدل همخانواده روی همان ارائهدهنده هنوز میتواند امتحان شود وقتی دورهٔ انتظار scoped به مدل دیگری باشد.
- پنجرههای billing/غیرفعال همچنان کل پروفایل را در همهٔ مدلها مسدود میکنند.
دورههای انتظار از backoff نمایی استفاده میکنند:
- ۱ دقیقه
- ۵ دقیقه
- ۲۵ دقیقه
- ۱ ساعت (cap)
وضعیت در auth-state.json زیر usageStats ذخیره میشود:
{
"usageStats": {
"provider:profile": {
"lastUsed": 1736160000000,
"cooldownUntil": 1736160600000,
"errorCount": 2
}
}
}
غیرفعالسازیهای billing
خرابیهای billing/اعتبار (برای مثال "insufficient credits" / "credit balance too low") شایستهٔ failover در نظر گرفته میشوند، اما معمولاً گذرا نیستند. OpenClaw بهجای یک دورهٔ انتظار کوتاه، پروفایل را غیرفعال علامتگذاری میکند (با backoff طولانیتر) و به پروفایل/ارائهدهندهٔ بعدی میچرخد.
هر پاسخ شبیه billing الزاماً `402` نیست، و هر HTTP `402` هم اینجا قرار نمیگیرد. OpenClaw متن صریح billing را حتی وقتی ارائهدهنده بهجای آن `401` یا `403` برمیگرداند در مسیر billing نگه میدارد، اما matcherهای مخصوص ارائهدهنده scoped به همان ارائهدهندهای میمانند که مالک آنهاست (برای مثال OpenRouter `403 Key limit exceeded`).در همین حال، خطاهای موقت 402 مربوط به پنجرهٔ مصرف و سقف هزینهٔ سازمان/workspace وقتی پیام retryable به نظر برسد (برای مثال weekly usage limit exhausted، daily limit reached, resets tomorrow یا organization spending limit exceeded) بهعنوان rate_limit طبقهبندی میشوند. آنها بهجای مسیر طولانی غیرفعالسازی billing، روی مسیر کوتاه دورهٔ انتظار/failover باقی میمانند.
وضعیت در auth-state.json ذخیره میشود:
{
"usageStats": {
"provider:profile": {
"disabledUntil": 1736178000000,
"disabledReason": "billing"
}
}
}
پیشفرضها:
- backoff مربوط به billing از ۵ ساعت شروع میشود، با هر خرابی billing دو برابر میشود، و روی ۲۴ ساعت cap میشود.
- شمارندههای backoff اگر پروفایل بهمدت ۲۴ ساعت شکست نخورده باشد reset میشوند (قابل پیکربندی).
- retryهای overloaded اجازهٔ ۱ چرخش پروفایل روی همان ارائهدهنده را پیش از model fallback میدهند.
- retryهای overloaded بهصورت پیشفرض از ۰ میلیثانیه backoff استفاده میکنند.
Model fallback
اگر همهٔ پروفایلهای یک ارائهدهنده شکست بخورند، OpenClaw به مدل بعدی در agents.defaults.model.fallbacks میرود. این برای خرابیهای احراز هویت، rate limitها و timeoutهایی اعمال میشود که چرخش پروفایل را تمام کردهاند (خطاهای دیگر fallback را جلو نمیبرند). خطاهای ارائهدهنده که جزئیات کافی را نمایان نمیکنند همچنان در وضعیت fallback با برچسب دقیق ثبت میشوند: empty_response یعنی ارائهدهنده هیچ پیام یا وضعیت قابل استفادهای برنگردانده است، no_error_details یعنی ارائهدهنده صراحتاً Unknown error (no error details in response) را برگردانده است، و unclassified یعنی OpenClaw preview خام را حفظ کرده اما هنوز هیچ classifierی با آن مطابق نشده است.
خطاهای بارگذاری بیش از حد و محدودیت نرخ، تهاجمیتر از وقفههای صورتحساب مدیریت میشوند. بهطور پیشفرض، OpenClaw اجازه یک تلاش دوباره برای همان نمایه احراز هویت ارائهدهنده را میدهد، سپس بدون انتظار به fallback مدل پیکربندیشده بعدی میرود. سیگنالهای مشغولبودن ارائهدهنده مانند ModelNotReadyException در همان دسته بارگذاری بیش از حد قرار میگیرند. این رفتار را با auth.cooldowns.overloadedProfileRotations، auth.cooldowns.overloadedBackoffMs، و auth.cooldowns.rateLimitedProfileRotations تنظیم کنید.
وقتی یک اجرا از primary پیشفرض پیکربندیشده، primary یک کار cron، primary یک agent با fallbackهای صریح، یا یک override fallback انتخابشده خودکار شروع میشود، OpenClaw میتواند زنجیره fallback پیکربندیشده متناظر را طی کند. primaryهای agent بدون fallbackهای صریح و انتخابهای صریح کاربر (برای مثال /model ollama/qwen3.5:27b، انتخابگر مدل، sessions.patch، یا overrideهای یکباره ارائهدهنده/مدل CLI) سختگیرانه هستند: اگر آن ارائهدهنده/مدل در دسترس نباشد یا پیش از تولید پاسخ شکست بخورد، OpenClaw بهجای پاسخدادن از یک fallback نامرتبط، شکست را گزارش میکند.
قواعد زنجیره نامزدها
OpenClaw فهرست نامزدها را از provider/model فعلیِ درخواستشده بهعلاوه fallbackهای پیکربندیشده میسازد.
کدام خطاها fallback را جلو میبرند
- شکستهای احراز هویت - محدودیتهای نرخ و اتمام cooldown - خطاهای بارگذاری بیش از حد/مشغولبودن ارائهدهنده - خطاهای failover با شکل timeout - غیرفعالسازیهای صورتحساب - `LiveSessionModelSwitchError`، که به یک مسیر failover نرمالسازی میشود تا یک مدل پایدارشده قدیمی، حلقه تلاش دوباره بیرونی ایجاد نکند - خطاهای ناشناخته دیگر وقتی هنوز نامزدهایی باقی ماندهاند - abortهای صریحی که شکل timeout/failover ندارند - خطاهای سرریز context که باید داخل منطق compaction/تلاش دوباره باقی بمانند (برای مثال `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`) - یک خطای ناشناخته نهایی وقتی هیچ نامزدی باقی نمانده استرفتار پرش cooldown در برابر probe
وقتی همه نمایههای احراز هویت برای یک ارائهدهنده از قبل در cooldown باشند، OpenClaw آن ارائهدهنده را بهطور خودکار برای همیشه رد نمیکند. برای هر نامزد جداگانه تصمیم میگیرد:
- شکستهای پایدار احراز هویت فوراً کل ارائهدهنده را رد میکنند. - غیرفعالسازیهای صورتحساب معمولاً رد میشوند، اما نامزد primary همچنان میتواند با throttle بررسی شود تا بازیابی بدون راهاندازی دوباره ممکن باشد. - نامزد primary ممکن است نزدیک به انقضای cooldown، با throttle جداگانه برای هر ارائهدهنده، probe شود. - siblingهای fallback همان ارائهدهنده میتوانند با وجود cooldown امتحان شوند، وقتی شکست گذرا به نظر میرسد (`rate_limit`، `overloaded`، یا ناشناخته). این بهویژه زمانی مهم است که محدودیت نرخ scoped به مدل باشد و یک مدل sibling ممکن است همچنان فوراً بازیابی شود. - probeهای cooldown گذرا به یکی برای هر ارائهدهنده در هر اجرای fallback محدود میشوند تا یک ارائهدهنده واحد fallback میانارائهدهندهای را متوقف نکند.overrideهای session و تعویض زنده مدل
تغییرات مدل session وضعیت مشترک هستند. اجراکننده فعال، فرمان /model، بهروزرسانیهای compaction/session، و سازگاری live-session همگی بخشهایی از همان ورودی session را میخوانند یا مینویسند.
این یعنی تلاشهای دوباره fallback باید با تعویض زنده مدل هماهنگ شوند:
- فقط تغییرات مدلِ صریحاً کاربرمحور یک live switch معلق را علامتگذاری میکنند. این شامل
/model،session_status(model=...)، وsessions.patchاست. - تغییرات مدلِ سیستممحور مانند چرخش fallback، overrideهای Heartbeat، یا Compaction بهتنهایی هرگز یک live switch معلق را علامتگذاری نمیکنند.
- overrideهای مدلِ کاربرمحور برای سیاست fallback بهعنوان انتخابهای دقیق در نظر گرفته میشوند، بنابراین یک ارائهدهنده انتخابشده غیرقابلدسترسی بهجای پنهانشدن پشت
agents.defaults.model.fallbacksبهصورت شکست نمایش داده میشود. - پیش از شروع یک تلاش دوباره fallback، اجراکننده پاسخ فیلدهای override fallback انتخابشده را در ورودی session پایدار میکند.
- overrideهای fallback خودکار در turnهای بعدی انتخابشده باقی میمانند تا OpenClaw در هر پیام یک primary شناختهشده خراب را probe نکند.
/new،/reset، وsessions.resetoverrideهای خودکار را پاک میکنند و session را به پیشفرض پیکربندیشده برمیگردانند. /statusمدل انتخابشده را نشان میدهد و، وقتی وضعیت fallback متفاوت باشد، مدل fallback فعال و دلیل را نیز نشان میدهد.- سازگاری live-session، overrideهای پایدارشده session را به فیلدهای مدل runtime قدیمی ترجیح میدهد.
- اگر خطای live-switch به نامزدی بعدی در زنجیره fallback فعال اشاره کند، OpenClaw بهجای پیمودن ابتدا نامزدهای نامرتبط، مستقیماً به همان مدل انتخابشده میپرد.
- اگر تلاش fallback شکست بخورد، اجراکننده فقط فیلدهای overrideی را که خودش نوشته است rollback میکند، و فقط اگر هنوز با همان نامزد شکستخورده منطبق باشند.
این جلوی race کلاسیک را میگیرد:
مدل primary انتخابشده شکست میخورد. نامزد fallback در حافظه انتخاب میشود. ذخیره session هنوز primary قدیمی را نشان میدهد. سازگاری live-session وضعیت قدیمی session را میخواند. پیش از شروع تلاش fallback، تلاش دوباره به مدل قدیمی برگردانده میشود.override fallback پایدارشده این پنجره را میبندد، و rollback محدود تغییرات دستی یا runtime جدیدتر session را دستنخورده نگه میدارد.
مشاهدهپذیری و خلاصههای شکست
runWithModelFallback(...) جزئیات هر تلاش را ثبت میکند که خوراک logها و پیامرسانی cooldown رو به کاربر هستند:
- ارائهدهنده/مدل امتحانشده
- دلیل (
rate_limit،overloaded،billing،auth،model_not_found، و دلیلهای failover مشابه) - وضعیت/کد اختیاری
- خلاصه خطای خوانا برای انسان
logهای ساختیافته model_fallback_decision همچنین وقتی یک نامزد شکست میخورد، رد میشود، یا یک fallback بعدی موفق میشود، فیلدهای تخت fallbackStep* را شامل میشوند. این فیلدها انتقال امتحانشده را صریح میکنند (fallbackStepFromModel، fallbackStepToModel، fallbackStepFromFailureReason، fallbackStepFromFailureDetail، fallbackStepFinalOutcome) تا صادرکنندههای log و تشخیص بتوانند شکست primary را بازسازی کنند، حتی وقتی fallback پایانی هم شکست میخورد.
وقتی همه نامزدها شکست بخورند، OpenClaw خطای FallbackSummaryError را پرتاب میکند. اجراکننده پاسخ بیرونی میتواند از آن برای ساختن پیام مشخصتری مانند «همه مدلها بهطور موقت تحت محدودیت نرخ هستند» استفاده کند و وقتی نزدیکترین زمان انقضای cooldown معلوم باشد، آن را نیز درج کند.
آن خلاصه cooldown آگاه از مدل است:
- محدودیتهای نرخ scoped به مدلِ نامرتبط برای زنجیره ارائهدهنده/مدل امتحانشده نادیده گرفته میشوند
- اگر مانع باقیمانده یک محدودیت نرخ scoped به مدلِ منطبق باشد، OpenClaw آخرین انقضای منطبق را که هنوز آن مدل را مسدود میکند گزارش میدهد
پیکربندی مرتبط
برای موارد زیر، پیکربندی Gateway را ببینید:
auth.profiles/auth.orderauth.cooldowns.billingBackoffHours/auth.cooldowns.billingBackoffHoursByProviderauth.cooldowns.billingMaxHours/auth.cooldowns.failureWindowHoursauth.cooldowns.overloadedProfileRotations/auth.cooldowns.overloadedBackoffMsauth.cooldowns.rateLimitedProfileRotationsagents.defaults.model.primary/agents.defaults.model.fallbacks- مسیریابی
agents.defaults.imageModel
برای نمای کلی گستردهتر انتخاب مدل و fallback، مدلها را ببینید.