# سیستم گاردریل (Guardrails System) ## چرا گاردریل؟ ایجنت‌های هوش مصنوعی بدون محدودیت، آسیب‌پذیرند. کاربر می‌تواند: - **Prompt Injection**: با دستورات مخفی، رفتار ایجنت را تغییر دهد (مثلاً «دستورات قبلی‌ات را فراموش کن») - **ورودی بسیار طولانی**: با ارسال متن‌های عظیم، هزینه توکن را بالا ببرد یا مدل را سردرگم کند - **محتوای نامناسب**: متن‌های توهین‌آمیز یا خارج از چارچوب ادب اسلامی ارسال کند **گاردریل‌ها** لایه‌های دفاعی هستند که **قبل از رسیدن ورودی به مدل**، آن را بررسی می‌کنند و در صورت تخلف، درخواست را رد می‌کنند. --- ## معماری ``` ورودی کاربر │ ▼ ┌──────────────────────────────────┐ │ pre_hooks (به ترتیب) │ │ │ │ 1. PromptInjectionGuardrail() │ ← گاردریل آماده agno (تشخیص prompt injection) │ 2. InputLimitGuardrail() │ ← گاردریل سفارشی (محدودیت طول ورودی) │ 3. rag_injection_hook │ ← تزریق RAG context │ │ └──────────────┬───────────────────┘ │ ✅ ورودی سالم ▼ ┌──────────────────────────────────┐ │ LLM (مدل زبانی) │ └──────────────────────────────────┘ ``` گاردریل‌ها در آرایه `pre_hooks` ایجنت تعریف می‌شوند و **به ترتیب** اجرا می‌شوند. اگر هر کدام خطا (`InputCheckError`) بدهند، زنجیره متوقف شده و پیام خطا به کاربر برمی‌گردد — **بدون اینکه مدل فراخوانی شود**. --- ## ساختار پوشه ``` src/guardrails/ ├── __init__.py ← ماژول پکیج └── limit.py ← InputLimitGuardrail (محدودیت طول ورودی) ``` --- ## گاردریل‌های فعال ### ۱. `PromptInjectionGuardrail` (از کتابخانه agno) | آیتم | مقدار | |------|-------| | **منبع** | `agno.guardrails.PromptInjectionGuardrail` | | **هدف** | تشخیص تلاش‌های Prompt Injection | | **نحوه کار** | با استفاده از مدل LLM، ورودی کاربر را تحلیل می‌کند و اگر دستور مخفی تشخیص دهد، درخواست را رد می‌کند | | **پیکربندی** | نیازی به تنظیم ندارد — آماده استفاده است | ```python from agno.guardrails import PromptInjectionGuardrail ``` --- ### ۲. `InputLimitGuardrail` (سفارشی) | آیتم | مقدار | |------|-------| | **منبع** | `src/guardrails/limit.py` | | **هدف** | جلوگیری از ارسال ورودی‌های بسیار طولانی | | **حد پیش‌فرض** | ۲۰۰۰ کاراکتر | | **ویژگی خاص** | پیام خطا را **به زبان کاربر** تولید می‌کند | #### نحوه کار ``` ورودی کاربر │ ▼ آیا طول ورودی > max_chars؟ │ ├─ خیر → ادامه pipeline ✅ │ └─ بله → تولید پیام خطا: 1. ۲۰۰ کاراکتر اول ورودی استخراج می‌شود (نمونه) 2. با یک prompt به LLM فرستاده می‌شود: «زبان این متن را تشخیص بده و پیام خطای مؤدبانه بنویس» 3. پیام خطا به زبان کاربر تولید و برگردانده می‌شود 4. InputCheckError پرتاب می‌شود → pipeline متوقف ``` #### پشتیبانی Sync و Async این گاردریل هر دو حالت را پشتیبانی می‌کند: | متد | کاربرد | |-----|--------| | `check()` | برای فراخوانی‌های sync (مثل `agent.run()`) | | `async_check()` | برای فراخوانی‌های async (مثل `await agent.arun()`) | اگر فراخوانی LLM برای تولید پیام خطا شکست بخورد، یک پیام پیش‌فرض انگلیسی برمی‌گردد: ``` ⚠️ Input too long. Max 2000 chars. ``` --- ## نحوه اتصال به ایجنت گاردریل‌ها در `src/agents/base_agent.py` درون آرایه `pre_hooks` تعریف شده‌اند: ```python self.agent = ContextAwareAgent( ... pre_hooks=[ PromptInjectionGuardrail(), # گاردریل ۱: ضد prompt injection InputLimitGuardrail(), # گاردریل ۲: محدودیت طول ورودی rag_injection_hook, # هوک RAG (گاردریل نیست) ], ... ) ``` > **نکته:** ترتیب مهم است. ابتدا prompt injection بررسی می‌شود، سپس طول ورودی، و در نهایت اگر ورودی سالم بود، RAG context تزریق می‌شود. --- ## نحوه اضافه کردن گاردریل جدید ### مرحله ۱: ساخت فایل گاردریل یک فایل جدید در `src/guardrails/` بسازید، مثلاً `profanity.py`: ```python from agno.guardrails.base import BaseGuardrail from agno.run.agent import RunInput from agno.exceptions import CheckTrigger, InputCheckError class ProfanityGuardrail(BaseGuardrail): """گاردریل برای فیلتر محتوای نامناسب""" def __init__(self): super().__init__() self.name = "Profanity Filter Guardrail" def check(self, run_input: RunInput) -> None: """بررسی sync — اگر مشکلی بود InputCheckError پرتاب کنید""" text = run_input.input_content if self._contains_profanity(text): raise InputCheckError( "محتوای نامناسب تشخیص داده شد.", check_trigger=CheckTrigger.INPUT_NOT_ALLOWED, ) async def async_check(self, run_input: RunInput) -> None: """بررسی async — همان منطق check ولی async""" text = run_input.input_content if self._contains_profanity(text): raise InputCheckError( "محتوای نامناسب تشخیص داده شد.", check_trigger=CheckTrigger.INPUT_NOT_ALLOWED, ) def _contains_profanity(self, text: str) -> bool: # منطق تشخیص محتوای نامناسب ... ``` #### قوانین کلیدی: | قانون | توضیح | |-------|-------| | از `BaseGuardrail` ارث‌بری کنید | کلاس پایه agno | | متد `check()` را پیاده‌سازی کنید | برای فراخوانی‌های sync | | متد `async_check()` را پیاده‌سازی کنید | برای فراخوانی‌های async | | `InputCheckError` پرتاب کنید | برای رد کردن ورودی | | `CheckTrigger.INPUT_NOT_ALLOWED` استفاده کنید | نوع خطا | ### مرحله ۲: اضافه کردن به ایجنت در `src/agents/base_agent.py`: ```python from src.guardrails.profanity import ProfanityGuardrail # در تعریف ایجنت: pre_hooks=[ PromptInjectionGuardrail(), InputLimitGuardrail(), ProfanityGuardrail(), # ← گاردریل جدید rag_injection_hook, # ← همیشه آخر باشد ], ``` > **نکته مهم:** `rag_injection_hook` همیشه باید **آخرین** آیتم در `pre_hooks` باشد، چون ورودی را تغییر می‌دهد و گاردریل‌ها باید ورودی اصلی کاربر را بررسی کنند. --- ## خلاصه | گاردریل | فایل | هدف | نوع | |---------|------|------|-----| | `PromptInjectionGuardrail` | `agno.guardrails` | ضد prompt injection | آماده (built-in) | | `InputLimitGuardrail` | `src/guardrails/limit.py` | محدودیت طول ورودی | سفارشی | | پارامتر ایجنت | مقدار | نقش | |---------------|-------|-----| | `pre_hooks` | آرایه‌ای از گاردریل‌ها و هوک‌ها | اجرای ترتیبی قبل از مدل |