اگر امروز یک عامل هوش مصنوعی میسازید که با ابزارهای خارجی تعامل دارد، احتمالاً متوجه شدهاید که حتی دقیقترین پرامپتها هم نمیتوانند جلوی خطاهای تصادفی را بگیرند. مشکل اینجاست که شما سعی میکنید با «صحبت کردن» از مدل بخواهید دقیق باشد، در حالی که مشکل در لایهی معماری و نحوه پاسخدهی ابزارهاست.
به نقل از راهنمای فنی منتشر شده در ۲۶ سپتامبر ۲۰۲۶ در وبسایت dev.to، مرز بین یک مدل زبانی بزرگ (LLM) — مثل کتابخانهداری که میلیاردها صفحه را خوانده و حالا با همان لحن کتابها جواب میدهد — و ابزارهای آن باید یک قرارداد سخت و صریح باشد، نه یک پیشنهاد یا توصیه. استدلال اصلی این راهنما این است که غریزه توسعهدهندگان برای بازنویسی مداوم پرامپت، اغلب باعث میشود مقصر واقعی را نادیده بگیرند: یک قرارداد ابزار مبهم. وقتی ابزاری صرفاً پیام «ok» را برمیگرداند، عامل مجبور است حدس بزند که آیا عملیات واقعاً موفق بوده یا فقط شروع شده است.
این تغییر دیدگاه، بارِ مسئولیتِ قابلیت اطمینان را از روی دوش هوش مدل برمیدارد و به ساختار سیستم میسپارد. همانطور که در تحلیل قبلی ما دربارهی توکنسازی و بصریسازی مکانیکهای خام آن اشاره کردیم، در اینجا تمرکز بر منطق سطح بالایی است که عاملها از طریق آن، توکنها را به وضعیتهای عملیاتی تبدیل میکنند. ابزار را مانند یک مرز فیزیکی تصور کنید؛ اگر خط مرزی تار باشد، عامل ناگزیر است در زمان اشتباه از آن عبور کند. این رویکرد به نوعی یادآور ضرورت قراردادهای سختگیرانه در مدیریت حافظه برای جلوگیری از خطاهای GraphRAG است که در مواجهه با دادههای حجیم، مانع از فروپاشی منطق بازیابی میشود.
بنبستِ ابزارهای مبهم
طبق این گزارش، وقتی ابزاری خروجی {"message": "ok"} میدهد، عامل با یک دوراهی مواجه میشود: آیا این «ok» یعنی ارائهدهنده پیام را پذیرفته است، یا ایمیل واقعاً به مقصد رسیده است، و یا کاربر پیش از این حساب خود را تایید کرده است؟ اینها واقعیتهای متفاوتی هستند، اما عاملها معمولاً همه را یکسان میبینند و به عنوان یک موفقیت کلی تلقی میکنند.
یک قرارداد کارآمد، «قصد» (Intention) را از «نتیجهی قابل مشاهده» (Observable Result) جدا میکند. به جای استفاده از عبارات خوشبینانه، ابزار باید یک شیء ساختاریافته برگرداند؛ مثلاً: {"status": "accepted", "operation_id": "op_4821", "next_check_after_seconds": 5, "retryable": false}. این ساختار به مدل اجازه میدهد بر اساس فیلدهای ثابت و پایدار تصمیم بگیرد، نه با تفسیر متنی که احتمال خطا در آن بالاست.
معماری سه-باکسی
برای پیادهسازی یک قرارداد مستحکم، این راهنما یک خط لوله سه مرحلهای را برای هر ادغام ابزار پیشنهاد میکند:
- ورودی (Input): آرگومانهای اعتبارسنجی شده با محدودیت اندازه سختگیرانه و یک شناسه همبستگی (Correlation ID) برای ردیابی دقیق درخواست.
- اجرا (Execution): یک آداپتور (Adapter) — شبیه به تبدیلهای برق که ولتاژ را برای دستگاه تنظیم میکند — که با ارائهدهنده خارجی ارتباط گرفته و پاسخهای خام API را ترجمه میکند.
- خروجی (Output): مجموعهای حداقلی از وضعیتهای خاصِ دامنه که عامل بدون نیاز به جزئیات داخلی ارائهدهنده، از آنها استفاده کند.
این لایه میانی حیاتی است. به جای ارسال خطای خام «429 Too Many Requests» به مدل، آداپتور باید آن را به وضعیتی مثل rate_limited تبدیل کند. مثالهای دیگر شامل تبدیل Timeoutها یا پاسخهای ناقص به وضعیتهایی مانند temporarily_unavailable یا unknown_result است.
علاوه بر این، ابزار باید صراحتاً اعلام کند چه کاری را «انجام نمیدهد». برای مثال، باید مشخص باشد که وضعیت accepted به معنای delivered نیست، و delivered لزوماً به معنای opened (باز شدن ایمیل) نیست. این دقت مانع از تصمیمات تجاری غلط بر اساس فرضهای مدل میشود.
ماشینهای وضعیت به جای متن
یک قرارداد ضعیف «جمله» برمیگرداند، اما یک قرارداد قوی «وضعیت» (State) را بازمیگرداند. برای ابزار تایید ایمیل، پیشنهاد میشود عبارت «پیام ارسال شد» با یک شیء JSON شامل status: "accepted"، یک operation_id و یک مقدار بولی برای retryable جایگزین شود.
وضعیتهای صریح باید از یک جریان منطقی پیروی کنند: started $\rightarrow$ accepted $\rightarrow$ observed $\rightarrow$ completed.
- started: از ایجاد نسخههای تکراری در صورت قطع شبکه در هنگام دریافت پاسخ جلوگیری میکند.
- accepted: تایید میکند که ارائهدهنده درخواست را دریافت و پذیرفته است.
- observed: نشان میدهد که شواهد بعدی (مانند دریافت پاسخ) یافت شده است.
- expired: یک اقدام بازیابی را تعریف میکند، نه یک شکست مرموز و نامشخص.
این رویکرد از تکرار عملیات در صورت وقوع Timeout شبکه جلوگیری میکند. اگر عامل با Timeout مواجه شود، میتواند از operation_id برای بررسی وضعیت پیش از تلاش مجدد برای ارسال ایمیل استفاده کند تا از تکرارناپذیری (Idempotency) مطمئن شود. کلیدهای تکرارناپذیری را میتوان از ترکیب user_id (شناسه کاربر)، هدف عملیات و یک پنجره زمانی خاص ساخت.
تست با دادههای ساختگی (Fixtures)
قابلیت اطمینان نیازمند شکستهای بازتولیدپذیر است. بر اساس مستندات این راهنما، توصیه میشود به جای استفاده از ایمیلهای واقعی تیم، از Fixtureها استفاده شود؛ مجموعهدادههای ایزولهای که صندوقهای ورودی خالی، پیامهای تاخیری یا لینکهای منقضی شده را شبیهسازی میکنند.
تستها باید شامل «موارد لبه» (Edge Cases) باشند؛ مثلاً استفاده از دامنههای غلطاملا شده (مانند temp gamil com) برای اطمینان از اینکه رابط کاربری دادههای کاربر را بهصورت خاموش «اصلاح» نمیکند. به همین ترتیب، میتوان از temp org mail استفاده کرد تا تایید شود که جستجوها نتایج «جادویی» یا اشتباه تولید نمیکنند. این سطح از سختگیری در تست، برای جلوگیری از رفتارهای پیشبینینشدهای است که در مدل Astra منجر به بهرهبرداری خودکار از نقاط ضعف ناشناخته شد و در نهایت باعث تعویق عرضه آن گشت.
یک مورد تست خوانا میتواند به این شکل باشد:{ "tool": "wait_for_verification", "fixture": "delayed_message", "expected": { "first_result": "waiting", "second_result": "observed", "max_polls": 3 } }
همچنین توسعهدهندگان باید محدودیت max_polls را اعمال کنند. یک عامل نباید تا ابد یک ابزار را چک (Poll) کند؛ پس از رسیدن به یک حد مشخص، باید یک توضیح concrete و یک گام بعدی پیشنهاد دهد — مثلاً «هنوز شواهدی یافت نشد؛ بعداً دوباره تلاش کنید» — نه اینکه توهم (Hallucination) — مثل دوستی که خاطرهای را اشتباه تعریف میکند — ایجاد کند که نتیجه رسیده است.
مشاهدهپذیری و زمینه
برای جلوگیری از پر شدن پنجره زمینه (Context Window) — میزان متنی که مدل همزمان در ذهن نگه میدارد، مثل میز کاری که جا برای چند ورق دارد — سیستم باید خلاصهٔ عامل را از شواهد اپراتور جدا کند. مدل فقط به status، operation_id، پرچم retryable و یک دلیل کوتاه برای شکست نیاز دارد. این مدیریت بهینه از تکنیکهای بارگذاری پیشرونده برای کاهش حجم Context الهام گرفته است تا از اشباع شدن حافظه کوتاهمدت مدل جلوگیری شود.
برچسبهای زمانی کامل، دادههای تأخیر (Latency)، کدهای خام ارائهدهنده و لاگهای نرمالشده باید به لاگهای سیستم بروند، نه به پرامپت. همچنین توصیه میشود از ذخیره محتوای کامل ایمیلها در Context خودداری شود. این کار باعث میشود عامل متمرکز بماند و از خطاهای «نمایشی» که در آن مدل برای یک Timeout فنی که نمیفهمد عذرخواهی میکند، کاسته شود.
گام بعدی شما
برای حرکت از مهندسی پرامپت به سمت معماری سیستم، توسعهدهندگان باید این مراحل را دنبال کنند:
- وضعیتها و انتقالهای (Transitions) ابزارهای خود را پیش از نوشتن پرامپت تعریف کنید.
- یک طرحواره (Schema) خروجی کوچک و نسخهبندی شده برای هر ابزار بسازید.
- خطاهای خارجی را به دستههای دامنه (Domain Categories) نرمالسازی کنید.
- از
operation_idو تکرارناپذیری برای محافظت از تلاشهای مجدد (Retries) استفاده کنید. - برای موارد تأخیر، تکرار و انقضا، مجموعهدادههای ساختگی (Fixtures) بسازید.
- خلاصه LLM را کوتاه نگه دارید و شواهد عملیاتی را خارج از Context قرار دهید.
این انضباط معماری، عامل را از یک نویسنده خلاق به یک اپراتور پیشبینیپذیر تبدیل میکند. در حالی که یک پرامپت هوشمندانه میتواند سوءتفاهمها را کاهش دهد، تنها یک قرارداد سختگیرانه است که اشتباه گرفتن «پذیرش درخواست» با «تایید نهایی» را غیرممکن میکند.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو