AR ▾
احصل على مفتاح API

واجهة Ollama API في Python، وبديل مُستضاف

تستغرق واجهة Ollama API في Python حوالي عشرة أسطر، وتعمل نفس بنية الشيفرة أيضًا مع واجهة API مُستضافة. يوضح هذا المقال الحالتين ويشرح متى تختار كلًا منهما.

تم التحديث

نقاط رئيسية

  • تستمع Ollama على المنفذ 11434 وتوفر واجهة API أصلية بالإضافة إلى نقطة النهاية /v1 على طراز OpenAI.
  • تعمل حزمة ollama، وrequests العادية، وحزمة OpenAI SDK؛ وتُعد حزمة OpenAI SDK الأكثر قابلية للحمل.
  • يتمثل الانتقال إلى واجهة API مُستضافة في تغيير عنوان URL الأساسي، والمفتاح، واسم النموذج.
  • يُعد التشغيل المحلي أفضل للأعمال دون اتصال وبأجهزة ثابتة؛ بينما يكون التشغيل المُستضاف أسهل عند عدم توفر GPU.
كمبيوتر محلي متصل بكابل مضيء بخادم سحابي، يمثل واجهات برمجة تطبيقات النماذج اللغوية الكبيرة المحلية والمستضافة

النسخة المختصرة

إذا بحثت عن ollama api python، فأنت عادةً تريد أحد ثلاثة أشياء: استدعاء نموذج يعمل على جهازك الخاص، أو بث الرموز منه، أو جعل نفس السكربت يعمل في مكان آخر. يوفر لك Ollama الخيارات الثلاثة. يشغل خادمًا محليًا، افتراضيًا على http://localhost:11434، وتتحدث إليه باستخدام حزمة ollama للغة Python، أو عبر HTTP العادي، أو مع أي عميل OpenAI مُوجّه إلى المسار /v1.

الشرط هو أن النموذج يجب أن يعمل على عتادك. سيكون الحاسوب المحمول بدون بطاقة رسوميات مناسبة بطيئًا مع النماذج الأكبر، والخادم بدونها غير مناسب. في هذه الحالة، يعد الـ API المتوافق مع OpenAI المستضاف المسار الأسهل، وبسبب تشابه تنسيق الطلب، فإن التحويل يكلفك ثلاثة أسطر من الإعداد. كلا المسارين مغطى أدناه، مع أكواد يمكنك لصقها.

استدعاء نموذج محلي باستخدام حزمة ollama

قم بتثبيت Ollama، واسحب نموذجًا، وتأكد من تشغيل الخادم. ثم قم بتثبيت عميل Python:

pip install ollama
ollama pull llama3.2

يبدو استدعاء الدردشة الأساسي هكذا. اسم النموذج هو أي شيء قمت بسحبه؛ llama3.2 هو مجرد مثال.

import ollama

response = ollama.chat(
    model="llama3.2",
    messages=[{"role": "user", "content": "Explain DNS in two sentences."}],
)
print(response["message"]["content"])

البث المتدفق

مرّر stream=True وستحصل على مكرر للقطع بدلاً من رد واحد. تحمل كل قطعة جزءًا من الإجابة في message.content.

import ollama

stream = ollama.chat(
    model="llama3.2",
    messages=[{"role": "user", "content": "Write a haiku about servers."}],
    stream=True,
)
for chunk in stream:
    print(chunk["message"]["content"], end="", flush=True)
print()

توجيه العميل إلى جهاز آخر

إذا كان Ollama يعمل على مضيف مختلف، أنشِ عميلًا بعنوان صريح، على سبيل المثال ollama.Client(host="http://192.168.1.20:11434"). بشكل افتراضي، يستمع الخادم فقط على الجهاز المحلي، لذا يحتاج الوصول عن بُعد إلى إعداد متعمد من جانب الخادم. لا تعرضه للإنترنت العام بدون وسيط ومصادقة أمامه، لأن الـ API الأصلي لا يحتوي على فحص للمفتاح الخاص به.

HTTP العادي مع requests

