0Pricing
AI Agents · درس

نشر الوكلاء خفيفي الوزن على الحافة

تشغيل نماذج صغيرة على Raspberry Pi وأجهزة الحافة للاستجابة منخفضة الكمون.

نشر الوكلاء خفيفي الوزن على الحافة درس مجاني في AI Agents على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في AI Agents، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة AI Agents 4 دروس في المجموع.

وكلاء الذكاء الاصطناعي الطرفي

يعمل الوكيل الطرفي مباشرةً على جهاز إنترنت الأشياء أو البوابة المحلية — مثل Raspberry Pi أو Jetson Nano أو حاسوب صناعي — بدلًا من العمل في السحابة. وتشمل الفوائد انخفاض زمن الاستجابة (لعدم الحاجة إلى رحلة ذهاب وإياب)، والعمل دون اتصال، وانخفاض تكلفة النطاق الترددي. أما المقابل فهو أن محدودية قدرة الحوسبة وذاكرة RAM تتطلب نماذج أصغر وأكثر كفاءة.

اختيار نموذج للنشر الطرفي

لا تستطيع الأجهزة الطرفية تشغيل GPT-4o أو Claude Opus. ومن النماذج الصغيرة التي تناسب Raspberry Pi 5 (بذاكرة RAM سعتها 8 GB): Phi-3-mini (3.8B من المعلمات)، وGemma-2B، وTinyLlama-1.1B. وعند تكميم هذه النماذج إلى 4 بت، فإنها تحتاج إلى 1–3 GB من ذاكرة RAM وتعمل بسرعة تتراوح بين 5 و15 رمزًا في الثانية على وحدة المعالجة المركزية.

# Model size reference for edge selection:
EDGE_MODELS = {
    'tinyllama-1.1b-q4': {
        'params': '1.1B', 'quantization': 'Q4_K_M',
        'ram_gb': 0.8, 'tokens_per_sec_cpu': 15,
        'use_case': 'simple classification, keyword detection'
    },
    'phi-3-mini-q4': {
        'params': '3.8B', 'quantization': 'Q4_K_M',
        'ram_gb': 2.5, 'tokens_per_sec_cpu': 8,
        'use_case': 'reasoning, multi-step decisions'
    },
    'gemma-2b-q4': {
        'params': '2B', 'quantization': 'Q4_K_M',
        'ram_gb': 1.5, 'tokens_per_sec_cpu': 10,
        'use_case': 'general assistant tasks'
    }
}

for name, info in EDGE_MODELS.items():
    print(f'{name}: {info["ram_gb"]}GB RAM, '
          f'{info["tokens_per_sec_cpu"]} tok/s — {info["use_case"]}')

تثبيت Ollama على Raspberry Pi

يُعد Ollama أسهل طريقة لتشغيل نماذج LLM الصغيرة على الأجهزة المحلية. فهو يدير تنزيل النماذج وتكميمها وواجهة REST API محلية متوافقة مع OpenAI SDK. ويكفي أمر واحد لتثبيته، وأمر آخر لسحب النموذج وتشغيله.

# Install Ollama (run on the Raspberry Pi terminal):
# curl -fsSL https://ollama.ai/install.sh | sh

# Pull and run a model:
# ollama pull phi3:mini
# ollama serve  (starts API on localhost:11434)

# Python client — uses the OpenAI-compatible endpoint:
from openai import OpenAI

local_client = OpenAI(
    base_url='http://localhost:11434/v1',
    api_key='ollama'  # Ollama ignores this but it is required by the SDK
)

def local_inference(prompt: str, model: str = 'phi3:mini') -> str:
    response = local_client.chat.completions.create(
        model=model,
        messages=[{'role': 'user', 'content': prompt}],
        max_tokens=256,
        temperature=0.1
    )
    return response.choices[0].message.content

result = local_inference('Is temperature 45C dangerous for a server room?')
print(result)

تكميم GGUF إلى 4 بت

GGUF (تنسيق GPT الموحّد المُولَّد) هو تنسيق الملفات الذي تستخدمه llama.cpp وOllama للنماذج المكمّمة. ويعني Q4_K_M التكميم المختلط إلى 4 بت؛ إذ يقل الحجم بنحو 75% مقارنةً بـ fp32، مع فقدان طفيف جدًا في الجودة لمهام الاستدلال الطرفي.

