14 KiB
مدیریت مدلهای LLM در سیستم Islamic Scholar Agent
📋 نمای کلی
سیستم مدیریت مدلهای LLM در پروژه Islamic Scholar Agent به صورت متمرکز و قابل تنظیم طراحی شده است. این سیستم جایگزین رویکرد قدیمی hardcoded مدلها شده و امکان تغییر سریع بین مدلهای مختلف، افزودن provider جدید و مدیریت تنظیمات را فراهم میکند.
🎯 چرایی این سیستم
مشکل رویکرد قدیمی
در گذشته، مدلهای LLM به صورت مستقیم در کد استفاده میشدند:
# ❌ رویکرد قدیمی - hardcoded
from agno.models.openrouter import OpenRouter
agent = Agent(
model=OpenRouter(id="deepseek/deepseek-r1-0528:free"),
...
)
این رویکرد مشکلات زیر را داشت:
- عدم انعطافپذیری: تغییر مدل نیازمند تغییر کد بود
- پراکندگی تنظیمات: هر مدل تنظیمات خودش را داشت
- مشکل در تست: نمیتوان به راحتی بین مدلها سوییچ کرد
- مدیریت API keys: کلیدها در کد پراکنده بودند
راهحل جدید
# ✅ رویکرد جدید - متمرکز و قابل تنظیم
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ها را تعریف میکند:
# 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ها:
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
کارخانه اصلی که مدلها را از تنظیمات ایجاد میکند:
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")
🚀 نحوه استفاده
استفاده پایه
# src/main.py
from src.models.factory import ModelFactory
def create_app():
# ایجاد factory
model = ModelFactory()
# استفاده از مدل پیشفرض
agent = IslamicScholarAgent(model.get_model(), knowledge_base)
return agent
تغییر مدل در زمان اجرا
# تغییر به مدل دیگر
gpt4_agent = IslamicScholarAgent(model_factory.get_model('gpt4'), knowledge_base)
# یا تغییر مدل پیشفرض در YAML
# models.yaml -> default: gpt4
افزودن مدل جدید
مرحله 1: افزودن به 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
# 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. سوئیچ سریع بین مدلها
# تغییر از DeepSeek به GPT-4 فقط با یک خط تغییر در YAML
# config/models.yaml
default: gpt4 # تغییر از deepseek_r1
2. مدیریت متمرکز تنظیمات
- همه تنظیمات در یک فایل YAML
- تغییر تنظیمات بدون تغییر کد
- امکان override توسط environment variables
3. امکان A/B Testing
# تست دو مدل مختلف در کنار هم
model_a = model_factory.get_model('deepseek_r1')
model_b = model_factory.get_model('gpt4')
# مقایسه عملکرد دو مدل
4. مدیریت آسان API Keys
# تنظیم متغیرهای محیطی
export MEGALLM_API_KEY="your_key_here"
export OPENROUTER_API_KEY="your_key_here"
export OPENAI_API_KEY="your_key_here"
5. افزودن Provider جدید بدون تغییر کد موجود
# افزودن 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
# استفاده از مدلهای mock/test در محیط تست
# config/models.test.yaml
models:
default: test_model
providers:
test:
models:
test_model:
id: "test-model"
temperature: 0.0
🔧 تنظیمات پیشرفته
Rate Limiting
# config/models.yaml
rate_limits:
requests_per_minute: 60
tokens_per_minute: 100000
تنظیمات مدل خاص
models:
deepseek_r1:
id: "deepseek/deepseek-r1-0528:free"
temperature: 0.6 # کنترل خلاقیت
max_tokens: 4096 # حداکثر طول پاسخ
supports_streaming: true # پشتیبانی از streaming
Environment Variables
# .env
MEGALLM_API_KEY=sk-...
OPENROUTER_API_KEY=sk-or-...
OPENAI_API_KEY=sk-...
🧪 تست سیستم
تستهای واحد
# 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
# 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
# فعال کردن debug در factory
import logging
logging.basicConfig(level=logging.DEBUG)
factory = ModelFactory()
model = factory.get_model() # لاگهای مفصل نمایش داده میشود
📈 مانیتورینگ و Observability
سیستم با Langfuse integration میتواند عملکرد مدلها را مانیتور کند:
- تعداد استفاده از هر مدل
- زمان پاسخ مدلها
- هزینههای API
- نرخ خطای هر مدل
🔄 مهاجرت از سیستم قدیمی
قبل از تغییر
# کد قدیمی
agent = Agent(model=OpenRouter(id="deepseek/deepseek-r1-0528:free"))
بعد از تغییر
# کد جدید
from src.models.factory import ModelFactory
model_factory = ModelFactory()
agent = Agent(model=model_factory.get_model('deepseek_r1'))
مهاجرت تدریجی
- ایجاد
ModelFactoryکنار کد قدیمی - تغییر gradual agentها به استفاده از factory
- حذف کد قدیمی پس از تست کامل
📚 بهترین تجربیات (Best Practices)
1. استفاده از Environment Variables
همیشه از environment variables برای API keys استفاده کنید:
api_key: ${OPENROUTER_API_KEY} # ✅ خوب
api_key: sk-or-... # ❌ بد
2. نامگذاری معنادار مدلها
models:
deepseek_r1: # ✅ واضح و معنادار
model1: # ❌ نامگذار بیمعنا
3. Validation تنظیمات
# اضافه کردن 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 مدلها
# Cache مدلها برای جلوگیری از recreate مکرر
@lru_cache(maxsize=10)
def get_model(self, model_name: Optional[str] = None):
# ... logic
🎯 نتیجهگیری
این سیستم مدیریت مدلهای LLM مزایای زیر را فراهم میکند:
- انعطافپذیری بالا: تغییر مدلها بدون تغییر کد
- مدیریت متمرکز: همه تنظیمات در یک مکان
- تسهیل توسعه: افزودن مدل جدید ساده
- امکان تست: A/B testing و مقایسه مدلها
- امنیت بهتر: API keys در environment variables
- قابل نگهداری: کد تمیز و سازمانیافته
این رویکرد نه تنها مشکلات سیستم قدیمی را حل میکند، بلکه پایهای محکم برای توسعه آینده سیستم فراهم میکند.