لا تحتاج إلى الحزمة على الإطلاق. نقطة النهاية الأصلية للمحادثة هي POST /api/chat. البث هو الافتراضي هناك، والتدفق يتكون من كائنات JSON مفصولة بأسطر، وليس SSE. اضبط "stream": false إذا كنت تريد كائنًا واحدًا للعودة.

import requests

r = requests.post(
    "http://localhost:11434/api/chat",
    json={
        "model": "llama3.2",
        "messages": [{"role": "user", "content": "Name three HTTP status codes."}],
        "stream": False,
    },
    timeout=120,
)
r.raise_for_status()
print(r.json()["message"]["content"])

اضبط مهلة زمنية سخية. يجب أن يحمل الطلب الأول النموذج إلى الذاكرة، وقد يستغرق ذلك وقتًا أطول بكثير من الطلبات اللاحقة.

قراءة البث المتدفق يدويًا يتطلب بضع أسطر إضافية. استدعِ requests.post(..., stream=True)، مرّر على r.iter_lines()، تخطّ الأسطر الفارغة، ونفّذ json.loads على كل منها. يحمل كل كائن جزءًا صغيرًا من الرد، والجزء الأخير يحتوي على "done": true. هذا مفيد في حاوية بسيطة حيث تفضل عدم تثبيت حزمة أخرى، كما يوضح بوضوح ما تفعله المكتبة لك. يقدّم الـ API المستضاف البث المتدفق بشكل مختلف، كخطوط SSE تبدأ بـ data:، وهو سبب آخر للسماح لـ SDK الخاص بـ OpenAI بتحليل البث المتدفق لك في كود قابل للحمل.

استخدام حزمة OpenAI SDK مع Ollama

يكشف Ollama أيضًا عن نقطة نهاية على طراز OpenAI تحت /v1. هذا يعني أن الحزمة الرسمية openai تعمل، وكذلك معظم البرامج التي تتيح لك ضبط عنوان URL الأساسي مخصص. المفتاح مطلوب من قبل الـ SDK لكنه يُتجاهل بواسطة Ollama المحلي، لذا فإن أي سلسلة ستعمل.

from openai import OpenAI

client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
resp = client.chat.completions.create(
    model="llama3.2",
    messages=[{"role": "user", "content": "Give me a one-line summary of TCP."}],
)
print(resp.choices[0].message.content)

هذا هو الشكل الأكثر فائدة، لأنه يفصل شيفرتك عن الخادم. يمكن لنفس الدالة التحدث إلى نموذج محلي اليوم وإلى شيء آخر غدًا، وهو القسم التالي.

نفس الشيفرة مع واجهة برمجة تطبيقات مستضافة

الخيار المستضاف هنا هو API متوافق مع OpenAI بنموذج واحد، uncensored، يشغله مزود مستقل ومضبط للإجابة بدون رفض المحتوى للاستخدام القانوني للبالغين. هو للنصوص فقط. عنوان URL الأساسي هو https://api.ollamaapi.cc/v1، وتوثّق باستخدام مفتاح Bearer من صفحة مفتاح API.

إليك نسخة تقرأ هدفها من متغيرات البيئة، مع قيم الاستضافة كقيم افتراضية. للعودة إلى خادمك المحلي، قم بتصدير متغيرين ولا تغير أي شيء آخر.

import os
from openai import OpenAI

client = OpenAI(
    base_url=os.getenv("LLM_BASE_URL", "https://api.ollamaapi.cc/v1"),
    api_key=os.getenv("LLM_API_KEY", "YOUR_API_KEY"),
)
MODEL = os.getenv("LLM_MODEL", "uncensored")

resp = client.chat.completions.create(
    model=MODEL,
    messages=[
        {"role": "system", "content": "You are a concise assistant."},
        {"role": "user", "content": "List four uses of a message queue."},
    ],
    temperature=0.7,
)
print(resp.choices[0].message.content)

للتشغيل محلياً، اضبط LLM_BASE_URL=http://localhost:11434/v1، وLLM_API_KEY=ollama، وLLM_MODEL=llama3.2. يحتوي دليل البدء السريع على نفس الإعداد في curl وNode.

