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

ساختار ماژولار Genkit: جایگزینی قطعات کوچک به‌جای کلاس‌های غول‌پیکر در عامل‌های

·۱۵ تیر ۱۴۰۵۱۰ دقیقه مطالعه
عوامل Genkit: چرا کل از مجموع اجزا بزرگ‌تر است
عوامل Genkit: چرا کل از مجموع اجزا بزرگ‌تر است
اشتراک‌گذاری
واقعاً چه چیز جدید است؟

جایگزینی کلاس‌های Monolithic با یک سیستم لایه‌بندی شده از ابزارها و وقفی‌ها؛ که اجازه می‌دهد مدیریت حالت (State) و دخالت انسان به‌صورت یک primitives بنیادین و نه یک پلاگین الحاقی، در هر دو محیط کلاینت و سرور یکسان عمل کند.

تصور کنید می‌خواهید یک دستیار برنامه‌نویسی بسازید که هرگز بدون اجازه شما فایلی را تغییر ندهد؛ در مدل‌های قدیمی، این کار به معنای دست‌وپنجه نرم کردن با هزاران خط کد پیچیده بود. اما اکنون با Genkit، شما می‌توانید همین رفتار را با ترکیب چند قطعه کوچک و بازتولیدپذیر در کمتر از ۱۰ خط کد ایجاد کنید.

بر اساس مستندات فنی منتشر شده در ۶ جولای ۲۰۲۶ در وب‌سایت dev.to، Genkit رویکردی کاملاً متفاوت را در پیش گرفته است. این رویکرد در واقع تکانه‌ای است به تلاش‌های گوگل برای پر کردن فاصله میان دموهای هوش مصنوعی و محیط‌های عملیاتی تا استقرار مدل‌ها در مقیاس صنعتی تسهیل شود. در حالی که توسعه سنتی بر پایه رویکرد «کلاس عامل بزرگ» (big agent class) استوار است، Genkit با عامل‌ها به عنوان ترکیبی از اولیه (primitives)های کوچک و بازتولیدپذیر برخورد می‌کند. اکثر چارچوب‌های فعلی یک کلاس Agent حجیم با ۵۰ گزینه مختلف به توسعه‌دهنده تحمیل می‌کنند و امیدوارند که نتیجه خوب باشد. این انتزاع‌های سطح بالا اغلب سازوکارهای داخلی را پنهان می‌کنند و باعث می‌شوند افزودن رفتارهای سفارشی دشوار شود. Genkit این وضعیت را معکوس کرده و ابزارها (tools)، میان‌افزارها (middleware)، وقفی‌ها (interrupts) و نشست‌ها (sessions) را به عنوان بلوک‌های سازنده اصلی قرار داده است.

این پیمانه‌ای (modularity) تضمین می‌کند که ویژگی‌های پیشرفته — مانند تأیید انسانی در حلقه (human-in-the-loop)، دستیارهای کدنویسی ایزوله‌شده (sandboxed) و تفویض اختیار چند-عاملی — نه به عنوان ویژگی‌ها یا پلاگین‌های جداگانه، بلکه به عنوان ویژگی‌های نوظهور از همان سیستم مرکزی ظاهر شوند که قطعاتش به هم قفل می‌شوند. این طراحی «بزرگ‌تر از مجموع اجزایش»، اجازه می‌دهد رفتارهای پیشرفته به صورت لایه‌لایه ترکیب شوند، به جای اینکه بعداً به صورت وصله‌ای به سیستم اضافه گردند.

برای درک بهتر، این سیستم را شبیه به لگو تصور کنید؛ شما با چند قطعه‌ی تکرارشونده می‌توانید هم یک خانه‌ی ساده بسازید و هم یک قلعه‌ی پیچیده. در Genkit، «قطعات» برای یک ربات ساده‌ی هواشناسی و یک دستیار حرفه‌ای کدنویسی یکسان هستند.

