پرش به محتوای اصلی
پرش به محتوای مقاله

پروژه جدید پایتون: حذف وابستگی‌های خارجی برای تحلیل عامل‌های هوش مصنوعی

·۲ تیر ۱۴۰۵۶ دقیقه مطالعه
راهنما
ساخت یک چارچوب عامل کوچک در پایتون برای درک نحوه کار LangGraph در پشت صحنه
ساخت یک چارچوب عامل کوچک در پایتون برای درک نحوه کار LangGraph در پشت صحنه
اشتراک‌گذاری
واقعاً چه چیز جدید است؟

ساخت یک مدل آموزشی عملیاتی (Reference Implementation) که دقیقاً مکانیسم‌های داخلی LangGraph را بدون استفاده از هیچ کتابخانه‌ای بازسازی می‌کند تا لایه‌های انتزاعی را برای یادگیرندگان حذف کند.

تصور کنید در حال استفاده از یک جعبه سیاه هستید که با یک دستور ساده، نتایج شگفت‌انگیز می‌دهد اما هیچ ایده‌ای ندارید که در لایه‌های زیرین چه می‌گذرد. اگر می‌خواهید از سطح «کاربر» به سطح «مععمار» سامانه‌های هوش مصنوعی برسید، باید بدانید بسیاری از چارچوب‌های حرفه‌ای عملاً همین ابهام را ایجاد می‌کنند. ساختن برنامه‌ها با چارچوب‌های حرفه‌ای AI اغلب حس استفاده از جعبه سیاهی را دارد که در آن فراخوانی متد .invoke() به شکلی جادویی یک نتیجه تولید می‌کند.

برای شکستن این لایه انتزاعی، یک توسعه‌دهنده یک چارچوب کوچک (Mini-framework) برای عامل‌ها منتشر کرده است که هدف آن شبیه‌سازی ساختار داخلی سیستم‌هایی مانند LangGraph بدون استفاده از هیچ وابستگی خارجی (External Dependency) است. هدف اصلی این است که تمام «لوله‌کشی‌های» زیرین — شامل ثبت‌کننده‌ها (Registry)، تنظیمات اعتبارسنجی شده، Mixinها، دکوراتورها، نشست‌ها (Sessions)، استریمینگ، TypedDictها، پروتکل‌ها و یک رابط خط فرمان (CLI) — به نمایش گذاشته شوند تا کل سیستم از طریق کد منبع قابل توضیح باشد.

بسیاری از یادگیرندگان با هوش مصنوعی عامل‌محور (Agentic AI) — یعنی سیستم‌هایی که مثل یک کارمند مستقل، می‌توانند تصمیم بگیرند و ابزارها را برای رسیدن به هدف به کار بگیرند — فقط به صورت تماس‌های API با آن تعامل می‌کنند و نسبت به لوله‌کشی‌های زیرین نابینا هستند. این شکاف دانشی باعث می‌شود وقتی کلاس‌های ابزار شکست می‌خورند، عیب‌یابی دشوار شود یا توسعه‌دهنده نتواند توضیح دهد چرا اعتبارسنجی باید در یک «توصیف‌گر» (Descriptor) قرار بگیرد نه در متد __init__؛ یا اینکه چگونه ParamSpec ایمنی نوع (Type Safety) را در پشته‌های دکوراتور حفظ می‌کند. در واقع، اتکای بیش از حد به مدل‌های پیشرفته بدون درک این زیرساخت‌ها می‌تواند منجر به شکست سیستم شود؛ موضوعی که در تحلیل شکست‌های عامل‌های هوش مصنوعی به تفصیل بررسی شده است. با بازسازی این سیستم‌ها از صفر، این پروژه الگوهای طراحی خاص پایتون را که معماری‌های مقیاس‌پذیر عامل‌ها را ممکن می‌سازد، آشکار می‌کند.

موتور محرک: ابزارهای خود‌ثبت‌شونده