البث المتدفق، وضع JSON والأدوات في جانب الواجهة المستضافة

تدعم نقطة النهاية المستضافة البث عبر SSE، ووضع JSON، واستدعاء الأدوات، ومعلمات أخذ العينات المعتادة (temperature، top_p، stop، seed والعقوبات). البث باستخدام SDK هو نفس الحلقة التي ستكتبها لأي خادم على نمط OpenAI:

stream = client.chat.completions.create(
    model="uncensored",
    messages=[{"role": "user", "content": "Tell a two-paragraph story about a lighthouse."}],
    stream=True,
    stream_options={"include_usage": True},
)
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)

للإخراج الهيكلي، اضبط response_format={"type": "json_object"} وقل في الـ ⟦prompt⟧ أنك تريد JSON. قم دائمًا بتحليل النتيجة داخل كتلة try على أي حال؛ يمكن للنموذج أن يعيد شيءًا لم تتوقعه.

يوجد اختلاف واحد عن الاستخدام المحلي يهم الكود: الحدود. يسمح المفتاح الكامل بـ 8 طلبات متزامنة و300 طلب في الدقيقة، ويحتفظ الطلب المتدفق بمكانه حتى ينتهي التدفق. إذا وزعت الطلبات باستخدام الخيوط، حدد حجم مجموعة الخيوط عند 8 وأعد المحاولة عند HTTP 429 باستخدام رأس Retry-After عند وجوده.

إدامة المحادثة

لا يتذكر كل من نقطة النهاية المحلية والمستضافة للدردشة أي شيء بين المكالمات. يرى الخادم فقط الرسائل التي ترسلها، لذا فإن الدردشة هي قائمة تقوم بإضافة عناصر إليها وإعادة إرسالها. النمط متطابق لكلا الهدفين، وهو سبب آخر للحفاظ على عميل على غرار OpenAI كخيارك الافتراضي.

history = [{"role": "system", "content": "You are a helpful assistant."}]

def ask(text):
    history.append({"role": "user", "content": text})
    resp = client.chat.completions.create(model=MODEL, messages=history)
    answer = resp.choices[0].message.content
    history.append({"role": "assistant", "content": answer})
    return answer

print(ask("Pick a name for a hiking app."))
print(ask("Give me a tagline for it."))

ملاحظتان عمليتان. أولاً، للنماذج المحلية طول سياق تضبطه ويجب على الذاكرة استيعابه؛ إذا تجاوزت السجل هذا الحد، يتم قطع الأدوار الأقدم أو يفشل الطلب، حسب الإعدادات. يقبل النموذج المستضاف نافذة سياق بحجم 100,000 رمز بما في ذلك الإكمال، وهو أكثر بكثير مما تحتاجه معظم الدردشات، لكن السجلات الطويلة لا تزال تكلف رموز الإدخال في كل دور. ثانيًا، بمجرد أن يصبح السجل طويلًا، قم بتلخيص الأدوار الأقدم في رسالة قصيرة واحدة بدلاً من إعادة إرسالها جميعًا. هذا يحافظ على استقرار زمن الاستجابة والتكلفة على كلا الخادمين.

إعادة المحاولة بأدب

على الـ API المستضاف، يؤدي الحمل الزائد المؤقت إلى إرجاع HTTP 429 مع رأس Retry-After: 5. يقوم غلاف صغير بالتعامل معه:

import time
from openai import RateLimitError

def chat_with_retry(messages, tries=4):
    for attempt in range(tries):
        try:
            return client.chat.completions.create(model=MODEL, messages=messages)
        except RateLimitError:
            time.sleep(5 * (attempt + 1))
    raise RuntimeError("still rate limited")

لا يفرض Ollama المحلي حدوداً على المعدل، لكنه يدرج الطلبات عندما يكون النموذج مشغولاً، لذا فإن نفس الغلاف لا يضر هناك.

محلي أم مستضاف: كيف تقرر

