رفع خطای context deadline exceeded در Ollama
خطای context deadline exceeded در Ollama نشاندهنده اتمام زمان انتظار برای پاسخ مدل است. برای رفع آن، تنظیمات timeout در کلاینت، پارامتر keep_alive و محدودیتهای nginx را بررسی کنید.
معنای واقعی خطای context deadline exceeded
خطای context deadline exceeded در Ollama در واقع گزارش یک timeout است. بخشی از کد Go برای درخواست، یک مهلت زمانی تعیین کرده است، مدل در آن بازه زمانی به پایان نرسیده و مهلت منقضی شده است. هیچ چیزی کرش نکرده و هیچ فایلی آسیب ندیده است. عملیات در لحظهای که زمان به پایان رسیده، همچنان در حال اجرا بوده است.
این عبارت از پکیج استاندارد context در زبان Go گرفته شده است و خود این موضوع یک سرنخ مفید است. یک کلاینت پایتون که بر پایه httpx ساخته شده باشد، به جای آن خطای httpx.ReadTimeout را صادر میکند. مرورگر نیز یک خطای شبکه ساده نمایش میدهد. اگر دقیقاً همین عبارت را مشاهده میکنید، یک برنامه Go از انتظار کشیدن دست کشیده است: ابزار خط فرمان Ollama، خودِ سرور Ollama، یا یک برنامه Go که در حال فراخوانی API (رابط برنامهنویسی کاربردی) است.
پنج لایه وجود دارند که میتوانند این مهلت زمانی را تعیین کنند. آنها در نقاط مختلفی دچار شکست میشوند و هر کدام نیاز به راهکار متفاوتی دارند، بنابراین کل کار در واقع تشخیص این است که کدام یک از آنها باعث بروز خطا شده است.
- کلاینت HTTP شما، که برای درخواست یک بودجه زمانی ثابت تعیین کرده است.
- مهلت زمانی بارگذاری مدل در سرور Ollama، که هنگام خواندن یک مدل حجیم از دیسک برای اولین بار فعال میشود.
keep_alive، که مدل را بین درخواستها از حافظه خارج میکند تا فراخوانی بعدی دوباره هزینه بارگذاری را متحمل شود.- یک
num_ctxکه آنقدر بزرگ است که پردازش پرامپت به تنهایی روی یک سیستم بدون GPU، چندین دقیقه طول میکشد. - یک reverse proxy مانند nginx یا Traefik، که پیش از پاسخ دادن Ollama، اتصال را قطع میکند.
این لیست را به ترتیب بررسی کنید. هر مرحله در ادامه، یک لایه را از تصویر حذف میکند تا از حدس و گمان دست بردارید.
بازتولید درخواست از طریق API برای حذف پروکسی از مسیر
درخواست را مستقیماً روی خود سرور و به سمت Ollama اجرا کنید، بدون اینکه پروکسی در میان باشد.
time curl -s http://127.0.0.1:11434/api/generate -d '{
"model": "llama3.1:8b",
"prompt": "Why is the sky blue?",
"stream": false
}' | head -c 400curl هیچ محدودیت زمانی کلی برای خود تعیین نمیکند و فقط یک timeout برای اتصال دارد، بنابراین این دستور تا زمانی که Ollama نیاز داشته باشد منتظر میماند. این کار مسئله را به دو بخش تقسیم میکند. اگر بدنه JSON بازگردانده شد، یعنی Ollama پاسخ داده است و محدودیت زمانی مربوط به بخشی است که پیش از آن قرار دارد. اگر این فراخوانی برای چند دقیقه معلق بماند، تأخیر در داخل Ollama است و پروکسی شما بیگناه است.
حالا همان درخواست را از طریق URL عمومی خود ارسال کنید و زمان آن را اندازه بگیرید.
curl -s -o /dev/null -w '%{http_code} %{time_total}\n' \
-X POST https://llm.example.com/api/generate \
-d '{"model": "llama3.1:8b", "prompt": "hi", "stream": false}'وضعیت 504 که پس از یک عدد رُند مشکوک مانند 60.0 یا 30.0 ثانیه چاپ شود، نشاندهنده timeout پروکسی است. پروکسیها از مقادیر پیشفرض رُند استفاده میکنند. یک مدل دو بار پشت سر هم دقیقاً در 60.000 ثانیه به پایان نمیرسد. اگر فراخوانی مستقیم بهجای کند بودن، فوراً رد (refuse) شود، شما بهجای مشکل محدودیت زمانی، با مشکل listener مواجه هستید و آدرسی که Ollama روی پورت 11434 به آن متصل میشود این مورد را پوشش میدهد.
مشاهده لاگ سرور هنگام اجرای درخواست
یک نشست (session) دوم باز کنید و لاگ سرویس را دنبال کنید، سپس درخواست را دوباره ارسال کنید.
journalctl -u ollama --no-pager --follow --pager-endیک شروع سرد (cold start) سالم، بارگذاری مدل، سپس شروع به کار runner و در نهایت پاسخدهی به درخواست را لاگ میکند. در مقابل، یک بارگذاری ناموفق به شکل زیر است و این همان رشتهای است که timeout بارگذاری خودِ سرور را مشخص میکند:
Error: timed out waiting for llama runner to start - progress 0.00 -این پیام به این معنی است که فرآیند مدل در بازه زمانی تعیینشده برای سرور، با موفقیت شروع نشده است. عدد پیشرفت به شما میگوید که فرآیند تا کجا پیش رفته است. مقدار 0.00 به این معنی است که runner پیش از رسیدن به مهلت زمانی، هیچ گزارشی ارسال نکرده است؛ این وضعیت معمولاً نشان میدهد که فایل همچنان در حال خواندن است یا سیستم در حال استفاده از swap است. برای جزئیات بیشتر در حین بارگذاری، سرویس را با تنظیم OLLAMA_DEBUG=1 مجدداً راهاندازی کرده و مراحل را تکرار کنید.
سنجش اینکه آیا تأخیر مربوط به بارگذاری است یا تولید
Ollama زمانبندیهای اختصاصی خود را گزارش میدهد، بنابراین نیازی به حدس زدن در این بخش ندارید.
ollama run --verbose llama3.1:8b "Why is the sky blue?"پس از دریافت پاسخ، این ابزار مقادیر total duration، load duration، prompt eval count، prompt eval rate، eval count و eval rate را چاپ میکند. دستور را دو بار اجرا کنید. در اجرای دوم، مقدار load duration باید تقریباً به صفر برسد، زیرا مدل از قبل در حافظه بارگذاری شده است. اگر این مقدار کاهش نیافت، مدل بین دو اجرای شما از حافظه خارج میشود که مربوط به مورد keep_alive در ادامه است.
همین اعداد در شیء نهایی JSON از طریق API با نامهای load_duration، prompt_eval_duration و eval_duration بازگردانده میشوند. طبق مستندات، تمام مدتزمانها به نانوثانیه هستند، بنابراین برای خواندن به ثانیه، آنها را بر 10^9 تقسیم کنید.
curl -s http://127.0.0.1:11434/api/generate -d '{
"model": "llama3.1:8b",
"prompt": "Why is the sky blue?",
"stream": false
}' | python3 -c 'import json,sys; d=json.load(sys.stdin); print({k: round(v/1e9, 2) for k, v in d.items() if k.endswith("_duration")})'بزرگترین عدد را بررسی کنید. اگر load_duration مقدار غالب است، شما با مشکل بارگذاری مدل مواجه هستید؛ پس به دو بخش بعدی بروید. اگر prompt_eval_duration مقدار غالب است، هزینه مربوط به پردازش پرامپت است؛ پس به بخش num_ctx بروید. اگر eval_duration مقدار غالب است، مدل بهسادگی روی این سختافزار بهکندی تولید میشود و هیچ تنظیمات timeout این وضعیت را تغییر نخواهد داد. خروجی را با num_predict کوتاهتر کنید یا از یک مدل کوچکتر استفاده نمایید.
افزایش OLLAMA_LOAD_TIMEOUT، پس از بررسی نسخه
متغیر سروری که مدت زمان انتظار برای شروع یک مدل را تعیین میکند OLLAMA_LOAD_TIMEOUT است. مقدار پیشفرض این متغیر در نسخههای مختلف تغییر کرده است، بنابراین به جای تکیه بر مقالات (از جمله همین مقاله)، آن را برای نسخهٔ نصبشدهٔ خود بررسی کنید. ابتدا نسخه را چاپ کنید.
ollama --versionسپس سورسکد مربوط به همان تگ خاص را در https://github.com/ollama/ollama/blob/<your version>/envconfig/config.go باز کرده و به دنبال OLLAMA_LOAD_TIMEOUT بگردید. مقداری که در آن فایل قرار دارد، همان پیشفرضی است که باینری شما با آن کامپایل شده است. مقدار دلخواه خود را از طریق یک drop-in در systemd تنظیم کنید.
sudo systemctl edit ollama.serviceمتغیرها را در بخش [Service] اضافه کنید؛ این روشی است که مستندات رسمی Ollama برای لینوکس ارائه داده است:
[Service]
Environment="OLLAMA_LOAD_TIMEOUT=15m"
Environment="OLLAMA_KEEP_ALIVE=-1"sudo systemctl daemon-reload
sudo systemctl restart ollama
systemctl show ollama --property=Environmentدستور آخر، محیطی (environment) را که سرویس واقعاً دریافت کرده است چاپ میکند. نتیجهٔ خالی به این معناست که فایل drop-in خارج از نشانگرهای ویرایشگر ذخیره شده یا تحت نام بخش اشتباهی قرار گرفته است، بنابراین هیچکدام از تنظیمات شما اعمال نشدهاند. توجه داشته باشید که این کار چه نتیجهای دارد: افزایش زمان انتظار (timeout)، مانع از تسلیم شدن سرور میشود، اما باعث افزایش سرعت نمیشود. اگر مدل در حافظه جا نشود، سیستم شروع به swap میکند، سرعت بارگذاری به شدت کاهش مییابد و انتخاب یک عدد بزرگتر، فقط زمان وقوع خطا را به تعویق میاندازد.
چرا اولین درخواست پس از یک وقفه، کند است
Ollama مدلهای غیرفعال را برای آزاد کردن حافظه از RAM خارج میکند. تنظیم keep_alive تعیین میکند که این اتفاق چه زمانی رخ دهد. طبق مستندات Ollama، مقدار پیشفرض 5 دقیقه است که در سپتامبر 2026 بررسی شد. بنابراین، یک برنامه چت که هر ساعت یکبار استفاده میشود، مدل را با هر پیام دوباره بارگذاری میکند و هر پیام هزینه کامل cold start را میپردازد. درخواستی که با timeout مواجه میشود، اولین درخواست پس از یک دوره سکوت است؛ دقیقاً همان الگویی که کاربران آن را تصادفی توصیف میکنند.
بررسی کنید در حال حاضر چه چیزی در حافظه مقیم است:
ollama ps
curl -s http://127.0.0.1:11434/api/psیک لیست خالی یا یک زمان انقضا که چند دقیقه با زمان فعلی فاصله دارد، این موضوع را تأیید میکند. keep_alive یک رشته مدتزمان مانند "10m" یا "24h"، یک عدد ساده بر حسب ثانیه، 0 برای تخلیه فوری، و یک عدد منفی برای نگه داشتن مدل در حافظه بهصورت نامحدود را میپذیرد. این تنظیم را میتوانید برای هر درخواست یا با استفاده از OLLAMA_KEEP_ALIVE در سرویس برای تمام درخواستها اعمال کنید.
curl -s http://127.0.0.1:11434/api/generate -d '{
"model": "llama3.1:8b",
"keep_alive": -1
}'درخواستی که شامل یک مدل باشد اما prompt نداشته باشد، مدل را بارگذاری کرده و بازمیگردد. این روش مستند برای گرم کردن (warm) یک سیستم پس از reboot است و باید در یک unit کوچک systemd قرار گیرد تا هیچکس منتظر cold start نماند. هزینه این کار مشخص است: یک مدل pinned حافظه خود را برای همیشه اشغال میکند، بنابراین در یک سیستم کوچک میتوانید یک مدل را pin کنید، نه چهار مدل را. نگه داشتن مدل در حافظه بین درخواستها محاسبات حافظه و نحوه ایجاد unit برای گرم کردن سیستم را توضیح میدهد.
چرا مقدار بزرگ num_ctx پیش از تولید اولین توکن باعث timeout میشود
پیش از آنکه مدل شروع به نوشتن کند، باید کل prompt شما را بخواند. این مرحله prefill نام دارد و همان چیزی است که prompt eval اندازهگیری میکند. پارامتر num_ctx طول context را تعیین میکند که همزمان دو کار انجام میدهد: سقف تعداد توکنهایی که مدل میتواند در نظر بگیرد را محدود کرده و اندازه KV cache (کش کلید-مقدار) را که سرور از پیش تخصیص میدهد، مشخص میکند. هر دو مورد باعث افزایش حجم پردازش میشوند.
در سروری که فقط از CPU استفاده میکند، prefill کند است و با تعداد توکنهای prompt رابطه خطی دارد. یک سند طولانی که در چت کپی میشود، ممکن است دقایق زیادی را در مرحله prefill سپری کند در حالی که کلاینت هیچ چیزی دریافت نمیکند، زیرا streaming هنوز آغاز نشده است. کلاینت به مهلت زمانی (deadline) خود میرسد و خطای context deadline exceeded را گزارش میدهد، در حالی که سرور در تمام این مدت در حال پردازش بوده است. این موضوع را با اعداد بخش قبل اثبات کنید: همان prompt را یک بار با "options": {"num_ctx": 2048} و بار دیگر با 32768 اجرا کنید و prompt_eval_duration را مقایسه نمایید.
مقدار پیشفرض سرور از OLLAMA_CONTEXT_LENGTH میآید و یک num_ctx در هر درخواست درون شیء options آن را override میکند. افزایش این مقدار تا سقف حداکثرِ اعلامشده برای مدل، صرفاً به این دلیل که آن حداکثر وجود دارد، یک اشتباه رایج است؛ زیرا تخصیص KV cache میتواند مدل را از RAM خارج کرده و یک تنظیمات کاری را به وضعیتی تبدیل کند که درگیر swapping میشود. انتخاب num_ctx بر اساس حافظه واقعی جزئیات مربوط به اندازهگیری را توضیح میدهد.
چرا nginx خطای 504 Gateway Time-out برمیگرداند
مستندات nginx برای proxy_read_timeout مقدار پیشفرض 60s را تعیین کرده است و لاگ خطای آن، علت شکست را بهصراحت بیان میکند:
upstream timed out (110: Connection timed out) while reading response header from upstreamنکتهٔ مهم در مستندات nginx این است که این زمانبندی «فقط بین دو عملیات خواندن متوالی تنظیم میشود، نه برای انتقال کل پاسخ». یک پاسخ streaming با هر تکه (chunk) ساعت را بازنشانی میکند، بنابراین چتهای streaming دچار وقفه نمیشوند. درخواستی با "stream": false تا زمانی که پاسخ کامل نشود، هیچ دادهای ارسال نمیکند، بنابراین کل فرایند تولید پاسخ باید در همان بازهٔ زمانی به پایان برسد. به همین دلیل است که یک مدل مشابه در پنجرهٔ چت کار میکند اما از طریق اسکریپت دچار timeout میشود.
location / {
proxy_pass http://127.0.0.1:11434;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
proxy_buffering off;
}sudo nginx -t && sudo systemctl reload nginxproxy_buffering off برای streaming اهمیت دارد. با فعال بودن buffering، nginx میتواند پاسخ را جمعآوری کرده و در انتها تحویل دهد؛ در نتیجه توکنها دیگر یکییکی ظاهر نمیشوند و یک استریمِ در حال کار، بهصورت یک فرایند متوقفشده (hang) به نظر میرسد.
Traefik کنترل مشابهی را روی ServersTransport که router از آن استفاده میکند، اعمال میکند.
http:
serversTransports:
ollama:
forwardingTimeouts:
dialTimeout: "30s"
responseHeaderTimeout: "0s"
idleConnTimeout: "60s"responseHeaderTimeout مدتزمان انتظار برای دریافت هدرهای پاسخ پس از ارسال درخواست را پوشش میدهد و مقدار صفر به معنای عدم وجود timeout است. سرویس باید با استفاده از serversTransport: ollama به آن transport ارجاع دهد، در غیر این صورت شما بلوکی را ویرایش کردهاید که توسط هیچچیز استفاده نمیشود.
کوانتیزاسیون کوچکتر سریعتر بارگذاری میشود زیرا دادههای کمتری برای خواندن وجود دارد
کوانتیزاسیون همان دقتی است که وزنها با آن ذخیره میشوند. دقت پایینتر به معنای فایل کوچکتر است و بارگذاری یک مدل عمدتاً شامل خواندن آن فایل از دیسک به حافظه است.
The data behind this chart
[
{
"label": "q4_K_M",
"download_size_gb": 4.9
},
{
"label": "q8_0",
"download_size_gb": 8.5
},
{
"label": "fp16",
"download_size_gb": 16
}
]اینها اندازههایی هستند که در صفحه مدل منتشر شدهاند، نه اندازهگیریهای بهدستآمده از یک سیستم تست. نسخه پیشفرض 8B با حجم 4.9 گیگابایت عرضه میشود. نسخه با دقت کامل همان مدل 16 گیگابایت است؛ یعنی بیش از سه برابر بایت بیشتر برای خواندن و بیش از سه برابر حافظه بیشتر برای نگهداری. در یک سرور اجارهای با فضای ذخیرهسازی اشتراکی، این تفاوت دقیقاً همان شکاف بین یک بارگذاری موفق و بارگذاریای است که با خطای timeout مواجه میشود. محاسبه اینکه کدام مدل در RAM شما جای میگیرد بررسی لازمی است که باید پیش از دریافت هر فایل حجیمی انجام دهید.
تغییرات لازم در سرور اجارهای
این موارد را به ترتیبی که اندازهگیریها نشان میدهند، یکییکی اعمال کنید و پس از هر تغییر، دستور زمانسنجی را دوباره اجرا کنید.
- مدل را با
OLLAMA_KEEP_ALIVE=-1ثابت (Pin) کنید یا آن را در زمان بوت گرم (Warm) کنید تا هیچ درخواست کاربری هزینه بارگذاری را متحمل نشود. - مقدار
num_ctxرا به میزانی که پرامپتهای شما واقعاً نیاز دارند کاهش دهید؛ این کار زمان prefill را کوتاه کرده و حافظهای که توسط KV cache اشغال شده بود را آزاد میکند. - از یک کوانتیزاسیون (Quantisation) کوچکتر استفاده کنید تا در زمان بارگذاری، بایتهای کمتری خوانده شود و مدل فضای کافی برای کش داشته باشد.
- مقدار
proxy_read_timeoutرا در Nginx یاresponseHeaderTimeoutرا در Traefik افزایش دهید و buffering را غیرفعال کنید تا توکنهای استریمشده به کلاینت برسند. - زمان timeout را در کلاینت خود افزایش دهید، زیرا یک برنامه Go یا Python با محدودیت 30 ثانیه، در برابر هر مدلی که زمان بیشتری برای فکر کردن نیاز دارد، با شکست مواجه میشود.
یک دلیل دیگر در پسِ تمام این موارد پنهان است. Ollama تعداد محدودی درخواست را بهطور همزمان پردازش میکند و بقیه را در صف قرار میدهد؛ بنابراین ممکن است درخواست کاربر دوم در صف منتظر بماند تا مهلت زمانی (Deadline) آن به پایان برسد، بدون اینکه مدل در حال پردازش کندی باشد. لاگ سرور نشان میدهد که درخواست با تأخیر پاسخ داده شده است، نه اینکه با خطا مواجه شده باشد. آنچه هنگام اشتراک چندین نفر از یک سرور Ollama رخ میدهد تنظیمات موازیسازی را پوشش میدهد و نصب پایه روی یک VPS تنظیمات سرویسی که این تغییرات بر اساس آن فرض شدهاند را توضیح میدهد.
FAQ
خطای "context deadline exceeded" در Ollama به چه معناست؟
این خطا به این معناست که مهلت زمانی درخواست پیش از پاسخدهی مدل به پایان رسیده است. این عبارت از بسته context در زبان Go نشأت میگیرد، بنابراین توسط یک برنامه نوشتهشده با Go چاپ شده است: ابزار خط فرمان Ollama، سرور Ollama یا یک برنامه Go که API را فراخوانی میکند. این یک خطای timeout است، بنابراین هیچچیز خراب یا فاسد نشده است. گام بعدی، یافتن لایهای است که این مهلت زمانی را تعیین کرده است، زیرا کلاینت، بارگذاری مدل، keep_alive، num_ctx و reverse proxy هرکدام محدودیتهای زمانی خاص خود را دارند.
آیا باید timeout کلاینت را افزایش دهم یا timeout مربوط به Ollama را؟
ابتدا اندازهگیری کنید. درخواست را با استفاده از curl مستقیماً روی خود سرور و به سمت http://127.0.0.1:11434 ارسال کنید، زیرا curl هیچ محدودیت زمانی کلی اعمال نمیکند. اگر آن فراخوانی یک بدنه JSON برگرداند، Ollama در حال پاسخدهی است و مهلت زمانی متعلق به کلاینت یا پروکسی شماست، پس آن را در همانجا افزایش دهید. اگر آن فراخوانی نیز معلق ماند، تأخیر در داخل Ollama است و فیلدهای load_duration و prompt_eval_duration در پاسخ به شما میگویند که آیا مدل در حال بارگذاری است یا در حال خواندن prompt شما.
چرا اولین درخواست timeout میدهد اما درخواست بعدی کار میکند؟
Ollama مدلهای بلااستفاده را برای آزاد کردن حافظه تخلیه میکند؛ این کار طبق زمانبندی تعیینشده توسط keep_alive انجام میشود. مقدار پیشفرض مستندشده، 5 دقیقه است که در سپتامبر 2026 بررسی شد. اولین درخواست پس از یک دوره بیکاری، مدل را از دیسک بارگذاری مجدد میکند و هزینه کامل cold start را میپردازد، در حالی که درخواستی که بلافاصله پس از آن ارسال شود، مدل را در حافظه مییابد و سریع پاسخ میدهد. برای مشاهده مدلهای بارگذاریشده و زمان انقضای آنها، ollama ps را اجرا کنید. برای نگهداری مدل در حافظه، OLLAMA_KEEP_ALIVE=-1 را تنظیم کنید و بپذیرید که حافظه اشغال باقی میماند.
چرا فقط هنگام عبور از nginx با شکست مواجه میشود؟
nginx پارامتر proxy_read_timeout را با مقدار پیشفرض 60s مستند کرده است و این timeout بین دو خواندن متوالی اعمال میشود، نه برای کل پاسخ. یک پاسخ streaming با هر chunk آن را بازنشانی میکند، در حالی که درخواستی که با "stream": false ارسال میشود باید در یک بازه زمانی واحد تکمیل شود. به همین دلیل است که پنجره چت کار میکند اما اسکریپت با شکست مواجه میشود. در لاگ خطای nginx به دنبال upstream timed out (110: Connection timed out) while reading response header from upstream بگردید، سپس proxy_read_timeout را افزایش داده و proxy_buffering off را تنظیم کنید.
آیا افزایش OLLAMA_LOAD_TIMEOUT باعث سریعتر شدن بارگذاری میشود؟
خیر. این فقط تغییر میدهد که سرور چقدر منتظر بماند تا تسلیم شود و timed out waiting for llama runner to start را لاگ کند. اگر مدل در حافظه جا نشود، سیستم از swap استفاده میکند، بارگذاری بسیار کند میشود و افزایش timeout فقط زمان شکست را به تعویق میاندازد بدون اینکه مشکل را حل کند. مقدار پیشفرض برای build خود را با اجرای ollama --version و خواندن envconfig/config.go در آن تگ بررسی کنید؛ سپس بارگذاریهایی که به دقیقه زمان نیاز دارند را نشانهای برای استفاده از یک quantization کوچکتر در نظر بگیرید.