Ollama: أساسيات REST API
REST API هو الواجهة الشاملة لـ Ollama — أي لغة، أي إطار عمل، فقط أرسل طلب HTTP وستكون متصلًا.
⚠️ ملاحظة: واجهة Ollama REST API لا تحتوي على مصادقة مدمجة — أي شخص يمكنه الوصول إلى منفذ الخدمة يمكنه استدعاء النماذج بحرية وعرض قائمة النماذج المثبتة. في الإنتاج، يجب إضافة مصادقة API Key عبر وكيل عكسي (مثل Nginx/Caddy)، وإلا فإن خدمة الذكاء الاصطناعي الخاصة بك تواجه مخاطر الاستخدام غير المشروع وتسريب البيانات واستنزاف الموارد.
📋 المتطلبات المسبقة: يجب أن تتقن ما يلي أولًا
- الدرس 3: التفاعل الأساسي عبر سطر الأوامر
- الدرس 4: إدارة النماذج
1. ماذا ستتعلم
- مقارنة نقاط النهاية
/api/generateمقابل/api/chat - طرق تحليل الاستجابات المتدفقة (NDJSON)
- ضبط معلمات الاستنتاج (Temperature، Top_P، num_ctx)
- curl عمليًا: إنشاء أحادي الطلقة وحوار متعدد الأدوار
- اختبار النموذج الأولي لواجهة برمجة التطبيقات لـ SupportBot لأليس
2. قصة حقيقية من مؤسس SaaS
(1) المشكلة: الردود اليدوية غير فعالة
أسست أليس منصة التجارة الإلكترونية GlobalShop. فريق خدمة العملاء المكون من 50 شخصًا يتعامل مع أكثر من 2000 تذكرة يوميًا. كل تذكرة تستغرق في المتوسط 8 دقائق، ووقت انتظار العملاء يتجاوز 30 دقيقة. تحتاج لدمج نموذج لغوي كبير في نظام خدمة العملاء عبر API لإنشاء مسودات ردود تلقائية.
(2) الحل: REST API يُولّد الردود فورًا
باستخدام curl لاستدعاء واجهة Ollama API، تُنشأ مسودات ردود خدمة العملاء في 3 ثوانٍ — يحتاج الوكلاء فقط للمراجعة والتأكيد:
BASH
curl http://localhost:11434/api/chat -d '{
"model": "qwen2.5",
"messages": [{"role": "user", "content": "Refund for order #12345"}]
}'
⚠️ تحذير: واجهة Ollama API لا تحتوي على مصادقة مدمجة — أي شخص يمكنه الوصول إلى المنفذ يمكنه استدعاءها. في الإنتاج، يجب إضافة مصادقة API Key عبر وكيل عكسي (Nginx/Caddy). انظر الدرس 20 لتقوية الأمان.
💡 نصيحة: واجهة API المتدفقة (
stream: true) مناسبة لواجهات المحادثة مع تأثير الكتابة الفورية؛ غير المتدفقة (stream: false) أفضل للمعالجة الدفعية وتكامل واجهة برمجة التطبيقات الخلفية. يُوصى بغير المتدفقة لتكامل API لأنها أبسط.
ℹ️ معلومة: الافتراضي في Ollama هو
http://127.0.0.1:11434، يمكن الوصول إليه من الجهاز المحلي فقط. للوصول من الشبكة المحلية، اضبط المتغير البيئي OLLAMA_HOST، لكن انتبه للمخاطر الأمنية.
3. دليل نقاط نهاية API الكامل
(1) مقارنة نقطتي النهاية الأساسيتين
| البُعد | /api/generate |
/api/chat |
|---|---|---|
| الغرض | إنشاء نص أحادي الطلقة | حوار متعدد الأدوار |
| الإدخال | model + prompt |
مصفوفة messages |
| السياق | طلب واحد | يدعم سجل المحادثة |
| توافق API | سطر الأوامر ollama run |
سطر الأوامر ollama chat |
| حالة الاستخدام | إنشاء، إكمال، ترجمة | خدمة عملاء، مساعدون، استنتاج متعدد الأدوار |
sequenceDiagram
participant C as Client
participant O as Ollama Server
C->>O: POST /api/chat {messages, model, stream}
O-->>C: NDJSON {message, done: false}
O-->>C: NDJSON {message, done: false}
O-->>C: NDJSON {message, done: true, stats}
(2) معلمات الطلب الشائعة
| المعلمة | النوع | الافتراضي | الوصف |
|---|---|---|---|
model |
string | مطلوب | اسم النموذج |
stream |
bool | true | هل الإخراج متدفق |
options |
object | — | معلمات الاستنتاج (انظر القسم التالي) |
format |
string | — | تنسيق الإخراج: json |
keep_alive |
string | 5m |
مدة بقاء النموذج في الذاكرة |
▶ مثال 1: طلب إنشاء أحادي الطلقة
BASH
# طلب إنشاء غير متدفق
curl http://localhost:11434/api/generate -d '{
"model": "llama3.2",
"prompt": "Write a haiku about coding",
"stream": false
}'
# الاستجابة (مختصرة)
# {
# "model": "llama3.2",
# "response": "Lines of logic flow,\nBug hides in the deep syntax—\nSemicolon found.",
# "done": true,
# "total_duration": 2500000000,
# "eval_count": 18
# }
الإخراج:
TEXT
{"status":"ok","data":{}}
▶ مثال 2: طلب حوار متعدد الأدوار
BASH
# محادثة بسجل رسائل
curl http://localhost:11434/api/chat -d '{
"model": "qwen2.5",
"messages": [
{"role": "system", "content": "You are a helpful customer service agent."},
{"role": "user", "content": "I want to return my order #12345"},
{"role": "assistant", "content": "I can help with that. May I ask the reason for the return?"},
{"role": "user", "content": "The product arrived damaged"}
],
"stream": false
}'
الإخراج:
TEXT
{"status":"ok","data":{}}
4. تحليل الاستجابات المتدفقة
💡 نصيحة: المتدفقة (
stream: true) وغير المتدفقة (stream: false) لكل منهما حالات استخدام: المتدفقة لواجهات المحادثة مع تأثير الكتابة الفوري حتى يرى المستخدم المحتوى بدون انتظار الاستجابة الكاملة؛ غير المتدفقة للمعالجة الدفعية وتكامل واجهة برمجة التطبيقات الخلفية حيث الحصول على استجابة JSON كاملة أسهل للتحليل البرمجي. نوصى بالبدء بغير المتدفقة للتحقق من المنطق، ثم التبديل للمتدفقة لتحسين تجربة المستخدم.
(1) شرح صيغة NDJSON
تستخدم الاستجابات المتدفقة NDJSON (JSON المحدد بأسطر جديدة)، كائن JSON واحد لكل سطر:
TEXT
{"model":"llama3.2","message":{"role":"assistant","content":"I"},"done":false}
{"model":"llama3.2","message":{"role":"assistant","content":" can"},"done":false}
{"model":"llama3.2","message":{"role":"assistant","content":" help"},"done":false}
{"model":"llama3.2","message":{"role":"assistant","content":""},"done":true,"total_duration":1500000000}
| الحقل | الوصف |
|---|---|
message.content |
شظية النص لهذه القطعة |
done |
هل هذه القطعة الأخيرة |
total_duration |
إجمالي وقت الاستنتاج (نانوثانية) |
eval_count |
عدد الرموز المُنشأة |
prompt_eval_count |
عدد رموز الإدخال |
(2) مقارنة المتدفقة وغير المتدفقة
| البُعد | المتدفقة (stream: true) | غير المتدفقة (stream: false) |
|---|---|---|
| تجربة المستخدم | إخراج حرف بحرف فوري | انتظار الاستجابة الكاملة |
| كمون أول رمز | منخفض جدًا (~200 مللي ثانية) | الانتظار حتى اكتمال الإنشاء |
| تعقيد التنفيذ | يتطلب تحليل NDJSON | قراءة JSON مباشرة |
| حالة الاستخدام | واجهات المحادثة، العرض الفوري | معالجة دفعية، واجهات خلفية |
▶ مثال 3: تحليل الاستجابات المتدفقة
BASH
# طلب متدفق مع إخراج فوري
curl http://localhost:11434/api/chat -d '{
"model": "llama3.2",
"messages": [{"role": "user", "content": "Hello!"}],
"stream": true
}' | while read -r line; do
# استخراج حقل المحتوى من كل سطر NDJSON
echo "$line" | python3 -c "
import sys, json
data = json.load(sys.stdin)
if data.get('message', {}).get('content'):
print(data['message']['content'], end='', flush=True)
"
done
الإخراج:
TEXT
{"status":"ok","data":{}}
5. ضبط معلمات الاستنتاج
(1) جدول المعلمات الأساسية
| المعلمة | النوع | النطاق | الافتراضي | التأثير |
|---|---|---|---|---|
temperature |
float | 0-2 | 0.8 | يتحكم في العشوائية؛ القيم الأخرى أكثر حسمًا |
top_p |
float | 0-1 | 0.9 | أخذ العينات النووية، يحد نطاق الرموز المرشحة |
top_k |
int | 1-100 | 40 | أخذ عينات من أعلى K مرشحين فقط |
num_ctx |
int | 128-131072 | 2048 | حجم نافذة السياق |
repeat_penalty |
float | 1-2 | 1.1 | معامل عقاب التكرار |
seed |
int | أي | -1 | بذرة عشوائية (-1 = عشوائي) |
(2) ضبط المعلمات حسب السيناريو
| السيناريو | temperature | top_p | ملاحظات |
|---|---|---|---|
| توليد الكود | 0.1-0.3 | 0.9 | يتطلب الحسم والدقة |
| ردود خدمة العملاء | 0.3-0.5 | 0.9 | مستقر مع سماح بتنوع معتدل |
| الكتابة الإبداعية | 0.7-1.0 | 0.95 | يتطلب تنوعًا وإبداعًا |
| تحليل البيانات | 0.1-0.2 | 0.9 | يجب أن يكون دقيقًا، لا هلاوس مسموحة |
⚠️ تحذير:
num_ctx يؤثر مباشرة على استخدام الذاكرة. نموذج 8B مع num_ctx=8192 يحتاج حوالي 6 غيغابايت VRAM؛ num_ctx=32768 يحتاج حوالي 12 غيغابايت VRAM. اضبطه حسب الحاجة — لا تزيده بشكل أعمى.
▶ مثال 4: مقارنة ضبط المعلمات
BASH
# temperature منخفض: إخراج حاسم
curl http://localhost:11434/api/generate -d '{
"model": "llama3.2",
"prompt": "What is 2+2?",
"stream": false,
"options": {"temperature": 0.1}
}'
# Response: "2+2 equals 4."
# temperature مرتفع: إخراج إبداعي
curl http://localhost:11434/api/generate -d '{
"model": "llama3.2",
"prompt": "What is 2+2?",
"stream": false,
"options": {"temperature": 1.5}
}'
# Response: "In the realm of mathematics, 2+2 opens the door to 4..."
الإخراج:
TEXT
{"status":"ok","data":{}}
▶ مثال 5: إخراج بصيغة JSON
BASH
# فرض تنسيق إخراج JSON
curl http://localhost:11434/api/chat -d '{
"model": "llama3.2",
"messages": [
{"role": "system", "content": "You are a product catalog API. Return JSON only."},
{"role": "user", "content": "List 3 laptops under $500"}
],
"format": "json",
"stream": false,
"options": {"temperature": 0.3}
}'
# الاستجابة بصيغة JSON صالحة
# {"products":[{"name":"Acer Aspire 5","price":449,"spec":"8GB RAM, 256GB SSD"},...]}
الإخراج:
TEXT
{"status":"ok","data":{}}
6. مثال شامل: النموذج الأولي لواجهة برمجة تطبيقات خدمة العملاء SupportBot
💡 نصيحة: عند استدعاء API في الإنتاج، تأكد من ضبط معلمة
keep_alive (مثلاً، "keep_alive": "5m") لتجنب التحميل/التفريغ المتكرر للنموذج الذي يسبب تأخيرات في الاستجابة.
BASH
#!/bin/bash
# ============================================
# شامل: النموذج الأولي لواجهة برمجة تطبيقات SupportBot
# خدمة عملاء متعددة الأدوار عبر REST API
# ============================================
API="http://localhost:11434/api/chat"
MODEL="qwen2.5"
# دالة: إرسال رسالة محادثة واستخراج الرد
chat() {
local system_prompt="$1"
local user_msg="$2"
local temp="${3:-0.4}"
curl -s "$API" -d "$(cat <<EOF
{
"model": "$MODEL",
"messages": [
{"role": "system", "content": "$system_prompt"},
{"role": "user", "content": "$user_msg"}
],
"stream": false,
"options": {"temperature": $temp, "num_ctx": 4096}
}
EOF
)" | python3 -c "import sys,json; print(json.load(sys.stdin)['message']['content'])"
}
# موجه نظام خدمة العملاء
SYSTEM="You are SupportBot, a customer service agent for an e-commerce store. Be polite, concise, and helpful. If you cannot answer, say 'Let me connect you with a human agent.'"
# محاكاة تفاعلات العملاء
echo "=== Query 1: Order Status ==="
chat "$SYSTEM" "Where is my order #88765? It has been 5 days."
echo ""
echo "=== Query 2: Return Request ==="
chat "$SYSTEM" "I received a damaged item. Order #12345. I want a refund."
echo ""
echo "=== Query 3: Product Question ==="
chat "$SYSTEM" "Does the wireless headphone support Bluetooth 5.3?"
echo ""
echo "=== Benchmark ==="
time chat "$SYSTEM" "Hello" > /dev/null
💻 الإخراج:
TEXT
=== Query 1: Order Status ===
I'd be happy to check on your order #88765. Based on our tracking system, your order is currently in transit and expected to arrive within 2-3 business days. You can track it at track.example.com/88765.
=== Query 2: Return Request ===
I'm sorry to hear about the damaged item. For order #12345, I've initiated a return request. You'll receive a prepaid shipping label via email within 24 hours. Once we receive the item, a full refund will be processed within 3-5 business days.
=== Query 3: Product Question ===
Yes, our wireless headphones support Bluetooth 5.3 with a range of up to 15 meters. They also feature active noise cancellation and 30-hour battery life.
❓ أسئلة شائعة
س لماذا يُرجع طلب curl خطأ connection refused؟
ج خدمة Ollama لا تعمل. شغّل
ollama serve أو تحقق من خدمة systemd: sudo systemctl status ollama.س هل أختار stream: true أم stream: false؟
ج استخدم
stream: true لواجهات المحادثة الأمامية للحصول على تأثير الكتابة الفورية. استخدم stream: false للمعالجة الخلفية الدفعية للحصول على استجابات كاملة مباشرة. يُوصى بغير المتدفقة لتكامل API لأنها أبسط.س كيف أحدّ من طول الإخراج؟
ج اضبط معلمة
num_predict، مثلاً، "num_predict": 200 لتحديد الإنشاء بـ 200 رمز. لاحظ أن هذا عدد رموز وليس أحرف.س هل يضمن format: json إخراج JSON صالح؟
ج يعمل في معظم الحالات، لكن ليس مضمونًا بنسبة 100%. نوصي بإضافة تحقق JSON في طبقة التطبيق، مع إعادة المحاولة أو الرجوع للمعالجة النصية عند فشل التحليل.
س كيف يحافظ الحوار متعدد الأدوار على السياق؟
ج يجب على العميل الحفاظ على مصفوفة
messages بنفسه، وإرسال سجل المحادثة الكامل مع كل طلب. خادم Ollama لا يخزن حالة الجلسة.س هل هناك حدود تزامن على استدعاءات API؟
ج افتراضيًا، يُعالج طلب واحد فقط في كل مرة. اضبط المتغير البيئي
OLLAMA_NUM_PARALLEL لزيادة التزامن، لكن هذا يتطلب VRAM إضافية. انظر الدرس 19 لضبط الأداء.📖 ملخص
/api/generateللإنشاء أحادي الطلقة؛/api/chatيدعم الحوار متعدد الأدوار- الاستجابات المتدفقة تستخدم صيغة NDJSON، إخراج قطعة بقطعة، مثالية لواجهات المحادثة
- temperature يتحكم في العشوائية — قيم منخفضة (0.1-0.3) للكود/التحليل، وقيم مرتفعة للإبداع
format: jsonيفرض إخراجًا منظّمًا، لكن يتطلب تحققًا في طبقة التطبيق- سيناريوهات خدمة العملاء تُوصى بـ temperature=0.3-0.5، موازنة بين الاستقرار والطبيعية
- الحوار متعدد الأدوار يتطلب من العميل الحفاظ على مصفوفة messages؛ الخادم عديم الحالة
📝 تمارين
- أساسي (صعوبة ⭐): استخدم curl لاستدعاء
/api/generateلتوليد وصف منتج، وجرّب كلتاstream: trueوstream: falseلمراقبة الفرق. - متوسط (صعوبة ⭐⭐): استخدم
/api/chatلتنفيذ حوار من 3 أدوار، مع الحفاظ يدويًا على مصفوفة messages، وإخراج الرد الكامل في كل دور. - متقدم (صعوبة ⭐⭐⭐): اكتب سكربت Shell يحاكي سير عمل خدمة عملاء SupportBot — يستقبل أسئلة، يستدعي API، يُرجع نتائج تصنيف (نية + رد) بصيغة JSON، مع دعم الإخراج المتدفق الفوري.