عوامل Genkit: چرا کل از مجموع اجزا بزرگ‌تر است

طبق اعلام سازندگان، هسته‌ی یک عامل در Genkit از سه رکن تشکیل شده است: یک پرامپت سیستمی (System Prompt)، مجموعه‌ای از ابزارها و یک ذخیره‌ساز حالت (State Store). توسعه‌دهندگان با استفاده از دستور ai.defineAgent می‌توانند سریعاً یک عامل را فعال کرده و از طریق agent.chat().sendStream() با آن تعامل کنند.

به‌عنوان مثال، یک عامل هواشناسی حداقلی تنها به چند جزء نیاز دارد:

  • ابزاری (مثلاً getWeather) که با ai.defineTool تعریف شده است. این ابزار شامل یک نام، توضیحات، طرح‌واره ورودی (inputSchema) با استفاده از z.object({ location: z.string() }) و طرح‌واره خروجی (outputSchema) با استفاده از z.object({ weather: z.string() }) است.
  • به طور خاص، هندلر ابزار getWeather شیئی حاوی وضعیت آب‌وهوا و دما (مثلاً «آفتابی در لندن، ۲۱ درجه فارنهایت») را بازمی‌گرداند.
  • تعریف عاملی که پرامپت سیستمی را تعیین می‌کند (مثلاً: «شما دستیاری هستید که در ارائه اطلاعات هواشناسی کمک می‌کنید. از ابزار getWeather استفاده کنید.») و ابزارها را به هم متصل می‌کند.
  • یک نشست چت (Chat Session) که استریم شدن تکه‌های داده را از طریق یک حلقه for await روی turn.stream مدیریت کرده و هر chunk.text را در خروجی می‌نویسد.

یکی از نقاط قوت این سیستم، مدیریت خودکار حالت (State) در گفتگوهای چندمرحله‌ای است که به صورت «رایگان» ارائه می‌شود. یک چت واحد، حالت را از طریق Store در طول دورهای مختلف حفظ می‌کند. یک توسعه‌دهنده می‌تواند در مورد هوای لندن بپرسد و سپس به‌سادگی بپرسد «پاریس چطور؟» یا «حالا این را به فرانسوی بگو»، بدون اینکه نیاز به مدیریت دستی تاریخچه گفتگو داشته باشد. تعامل با عامل درست مانند توسعه عادی در Node.js است زیرا حالت در پشت صحنه به طور خودکار ردیابی می‌شود.

در مورد مدیریت حافظه، Genkit دو مسیر پیش روی شما می‌گذارد. مدیریت حالت با یک خط تنظیم انجام می‌شود. با ارسال FileSessionStore('./.snapshots') به عامل، سرور مدیریت نشست را بر عهده می‌گیرد. نشست روی سرور باقی می‌ماند و چت به‌طور خودکار آن را ردیابی می‌کند.

در مقابل، با حذف پارامتر store ، عامل روی سرور «بدون حالت» (Stateless) می‌شود. در این حالت، کلاینت مالک یک بلوک وضعیت (state blob) است و آن را در هر دور گفتگو بازمی‌گرداند. توسعه‌دهنده چت را با استفاده از weatherAgentStateless.chat(state ? { state } : undefined) از سرگیرد و سپس بلوک وضعیت به‌روزشده را از طریق res.raw.state همراه با پیام به کلاینت بازمی‌گرداند.

این انعطاف‌پذیری برای معماری‌های مختلف استقرار حیاتی است:

  • حالت مدیریت‌شده توسط سرور: ساده‌ترین حالت برای بک‌اندهای مورد اعتماد است که در آن سرور گفتگو را ذخیره می‌کند.
  • حالت مدیریت‌شده توسط کلاینت: ایده‌آل برای استقرار در محیط‌های بدون حالت (Stateless) یا Serverless، مقیاس‌پذیری افقی آسان، یا سناریوهایی که کلاینت (و نه سرور) باید مالک حافظه گفتگو باشد. سرور هیچ چیز بین دورها نگه نمی‌دارد؛ صرفاً از بلوک دریافت‌شده از کلاینت شروع کرده و نسخه به‌روزشده را بازپس می‌دهد.