طبق اعلام سازنده، این چارچوب مشکل رایج «پیدا نشدن ابزار» (Tool not found) را — جایی که ابزاری در کد اضافه شده اما در یک دیکشنری دستی فراموش شده است — با حذف ثبت‌های دستی حل کرده است. به جای استفاده از دیکشنری‌های دستی، سیستم از متد __init_subclass__ در کلاس BaseTool استفاده می‌کند. این متد در زمان «تعریف کلاس» اجرا می‌شود و نه در زمان «نمونه‌سازی» (Instantiation). این بدان معناست که محیط اجرا (Runtime) به محض وارد کردن (Import) ماژول، از وجود تمام ابزارها آگاه می‌شود.

  • کشف خودکار: ابزارهایی مانند SearchTool صرفاً با اعلام خود از طریق آرگومان‌های کلاس مانند tool_name="search" و streamable=True ثبت می‌شوند. به محض اینکه پایتون کلاس را تجزیه (Parse) کند، ابزار به‌طور خودکار ثبت می‌شود.
  • طراحی شکست سریع (Fail-Fast): اگر توسعه‌دهنده فراموش کند آرگومان tool_name را تعریف کند، سیستم بلافاصله در مرحله Import یک خطای TypeError ایجاد می‌کند، نه اینکه در حین اجرا با یک شکست گیج‌کننده مواجه شود.
  • حل تعارض: کلاس ToolRegistry یک دیکشنری تخت از نوع dict[str, type] را ذخیره می‌کند و اگر دو کلاس مختلف سعی کنند نام ابزار یکسانی را تصاحب کنند، خطای DuplicateToolError را صادر می‌کند.

ساخت یک چارچوب عامل کوچک در پایتون برای درک نحوه کار LangGraph در پشت صحنه

کنترل دقیق با توصیف‌گرهای داده

مقادیر اشتباه در تنظیمات که به‌طور خاموش در حلقه‌های تکرار (Retry loops) پیش می‌روند، عامل اصلی دردهای عملیاتی در محیط تولید هستند. برای جلوگیری از این مورد، این چارچوب از توصیف‌گرهای داده (Data Descriptors) پایتون برای رهگیری متد __set__ استفاده می‌کند. این کار تضمین می‌کند که اعتبارسنجی در لحظه «مقداردهی» رخ دهد، نه در زمان «اجرا».

  • IdentifierField: از یک عبارت منظم (^[a-z][a-z0-9_-]*) استفاده می‌کند تا تضمین کند نام ابزارها شناسه‌های معتبر (حروف کوچک الفبایی و عددی) هستند.
  • IntegerRange: بررسی می‌کند که مقادیر دقیقاً عدد صحیح باشند و در بازه مشخصی قرار گیرند (مثلاً ۰ تا ۵ برای تعداد دفعات تلاش مجدد). اگر به جای عدد صحیح، یک مقدار Boolean پاس داده شود، صراحتاً خطای TypeError می‌دهد.
  • FloatRange: تضمین می‌کند که مهلت‌های زمانی (Timeouts) بین ۰.۱ تا ۱۲۰.۰ ثانیه اعتبارسنجی شوند.
  • BooleanField: یک بررسی استاندارد و اعتبارسنج شده برای تنظیماتی مانند streaming_enabled فراهم می‌کند.

این توصیف‌گرها با استفاده از __slots__ در ToolConfig ادغام شده‌اند تا بهره‌وری حافظه افزایش یابد. این معماری به سیستم اجازه می‌دهد بر اساس تنظیمات، یک «پروفایل قابلیت اعتماد» (Reliability Profile) اختصاص دهد: تنظیماتی با بیش از ۳ بار تلاش مجدد و Timeout بیش از ۱۵ ثانیه، «تاب‌آور» (Resilient) نامیده می‌شود؛ تنظیماتی با ۰ بار تلاش مجدد، «شکست سریع» (Fast-fail) است و هر مورد دیگر «متعادل» (Balanced) برچسب می‌خورد.

ترکیب رفتاری از طریق Mixins

به جای داشتن یک کلاس پایه حجیم و臃肿، سیستم از Mixinها استفاده می‌کند تا رفتارها را از طریق ترتیب تفکیک متدها (MRO) در پایتون ترکیب کند. کلاس BaseTool از LoggingMixin، RetryMixin و MetricsMixin ارث‌بری می‌کند. هر یک از این Mixinها بدون حالت (Stateless) هستند و از __slots__ = () برای به حداقل رساندن سربار حافظه در عین ارائه قابلیت‌های تخصصی استفاده می‌کنند.

  • LoggingMixin: یک متد محدود شده self.log(message) فراهم می‌کند که به‌طور خودکار هر ورودی لاگ را با نام ابزار پیشوند می‌زند تا فیلتر کردن گزارش‌ها ساده‌تر شود.
  • RetryMixin: متد self.with_retries(operation) را پیاده‌سازی می‌کند که هر تابع قابل فراخوانی (Callable) را در یک حلقه قرار می‌دهد. اگر عملیاتی شکست بخورد، یک هشدار ثبت می‌کند (مثلاً attempt 1/3 failed) و تا زمانی که حداکثر تعداد تلاش‌ها تمام شود یا عملیات موفق شود، ادامه می‌دهد.
  • MetricsMixin: متد self.record_metric() و یک شیء self.metrics را ادغام می‌کند که توسط یک کلاس Slotted به نام ToolMetrics پشتیبانی می‌شود تا تعداد کل اجراها، تعداد شکست‌ها و مدت زمان اجرا را ردیابی کند.

