شغّل الذكاء الاصطناعي على جهازك — وخلّه معك في أي مكان
كيف حوّلت جهاز MSI ببطاقة RTX 5090 إلى سيرفر ذكاء اصطناعي خاص، أوصله من أي شبكة عبر Tailscale، وأتحدّث معه من الطرفية بكود بايثون بسيط.
كل مرة تستخدم فيها نموذج ذكاء اصطناعي على الإنترنت، بياناتك تطلع من جهازك وتروح لسيرفر ما تملكه. وفي كل شهر تدفع اشتراك. السؤال البسيط: ليش ما نشغّل النموذج على جهازنا؟
عندي جهاز MSI فيه بطاقة RTX 5090 بذاكرة 32 جيجابايت — وهذي كافية لتشغيل نماذج محترمة محلياً. المشكلة الوحيدة: الجهاز في البيت، وأنا مو دائماً في البيت. الحل كان Tailscale.
الفكرة باختصار
- 1Ollama يشغّل النموذج على جهاز الـ MSI ويفتح واجهة API محلية على المنفذ
11434. - 2Tailscale يبني شبكة خاصة مشفّرة بين أجهزتك، ويعطي كل جهاز عنوان ثابت يبدأ بـ
100.. - 3أي جهاز داخل الشبكة — لابتوب، جوال، جهاز في مقهى — يتصل بالنموذج كأنه في نفس الغرفة.
النتيجة: نموذج يشتغل على كرتك، بدون اشتراك، وبدون ما تفتح أي منفذ للإنترنت.
الخطوة الأولى: ثبّت Ollama وشغّل نموذج
نزّل Ollama من ollama.com وثبّته على جهاز الـ MSI. بعدها من الطرفية:
# Pull and run a model
ollama pull llama3.1
ollama run llama3.1
# Check the service is up
curl http://localhost:11434/api/tagsإذا رجع لك ردّ JSON فيه قائمة النماذج، فكل شيء تمام. تقدر تتأكد إن البطاقة تشتغل فعلاً بـ nvidia-smi وأنت تشغّل النموذج — لازم تشوف استهلاك الذاكرة يرتفع.
الخطوة الثانية: خلّ Ollama يسمع على الشبكة
افتراضياً Ollama يسمع على 127.0.0.1 فقط — يعني ما يستقبل أي اتصال من خارج الجهاز. لازم تغيّر متغيّر البيئة OLLAMA_HOST.
على ويندوز: ابحث عن «Edit the system environment variables» ← Environment Variables ← أضف متغيّر جديد، ثم أعد تشغيل Ollama من شريط المهام حتى يقرأ القيمة الجديدة.
# Best: bind to your Tailscale IP only
OLLAMA_HOST=100.x.x.x:11434
# Broader: listens on every interface - be careful
OLLAMA_HOST=0.0.0.0:11434الخطوة الثالثة: اربط الأجهزة بـ Tailscale
ثبّت Tailscale على الجهازين — سيرفر الـ MSI والجهاز اللي راح تتصل منه — وسجّل الدخول بنفس الحساب. بعدها اطلب عنوان السيرفر:
tailscale up
tailscale ip -4 # prints an address like 100.66.x.xهذا العنوان ثابت ويتبع الجهاز في أي شبكة — بيت، مكتب، بيانات الجوال. جرّب من الجهاز الثاني: curl http://100.x.x.x:11434/api/tags. إذا رجع لك نفس ردّ JSON، خلصت الشبكة.
الخطوة الرابعة: كود بايثون للمحادثة
ثبّت المكتبة الرسمية بـ pip install ollama، وهذا أبسط سكربت يعرض النماذج المتاحة ويفتح محادثة:
from ollama import Client
client = Client(host="http://100.x.x.x:11434")
models = client.list()["models"]
for i, model in enumerate(models, 1):
print(f"{i}. {model['model']}")
choice = int(input("\nSelect a model: "))
model = models[choice - 1]["model"]
print(f"\nChatting with {model}")
print("Type 'exit' to quit.\n")
messages = []
while True:
user_input = input("You: ")
if user_input.lower() == "exit":
break
messages.append({"role": "user", "content": user_input})
response = client.chat(model=model, messages=messages)
reply = response["message"]["content"]
print(f"AI: {reply}\n")
messages.append({"role": "assistant", "content": reply})نسخة أفضل للاستخدام اليومي
السكربت فوق يشتغل تمام، لكن فيه ثلاث مشاكل عملية: ينتظر الرد كامل قبل ما يطبع شيء، وينهار لو انقطع الاتصال أو أدخلت رقماً غلط، ويكبر سجل المحادثة بلا حدود حتى يبطّئ النموذج. هذي نسخة تعالج الثلاثة:
from ollama import Client
HOST = "http://100.x.x.x:11434" # your machine's Tailscale IP
MAX_HISTORY = 20 # keep only the last 20 messages
client = Client(host=HOST)
def pick_model():
models = client.list()["models"]
for i, m in enumerate(models, 1):
print(f"{i}. {m['model']}")
while True:
raw = input("\nSelect a model: ").strip()
if raw.isdigit() and 1 <= int(raw) <= len(models):
return models[int(raw) - 1]["model"]
print("Invalid choice, try again.")
def main():
try:
model = pick_model()
except Exception as e:
print(f"Could not reach the server: {e}")
return
print(f"\nChatting with {model} - type 'exit' to quit.\n")
messages = []
while True:
user_input = input("You: ").strip()
if user_input.lower() in ("exit", "quit"):
break
if not user_input:
continue
messages.append({"role": "user", "content": user_input})
print("AI: ", end="", flush=True)
reply = ""
try:
for chunk in client.chat(model=model, messages=messages, stream=True):
piece = chunk["message"]["content"]
print(piece, end="", flush=True)
reply += piece
except Exception as e:
print(f"\n[error] {e}\n")
messages.pop()
continue
print("\n")
messages.append({"role": "assistant", "content": reply})
messages = messages[-MAX_HISTORY:]
if __name__ == "__main__":
main()الفرق الأوضح هو stream=True — الحروف تنطبع أول بأول بدل ما تنتظر الرد كامل. الإحساس يصير قريب من أي واجهة محادثة تعرفها.
ملاحظات من التجربة
- الذاكرة هي الحد. حجم النموذج لازم يدخل في ذاكرة البطاقة، وإلا ينزل جزء منه على المعالج ويصير بطيء. راقب بـ
ollama ps. - أول رد يكون أبطأ لأن النموذج يُحمّل للذاكرة. الردود اللي بعده أسرع بكثير.
- Tailscale ما يحتاج إعدادات راوتر — لا Port Forwarding ولا IP ثابت من مزوّد الخدمة.
- راجع صلاحيات الشبكة من لوحة تحكم Tailscale (ACLs) لو عندك أجهزة كثيرة أو تشارك الشبكة مع أحد.
الخلاصة
ثلاث قطع فقط: جهاز فيه بطاقة قوية، Ollama يشغّل النموذج، وTailscale يوصلك فيه من أي مكان. بياناتك ما تغادر أجهزتك، وما فيه اشتراك شهري، والنموذج يشتغل حتى بدون إنترنت لو كنت على نفس الشبكة.
الشرح كامل بالفيديو فوق — وإذا واجهتك مشكلة، اكتب لي في التعليقات.