از آنجایی که هر دو روش از یک API استفاده می‌کنند، توسعه‌دهندگان هنگام انتقال به زیرساخت بدون حالت، نیازی به بازنویسی منطق چت ندارند. چه حافظه در سمت سرور باشد و چه در سمت کلاینت، قابلیت‌های فراخوانی ابزار و گفتگوهای چندمرحله‌ای دقیقاً یکسان عمل می‌کنند.

بزرگ‌ترین نوآوری Genkit در معرفی «وقفی‌ها» (Interrupts) است که مانند یک ابرقدرت عمل می‌کنند. وقفی‌ها در واقع ابزارهایی هستند که عمداً هیچ هندلری ندارند. وقتی یک مدل یک وقفی را «فراخوانی» می‌کند، عامل تابعی را اجرا نمی‌کند؛ بلکه متوقف شده، درخواست را برای توسعه‌دهنده نمایش می‌دهد و منتظر می‌ماند. این کار یک فراخوانی ابزار استاندارد را به یک دکمه توقف تبدیل می‌کند و آن را به پاک‌ترین ابزار موجود برای پیاده‌سازی حلقه تأیید انسانی تبدیل می‌کند.

  • سازوکار توقف (Pause): اجرا متوقف شده و کنترل را به توسعه‌دهنده می‌سپارد. داده‌های درخواست‌شده در res.interrupts به صورت لیستی از درخواست‌های معلق قرار می‌گیرند.
  • سازوکار بازگشت (Resume): کنترل از طریق chat.resumeStream() بازپس گرفته می‌شود که اجازه می‌دهد اجرا دقیقاً از همان نقطه‌ای که متوقف شده بود ادامه یابد. همان شیء چت، اسنپ‌شات را برای توسعه‌دهنده ردیابی می‌کند.

دو سبک متمایز برای بازگشت وجود دارد:

  • respond: خروجی ابزار را مستقیماً تامین می‌کند. بدنه ابزار هرگز اجرا نمی‌شود. این حالت برای تأییدیه‌ها یا پرسیدن سؤالات شفاف‌کننده از کاربر عالی است. برای مثال، کاربر می‌تواند با { approved: true, feedback: 'Looks good' } پاسخ دهد.
  • restart: فراخوانی ابزار اصلی را دوباره صادر می‌کند تا این بار واقعاً اجرا شود. این مورد اغلب با متادیتایی مانند { toolApproved: true } علامت‌گذاری می‌شود تا به هندلر ابزار اطلاع دهد که مورد تأیید قرار گرفته است.

مثلاً در یک عامل بانکی، می‌توان برنامه‌ریزی کرد که همیشه از یک وقفی userApproval (که با inputSchema برای جزئیات عملیات و outputSchema برای تأیید/بازخورد تعریف شده) پیش از فراخوانی ابزار transferMoney استفاده کند. عامل متوقف می‌شود و سیستم res.interrupts را برای یافتن درخواست userApproval چک می‌کند. اجرا تنها زمانی ادامه می‌یابد که یک انسان تأیید Boolean را ارسال کند.

از آنجایی که توقف فقط داده است و بازگشت فقط یک فراخوانی دیگر، این سازوکار را نسبت به محیط مستقل می‌کند. این روش در یک Prompt خط فرمان (CLI)، یک تست خودکار یا یک دیالوگ مبتنی بر مرورگر دقیقاً یکسان عمل می‌کند و نیازی به پیکربندی «حالت خاص» برای انسان-در-حلقه نیست.