لا يوجد خيار أفضل بشكل عام. استخدم النقاط أدناه كقائمة مراجعة.

  • اختر Ollama المحلي إذا كنت بحاجة للعمل دون اتصال، إذا كان يجب ألا تغادر البيانات الجهاز أبدًا، إذا كنت تمتلك بالفعل بطاقة رسوميات مناسبة، أو إذا كنت تريد تجربة نماذج مفتوحة مختلفة بسرعة.
  • اختر API مستضاف إذا لم يكن لديك بطاقة رسوميات، إذا كنت تعمل على خادم افتراضي صغير أو في CI، إذا كان عدة أشخاص أو خدمات يشاركون خادماً خلفياً واحداً، أو إذا كنت تريد نافذة سياق طويلة دون ضبط الذاكرة بنفسك. يقبل النموذج المستضاف ما يصل إلى 100,000 رمز من الـ prompt بالإضافة إلى الإكمال.
  • امزج الاثنين أثناء التطوير: طور محلياً، ثم وجه الإنتاج نحو الـ URL المستضاف من خلال متغيرات البيئة.

يُحسب استخدام النسخة المستضافة لكل رمز، بسعر $0.15 لكل مليون رمز إدخال و$0.50 لكل مليون رمز إخراج، من رصيد مسبق الدفع. تذكر صفحة الأسعار مبالغ الشحن، ويمكن للحسابات الجديدة المطالبة برصيد تجريبي مجاني بقيمة $0.50 بنقرة واحدة دون الحاجة لبطاقة. لا تُستخدم الموجّهات في التدريب.

الأخطاء التي ستواجهها

العرضالسبب المحتملالحل
رفض الاتصال على المنفذ 11434خادم Ollama لا يعملشغّل التطبيق أو نفذ ollama serve
النموذج غير موجودلم يتم سحب النموذج أبداً، أو الاسم يحتوي على خطأ مطبعيقم بتشغيل ollama list، ثم ollama pull الاسم الذي تستخدمه
انتهت مهلة أول طلبالنموذج لا يزال قيد التحميلارفع حد المهلة، أو أرسل طلب إيقاظ
خطأ مصادقة على الـ ⟦API⟧API المُستضافمفتاح Bearer مفقود أو غير صحيحتحقق من LLM_API_KEY وعنوان URL الأساسي
HTTP 429 مع رمز concurrencyأكثر من 8 طلبات قيد التنفيذ (2 على مفتاح تجريبي)خفض عدد العاملين
HTTP 429 مع الرمز rate_limitedتجاوز حدّ الطلبات في الدقيقةتراجع وأعد المحاولة

الطلبات الفاشلة أو المرفوضة على جانب الاستضافة لا تُحسب تكلفة، لذا فإن منطق إعادة المحاولة لا يكلفك مقابل المحاولات الفاشلة.

أسئلة وأجوبة

ما هو عنوان Ollama API الافتراضي؟

يستمع خادم Ollama المحلي إلى http://localhost:11434. توجد نقاط النهاية الأصلية تحت /api، مثل /api/chat، بينما نقطة النهاية على طراز OpenAI تقع تحت /v1.

هل يمكنني استخدام OpenAI Python SDK مع Ollama؟

نعم. اضبط base_url على http://localhost:11434/v1 ومرّر أي سلسلة كمفتاح API. يرسل الـ SDK بعد ذلك طلبات إكمال المحادثات القياسية إلى النموذج المحلي لديك.

كيف أتحول من Ollama إلى API مستضاف؟

غيّر عنوان URL الأساسي والمفتاح واسم النموذج. إذا كان الكود الخاص بك يقرأها من متغيرات البيئة، فلا حاجة لتغيير الكود.

هل يعمل API المستضاف بدون GPU من جانبي؟

نعم. يعمل النموذج عند المزود، لذا يحتاج سكريبتك فقط إلى اتصال بالإنترنت ومفتاح Bearer. تدفع مقابل كل رمز من رصيد مسبق الدفع.

مفتاحك على بُعد خطوة واحدة

أنشئ حساباً، وانسخ المفتاح، ثم غيّر URL الأساسي. هذه هي الإعدادات الكاملة.

احصل على مفتاح API