کاربران می‌توانند زنجیره کامل ارث‌بری را در زمان اجرا از طریق CLI بررسی کنند. اجرای دستور python main.py describe search توالی MRO را نشان می‌دهد: SearchTool -> BaseTool -> LoggingMixin -> RetryMixin -> MetricsMixin -> ABC -> object.

ایمنی نوع و مدیریت چرخه حیات

دکوراتورهای ساده پایتون اغلب امضای نوع (Type Signatures) را پاک می‌کنند و باعث می‌شوند mypy به جای آرگومان‌های واقعی تابع، عبارت Callable[..., Any] را ببیند. برای حل این مشکل، این پروژه از ParamSpec (به عنوان P) و TypeVar (به عنوان R) استفاده می‌کند. این کار تضمین می‌کند که وقتی ابزارها با دکوراتورهای @log_execution یا @measure_time تزیین می‌شوند، کامپایلر همچنان امضای کامل متد run() را تشخیص دهد.

هر بار اجرای ابزار در یک مدیر زمینه (Context Manager) به نام ExecutionSession قرار می‌گیرد. این مدیریت‌کننده چرخه حیات، موارد زیر را مدیریت می‌کند:

  • شناسایی: تولید یک شناسه نشست منحصربه‌فرد (session_id) با استفاده از session-uuid4().hex[:10] که در ToolContext جریان می‌یابد و از طریق ToolOutput خارج می‌شود تا ردیابی کامل (Traceability) ممکن شود.
  • ردیابی منابع: متد __enter__ زمان شروع را ثبت کرده و آغاز جلسه را لاگ می‌کند. از طریق session.add_resource()، سیستم دارایی‌های زمان اجرا را ردیابی می‌کند.
  • خروج پاکیزه: متد __exit__ متد cleanup() را فراخوانی می‌کند تا منابع ردیابی شده را به ترتیب معکوس آزاد کند و مدت زمان کل جلسه را ثبت نماید. این متد مقدار False برمی‌گرداند تا استثناها (Exceptions) به‌طور عادی به فراخواننده منتقل شوند.

قراردادهای ساختاری و استریم

این چارچوب تفاوت میان کلاس پایه و قرارداد عملیاتی را با استفاده از ToolProtocol روشن می‌کند. با استفاده از @runtime_checkable و تایپینگ ساختاری (Structural Typing)، سیستم قراردادی ایجاد می‌کند که نیازمند متدهایی مانند execute()، stream() و run() است. این بدان معناست که هر ابزار شخص‌ثالثی که ToolProtocol را پیاده‌سازی کند، حتی اگر از BaseTool ارث‌بری نکند، کاملاً با CLI سازگار است. در حالی که این معماری برای سیستم‌های پیچیده است، گاهی اوقات ساده‌سازی بیش از حد با اسکریپت‌های بَش در سناریوهای خاص، کارایی بیشتری را نشان می‌دهد.

برای خروجی‌ها، سیستم از یک TypedDict به نام ToolOutput استفاده می‌کند تا تضمین کند هر نتیجه شامل این موارد است: tool (رشته)، content (رشته)، tokens (لیستی از رشته‌ها)، duration_ms (عدد اعشاری) و session_id (رشته).

سیستم دو مسیر اجرا را پشتیبانی می‌کند:
۱. استاندارد: متد execute() را فراخوانی می‌کند تا یک رشته کامل را برگرداند.
۲. استریمینگ: از یک Generator در متد stream() استفاده می‌کند تا توکن‌ها را یکی‌یکی تولید کند (مثلاً با تقسیم یک رشته بر اساس فاصله‌ها).

نکته کلیدی این است که BaseTool.run() هر دو مسیر را در یک بلوک try...finally قرار می‌دهد. این کار تضمین می‌کند که متد self.record_metric() تحت هر شرایطی (چه ابزار موفق شود و چه با شکست مواجه شود) فراخوانی شود و مشاهده‌پذیری (Observability) مورد نیاز برای سیستم‌های سطح تولید فراهم گردد.