قدرت واقعی Genkit در لایه‌های میان‌افزاری آن است. قابلیت‌ها به‌صورت یک آرایه در use: [...] تعریف می‌شوند؛ هر ورودی، تکه‌ای از یک میان‌افزار است که ابزارها و رفتارها را در حلقه تولید (generate loop) عامل می‌بافد. این ساختار مانند یک پیاز عمل می‌کند که لایه‌ها را دور حلقه تولید می‌پیچند و نیاز به کدهای چسبک (glue code) سفارشی را از بین می‌برند.

پکیج @genkit-ai/middleware کارخانه‌های تولید میان‌افزارهای سطح صنعتی را فراهم می‌کند. در یک دستیار کدنویسی کامل، این لایه‌ها ترکیب می‌شوند تا یک محیط ایزوله‌شده (Sandboxed) ایجاد کنند:

  • toolApproval: گیت‌هایی برای ابزارهای حساس ایجاد می‌کند. برای مثال، ابزارهای list_files (لیست فایل‌ها)، read_file (خواندن فایل)، use_skill (استفاده از مهارت)، run_shell (اجرای شل) و ask_user (پرسش از کاربر) می‌توانند به طور خودکار تأیید شوند، در حالی که عملیات نوشتن نیاز به تأیید دارند.
  • filesystem: عامل را به یک دایرکتوری خاص (rootDirectory) با دسترسی کنترل‌شده خواندن/نوشتن (allowWriteAccess: true) محدود کرده و ابزارهایی مانند read_file و search_and_replace را اضافه می‌کند.
  • skills: کنوانسیون‌های کدنویسی یا دانش دامنه را در صورت نیاز از طریق ابزار use_skill و با استفاده از skillPaths بارگذاری می‌کند.
  • retry: خطاهای گذرا (transient) مدل را به‌طور خودکار مدیریت می‌کند تا پایداری سیستم تضمین شود.

در یک تنظیمات تولیدی (Production)، یک عامل ممکن است محدودیتی مانند maxTurns (مثلاً ۳۰ دور) داشته باشد تا از ایجاد حلقه‌های بی‌نهایت در وظایف پیچیده جلوگیری کند.

ترتیب این لایه‌ها یک پیچ تنظیم حیاتی است. قرار دادن toolApproval قبل از filesystem تضمین می‌کند که یک وقفی ایجاد شده توسط تأیید معلق، به‌طور شفاف به بالا منتقل شود و توسط مدیریت خطای داخلی میان‌افزار سیستم‌فایل بلعیده نشود. میان‌افزارها مانند پیاز ترکیب می‌شوند؛ توالی آن‌ها تعیین می‌کند که درخواست‌ها و پاسخ‌ها چگونه رهگیری شوند.

این ساختار باعث ظهور رفتارهای پیچیده می‌شود. چون این اولیه (primitives)ها یکدیگر را تقویت می‌کنند، رفتارهای پیچیده به‌طور طبیعی از طریق ترکیب مجدد پدید می‌آیند.

گیت‌های تأیید به عنوان وقفی‌ها:
میان‌افزار toolApproval از سیستم مجزایی استفاده نمی‌کند؛ بلکه دقیقاً همان نوع وقفی‌ای را صادر می‌کند که در دمو بانکی استفاده شد. این بدان معناست که کد مدیریت در سمت کلاینت — چک کردن res.interrupts و فراخوانی resumeStream — در تمام ویژگی‌ها یکسان است. شما یک بار الگو را یاد می‌گیرید و همه جا به کار می‌برید.

ابزارهای خود-گارد (Self-Guarding):
یک ابزار می‌تواند با استفاده از ctx.interrupt() درون هندلر خود، گیت امنیتی خودش را فعال کند. برای مثال، ابزار run_shell می‌تواند از یک مدل ارزان و سریع (مانند liteModel) استفاده کند تا یک دستور را از طریق پرامپتی که دستور شل را از نظر ایمنی ارزیابی می‌کند، به عنوان «ایمن» یا «پرخطر» طبقه‌بندی کند.