# Understanding quantisation quality levels:
QUANTISATION_GUIDE = {
    'Q2_K': {'size_multiplier': 0.25, 'quality': 'poor', 'ram': 'minimal'},
    'Q4_K_M': {'size_multiplier': 0.45, 'quality': 'good', 'ram': 'low'},
    'Q5_K_M': {'size_multiplier': 0.55, 'quality': 'better', 'ram': 'medium'},
    'Q8_0': {'size_multiplier': 0.75, 'quality': 'near-original', 'ram': 'high'},
    'F16': {'size_multiplier': 1.0, 'quality': 'original', 'ram': 'full'}
}

# For edge: Q4_K_M is the sweet spot
# 7B model: 7B * 4bit/8 = 3.5 GB in Q4 vs 14 GB in F16

def estimate_vram_gb(param_billions: float, quant: str) -> float:
    multiplier = QUANT_GUIDE = {
        'Q4_K_M': 0.45, 'Q8_0': 0.75, 'F16': 1.0
    }
    return round(param_billions * multiplier.get(quant, 0.5), 2)

print(f'Phi-3-mini Q4_K_M: {estimate_vram_gb(3.8, "Q4_K_M")} GB')
print(f'Phi-3-mini F16: {estimate_vram_gb(3.8, "F16")} GB')

تحسين سرعة الاستدلال على وحدة المعالجة المركزية

في الأجهزة الطرفية التي تعتمد على وحدة المعالجة المركزية فقط، تعتمد سرعة الاستدلال على عدد الخيوط والتخزين المؤقت للموجّه. اضبط عدد الخيوط ليتوافق مع أنوية وحدة المعالجة المركزية، واجعل موجّه النظام قصيرًا (إذ يُعاد تجهيزه عند كل استدعاء إذا لم يكن مخزنًا مؤقتًا)، واجمع الاستعلامات المتكررة في دفعات كلما أمكن.

import os
import time

# Ollama environment variables for performance tuning
# Set before starting the Ollama service:
# OLLAMA_NUM_PARALLEL=1  (single request at a time on small devices)
# OLLAMA_MAX_LOADED_MODELS=1  (only keep one model in RAM)

def timed_inference(prompt: str, client, model: str = 'phi3:mini') -> dict:
    start = time.time()
    response = client.chat.completions.create(
        model=model,
        messages=[{'role': 'user', 'content': prompt}],
        max_tokens=128
    )
    elapsed = time.time() - start
    text = response.choices[0].message.content
    tokens = len(text.split())  # approximate
    return {
        'text': text,
        'elapsed_s': round(elapsed, 2),
        'approx_tps': round(tokens / elapsed, 1)
    }

result = timed_inference('Classify: temperature=45C, normal range 18-30C. Action?',
                         local_client)
print(result)

بنية هجينة للحوسبة الطرفية والسحابية

تستخدم البنية المثلى نموذج الحوسبة الطرفية لاتخاذ القرارات السريعة منخفضة المخاطر (مثل التصنيف ومنطق العتبات)، وتزامن البيانات مع النموذج السحابي لاتخاذ القرارات المعقدة أو النادرة أو عالية المخاطر. يضع الوكيل الطرفي الاستعلامات المعقدة في قائمة انتظار ويرسلها عندما يتوفر الاتصال.

import anthropic
import time

class HybridAgent:
    def __init__(self, edge_client, cloud_api_key: str):
        self.edge = edge_client  # Ollama local client
        self.cloud = anthropic.Anthropic(api_key=cloud_api_key)
        self.pending_cloud_queries = []

    def decide(self, context: dict) -> str:
        # Fast path: edge model for simple binary decisions
        simple_prompt = (
            f'Sensor: {context}. '
            'Respond with exactly one word: NORMAL or ALERT.'
        )
        edge_result = self.edge.chat.completions.create(
            model='phi3:mini',
            messages=[{'role': 'user', 'content': simple_prompt}],
            max_tokens=5
        ).choices[0].message.content.strip()

        if edge_result == 'ALERT':
            # Queue complex analysis for cloud
            self.pending_cloud_queries.append(context)

        return edge_result

    def sync_to_cloud(self):
        """Call when online connectivity is available."""
        for ctx in self.pending_cloud_queries:
            result = self.cloud.messages.create(
                model='claude-opus-4-5', max_tokens=512,
                messages=[{'role': 'user', 'content':
                    f'Full analysis of: {ctx}'}]
            )
            print('Cloud analysis:', result.content[0].text[:100])
        self.pending_cloud_queries.clear()

قائمة انتظار غير متصلة لمزامنة السحابة

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

import sqlite3
import json
from datetime import datetime

DB_PATH = '/home/pi/agent_buffer.db'