این تحلیل عمیق معماری، تمرکز را از «چگونه از یک عامل استفاده کنیم» به «چگونه موتور را بسازیم که عامل را اجرا کند» تغییر می‌دهد. این پروژه نشان می‌دهد که پیچیدگی چارچوب‌های تولیدی، جادو نیست، بلکه مجموعه‌ای از الگوهای منضبط پایتون — مانند توصیف‌گرها برای اعتبارسنجی و پروتکل‌ها برای توسعه‌پذیری — است که برای پایداری طراحی شده‌اند.

این پروژه اولین بخش از یک سری ساخت ۱۶ هفته‌ای است. پس از این پی‌ریزی پایتون، این دوره از طریق یک برنامه جامع پیش خواهد رفت: پردازش زبان طبیعی (NLP)، جاسازی‌ها (Embeddings)، داخلیاتی مدل‌های زبانی بزرگ (LLM Internals)، بازیابی تقویت‌شده (RAG) و در نهایت استقرار چندعاملی از طریق پروتکل زمینه مدل (MCP).

گام بعدی شما

  • بررسی مخزن کد این پروژه برای درک نحوه پیاده‌سازی __init_subclass__ جهت حذف ثبت دستی ابزارها.
  • جایگزینی اعتبارسنجی‌های ساده در __init__ با توصیف‌گرهای داده (Descriptors) برای افزایش پایداری ورودی‌ها در پروژه‌های خود.
  • مطالعه مستندات ParamSpec برای جلوگیری از دست رفتن Type Hint‌ها هنگام نوشتن دکوراتورهای سفارشی.

ama این تنها لایه اول از یک نقشه جامع است؛ در گام‌های بعدی، این مسیر از مفاهیم پایه پایتون به سمت دنیای پیچیده NLP و استقرار چندعاملی با پروتکل MCP حرکت خواهد کرد.

چرا این موضوع مهم است؟

این رویکرد با افشای معماری داخلی عامل‌ها، سطح تخصص توسعه‌دهندگان را از اجرای دستورات ساده به طراحی سیستم‌های تاب‌آور ارتقا می‌دهد. اعتبار این متدولوژی در استفاده از استانداردهای سخت‌گیرانه Type-Safety است که برای محیط‌های عملیاتی حیاتی است.

تأثیر برای ایران

این پروژه برای برنامه‌نویسان ایرانی که به دلیل محدودیت‌های API یا هزینه‌های بالا، نیاز به بهینه‌سازی دقیق لایه‌های استنتاج دارند، یک نقشه راه عالی برای ساخت سیستم‌های سبک و بهینه است.

·نگاه ما
تحریریه دات‌هوش

این پروژه ثابت می‌کند که پیچیدگی چارچوب‌های صنعتی مثل LangGraph، ناشی از جادوی نرم‌افزاری نیست، بلکه حاصل به‌کارگیری سخت‌گیرانه الگوهای طراحی پایتون است. تمرکز بر «قراردادهای ساختاری» (Structural Typing) به جای ارث‌بری‌های عمیق، نشان می‌دهد که آینده توسعه عامل‌ها به سمت انعطاف‌پذیری بیشتر و کاهش وابستگی به کلاس‌های پایه حرکت می‌کند. این رویکرد، مرز بین استفاده از ابزار و مهندسی ابزار را برای توسعه‌دهندگان جابه‌جا می‌کند.

منابع

این گزارش با خط‌لولهٔ خودکار دات‌هوش از منابع معتبر جهانی تدوین و زیر نظر تحریریه منتشر شده است. روش کار ما

گفتگو

پنج‌شنبه‌های هوش‌محور

بسته‌ی هفتگی دات‌هوش

۵ خبر، ۲ ابزار، ۱ پرامپت در هر شماره. به‌زودی راه‌اندازی می‌شود — هر پنج‌شنبه صبح.

خبر کلیدی
ابزار کاربردی
پرامپت حرفه‌ای
تحلیل پژوهش
به‌زودی
زاویه‌ی ایرانی
به‌زودی
تمرین این هفته
به‌زودی

راهنماهای دات‌هوش

راهنماهای کاربردیِ دات‌هوش برای کار با هوش مصنوعی — از همین‌جا شروع کنید:

دات‌هوش

راهنمای فارسی هوش مصنوعی — با نگاه به ایران

اخبار روزانه، معرفی ابزارها و مدل‌ها، و آموزشِ کار با هوش مصنوعی؛ همیشه با این پرسش که از ایران چه چیزی کار می‌کند و چه چیزی نه.