اگر دستور «پرخطر» تشخیص داده شود، ابزار یک وقفی حاوی دستور و دلیل ریسک ایجاد می‌کند، عامل را متوقف کرده و تصمیم را به انسان می‌سپارد. اگر دستور ایمن باشد یا قبلاً تأیید شده باشد (که از طریق ctx.metadata?.resumed?.toolApproved چک می‌شود)، فوراً اجرا می‌شود. این یک اقدام «خود-گارد» را از سه اولیه ساده می‌سازد: یک مدل، یک ابزار و یک وقفی.

زیر-عامل‌ها به عنوان ابزارها:
تفویض اختیار چند-عاملی با تبدیل زیر-عامل‌ها (Sub-agents) به ابزارها ساده شده است. یک عامل ارکستراتور از میان‌افزار agents برای سپردن وظایف به دستیارهای تخصصی، مانند یک «پژوهشگر» یا «کدنویس» استفاده می‌کند. پرامپت سیستمی ارکستراتور ممکن است به او دستور دهد: «درخواست را تحلیل کن، به زیر-عامل مناسب تفویض کن و سپس یک پاسخ نهایی ترکیب کن».

این سیستم تفویض شامل گاردریل‌ها و تنظیمات خاصی است:

  • maxDelegations: با محدود کردن تعداد دفعات پاس دادن (مثلاً حداکثر ۵ بار)، از حلقه‌های بی‌‌پایان جلوگیری می‌کند.
  • historyLength: کنترل می‌کند که چه مقدار از زمینه گفتگو به زیر-عامل‌ها ارسال شود (مثلاً ۴ دور).
  • artifactStrategy: از استراتژی session برای ادغام خروجی‌های زیر-عامل در نشست والد استفاده می‌کند. این به ارکستراتور اجازه می‌دهد با استفاده از میان‌افزار artifacts({ readonly: true }) آنچه را که زیر-عامل‌ها تولید کرده‌اند بخواند.

این میان‌افزار ابزارهای خاصی مانند delegate_to_researcher یا delegate_to_coder را تزریق می‌کند. وقتی ارکستراتور یکی را فراخوانی می‌کند، میان‌افزار زیر-عامل را اجرا کرده و پاسخ را به عنوان نتیجه ابزار برمی‌گرداند. از آنجا که زیر-عامل‌ها آرتیفکت‌هایی می‌نویسند که در این نشست مشترک ادغام می‌شوند، یافته‌های پژوهشگر بدون نیاز به یک موتور چند-عاملی سفارشی، بلافاصله در دسترس کدنویس و ارکستراتور قرار می‌گیرد.

در نهایت، Genkit شکاف بین سرور و مرورگر را با استفاده از یک پروتکل مشترک پر کرده است. با قرار دادن یک عامل در expressHandler در بک‌اند، آن عامل به عنوان یک نقطه انتهایی (Endpoint) استاندارد HTTP در دسترس قرار می‌گیرد (مثلاً app.post('/api/bankingAgent', expressHandler(bankingAgent))).

در سمت کلاینت، remoteAgent({ url }) دقیقاً همان سطح API سرور را ارائه می‌دهد. توسعه‌دهندگان از chat()، sendStream() و resumeStream() به‌طور یکسان استفاده می‌کنند. کلاینت نیازی به لایه منطقی جداگانه برای مدیریت وقفی‌ها ندارد؛ صرفاً وقتی یک وقفی معلق در پاسخ می‌یابد، یک دیالوگ React را رندر می‌کند و سپس دستور respond را به سرور می‌فرستد.

این تقارن به توسعه موبایل از طریق Genkit Dart SDK گسترش می‌یابد و به اپلیکیشن‌های Flutter اجازه می‌دهد تا همان مدل ذهنی و ساختار API پیاده‌سازی‌های وب و سرور را به اشتراک بگذارند. الگوی وقفی/بازگشت که در یک جریان تست ساده آموخته شده، همان الگویی است که یک دیالوگ تأیید سطح تولید را در یک اپلیکیشن موبایل به پیش می‌برد.

