# مدیریت مدل‌های LLM در سیستم Islamic Scholar Agent ## 📋 نمای کلی سیستم مدیریت مدل‌های LLM در پروژه Islamic Scholar Agent به صورت متمرکز و قابل تنظیم طراحی شده است. این سیستم جایگزین رویکرد قدیمی hardcoded مدل‌ها شده و امکان تغییر سریع بین مدل‌های مختلف، افزودن provider جدید و مدیریت تنظیمات را فراهم می‌کند. ## 🎯 چرایی این سیستم ### مشکل رویکرد قدیمی در گذشته، مدل‌های LLM به صورت مستقیم در کد استفاده می‌شدند: ```python # ❌ رویکرد قدیمی - hardcoded from agno.models.openrouter import OpenRouter agent = Agent( model=OpenRouter(id="deepseek/deepseek-r1-0528:free"), ... ) ``` این رویکرد مشکلات زیر را داشت: - **عدم انعطاف‌پذیری**: تغییر مدل نیازمند تغییر کد بود - **پراکندگی تنظیمات**: هر مدل تنظیمات خودش را داشت - **مشکل در تست**: نمی‌توان به راحتی بین مدل‌ها سوییچ کرد - **مدیریت API keys**: کلیدها در کد پراکنده بودند ### راه‌حل جدید ```python # ✅ رویکرد جدید - متمرکز و قابل تنظیم from src.models.factory import ModelFactory model_factory = ModelFactory() agent = Agent( model=model_factory.get_model(), # استفاده از مدل پیش‌فرض # یا model=model_factory.get_model('gpt4'), # تغییر به مدل دیگر ... ) ``` ## 🏗️ معماری سیستم ### ساختار فایل‌ها ``` config/ ├── models.yaml # تنظیمات متمرکز مدل‌ها src/models/ ├── base_model.py # کلاس پایه abstract ├── factory.py # کارخانه مدل‌ها └── ... # implementهای خاص هر provider ``` ### فایل‌های کلیدی #### 1. `config/models.yaml` فایل تنظیمات مرکزی که همه مدل‌ها و providerها را تعریف می‌کند: ```yaml # config/models.yaml models: # سوئیچ اصلی - تغییر این مقدار = تغییر مدل کل سیستم default: deepseek_r1 providers: # Provider 1: MegaLLM (OpenAI-Like) openai_like: api_key: ${MEGALLM_API_KEY} base_url: ${API_URL} models: deepseek_v3: id: "deepseek-ai/deepseek-v3.1" temperature: 0.7 max_tokens: 4096 supports_streaming: true # Provider 2: OpenRouter openrouter: api_key: ${OPENROUTER_API_KEY} base_url: ${OPENROUTER_BASE_URL} models: deepseek_r1: id: "deepseek/deepseek-r1-0528:free" temperature: 0.6 max_tokens: 4096 # Rate limiting rate_limits: requests_per_minute: 60 tokens_per_minute: 100000 ``` #### 2. `src/models/base_model.py` کلاس پایه abstract برای همه providerها: ```python from abc import ABC, abstractmethod from typing import Optional import os class BaseLLMProvider(ABC): """Abstract base class for LLM providers""" def __init__(self, api_key: str, base_url: Optional[str] = None): self.api_key = api_key self.base_url = base_url @abstractmethod def get_model(self): """Return configured model instance""" pass ``` #### 3. `src/models/factory.py` کارخانه اصلی که مدل‌ها را از تنظیمات ایجاد می‌کند: ```python import os import yaml from typing import Optional from agno.models.openrouter import OpenRouter from agno.models.openai.like import OpenAILike class ModelFactory: """Factory for creating LLM instances from configuration""" def __init__(self, config_path: str = "config/models.yaml"): # بارگذاری YAML with open(config_path) as f: self.config = yaml.safe_load(f) def get_model(self, model_name: Optional[str] = None): # 1. تعیین مدل مورد استفاده if model_name is None: model_name = self.config['models']['default'] print(f"Using default model: {model_name}") # 2. جستجو در همه providerها providers = self.config['models']['providers'] for provider_name, provider_data in providers.items(): if model_name in provider_data['models']: # یافت شد! print(f"Found model: {model_name} in provider: {provider_name}") model_config_data = provider_data['models'][model_name] # Resolve environment variables api_key_env = provider_data.get('api_key') if api_key_env and api_key_env.startswith("${"): api_key = os.getenv(api_key_env[2:-1]) else: api_key = api_key_env base_url_env = provider_data.get('base_url') if base_url_env and base_url_env.startswith("${"): base_url = os.getenv(base_url_env[2:-1]) else: base_url = base_url_env # 3. ایجاد کلاس مناسب if provider_name == 'openai_like': return OpenAILike( id=model_config_data['id'], api_key=api_key, base_url=base_url, max_tokens=model_config_data.get('max_tokens', 4096), default_headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, ) elif provider_name == 'openrouter': return OpenRouter( id=model_config_data['id'], api_key=api_key, base_url=base_url, default_headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, ) raise ValueError(f"Model '{model_name}' not found in configuration") ``` ## 🚀 نحوه استفاده ### استفاده پایه ```python # src/main.py from src.models.factory import ModelFactory def create_app(): # ایجاد factory model = ModelFactory() # استفاده از مدل پیش‌فرض agent = IslamicScholarAgent(model.get_model(), knowledge_base) return agent ``` ### تغییر مدل در زمان اجرا ```python # تغییر به مدل دیگر gpt4_agent = IslamicScholarAgent(model_factory.get_model('gpt4'), knowledge_base) # یا تغییر مدل پیش‌فرض در YAML # models.yaml -> default: gpt4 ``` ### افزودن مدل جدید #### مرحله 1: افزودن به YAML ```yaml # config/models.yaml models: providers: openai: api_key: ${OPENAI_API_KEY} base_url: https://api.openai.com/v1 models: gpt4: id: "gpt-4o" temperature: 0.7 max_tokens: 4096 supports_streaming: true ``` #### مرحله 2: افزودن logic به factory ```python # src/models/factory.py elif provider_name == 'openai': return OpenAIChat( id=model_config_data['id'], api_key=provider_config['api_key'], temperature=model_config_data.get('temperature', 0.7), max_tokens=model_config_data.get('max_tokens', 4096), ) ``` ## ✅ مزایای این سیستم ### 1. **سوئیچ سریع بین مدل‌ها** ```python # تغییر از DeepSeek به GPT-4 فقط با یک خط تغییر در YAML # config/models.yaml default: gpt4 # تغییر از deepseek_r1 ``` ### 2. **مدیریت متمرکز تنظیمات** - همه تنظیمات در یک فایل YAML - تغییر تنظیمات بدون تغییر کد - امکان override توسط environment variables ### 3. **امکان A/B Testing** ```python # تست دو مدل مختلف در کنار هم model_a = model_factory.get_model('deepseek_r1') model_b = model_factory.get_model('gpt4') # مقایسه عملکرد دو مدل ``` ### 4. **مدیریت آسان API Keys** ```bash # تنظیم متغیرهای محیطی export MEGALLM_API_KEY="your_key_here" export OPENROUTER_API_KEY="your_key_here" export OPENAI_API_KEY="your_key_here" ``` ### 5. **افزودن Provider جدید بدون تغییر کد موجود** ```yaml # افزودن provider جدید به YAML providers: anthropic: api_key: ${ANTHROPIC_API_KEY} models: claude3: id: "claude-3-sonnet-20240229" temperature: 0.7 ``` ### 6. **امکان توسعه‌پذیری** - هر provider می‌تواند تنظیمات خاص خودش را داشته باشد - امکان افزودن validation خاص هر مدل - پشتیبانی از rate limiting متمرکز ### 7. **تسهیل Testing** ```python # استفاده از مدل‌های mock/test در محیط تست # config/models.test.yaml models: default: test_model providers: test: models: test_model: id: "test-model" temperature: 0.0 ``` ## 🔧 تنظیمات پیشرفته ### Rate Limiting ```yaml # config/models.yaml rate_limits: requests_per_minute: 60 tokens_per_minute: 100000 ``` ### تنظیمات مدل خاص ```yaml models: deepseek_r1: id: "deepseek/deepseek-r1-0528:free" temperature: 0.6 # کنترل خلاقیت max_tokens: 4096 # حداکثر طول پاسخ supports_streaming: true # پشتیبانی از streaming ``` ### Environment Variables ```bash # .env MEGALLM_API_KEY=sk-... OPENROUTER_API_KEY=sk-or-... OPENAI_API_KEY=sk-... ``` ## 🧪 تست سیستم ### تست‌های واحد ```python # tests/test_models.py def test_model_factory_default(): factory = ModelFactory() model = factory.get_model() assert model.id == "deepseek/deepseek-r1-0528:free" def test_model_factory_specific(): factory = ModelFactory() model = factory.get_model('gpt4') assert model.id == "gpt-4o" ``` ### تست‌های integration ```python # tests/test_agent_with_models.py @pytest.mark.parametrize("model_name", ["deepseek_r1", "gpt4"]) def test_agent_with_different_models(model_name): factory = ModelFactory() model = factory.get_model(model_name) agent = IslamicScholarAgent(model, knowledge_base) response = agent.run("What is salah?") assert len(response.content) > 0 ``` ## 🚨 عیب‌یابی ### مشکلات رایج #### 1. Model not found ``` ValueError: Model 'unknown_model' not found in configuration ``` **راه‌حل**: بررسی کنید مدل در `config/models.yaml` تعریف شده باشد. #### 2. API Key not set ``` Error: API key for provider 'openrouter' not found ``` **راه‌حل**: متغیر محیطی مربوطه را تنظیم کنید. #### 3. Invalid YAML syntax ``` yaml.YAMLError: mapping values are not allowed here ``` **راه‌حل**: syntax YAML را بررسی کنید. ### Debug Mode ```python # فعال کردن debug در factory import logging logging.basicConfig(level=logging.DEBUG) factory = ModelFactory() model = factory.get_model() # لاگ‌های مفصل نمایش داده می‌شود ``` ## 📈 مانیتورینگ و Observability سیستم با Langfuse integration می‌تواند عملکرد مدل‌ها را مانیتور کند: - تعداد استفاده از هر مدل - زمان پاسخ مدل‌ها - هزینه‌های API - نرخ خطای هر مدل ## 🔄 مهاجرت از سیستم قدیمی ### قبل از تغییر ```python # کد قدیمی agent = Agent(model=OpenRouter(id="deepseek/deepseek-r1-0528:free")) ``` ### بعد از تغییر ```python # کد جدید from src.models.factory import ModelFactory model_factory = ModelFactory() agent = Agent(model=model_factory.get_model('deepseek_r1')) ``` ### مهاجرت تدریجی 1. ایجاد `ModelFactory` کنار کد قدیمی 2. تغییر gradual agentها به استفاده از factory 3. حذف کد قدیمی پس از تست کامل ## 📚 بهترین تجربیات (Best Practices) ### 1. **استفاده از Environment Variables** همیشه از environment variables برای API keys استفاده کنید: ```yaml api_key: ${OPENROUTER_API_KEY} # ✅ خوب api_key: sk-or-... # ❌ بد ``` ### 2. **نام‌گذاری معنادار مدل‌ها** ```yaml models: deepseek_r1: # ✅ واضح و معنادار model1: # ❌ نام‌گذار بی‌معنا ``` ### 3. **Validation تنظیمات** ```python # اضافه کردن validation در factory def _validate_config(self): """Validate configuration on load""" required_keys = ['models', 'providers'] for key in required_keys: if key not in self.config: raise ValueError(f"Missing required config key: {key}") ``` ### 4. **Caching مدل‌ها** ```python # Cache مدل‌ها برای جلوگیری از recreate مکرر @lru_cache(maxsize=10) def get_model(self, model_name: Optional[str] = None): # ... logic ``` ## 🎯 نتیجه‌گیری این سیستم مدیریت مدل‌های LLM مزایای زیر را فراهم می‌کند: 1. **انعطاف‌پذیری بالا**: تغییر مدل‌ها بدون تغییر کد 2. **مدیریت متمرکز**: همه تنظیمات در یک مکان 3. **تسهیل توسعه**: افزودن مدل جدید ساده 4. **امکان تست**: A/B testing و مقایسه مدل‌ها 5. **امنیت بهتر**: API keys در environment variables 6. **قابل نگهداری**: کد تمیز و سازمان‌یافته این رویکرد نه تنها مشکلات سیستم قدیمی را حل می‌کند، بلکه پایه‌ای محکم برای توسعه آینده سیستم فراهم می‌کند.