8.5 KiB
سیستم گاردریل (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، ورودی کاربر را تحلیل میکند و اگر دستور مخفی تشخیص دهد، درخواست را رد میکند |
| پیکربندی | نیازی به تنظیم ندارد — آماده استفاده است |
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 تعریف شدهاند:
self.agent = ContextAwareAgent(
...
pre_hooks=[
PromptInjectionGuardrail(), # گاردریل ۱: ضد prompt injection
InputLimitGuardrail(), # گاردریل ۲: محدودیت طول ورودی
rag_injection_hook, # هوک RAG (گاردریل نیست)
],
...
)
نکته: ترتیب مهم است. ابتدا prompt injection بررسی میشود، سپس طول ورودی، و در نهایت اگر ورودی سالم بود، RAG context تزریق میشود.
نحوه اضافه کردن گاردریل جدید
مرحله ۱: ساخت فایل گاردریل
یک فایل جدید در src/guardrails/ بسازید، مثلاً profanity.py:
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:
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 |
آرایهای از گاردریلها و هوکها | اجرای ترتیبی قبل از مدل |