تحلیل: تغییر پارادایم عامل‌ها

رویکرد Genkit نشان‌دهنده تغییری از «عامل-به-عنوان-محصول» به «عامل-به-عنوان-ترکیب» است. با کاهش واژگان به چند اولیه — ابزارها، وقفی‌ها و میان‌افزارها — بار شناختی توسعه‌دهندگان کاهش می‌یابد.

برای متخصصان، این به معنای پایان مبارزه با «جعبه‌های سیاه» چارچوب‌های یکپارچه (Monolithic) است. وقتی رفتاری نیاز به تغییر دارد، شما در یک کلاس پیکربندی با ۵۰ گزینه جستجو نمی‌کنید؛ بلکه به‌سادگی یک قطعه میان‌افزار را اضافه کرده یا ترتیب آن را تغییر می‌دهید. این طراحی، چارچوب عامل را به مجموعه‌ای از قطعات متصل‌شونده تبدیل می‌کند، نه یک معماری صلب.

این معماری به‌طور مؤثری «لوله‌کشی» هوش مصنوعی عاملی را کالا می‌کند. ارکستراسیون سطح بالا — که قبلاً نیاز به مهندسی سفارشی داشت — به یک وظیفه پیکربندی تبدیل می‌شود و به توسعه‌دهندگان اجازه می‌دهد بر ابزارها و پرامپت‌های سیستمی متمرکز شوند که ارزش تجاری ایجاد می‌کنند. نتیجه، تجربه توسعه‌دهنده‌ای است که واقعاً جذاب و شهودی است زیرا قطعات یکدیگر را تقویت می‌کنند.

برای مشاهده این اولیه در عمل، نمونه‌های دنیای واقعی در مخزن رسمی Genkit و راهنمای جامع عامل‌ها را بررسی کنید.

گام بعدی شما

  • بررسی مخزن رسمی Genkit برای مشاهده نمونه‌های پیاده‌سازی عامل‌های کدنویس.
  • آزمایش پیاده‌سازی یک جریان کاری «تأیید انسانی» برای ابزارهای حساس در پروژه‌های فعلی خود.
  • مطالعه راهنمای جامع عامل‌ها برای درک ترتیب بهینه لایه‌های میان‌افزاری.

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

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

این معماری با حذف کلاس‌های حجیم و جایگزینی آن‌ها با primitives، سرعت توسعه عامل‌های تجاری را افزایش می‌دهد. اعتبار این رویکرد در این است که اجازه می‌دهد رفتارهای پیچیده بدون تغییر در هسته مدل، تنها با جابجایی لایه‌های میان‌افزاری کنترل شوند.

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

توسعه‌دهندگان ایرانی که با محدودیت‌های API و نیاز به بهینه‌سازی هزینه‌ها روبرو هستند، می‌توانند از معماری Stateless این ابزار برای کاهش مصرف منابع سرور در استقرارات Serverless استفاده کنند.

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

Genkit با تبدیل «عامل» از یک محصول یکپارچه به یک ترکیب ماژولار، بار شناختی توسعه‌دهندگان را به شدت کاهش داده است. این رویکرد در واقع «لوله‌کشی» هوش مصنوعی را به یک کالای عمومی تبدیل می‌کند تا برنامه‌نویس به‌جای جنگ با جعبه‌های سیاه چارچوب‌ها، بر روی ابزارها و پرامپت‌های ارزش‌آفرین تمرکز کند. به باور ما، این مدلِ «تركيب‌پذیری»، استانداردی خواهد شد که تمام چارچوب‌های Agentic آینده را مجبور به پذیرش آن می‌کند.

منابع

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

گفتگو

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

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

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

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

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

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

دات‌هوش

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

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