def init_buffer_db():
    conn = sqlite3.connect(DB_PATH)
    conn.execute("""
        CREATE TABLE IF NOT EXISTS sync_queue (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            type TEXT NOT NULL,
            payload TEXT NOT NULL,
            created_at TEXT NOT NULL,
            synced INTEGER DEFAULT 0
        )
    """)
    conn.commit()
    conn.close()

def buffer_for_sync(record_type: str, payload: dict):
    conn = sqlite3.connect(DB_PATH)
    conn.execute(
        'INSERT INTO sync_queue (type, payload, created_at) VALUES (?, ?, ?)',
        (record_type, json.dumps(payload), datetime.utcnow().isoformat())
    )
    conn.commit()
    conn.close()

def flush_to_cloud(cloud_fn):
    conn = sqlite3.connect(DB_PATH)
    rows = conn.execute(
        'SELECT id, type, payload FROM sync_queue WHERE synced=0 LIMIT 100'
    ).fetchall()
    for row_id, r_type, payload in rows:
        cloud_fn(r_type, json.loads(payload))
        conn.execute('UPDATE sync_queue SET synced=1 WHERE id=?', (row_id,))
    conn.commit()
    conn.close()
    print(f'Synced {len(rows)} records to cloud')

if __name__ == '__main__':
    import os, tempfile
    DB_PATH = os.path.join(tempfile.gettempdir(), 'agent_buffer_demo.db')
    init_buffer_db()
    buffer_for_sync('sensor_reading', {'temp': 22.5})
    flush_to_cloud(lambda t, p: print(f'Synced to cloud: {t} -> {p}'))

مراقبة صحة الوكيل الطرفي

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

import subprocess
import psutil  # pip install psutil

def get_edge_health() -> dict:
    cpu_percent = psutil.cpu_percent(interval=1)
    ram = psutil.virtual_memory()
    disk = psutil.disk_usage('/')

    # Read CPU temperature (Raspberry Pi specific)
    try:
        temp_output = subprocess.check_output(
            ['vcgencmd', 'measure_temp'], text=True
        )
        cpu_temp = float(temp_output.strip().replace("temp=", "").replace("'C", ""))
    except Exception:
        cpu_temp = -1.0  # not available on non-Pi hardware

    return {
        'cpu_percent': cpu_percent,
        'cpu_temp_c': cpu_temp,
        'ram_used_pct': ram.percent,
        'ram_available_mb': round(ram.available / 1024 / 1024),
        'disk_used_pct': disk.percent,
        'timestamp': datetime.utcnow().isoformat()
    }

health = get_edge_health()
print('Edge health:', health)

تخزين نتائج الاستدلال مؤقتًا للوكلاء الطرفية

تكون النماذج الطرفية بطيئة؛ لذا خزّن الاستجابات مؤقتًا للمدخلات المتطابقة. في مهام تصنيف المستشعرات، غالبًا ما يتكرر الطلب نفسه (مثل "temperature=23.5, classify"). تتجنب ذاكرة تخزين مؤقتة بسيطة من نوع dict، مع مدة صلاحية TTL، استدعاءات الاستدلال المتكررة بلا داعٍ.

from datetime import datetime, timedelta
import hashlib

class InferenceCache:
    def __init__(self, ttl_seconds: int = 60):
        self.ttl = timedelta(seconds=ttl_seconds)
        self._cache: dict = {}  # hash -> {'result', 'expires'}

    def _key(self, prompt: str) -> str:
        return hashlib.md5(prompt.encode()).hexdigest()

    def get(self, prompt: str):
        key = self._key(prompt)
        entry = self._cache.get(key)
        if entry and datetime.utcnow() < entry['expires']:
            return entry['result']
        return None

    def set(self, prompt: str, result: str):
        key = self._key(prompt)
        self._cache[key] = {
            'result': result,
            'expires': datetime.utcnow() + self.ttl
        }

cache = InferenceCache(ttl_seconds=60)

def cached_edge_inference(prompt: str, client) -> str:
    cached = cache.get(prompt)
    if cached:
        print('Cache hit')
        return cached
    result = local_inference(prompt, client)
    cache.set(prompt, result)
    return result

قائمة التحقق من النشر

قبل نشر وكيل طرفي في بيئة الإنتاج، تحقّق من أن النموذج يتسع في الذاكرة العشوائية المتاحة مع هامش احتياطي قدره 20%، وأن وقت استجابة الاستدلال يفي بمتطلبات الاستجابة للأحداث، وأنه تم اختبار المخزن المؤقت للعمل دون اتصال، وأن مراقبة الصحة تنشر البيانات، وأن إعادة التشغيل التلقائي عند حدوث عطل مهيأة.

