Ollama أم llama.cpp على VPS؟ أيهما تختار؟
تعرّف إلى الفرق بين المحرّك والطبقة الإضافية، واختر ما يناسب VPS يعمل بالمعالج فقط، مع أثر التكميم على RAM ومتى لا يناسبك أيٌّ منهما.
Ollama مقابل llama.cpp: أي طبقة تريد تشغيلها؟
ليسا Ollama وllama.cpp متنافسين بالمعنى الذي يفترضه السؤال. يمثّل llama.cpp محرّك الاستدلال: يحمّل ملف النموذج ويحوّل prompt إلى tokens. أما Ollama فهو مدير للنماذج، وخدمة daemon تعمل في الخلفية، وواجهة HTTP API تعمل فوق ذلك المحرّك. ما زال README الخاص بـOllama يدرج llama.cpp بوصفه backend للاستدلال (تم التحقق في 2 August 2026). لذلك، السؤال الحقيقي هو: أي طبقة تريد تشغيلها على VPS، وليس أيهما أسرع؟
شغّل Ollama عندما تريد خدمة تجلب النماذج بالاسم وتواصل العمل دون تدخل مستمر. وشغّل llama.cpp مباشرة عندما يكون الخادم صغيراً وتحتاج إلى اختيار ملف النموذج المحدد، وحجم السياق المحدد، وعدد مؤشرات الترابط المحدد، لأن كل إعداد من هذه الإعدادات يستهلك على VPS صغير مقداراً من الذاكرة لا يتوفر لديك.
ما الذي يمثله كل مشروع فعلياً
llama.cpp هو تطبيق بلغة C وC++ لتنفيذ استدلال نماذج Transformer، ومبني على مكتبة ggml. يقرأ ملفات GGUF. وGGUF، أي تنسيق الملفات العام لـGGML، هو حاوية في ملف واحد تضم الأوزان، وأداة تقسيم الرموز، والبيانات الوصفية التي يحتاج إليها المحرك لتشغيل النموذج. يوفّر المشروع ملفات تنفيذية منفصلة للمهام المختلفة. llama-server هو خادم HTTP، وllama-cli هو موجّه تفاعلي، وllama-bench يقيس معدل المعالجة. تُوسَم الإصدارات برقم البناء بدلاً من رقم إصدار دلالي. الوسم الحالي هو b10224، وقد نُشر في 2 August 2026، ويصدر وسم جديد في معظم أيام العمل.
Ollama هو برنامج مكتوب بلغة Go. يحمّل برنامج خفي يعمل في الخلفية، ويُشغَّل باستخدام ollama serve، النماذج ويجيب عن طلبات HTTP، بينما يتصل عميل سطر الأوامر بهذا البرنامج الخفي. ويوجد خلف كليهما سجل في ollama.com يضم نماذج مُعدّة مسبقاً. يستخدم Ollama الإصدارات الدلالية، وقد صدر v0.32.5 في 27 July 2026. يجلب ollama pull ملف GGUF مع قالب مطالبة ومجموعة من المعلمات الافتراضية، ثم يخزّنه ضمن /usr/share/ollama/.ollama/models في Linux.
هذا التغليف هو الفارق الكامل بين المشروعين. يحدّد Ollama نيابةً عنك التكميم والقالب وطول السياق، ويمنحك اسماً واحداً لتتذكره. أما llama.cpp فلا يحدّد شيئاً، ويمنحك خيارات.
المحور 1: التحكم في النموذج والـquantisation
تقلّل عملية الـquantisation حجم كل وزن من 16 أو 32 بت إلى 4 أو 5 أو 8 بت. وهذا ما يجعل نموذجاً يضم 8 مليارات معلَمة مناسباً لذاكرة RAM في VPS عادي. تصبح تسمية GGUF واضحة بعد معرفة النمط: يشير Q4_K_M إلى quantisation من نوع K بدقة 4 بت وبحجم متوسط. يحافظ الرقم الأعلى على دقة أكبر ويستهلك ذاكرة أكثر.
The data behind this chart
[
{
"label": "Q2_K",
"file_size_gib": 2.96
},
{
"label": "Q3_K_M",
"file_size_gib": 3.74
},
{
"label": "Q4_K_M",
"file_size_gib": 4.58
},
{
"label": "Q5_K_M",
"file_size_gib": 5.34
},
{
"label": "Q6_K",
"file_size_gib": 6.14
},
{
"label": "Q8_0",
"file_size_gib": 7.95
}
]هذه هي أحجام الملفات المنشورة في مستودع bartowski/Meta-Llama-3.1-8B-Instruct-GGUF على Hugging Face، وقد قُرئت في 2 August 2026 وحُوّلت من bytes إلى GiB. توجد 6 إصدارات مبنية من نموذج واحد، وأصغرها حجمه 2.96 GiB، مقابل 7.95 GiB لأكبرها. الحجم الافتراضي الشائع، Q4_K_M، هو 4.58 GiB. في VPS بسعة 4 GiB، يحدد هذا الاختيار وحده ما إذا كان النموذج سيُحمّل أم لا.
مع llama.cpp، تحدد اسم الملف، ولذلك تختار هذا الصف بنفسك.
llama-server -m ~/models/Meta-Llama-3.1-8B-Instruct-Q4_K_M.gguf \
-c 4096 -t 4 --host 127.0.0.1 --port 8080يشير -c إلى حجم السياق بوحدة tokens، ويشير -t إلى عدد الخيوط، ويحدد -ngl عدد الطبقات التي تُنقل إلى GPU (وتكون قيمته 0 على جهاز يعمل بوحدة CPU فقط). لا تُخمَّن أي قيمة نيابةً عنك.
مع Ollama، تأتي quantisation مع الـtag الذي تسحبه، ويعرض ollama ls ما لديك فعلياً على القرص. عندما لا يحتوي الـregistry على الإصدار الذي تريده، استورد ملف GGUF بنفسك. اكتب Modelfile:
FROM ./Meta-Llama-3.1-8B-Instruct-Q4_K_M.gguf
PARAMETER num_ctx 4096ثم أنشئه وتحقق من النتيجة:
ollama create llama31-q4 -f ./Modelfile
ollama lsطول السياق هو الإعداد الذي يسبب المشكلات للمستخدمين. يختار Ollama قيمته الافتراضية من VRAM المتاحة، ويدخل الجهاز الذي لا يضم GPU في أصغر فئة: 4096 tokens. إذا أرسلت إليه مستنداً من 20,000 token، فسيتم إسقاط الـtokens الإضافية قبل أن يراها النموذج، ولذلك تكون الإجابة خاطئة بثقة بشأن ملف لم يقرأ منه إلا نصفه. ارفع القيمة باستخدام OLLAMA_CONTEXT_LENGTH في الـdaemon، أو باستخدام PARAMETER num_ctx في Modelfile. ولا يوفّر llama.cpp قيمة افتراضية يمكن الوثوق بها أيضاً. عيّن -c صراحةً، وتأكد من القيمة التي عيّنتها.
حساب الذاكرة الذي لا يوضحه أحد
ملف النموذج ليس التكلفة الكاملة. تخزّن ذاكرة KV المؤقتة (ذاكرة المفتاح/القيمة المؤقتة) إدخالاً واحداً لكل طبقة ولكل رمز من سياق المحادثة، وتزداد مع نمو المحادثة.
احسبها لنموذج Llama 3.1 8B. يتكوّن النموذج من 32 طبقة، و8 رؤوس للمفتاح/القيمة، ويبلغ بُعد الرأس 128. يخزّن كل رمز مفتاحاً وقيمة، بحجم 2 بايت لكل منهما بتنسيق f16، لذلك تكون العملية 2 x 8 x 128 x 2 = 4096 بايت لكل طبقة. وعبر 32 طبقة، يصبح ذلك 128 KiB لكل رمز. لذلك يستهلك سياق من 4096 رمزاً 512 MiB، بينما يستهلك سياق من 32,768 رمزاً 4 GiB.
لذلك يحتاج نموذج Q4_K_M 8B بسياق 4k إلى نحو 4.58 GiB للأوزان، إضافة إلى نحو 0.5 GiB لذاكرة التخزين المؤقت، وإضافة إلى بيئة التشغيل نفسها. لن يتسع ذلك في 4 GiB من RAM. ويتسع في 8 GiB مع مساحة كافية للتشغيل. إذا رفعت السياق إلى 32k على الخادم نفسه ذي سعة 8 GiB، فستستهلك ذاكرة التخزين المؤقت وحدها المساحة المتاحة. راقب الاستخدام مباشرةً عبر free -h أثناء تحميل النموذج، ولا تثق بتقدير لم تقسه. إذا كنت تحدد سعة نموذج يتجاوز 8B بكثير، فإن الحساب نفسه المطبق على نموذج 27B على VPS يعمل بالمعالج فقط يوضح ما يمكن لكل مستوى بين 8 و64 GB استيعابه فعلياً.
يؤدي Ollama إلى مضاعفة ذلك. تكون قيمة OLLAMA_NUM_PARALLEL الافتراضية هي 1، وتتوسع الذاكرة التي يحتاجها النموذج بما يتناسب مع حاصل ضرب هذه القيمة في طول السياق. إذا رفعت القيمتين معاً، فسيطلب البرنامج الخفي بهدوء عدة أضعاف RAM التي توقعتها. ويحدد الحساب نفسه الحد الأقصى لعدد المستخدمين المتزامنين، لأن كل طلب متزامن يحتاج إلى جزء خاص به من ذاكرة KV المؤقتة، وهذا هو سبب توقف خادم يبدو مناسباً لشخص واحد عند خمسة مستخدمين.
المحور 2: البرنامج الخفي الذي يجب عليك تشغيله
يكتب سكربت تثبيت Ollama وحدة systemd، وينشئ مستخدم نظام ollama، ويفعّل الخدمة. تحصل بذلك على إدارة دورة الحياة من دون كتابة أي من هذه الإعدادات بنفسك. تُدار الإعدادات عبر systemd:
sudo systemctl edit ollama[Service]
Environment="OLLAMA_CONTEXT_LENGTH=8192"
Environment="OLLAMA_KEEP_ALIVE=30m"sudo systemctl daemon-reload
sudo systemctl restart ollama
journalctl -e -u ollamaيكون OLLAMA_KEEP_ALIVE أكثر أهمية على VPS يعمل بوحدة CPU من أي بيئة أخرى. تُحتفظ النماذج في الذاكرة لمدة 5 دقائق افتراضياً، ثم تُفرَّغ منها. يجب أن يقرأ الطلب التالي الملف بأكمله من القرص قبل أن يتمكن من الرد، لذلك تؤدي إعادة تحميل بحجم 4.58 GiB إلى تحويل رد يستغرق ثانيتين إلى رد يستغرق ثلاثين ثانية على وحدات التخزين البطيئة. يعالج keep-alive طويل زمن الاستجابة، لكنه يستهلك RAM باستمرار. كلا الخيارين له تكلفة فعلية. اختر الخيار الأقل ضرراً.
لا يوفّر llama.cpp برنامجاً خفياً، لذلك تكتب الوحدة بنفسك على النحو التالي باستخدام /etc/systemd/system/llama-server.service:
[Unit]
Description=llama.cpp server
After=network-online.target
[Service]
ExecStart=/usr/local/bin/llama-server -m /srv/models/model-Q4_K_M.gguf -c 4096 -t 4 --host 127.0.0.1 --port 8080
Restart=always
RestartSec=3
User=llama
[Install]
WantedBy=multi-user.targetفعّلها باستخدام sudo systemctl enable --now llama-server. تحتفظ العملية بعد ذلك بالنموذج طوال مدة تشغيلها. لا تُفرَّغ الذاكرة عند الخمول، ما يعني عدم حدوث إعادة تحميل مفاجئة، وعدم وجود طريقة لاستعادة الذاكرة إلا بإيقاف الخدمة. إذا كانت كتابة الوحدات أمراً جديداً عليك، فهذا هو النمط نفسه المتبع في تشغيل خدماتك الخاصة عبر systemd على VPS.
المحور 3: واجهة API التي سيتصل بها تطبيقك
أصبح نطاق هذا المحور أضيق بكثير. يدعم المشروعان الآن تنسيق محادثات OpenAI، لذلك تعمل معظم مكتبات العملاء مع أيٍّ منهما بعد تغيير عنوان URL الأساسي فقط.
يستمع Ollama على 127.0.0.1:11434. ومساره المتوافق مع OpenAI هو http://localhost:11434/v1/chat/completions، كما يوفّر إلى جانبه واجهة API أصلية على /api/chat. كما توجد وثائق لمسار متوافق مع Anthropic.
curl -X POST http://localhost:11434/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model": "llama31-q4", "messages": [{"role": "user", "content": "Say this is a test"}]}'يستمع llama-server على 127.0.0.1:8080، ويخدم /v1/chat/completions و/v1/completions و/v1/embeddings، إضافةً إلى نقطة النهاية الخاصة به /completion وواجهة ويب مضمّنة. كما يوفّر مسارات تشغيلية لا يوفّرها Ollama: /health لفحص الجاهزية، و/props لإعدادات النموذج المحمّل، و/slots لمعرفة ما تنفّذه كل خانة طلب، و/metrics بتنسيق Prometheus. إذا كنت تخطط لمراقبة هذه الخدمة، فمن المرجح أن يكون هذا الفرق هو العامل الحاسم.
لا يفعّل أيٌّ من الخادمين المصادقة تلقائياً. ويستمع كلاهما افتراضياً على loopback لسبب وجيه. صِل إليهما عبر نفق SSH أو من خلف reverse proxy، ولا تفتح المنفذين 11434 أو 8080 على الإنترنت مطلقاً.
ما الذي يستطيع VPS يعمل بالـCPU فقط إنجازه فعلياً
يشغّل VPS يعمل بالـCPU فقط نماذج صغيرة ببطء. هذا هو الملخص الصريح، والمهم هو معرفة الحد الفاصل. قِس الأداء قبل أن تبني أي تصميم حوله:
llama-bench -m ~/models/Meta-Llama-3.1-8B-Instruct-Q4_K_M.gguf -p 512 -n 128يمثل العمود pp سرعة معالجة المطالبة، ويمثل العمود tg سرعة توليد الرموز، وكلتاهما مقاسة بالرموز في الثانية. في خطة vCPU مشتركة، يحقق نموذج 8B باستخدام Q4_K_M عادةً أرقاماً أحادية منخفضة في tg. معالجة المطالبة هي الجزء الأبطأ: تُعالَج المطالبة كاملة قبل ظهور أول رمز في الناتج، لذلك تضيف مطالبة نظام طويلة وقت انتظار إلى كل طلب.
يمكن استخدام CPU لتشغيل نموذج من 1B إلى 4B للتصنيف، أو الاستخراج، أو التلخيص القصير، أو التوجيه. تصل الردود خلال ثوانٍ، وتناسب الذاكرة خطة عادية. لا يصلح CPU للدردشة التفاعلية بسرعة القراءة، أو مساعدي البرمجة، أو معالجة المستندات الطويلة، أو أي مهمة تتضمن حلقة وكيل تنفذ طلبات كثيرة بالتتابع. إذا نفذت الحلقة 12 طلباً، واستغرق كل طلب 4 ثوانٍ، فستنتظر دقيقة قبل ظهور أي ناتج. إذا كان مساعد البرمجة هو الخطة أساساً، فإن توجيه وكيل إلى نموذج تستضيفه بنفسك يوضح المهام التي يتفوق فيها نموذج محلي صغير فعلاً، والمهام التي يجب أن تبقى على API مستضاف.
هناك خياران عندما لا تكون الأرقام كافية. إذا كانت المشكلة هي التزامن، أي وصول مستخدمين كثيرين إلى نموذج واحد في الوقت نفسه، فإن اختيار المحرك يتغير، وتغطي مقارنة Ollama مع vLLM لخدمة الطلبات المتزامنة هذا الجانب. وإذا كانت المشكلة هي السرعة الخام، فالحل هو VPS مزود بوحدة GPU، حيث يبدأ -ngl باكتساب معنى فعلي. قبل أي من الخيارين، احصل على خط أساس للعتاد نفسه، لأن عرض نطاق القرص والذاكرة يؤثر في وقت التحميل بقدر تأثير CPU. تستحق مقارنة VPS قابلة للتكرار ساعة من وقتك.
ثبّت llama.cpp مع تثبيت إصدار البناء
يتغير كلا المشروعين أسبوعياً، لذلك سجّل الإصدار الذي نشرته. يثبّت أمر one-liner من المشروع المصدر إصدار البناء الحالي:
curl -LsSf https://llama.app/install.sh | sh
llama serve -hf ggml-org/Qwen3.5-0.8B-GGUFلتثبيت إصدار بناء محدد، نزّل ملف tarball المُسبق البناء من صفحة الإصدارات بدلاً من ذلك. الإصدار b10224 هو الوسم الحالي في 2 August 2026:
curl -LO https://github.com/ggml-org/llama.cpp/releases/download/b10224/llama-b10224-bin-ubuntu-x64.tar.gz
tar xf llama-b10224-bin-ubuntu-x64.tar.gz
find . -type f -name 'llama-server'أو ابنِ الوسم نفسه من المصدر:
sudo apt update && sudo apt install -y build-essential cmake git libssl-dev
git clone https://github.com/ggml-org/llama.cpp
cd llama.cpp
git checkout b10224
cmake -B build
cmake --build build --config Release -j $(nproc)يُعدّ libssl-dev الاعتمادية الموثقة لميزات HTTPS. تستغرق عملية الترجمة عدة دقائق، وتتطلب ذاكرة RAM أكبر مما توفره أصغر الخطط، لذلك نفّذ عملية البناء على جهاز أكبر وانسخ الملفات الثنائية إذا نفدت الموارد على الجهاز الصغير.
تثبيت Ollama مع تثبيت الإصدار
curl -fsSL https://ollama.com/install.sh | OLLAMA_VERSION=0.32.5 sh
ollama -vيقرأ البرنامج النصي OLLAMA_VERSION، لذا يمكنك تثبيت إصدار معروف الاستقرار بدلاً من استخدام الإصدار الذي صدر هذا الصباح. نُشر الإصدار v0.32.5 في 27 July 2026. يتوفر أيضاً مسار يدوي إذا كنت تفضّل عدم تمرير برنامج نصي إلى shell:
sudo rm -rf /usr/lib/ollama
curl -fsSL https://ollama.com/download/ollama-linux-amd64.tar.zst | sudo tar x -C /usr
ollama -vلا ينشئ المسار اليدوي وحدة systemd أو حساب الخدمة، لذلك عليك إضافتهما بنفسك. يشرح الدليل الكامل لتشغيل Ollama على VPS إعداد الخدمة خطوة بخطوة.
حالات الفشل والنصوص التي ستراها
يرفض Ollama تحميل النموذج. يعرض ollama run سطراً بهذا الشكل:
Error: model requires more system memory (5.6 GiB) than is available (3.2 GiB)يتحقق Ollama من الحجم قبل التحميل، لذلك يفشل سريعاً ويذكر السبب. انتقل إلى صف تكميم أدنى، أو خفّض طول السياق، أو اختر نموذجاً أصغر.
لا يفشل llama.cpp، بل يصبح بطيئاً جداً. يستخدم llama.cpp تعيين الذاكرة للملف GGUF افتراضياً، لذلك يبدأ حتى إذا كان الملف أكبر من RAM. ثم يقرأ kernel الأوزان من القرص وإليه مع كل token، فتنخفض سرعة التوليد إلى ثوانٍ لكل token بينما يصل استخدام القرص إلى 100 بالمئة. مرّر --no-mmap لفرض تخصيص فعلي، بحيث يفشل فوراً بدلاً من التدهور. عندما يتدخل kernel، يعرض dmesg السبب:
Out of memory: Killed process 1234 (llama-server)لن يُحمَّل ملف النموذج إطلاقاً. ينتج GGUF المبني لعائلة نماذج أحدث من محركك خطأً يذكر البنية التي لا يعرفها:
error loading model architecture: unknown model architecture: 'qwen3next'الحل هو ترقية المحرك، وليس استخدام ملف مختلف. هذه إحدى تبعات تثبيت الإصدار، ولهذا يجب تدوين رقم البناء. تحتاج إلى معرفة الإصدار الذي ستُرقي منه.
تستجيب واجهة API محلياً، لكن تطبيقك لا يستطيع الوصول إليها. يربط Ollama الواجهة بالعنوان 127.0.0.1:11434، لذلك يحصل المضيف الآخر على رفض للاتصال. اضبط OLLAMA_HOST=0.0.0.0:11434 عبر systemctl edit ollama فقط عندما يكون المنفذ خلف جدار ناري أو شبكة خاصة، لأن واجهة API لا تضع مصادقة أمامها.
يكون الرد الأول بعد توقف بطيئاً جداً. حدث تفريغ النموذج بعد خمول دام 5 دقائق، ويُقرأ النموذج من القرص مرة أخرى. يعرض ollama ps، عند تشغيله قبل الطلب مباشرة، عدم تحميل أي نموذج، وهذا يؤكد السبب. ارفع OLLAMA_KEEP_ALIVE.
إذن، أيّهما ينبغي أن تستخدم؟
استخدم Ollama عندما تريد أن يتولى البرنامج إدارة النماذج، وأن تحصل على نقطة نهاية متوافقة مع OpenAI دون إعداد إضافي. هذا هو الخيار الافتراضي المناسب لأول عملية نشر، وكذلك لأي استخدام ستتغير فيه اختيارات النموذج باستمرار.
استخدم llama.cpp مباشرةً عندما تكون الذاكرة محدودة بما يكفي لتحتاج إلى اختيار صف quantisation بنفسك، أو عندما تريد /health و/slots و/metrics للمراقبة، أو عندما تحتاج إلى flag لا يتيحه Ollama. هذا هو الخيار العملي على VPS لا يتسع للنموذج إلا بالكاد، لأن الإعدادات التي تتيح تشغيله هي نفسها التي يختارها Ollama نيابةً عنك.
من الطبيعي تشغيل البرنامجين معاً. استخدم Ollama للتجارب، وllama.cpp للنموذج الذي تضعه في production ولا تريد تغييره لاحقاً.
FAQ
هل Ollama مجرد غلاف حول llama.cpp؟
إلى حد كبير، لكن الغلاف ينفّذ مهام فعلية. يذكر ملف README الخاص بـOllama أن llama.cpp هو الواجهة الخلفية للاستدلال فيها (وفق التحقق في 2 August 2026). يضيف Ollama فوقه سجلّاً للنماذج، وقالباً للمطالبة يحوّل رسائل المحادثة إلى مطالبة، ومجموعة من المعلمات الافتراضية لأخذ العينات، وخدمة daemon تفرغ النماذج عند الخمول، وواجهة HTTP API. عند مقارنة عدد الرموز في الثانية باستخدام الإعدادات نفسها، فأنت تقارن المحرك نفسه بنفسه. الخيار الفعلي بينهما هو طبقة الإدارة.
أيهما أسرع على VPS يعمل بالمعالج فقط؟
يشتركان في المحرك، لذلك تكون النتائج متقاربة عند استخدام ملف النموذج نفسه، ونوع quantisation نفسه، وحجم السياق نفسه، وعدد الخيوط نفسه. عادةً تنتج الفروقات التي يذكرها المستخدمون عن اختلاف الإعدادات الافتراضية، ولا سيما طول السياق وعدد الخيوط، وليس عن اختلاف المحرك. قِس الأداء باستخدام llama-bench -m <file> -p 512 -n 128 وقارن عمود tg على خادمك قبل تصديق أي أرقام منشورة.
هل يمكنني استخدام ملف GGUF الخاص بي مع Ollama؟
نعم. ضع الملف على الخادم، واكتب ملف Modelfile يكون سطره الأول FROM ./your-model.gguf، ثم أضف أي أسطر PARAMETER تحتاج إليها، مثل num_ctx، وبعد ذلك شغّل ollama create your-name -f ./Modelfile. سيعرض ollama ls الملف بجانب أي ملفات جلبتها من السجل. هذه هي طريقة استخدام quantisation غير متوفرة في السجل.
ما مقدار RAM الذي أحتاج إليه لنموذج 8B؟
احسب حجم الملف، ثم أضف إليه حجم KV cache ومتطلبات وقت التشغيل. يبلغ حجم إصدار Q4_K_M من Llama 3.1 8B على القرص نحو 4.58 GiB، ويضيف سياق من 4096 token نحو 512 MiB من الذاكرة المؤقتة. لذلك تكون RAM بسعة 8 GiB مناسبة، بينما لا تكفي سعة 4 GiB. تتناسب الذاكرة المؤقتة مع حجم السياق؛ فالنموذج نفسه عند استخدام سياق من 32,768 token يحتاج وحده إلى نحو 4 GiB من الذاكرة المؤقتة. مع Ollama، تذكّر أن المتطلب يتناسب أيضاً مع OLLAMA_NUM_PARALLEL.