# systemd service file for auto-restart (save as /etc/systemd/system/edge-agent.service)

SYSTEMD_SERVICE = '''
[Unit]
Description=IoT Edge Agent
After=network.target ollama.service
Requires=ollama.service

[Service]
User=pi
WorkingDirectory=/home/pi/edge-agent
ExecStart=/usr/bin/python3 /home/pi/edge-agent/agent.py
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
'''

# Enable:
# sudo systemctl enable edge-agent
# sudo systemctl start edge-agent
# sudo journalctl -u edge-agent -f  (follow logs)

print('Deployment checklist:')
checklist = [
    'Model RAM fits with 20% headroom',
    'Inference latency < response time requirement',
    'Offline SQLite buffer tested',
    'Health metrics publishing to cloud',
    'systemd auto-restart configured'
]
for item in checklist:
    print(f'  [ ] {item}')

إعداد أجهزة Raspberry Pi

قبل نشر البرنامج، جهّز الأجهزة. يُعد Raspberry Pi 5 بذاكرة عشوائية سعتها 8 GB الحد الأدنى الموصى به لتشغيل Phi-3-mini. فعّل تقسيم ذاكرة GPU، وعطّل swap (فهو يقلل من عمر وحدة التخزين الفلاشية)، واضبط عنوان IP ثابتًا لضمان الوصول عن بُعد بصورة موثوقة.

# Raspberry Pi setup notes (run manually over SSH):
# sudo raspi-config -> System -> GPU Memory -> 256
# Disable swap to protect SD card:
# sudo dphys-swapfile swapoff && sudo dphys-swapfile uninstall

def check_available_ram_mb():
    try:
        with open('/proc/meminfo') as f:
            for line in f:
                if line.startswith('MemAvailable'):
                    return int(line.split()[1]) // 1024
    except FileNotFoundError:
        return None

ram_mb = check_available_ram_mb()
if ram_mb is None:
    print('Could not read /proc/meminfo on this OS — simulated Pi reading: MemAvailable ~ 850 MB')
else:
    print(f'Available RAM: {ram_mb} MB')

اختبار المعرفة

ماذا يعني التكميم Q4_K_M لنموذج لغوي؟

مراجعة: نشر الوكلاء خفيفة الوزن على الحافة

ما تناولته في هذا الدرس:

  • اختيار النموذج: Phi-3-mini وGemma-2B وTinyLlama للحوسبة الطرفية؛ والتكميم Q4_K_M
  • Ollama: خادم LLM محلي مزود بواجهة API متوافقة مع OpenAI على المنفذ 11434
  • البنية الهجينة: نموذج طرفي للقرارات السريعة، وسحابة للتحليل المعقد
  • المخزن المؤقت للعمل دون اتصال: قائمة انتظار SQLite تُرسل محتوياتها إلى السحابة عند إعادة الاتصال
  • ذاكرة تخزين نتائج الاستدلال مؤقتًا: تتجنب ذاكرة TTL التخزين المؤقت الاستدلال المتكرر للطلبات المتطابقة
  • النشر: خدمة systemd لإعادة التشغيل التلقائي عند حدوث عطل

الدورة التالية: سوق الوكلاء وأنظمة الإضافات.

الأسئلة الشائعة

هل درس «نشر الوكلاء خفيفي الوزن على الحافة» مجاني؟

نعم — نص درس «نشر الوكلاء خفيفي الوزن على الحافة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة AI Agents، انتقل إلى CoddyKit PRO. تتضمن دورة AI Agents 4 دروس في المجموع.

ماذا ستتعلم في «نشر الوكلاء خفيفي الوزن على الحافة»؟

تشغيل نماذج صغيرة على Raspberry Pi وأجهزة الحافة للاستجابة منخفضة الكمون. تتمرن على AI Agents مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ AI Agents؟

لا تُشترط خبرة سابقة. AI Agents على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «نشر الوكلاء خفيفي الوزن على الحافة»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس AI Agents هذا؟

نعم. كل درس في AI Agents يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. بروتوكول MQTT لتكامل الوكلاء
  2. معالجة بيانات السلاسل الزمنية لدى الوكلاء
  3. الاستجابة الآلية لأحداث المستشعرات
  4. نشر الوكلاء خفيفي الوزن على الحافة
← العودة إلى AI Agents