عنوان:

‫راهنمای مهندسی پرامپت برای برنامه‌نویسان


نویسنده: وحید نصیری
تاریخ: ۱۴۰۴/۰۳/۰۶ ۲۰:۲۳
آدرس: www.dntips.ir
در دنیای امروز توسعه نرم‌افزار، برنامه‌نویسان به طور فزاینده‌ای به دستیاران کدنویسی مبتنی بر هوش مصنوعی (AI coding assistants) برای سرعت بخشیدن به جریان‌های کاری روزانه خود متکی هستند. این ابزارها قادر به تکمیل خودکار توابع (functions)، پیشنهاد رفع اشکالات (bug fixes) و حتی تولید کل ماژول‌ها (modules) یا حداقل محصولات قابل عرضه (MVPs) هستند. با این حال، همان‌طور که بسیاری از توسعه‌دهندگان تجربه کرده‌اند، کیفیت خروجی هوش مصنوعی تا حد زیادی به کیفیت پرامپت (prompt) ارائه شده وابسته است. به همین دلیل، مهندسی پرامپت (Prompt Engineering) به یک مهارت اساسی تبدیل شده است. درخواست‌های ضعیف و مبهم می‌توانند منجر به پاسخ‌های نامربوط یا عمومی شوند، در حالی که پرامپت‌های به دقت تنظیم شده، راه‌حل‌های کدنویسی دقیق، کاربردی و حتی خلاقانه تولید می‌کنند. این راهنما به صورت عملی به بررسی نحوه سیستماتیک تنظیم پرامپت‌های مؤثر برای وظایف رایج توسعه می‌پردازد.

مبانی مهندسی پرامپت
مهندسی پرامپت، که به معنای هنر و علم طراحی و بهینه‌سازی ورودی‌ها (prompts) برای مدل‌های هوش مصنوعی، به ویژه مدل‌های زبان بزرگ (Large Language Models - LLMs) است، با هدف دستیابی به پاسخ‌های مطلوب از این مدل‌ها انجام می‌شود. با تنظیم دقیق پرامپت‌ها، می‌توان به مدل هوش مصنوعی زمینه (context)، دستورالعمل‌ها و مثال‌هایی ارائه داد که به آن کمک می‌کند تا هدف (intent) شما را درک کرده و به شیوه‌ای معنادار پاسخ دهد. این فرآیند را می‌توان به ارائه یک نقشه راه به هوش مصنوعی تشبیه کرد که آن را به سمت خروجی مورد نظر هدایت می‌کند.
پرامپت دادن به یک ابزار کدنویسی مبتنی بر هوش مصنوعی تا حدودی شبیه به ارتباط با یک همکار بسیار دقیق و گاه آگاه است. برای دستیابی به نتایج مفید، باید صحنه را به وضوح آماده کرده و هوش مصنوعی را در مورد آنچه می‌خواهید و نحوه آن راهنمایی کنید. اصول بنیادینی که تمامی مثال‌های این راهنما را زیربنا قرار می‌دهند، به شرح زیر است:
  • ارائه زمینه غنی (Provide Rich Context): همیشه فرض کنید که هوش مصنوعی هیچ دانشی فراتر از آنچه شما ارائه می‌دهید، در مورد پروژه شما ندارد. جزئیات مربوطه مانند زبان برنامه‌نویسی (programming language)، چارچوب (framework)، و کتابخانه‌ها (libraries)، و همچنین تابع (function) یا قطعه کد (snippet) مورد بحث را لحاظ کنید. در صورت وجود خطا، پیام خطای دقیق (exact error message) را ارائه دهید و توضیح دهید که کد باید چه کاری انجام دهد. دقت و زمینه تفاوت بین پیشنهادهای مبهم و راه‌حل‌های دقیق و قابل اجرا را ایجاد می‌کند. به عنوان مثال، پرامپت شما می‌تواند شامل یک مقدمه کوتاه باشد: "من یک تابع Node.js دارم که از Express و Mongoose استفاده می‌کند و باید یک کاربر را بر اساس شناسه (ID) واکشی کند، اما خطای TypeError می‌دهد. در اینجا کد و خطا آمده است...". هرچه توضیحات مقدماتی بیشتری ارائه دهید، هوش مصنوعی کمتر نیاز به حدس و گمان خواهد داشت.
  • در مورد هدف یا سوال خود دقیق باشید (Be Specific About Your Goal or Question): پرسش‌های مبهم منجر به پاسخ‌های مبهم می‌شوند. به جای پرسیدن چیزی مانند "چرا کد من کار نمی‌کند؟"، دقیقاً مشخص کنید که چه بینشی نیاز دارید. برای مثال: "این تابع JavaScript به جای نتیجه مورد انتظار، undefined برمی‌گرداند. با توجه به کد زیر، می‌توانید به من کمک کنید تا دلیل آن و نحوه رفع آن را شناسایی کنم؟" به احتمال زیاد پاسخ مفیدی را به همراه خواهد داشت. یک فرمول پرامپت برای اشکال‌زدایی (debugging) این است: "انتظار می‌رود [رفتار مورد انتظار] را انجام دهد، اما به جای آن [رفتار فعلی] را انجام می‌دهد، وقتی [ورودی نمونه] به آن داده می‌شود. باگ (bug) کجاست؟" به همین ترتیب، اگر به دنبال بهینه‌سازی هستید، نوع خاصی از بهینه‌سازی را درخواست کنید (مانند "چگونه می‌توانم عملکرد زمان اجرا (runtime performance) این تابع مرتب‌سازی (sorting function) را برای ۱۰ هزار آیتم بهبود بخشم؟"). دقت، تمرکز هوش مصنوعی را هدایت می‌کند.
  • شکستن وظایف پیچیده (Break Down Complex Tasks): هنگام پیاده‌سازی یک ویژگی جدید (new feature) یا مواجهه با یک مشکل چند مرحله‌ای، کل مشکل را در یک پرامپت عظیم وارد نکنید. اغلب مؤثرتر است که کار را به بخش‌های کوچک‌تر تقسیم کرده و تکرار (iterate) کنید. به عنوان مثال، "ابتدا یک اسکلت (skeleton) کامپوننت React برای صفحه لیست محصولات تولید کنید. سپس، مدیریت وضعیت (state management) را اضافه خواهیم کرد. در نهایت، فراخوانی API (API call) را یکپارچه خواهیم کرد." هر پرامپت بر اساس قبلی ساخته می‌شود. اغلب توصیه نمی‌شود که یک ویژگی بزرگ را یکجا درخواست کنید؛ در عوض، با یک هدف سطح بالا شروع کنید و سپس به صورت تکراری هر قطعه را درخواست کنید. این رویکرد نه تنها پاسخ‌های هوش مصنوعی را متمرکز و قابل مدیریت نگه می‌دارد، بلکه نحوه ساخت تدریجی یک راه‌حل توسط یک انسان را نیز منعکس می‌کند.
  • گنجاندن مثال‌هایی از ورودی/خروجی یا رفتار مورد انتظار (Include Examples of Inputs/Outputs or Expected Behavior): اگر می‌توانید آنچه را که می‌خواهید با یک مثال نشان دهید، این کار را انجام دهید. برای مثال، "با توجه به آرایه [۳,۱,۴]، این تابع باید [۱,۳,۴] را برگرداند." ارائه یک مثال مشخص در پرامپت به هوش مصنوعی کمک می‌کند تا هدف شما را درک کند و ابهام را کاهش می‌دهد. این شبیه به دادن یک مورد آزمایشی سریع به یک توسعه‌دهنده تازه‌کار است – الزامات را روشن می‌کند. در اصطلاح مهندسی پرامپت، این گاهی اوقات "few-shot prompting" نامیده می‌شود، که در آن شما یک الگو (pattern) را برای هوش مصنوعی نشان می‌دهید تا از آن پیروی کند. حتی یک مثال از رفتار صحیح می‌تواند پاسخ مدل را به طور قابل توجهی هدایت کند.
  • استفاده از نقش‌ها یا شخصیت‌ها (Leverage Roles or Personas): یک تکنیک قدرتمند که در بسیاری از مثال‌های پرامپت پرطرفدار رایج شده است، درخواست از هوش مصنوعی برای "عمل کردن به عنوان" یک شخص (persona) یا نقش (role) خاص است. این می‌تواند بر سبک و عمق پاسخ تأثیر بگذارد. به عنوان مثال، "به عنوان یک توسعه‌دهنده ارشد React عمل کنید و کد من را برای باگ‌های احتمالی بررسی کنید" یا "شما یک متخصص عملکرد JavaScript هستید. تابع زیر را بهینه کنید." با تعیین یک نقش، دستیار را برای اتخاذ لحن مربوطه آماده می‌کنید – چه یک بازبین کد سخت‌گیر باشد، چه یک معلم مفید برای یک توسعه‌دهنده تازه‌کار، یا یک تحلیلگر امنیت که به دنبال آسیب‌پذیری‌هاست. پرامپت‌های به اشتراک گذاشته شده در جامعه موفقیت این روش را نشان داده‌اند، مانند "به عنوان یک مدیریت‌کننده خطای JavaScript عمل کنید و این تابع را برای من اشکال‌زدایی کنید. داده‌ها به درستی از فراخوانی API رندر (render) نمی‌شوند." در استفاده ما، همچنان باید کد و جزئیات مشکل را ارائه دهیم، اما پرامپت‌های نقش‌آفرینی می‌توانند راهنمایی‌های ساختاریافته‌تر و در سطح متخصص ارائه دهند.
  • تکرار و پالایش مکالمه (Iterate and Refine the Conversation): مهندسی پرامپت یک فرآیند تعاملی است، نه یک معامله یک‌باره. توسعه‌دهندگان اغلب باید پاسخ اول هوش مصنوعی را مرور کرده و سپس سوالات تکمیلی (follow-up questions) بپرسند یا تصحیح کنند. اگر راه‌حل کاملاً درست نیست، ممکن است بگویید: "این راه‌حل از بازگشت (recursion) استفاده می‌کند، اما من یک رویکرد تکراری (iterative approach) را ترجیح می‌دهم – می‌توانید دوباره بدون بازگشت امتحان کنید؟" یا "عالی است، حالا می‌توانید نام متغیرها (variable names) را بهبود ببخشید و نظرات (comments) اضافه کنید؟" هوش مصنوعی زمینه را در یک جلسه چت (chat session) به خاطر می‌سپارد، بنابراین می‌توانید به تدریج آن را به سمت نتیجه مطلوب هدایت کنید. نکته کلیدی این است که هوش مصنوعی را به عنوان یک شریک که می‌توانید آموزش دهید – پیشرفت بر کمال در اولین تلاش – ببینید.
  • حفظ وضوح و سازگاری کد (Maintain Code Clarity and Consistency): این آخرین اصل کمی غیرمستقیم است اما برای ابزارهایی که بر روی زمینه کد (code context) شما کار می‌کنند بسیار مهم است. کدهای تمیز و خوش‌ساختار و نظرات را بنویسید، حتی قبل از اینکه هوش مصنوعی وارد عمل شود. نام‌های معنی‌دار برای توابع و متغیرها، قالب‌بندی سازگار و رشته‌های مستند (docstrings) نه تنها درک کد شما را برای انسان‌ها آسان‌تر می‌کنند، بلکه سرنخ‌های قوی‌تری در مورد آنچه شما انجام می‌دهید به هوش مصنوعی می‌دهند. اگر یک الگو یا سبک سازگار را نشان دهید، هوش مصنوعی آن را ادامه خواهد داد. با این ابزارها مانند توسعه‌دهندگان تازه‌کار بسیار دقیق رفتار کنید – آن‌ها هر نشانه را از کد و نظرات شما دریافت می‌کنند.
با در نظر گرفتن این اصول بنیادی، می‌توان به سناریوهای خاصی پرداخت. در ابتدا، اشکال‌زدایی مورد بررسی قرار می‌گیرد، که شاید فوری‌ترین مورد استفاده باشد: شما کدی دارید که به درستی کار نمی‌کند، و می‌خواهید هوش مصنوعی به شما در پیدا کردن دلیل آن کمک کند.



مشاهده مطلب اصلی

نظرات

  • وحید نصیری در ۱۴۰۴/۰۳/۰۶ ۲۰:۳۰
    پیروی از الگوهای مناسب در پرسش‌نویسی (Prompt Engineering) هنگام استفاده از هوش مصنوعی برای رفع اشکال (Debugging) کد، می‌تواند فرایند شناسایی و رفع خطاها را به‌طور چشمگیری بهبود بخشد. این رویکرد، مشابه تکنیک "اشکال‌زدایی اردک لاستیکی" (Rubber Duck Debugging) است، با این تفاوت که هوش مصنوعی نه تنها به توضیحات توسعه‌دهنده گوش می‌دهد، بلکه با پیشنهادهای عملی نیز به او کمک می‌کند.

    اصول کلیدی برای پرسش‌نویسی مؤثر در رفع اشکال
    موفقیت در استفاده از دستیار هوش مصنوعی برای رفع اشکال، به چگونگی توصیف مشکل بستگی دارد. چهار اصل مهم در این زمینه وجود دارد:

    1. توصیف واضح مشکل و علائم آن
    برای شروع، باید به‌طور دقیق توضیح داد که چه چیزی اشتباه پیش می‌رود و کد قرار است چه کاری انجام دهد. همیشه پیام خطای دقیق یا رفتار نادرست مشاهده شده را ذکر کنید. به‌عنوان مثال، به‌جای گفتن "کد من کار نمی‌کند"، بهتر است این‌گونه پرسش‌نویسی شود: "یک تابع جاوااسکریپت (JavaScript) دارم که قرار است مجموع یک آرایه (Array) از اعداد را محاسبه کند، اما به‌جای جمع واقعی، مقدار NaN (مخفف Not a Number به معنی "عدد نیست") را برمی‌گرداند. کد به شرح زیر است: [کد را اینجا قرار دهید]. این تابع برای آرایه‌ای از اعداد مانند [1, 2, 3] باید یک عدد (مجموع) را خروجی دهد، اما من NaN دریافت می‌کنم. دلیل این خطا (Bug) چه می‌تواند باشد؟" این نوع پرسش، زبان برنامه‌نویسی، رفتار مورد انتظار، خروجی نادرست مشاهده شده و کد مرتبط را مشخص می‌کند که همگی اطلاعاتی حیاتی هستند. ارائه یک زمینه ساختاریافته (شامل کد، خطا، نتیجه مورد انتظار و اقداماتی که انجام داده‌اید)، نقطه شروع قوی‌ای را برای هوش مصنوعی فراهم می‌آورد.

    2. استفاده از رویکرد گام‌به‌گام یا خط‌به‌خط برای خطاهای پیچیده
    برای خطاهای منطقی (Logic Bugs) پیچیده‌تر، که در آن‌ها پیام خطای واضحی دریافت نمی‌شود اما خروجی نادرست است، می‌توان از هوش مصنوعی درخواست کرد تا اجرای کد را گام‌به‌گام بررسی کند. به‌عنوان مثال: "این تابع (Function) را خط‌به‌خط بررسی کن و مقدار total را در هر مرحله دنبال کن. این مقدار به‌درستی جمع نمی‌شود – منطق در کجا دچار مشکل شده است؟" این نمونه‌ای از پرسش‌نویسی "اشکال‌زدایی اردک لاستیکی" (Rubber Duck Debugging) است که در آن از هوش مصنوعی خواسته می‌شود تا فرایند اشکال‌زدایی انسانی را با استفاده از پرینت‌ها (Prints) یا یک دیباگر (Debugger) شبیه‌سازی کند. چنین پرسش‌هایی اغلب مسائل ظریفی مانند ریست (Reset) نشدن متغیرها (Variables) یا منطق شرطی (Conditional Logic) نادرست را آشکار می‌کنند، زیرا هوش مصنوعی وضعیت (State) را در هر مرحله تشریح خواهد کرد. اگر به بخش خاصی از کد مشکوک هستید، می‌توانید بر آن تمرکز کنید: "توضیح بده فراخوانی filter در اینجا چه کاری انجام می‌دهد و آیا ممکن است آیتم‌های بیشتری را از آنچه باید، حذف کند؟" درگیر کردن هوش مصنوعی در نقش توضیحی می‌تواند در فرایند توضیح، خطا را آشکار سازد.

    3. ارائه نمونه‌های قابل تکثیر و حداقل (Minimal Reproducible Examples)
    گاهی اوقات، پایگاه کد (Codebase) شما بزرگ است، اما خطا را می‌توان در یک قطعه کد کوچک‌تر نشان داد. اگر می‌توانید کدی را که هنوز مشکل را تکثیر می‌کند، استخراج یا ساده‌سازی کنید، این کار را انجام داده و آن را به هوش مصنوعی ارائه دهید. این کار نه تنها تمرکز بر هوش مصنوعی را آسان‌تر می‌کند، بلکه شما را وادار به روشن کردن مشکل نیز می‌سازد (که خود اغلب یک تمرین مفید است). به‌عنوان مثال، اگر در یک فراخوانی تابع (Function Call) با عمق زیاد، TypeError دریافت می‌کنید، سعی کنید آن را با چند خط کد که می‌توانید به اشتراک بگذارید، تکثیر کنید. هدف، جداسازی خطا با حداقل کد است. می‌توانید هوش مصنوعی را در این فرایند مشارکت دهید و بگویید: "این یک مثال ساده شده است که هنوز خطا را فعال می‌کند [قطعه کد را وارد کنید]. چرا این خطا رخ می‌دهد؟" با ساده‌سازی، نویز (Noise) را حذف کرده و به هوش مصنوعی کمک می‌کنید تا مشکل را دقیقاً شناسایی کند.

    4. طرح پرسش‌های متمرکز و پیگیری‌ها
    پس از ارائه زمینه (Context)، اغلب مؤثر است که مستقیماً آنچه نیاز دارید را بپرسید، به‌عنوان مثال: "چه چیزی می‌تواند باعث این مشکل شود و چگونه می‌توانم آن را رفع کنم؟" این کار، هوش مصنوعی را به تشخیص و پیشنهاد راه‌حل دعوت می‌کند. اگر پاسخ اولیه هوش مصنوعی نامشخص یا تا حدی مفید بود، در پرسیدن سؤالات پیگیری تردید نکنید. می‌توانید بگویید: "آن توضیح منطقی به نظر می‌رسد. می‌توانید نشان دهید چگونه کد را رفع کنم؟ لطفاً کد اصلاح شده را ارائه دهید." در یک محیط چت، هوش مصنوعی تاریخچه مکالمه را در اختیار دارد، بنابراین می‌تواند مستقیماً کد اصلاح شده را خروجی دهد. اگر از ابزاری درون‌خطی (Inline Tool) مانند Copilot در VS Code یا Cursor بدون چت استفاده می‌کنید، ممکن است به‌جای آن، بالای کد یک کامنت (Comment) مانند // BUG: returns NaN, fix this function بنویسید و مشاهده کنید که چگونه به‌طور خودکار تکمیل می‌شود – اما به‌طور کلی، چت تعاملی توضیحات کامل‌تری را ارائه می‌دهد. الگوی پیگیری دیگر این است: اگر هوش مصنوعی یک راه‌حل ارائه داد اما شما دلیل آن را متوجه نشدید، بپرسید "می‌توانید توضیح دهید چرا آن تغییر مشکل را حل می‌کند؟" به این ترتیب، هم برای دفعات بعدی یاد می‌گیرید و هم صحت استدلال هوش مصنوعی را دو بار بررسی می‌کنید.

    مثال اشکال‌زدایی: پرسش‌نویسی ضعیف در برابر بهبودیافته
    برای درک بهتر اصول اشکال‌زدایی، تفاوت بین یک پرسش‌نویسی ضعیف و یک پرسش‌نویسی بهبودیافته را با یک مثال عملی مشاهده می‌کنیم. فرض کنید یک تابع ساده Node.js داریم که قرار است لیستی از اشیای کاربر (User Objects) را به یک نگاشت (Map) بر اساس شناسه کاربر (User ID) تبدیل کند، اما خطا می‌دهد.
    کد باگ‌دار:
    // Buggy function: converts array of users to a map by ID
    function mapUsersById(users) {
      const userMap = {};
      for (let i = 0; i <= users.length; i++) {  
        // Note: using <= will go out of bounds on the last iteration
        const user = users[i];
        userMap[user.id] = user;
      }
      return userMap;
    }
    
    // Example usage:
    const result = mapUsersById([{ id: 1, name: "Alice" }]);
    این کد قرار است بر روی آرایه کاربران تکرار (Iterate) کرده و یک شیء (Object) بسازد که کلیدهای آن، شناسه‌های کاربر باشند. با این حال، یک خطا (Bug) وجود دارد: حلقه (Loop) از i <= users.length به‌جای i < users.length استفاده می‌کند. این باعث می‌شود که users[i] در آخرین تکرار undefined باشد، که به احتمال زیاد منجر به خطای زمان اجرا (Runtime Error) می‌شود (مثلاً تلاش برای دسترسی به ویژگی id از undefined).

    ❌ پرسش‌نویسی ضعیف:
    "چرا تابع mapUsersById من کار نمی‌کند؟"
    پاسخ هوش مصنوعی (شبیه‌سازی شده):
    "بدون اطلاعات بیشتر، گفتن آن دشوار است. آیا مطمئنید تابع با یک آرایه مناسب از کاربران فراخوانی می‌شود؟ شاید مشکل این است که users خالی است یا یک آرایه نیست، که باعث می‌شود حلقه به‌درستی اجرا نشود. همچنین ممکن است هنگام تنظیم ویژگی بر روی userMap خطایی وجود داشته باشد. اطمینان حاصل کنید که هر کاربر یک ویژگی id دارد. اگر users مقدار undefined یا null داشته باشد، این نیز باعث عدم کارکرد آن خواهد شد."
    تحلیل: این پاسخ بسیار مبهم است. پرسش هیچ جزئیاتی به‌جز نام تابع ارائه نداد، بنابراین هوش مصنوعی در مورد علل عمومی حدس می‌زند (مثلاً "شاید آرایه خالی است یا آرایه نیست"، "مطمئن شوید هر کاربر یک id دارد"). هوش مصنوعی خطای واقعی را شناسایی نکرد. این نوع پاسخی است که وقتی سؤال مبهم باشد، دریافت می‌کنید – مدل فقط می‌تواند نکات اشکال‌زدایی متداول را تکرار کند. از دیدگاه یک توسعه‌دهنده دات‌نت (Microsoft .NET), این پاسخ بسیار غیرمفید است، زیرا به اشتباه واقعی اشاره نمی‌کند. فقدان زمینه و جزئیات در پرسش منجر به پاسخی عمومی می‌شود (در واقع، معادل هوش مصنوعی عبارت "آیا سعی کردی آن را خاموش و روشن کنی؟").

    ✅ پرسش‌نویسی بهبودیافته:
    "من یک تابع جاوااسکریپت به نام mapUsersById دارم که باید یک آرایه از اشیای کاربر را به یک نگاشت (شیء) که توسط شناسه کاربر کلیدگذاری شده است، تبدیل کند. با این حال، وقتی آن را اجرا می‌کنم، خطا می‌دهد. به‌عنوان مثال، وقتی [{id: 1, name: "Alice"}] را به آن ارسال می‌کنم، TypeError: Cannot read property 'id' of undefined دریافت می‌کنم. کد تابع به شرح زیر است:
    function mapUsersById(users) {
      const userMap = {};
      for (let i = 0; i <= users.length; i++) {  
        const user = users[i];
        userMap[user.id] = user;
      }
      return userMap;
    }
    این تابع باید {"1": {id: 1, name: "Alice"}} را برگرداند. خطا چیست و چگونه می‌توانم آن را رفع کنم؟"
    پاسخ هوش مصنوعی (شبیه‌سازی شده):
    "خطای Cannot read property 'id' of undefined نشان می‌دهد که در نقطه‌ای، متغیر user مقدار undefined دارد و سپس شما سعی می‌کنید به user.id دسترسی پیدا کنید. با نگاهی به حلقه شما، مشکل در محدوده‌های حلقه (Loop Bounds) است. شما از i <= users.length استفاده می‌کنید. اگر users.length برابر با 1 باشد (برای یک کاربر در آرایه)، حلقه با i = 0 و i = 1 اجرا می‌شود. وقتی i برابر با 1 باشد، users[1] مقدار undefined دارد (زیرا تنها ایندکس (Index) در آرایه 0 است). بنابراین user در آن تکرار undefined می‌شود و user.id یک TypeError ایجاد می‌کند. راه‌حل این است که شرط حلقه را به i < users.length تغییر دهید تا i از 0 تا users.length - 1 حرکت کند. به‌عنوان مثال:
    for (let i = 0; i < users.length; i++) {
      const user = users[i];
      userMap[user.id] = user;
    }
    به این ترتیب، i برای اولین (و تنها) عنصر، 0 خواهد بود و سپس حلقه متوقف می‌شود. با این تغییر، تابع شما دیگر با یک user تعریف نشده مواجه نخواهد شد و باید همان‌طور که انتظار می‌رود کار کند و برای ورودی داده شده، {"1": {id: 1, name: "Alice"}} را برگرداند."
    تحلیل: این پاسخ به‌طور مستقیم خطا (استفاده از <= در حلقه) را شناسایی می‌کند و توضیح می‌دهد که چرا باعث undefined شدن user می‌شود. سپس راه‌حل صحیح کد (i < users.length) را ارائه می‌دهد و نتیجه مورد انتظار را تأیید می‌کند. پرسش‌نویسی بهبودیافته موفق بود زیرا از اصول پیروی کرد: زبان (JavaScript) را مشخص کرد، هدف تابع را توضیح داد، پیام خطای دقیق و یک ورودی نمونه را شامل شد و حتی قطعه کد مورد نظر را ارائه داد. توجه داشته باشید که هوش مصنوعی چگونه از پیام خطا به‌عنوان سرنخ برای تمرکز بر محدوده‌های حلقه استفاده کرد – یک پرسش هدفمند هوش مصنوعی را قادر ساخت تا در حل مسئله واقعی مشارکت کند، و به‌طور مؤثر شبیه‌سازی کرد که یک دیباگر (Debugger) انسانی چگونه فکر می‌کند: "از کجا می‌تواند undefined آمده باشد؟ احتمالاً از ایندکس‌گذاری (Indexing) حلقه." این یک نمایش عینی از مزایای پرسش‌نویسی جزئی است.

    تاکتیک‌های اضافی برای اشکال‌زدایی عمیق‌تر
    فراتر از شناسایی خطاهای واضح، می‌توان از مهندسی پرسش‌نویسی (Prompt Engineering) برای کمک به اشکال‌زدایی عمیق‌تر استفاده کرد:
    • پرسش در مورد علل بالقوه: اگر واقعاً گیج شده‌اید، می‌توانید سؤال را کمی گسترش دهید: "برخی دلایل احتمالی برای TypeError: cannot read property 'foo' of undefined در این کد چیست؟" به همراه کد. مدل ممکن است چند سناریو (مثلاً شیء (Object) مقداردهی اولیه نشده، شرایط رقابتی (Race Condition)، دامنه متغیر (Variable Scoping) اشتباه و غیره) را فهرست کند. این می‌تواند به شما زوایای بررسی‌ای را بدهد که به آن‌ها فکر نکرده‌اید. این مانند طوفان فکری (Brainstorming) با یک همکار است.
    • "از اردک لاستیکی بپرس" – یعنی، کد خود را برای هوش مصنوعی توضیح دهید: این ممکن است غیرعادی به نظر برسد (چرا برای دستیار توضیح دهیم؟)، اما عمل نوشتن یک توضیح می‌تواند درک شما را روشن کند و سپس می‌توانید از هوش مصنوعی بخواهید آن را تأیید یا نقد کند. به‌عنوان مثال: "من توضیح خواهم داد که این تابع چه کاری انجام می‌دهد: [توضیح شما]. با توجه به این، آیا استدلال من صحیح است و آیا محل خطا را آشکار می‌کند؟" هوش مصنوعی ممکن است نقصی در توضیح شما پیدا کند که به خطای واقعی اشاره دارد. این تکنیک از هوش مصنوعی به‌عنوان یک اردک لاستیکی فعال استفاده می‌کند که نه تنها گوش می‌دهد، بلکه پاسخ نیز می‌دهد.
    • از هوش مصنوعی بخواهید سناریوهای آزمایشی (Test Cases) ایجاد کند: می‌توانید بپرسید: "آیا می‌توانید چند سناریوی آزمایشی (ورودی) ارائه دهید که ممکن است این تابع را خراب کند؟" دستیار ممکن است به موارد حدی (Edge Cases) که شما به آن‌ها فکر نکرده بودید (آرایه خالی، اعداد بسیار بزرگ، مقادیر null و غیره) دست یابد. این هم برای اشکال‌زدایی و هم برای تولید تست‌ها جهت اطمینان از استحکام آینده (Future Robustness) مفید است.
    • نقش یک بازبین کد (Code Reviewer) را بازی کنید: به‌عنوان جایگزینی برای یک پرسش مستقیم "این را اشکال‌زدایی کن"، می‌توانید بگویید: "به‌عنوان یک بازبین کد عمل کن. این یک قطعه کد است که آن‌طور که انتظار می‌رود کار نمی‌کند. آن را بررسی کن و هرگونه اشتباه یا رویه بد (Bad Practices) را که می‌تواند باعث مشکل شود، نشان بده: [کد]". این هوش مصنوعی را در حالت انتقادی (Critical Mode) قرار می‌دهد. بسیاری از توسعه‌دهندگان در دات‌نت (Microsoft .NET) معتقدند که بیان درخواست به‌عنوان یک بازبینی کد، منجر به تحلیل بسیار کاملی می‌شود، زیرا مدل در مورد هر قسمت از کد نظر می‌دهد (و اغلب در این فرایند، خطا را پیدا می‌کند). این می‌تواند نه تنها خطای مورد نظر، بلکه سایر مسائل (مانند احتمال از دست رفتن بررسی‌های null) را نیز آشکار کند که ممکن است مفید باشند.
    در نهایت، هنگام اشکال‌زدایی با یک دستیار هوش مصنوعی، جزئیات و جهت‌دهی، دوستان شما هستند. سناریو، علائم را ارائه دهید و سپس پرسش‌های هدفمند بپرسید. تفاوت بین یک پرسش‌نویسی ناموفق "کار نمی‌کند، کمک کن!" و یک پرسش‌نویسی دقیق برای اشکال‌زدایی، تفاوت شب و روز است، همان‌طور که در بالا مشاهده شد.

  • وحید نصیری در ۱۴۰۴/۰۳/۰۶ ۲۰:۳۸
    راهنمای پرامپت‌نویسی برای بازآرایی و بهینه‌سازی کد با کمک هوش مصنوعی

    در عصر حاضر، دستیارهای هوش مصنوعی به ابزاری قدرتمند برای بازآرایی (Refactoring) کد، یعنی تمیزتر، سریع‌تر و اصولی‌تر کردن آن بدون تغییر در عملکرد اصلی، تبدیل شده‌اند. این دستیارها با آموزش بر روی حجم عظیمی از کدها، شامل نمونه‌های فراوان از راه‌حل‌های بهینه و ساختارمند، دانش وسیعی را در اختیار دارند. با این حال، برای بهره‌برداری مؤثر از این دانش، لازم است که پرامپت (Prompt) ارسالی شما به هوش مصنوعی به وضوح مشخص کند که "بهتر" در موقعیت شما به چه معناست. در ادامه، الگوهای پرامپت‌نویسی برای وظایف بازآرایی کد تشریح می‌شوند.

    اصول کلیدی برای پرامپت‌های بازآرایی

    1. اهداف بازآرایی خود را به صراحت بیان کنید.
    عبارت‌هایی نظیر "این کد را بازآرایی کن" بسیار کلی و باز هستند و نمی‌توانند هوش مصنوعی را به درستی هدایت کنند. لازم است به صورت دقیق مشخص کنید که آیا هدف شما افزایش خوانایی (Readability)، کاهش پیچیدگی (Complexity)، بهینه‌سازی عملکرد (Performance Optimization) یا استفاده از الگوها و کتابخانه‌های (Libraries) متفاوت است. هوش مصنوعی به یک هدف مشخص نیاز دارد. برای مثال، یک پرامپت خوب می‌تواند این گونه باشد: "تابع (Function) زیر را برای بهبود خوانایی و قابلیت نگهداری (Maintainability) بازآرایی کن (تکرار را کاهش بده، از نام‌های متغیر (Variable Names) واضح‌تر استفاده کن)". یا "این الگوریتم (Algorithm) را برای سرعت بهینه کن – بر روی ورودی‌های (Inputs) بزرگ بسیار کند است". با تعیین اهداف خاص، شما به مدل کمک می‌کنید تا تصمیم بگیرد کدام تبدیل‌ها (Transformations) را اعمال کند. به عنوان مثال، اگر به عملکرد اهمیت می‌دهید، ممکن است از یک الگوریتم مرتب‌سازی (Sorting Algorithm) کارآمدتر یا کشینگ (Caching) استفاده کند، در حالی که تمرکز بر خوانایی ممکن است منجر به تقسیم یک تابع به توابع کوچکتر یا اضافه کردن کامنت‌ها (Comments) شود. در صورت داشتن چندین هدف، آن‌ها را لیست کنید. یک الگوی پرامپت از راهنمای Strapi حتی پیشنهاد می‌کند که مشکلات را نیز به صورت شماره‌گذاری شده ذکر کنید: "مسائلی که می‌خواهم به آن‌ها رسیدگی شود: ۱) [مشکل عملکردی (Performance Issue)]، ۲) [تکرار کد (Code Duplication)]، ۳) [استفاده از API منسوخ (Outdated API Usage)]". به این ترتیب، هوش مصنوعی دقیقاً می‌داند چه چیزی را باید اصلاح کند. به خاطر داشته باشید که هوش مصنوعی ذاتاً نمی‌داند شما چه چیزی را در کد یک مشکل تلقی می‌کنید – این شما هستید که باید به آن بگویید.

    2. زمینه (Context) کد لازم را فراهم کنید.
    هنگام بازآرایی، معمولاً قطعه کدی که نیاز به بهبود دارد را در پرامپت وارد می‌کنید. مهم است که کل تابع یا بخشی که می‌خواهید بازآرایی شود، و گاهی اوقات کمی از زمینه پیرامون آن (مانند نحوه استفاده از تابع یا کد مرتبط که می‌تواند بر نحوه بازآرایی شما تأثیر بگذارد) را نیز لحاظ کنید. همچنین زبان برنامه‌نویسی (Language) و فریم‌ورک (Framework) را ذکر کنید، زیرا کد "اصولی" بین مثلاً Node.js اصولی در مقابل Deno اصولی، یا کامپوننت‌های (Components) کلاس React در مقابل کامپوننت‌های تابعی (Functional Components) متفاوت است. به عنوان مثال: "یک کامپوننت React دارم که به صورت کلاس نوشته شده است. لطفاً آن را به یک کامپوننت تابعی با استفاده از هوک‌ها (Hooks) بازآرایی کن". هوش مصنوعی سپس مراحل معمول (استفاده از useState، useEffect و غیره) را اعمال خواهد کرد. اگر فقط می‌گفتید "این کامپوننت React را بازآرایی کن" بدون مشخص کردن سبک (Style)، هوش مصنوعی ممکن بود نداند که شما به طور خاص هوک‌ها را می‌خواستید. جزئیات مربوط به نسخه (Version) یا محیط (Environment) را در صورت لزوم لحاظ کنید. به عنوان مثال، "این یک پایگاه کد (Codebase) Node.js v14 است" یا "ما از ماژول‌های ES6 استفاده می‌کنیم". این می‌تواند بر استفاده هوش مصنوعی از سینتکس (Syntax) خاص (مانند import/export در مقابل require) تأثیر بگذارد که بخشی از یک بازآرایی صحیح است. اگر می‌خواهید مطمئن شوید که چیزی ناسازگار (Incompatible) را معرفی نمی‌کند، محدودیت‌های خود را ذکر کنید.

    3. درخواست توضیحات همراه با کد را تشویق کنید.
    یک راه عالی برای یادگیری از بازآرایی انجام شده توسط هوش مصنوعی (و برای تأیید صحت آن) این است که درخواست توضیحات در مورد تغییرات را داشته باشید. به عنوان مثال: "لطفاً نسخه بازآرایی شده کد را پیشنهاد کن و بهبودهایی که اعمال کردی را توضیح بده". این حتی در الگوی پرامپت مورد اشاره نیز گنجانده شده بود: "...کد بازآرایی شده را با توضیحات تغییراتت پیشنهاد کن". هنگامی که هوش مصنوعی توضیحات را ارائه می‌دهد، می‌توانید ارزیابی کنید که آیا کد را درک کرده و اهداف شما را برآورده کرده است یا خیر. توضیحات ممکن است بگوید: "دو حلقه (Loops) مشابه را در یک حلقه ترکیب کردم تا تکرار را کاهش دهم، و از یک دیکشنری (Dictionary) برای جستجوهای (Lookups) سریع‌تر استفاده کردم". اگر چیزی در توضیح اشتباه به نظر می‌رسد، این یک هشدار است که کد را با دقت بررسی کنید. به طور خلاصه، از قابلیت هوش مصنوعی برای توضیح به عنوان یک محافظ (Safeguard) استفاده کنید – این مانند این است که هوش مصنوعی یک بازبینی کد (Code Review) بر روی بازآرایی خود انجام دهد.

    4. از ایفای نقش (Role-Play) برای تعیین یک استاندارد بالا استفاده کنید.
    همانطور که پیشتر ذکر شد، درخواست از هوش مصنوعی برای ایفای نقش یک بازبین کد یا یک مهندس ارشد می‌تواند بسیار مؤثر باشد. برای بازآرایی، می‌توانید بگویید: "به عنوان یک متخصص باتجربه TypeScript عمل کن و این کد را برای همسویی با بهترین شیوه‌ها (Best Practices) و استانداردهای مدرن بازآرایی کن". این اغلب نه تنها تغییرات سطحی، بلکه بهبودهای بصیرت‌آمیزتری را به همراه دارد زیرا هوش مصنوعی سعی می‌کند مطابق با شخصیت "متخصص" عمل کند. یک مثال محبوب از راهنمای پرامپت، داشتن هوش مصنوعی در نقش یک مربی (Mentor) است: "مانند یک توسعه‌دهنده باتجربه پایتون که یک توسعه‌دهنده جونیور (Junior) را راهنمایی می‌کند، عمل کن. توضیحات و docstring ها را ارائه بده. کد را برای بهینه‌سازی بازنویسی کن". نتیجه در آن مورد این بود که هوش مصنوعی از یک ساختار داده (Data Structure) کارآمدتر (set برای حذف تکرارها) استفاده کرد و یک راه‌حل تک خطی (One-line Solution) برای تابعی ارائه داد که در ابتدا از یک حلقه استفاده می‌کرد. ایفای نقش به هوش مصنوعی کمک کرد نه تنها بازآرایی کند، بلکه توضیح دهد چرا رویکرد جدید بهتر است (در آن مورد، استفاده از set یک بهینه‌سازی شناخته شده برای منحصر به فرد بودن است).

    مثال بازآرایی: پرامپت ضعیف در مقابل پرامپت هدف‌گرا
    فرض کنید تابعی داریم که دو فراخوانی پایگاه داده (Database Calls) انجام می‌دهد و پردازش‌هایی را انجام می‌دهد. این تابع کار می‌کند، اما ساختار زیبایی ندارد – کد تکراری است و خواندن آن دشوار است. می‌خواهیم آن را برای وضوح و کارایی بازآرایی کنیم. در اینجا نگاهی به دو رویکرد پرامپت‌نویسی داریم:

    ❌ پرامپت 1 (ناقص): "تابع getCombinedData بالا را بازآرایی کن."
    تحلیل: اگرچه هوش مصنوعی ممکن است یک بازآرایی خوب ارائه دهد (مثلاً واکشی (Fetching) موازی، جستجوهای کارآمد)، اما فرضیات زیادی در مورد اولویت‌های شما (مانند عملکرد به جای پیام‌های خطای (Error Messages) خاص) انجام می‌دهد. این خطر تغییرات ناخواسته در رفتار (Behavioral Changes) یا از دست دادن الزامات حیاتی را به همراه دارد. به عنوان مثال، در پاسخ به این پرامپت، هوش مصنوعی ممکن است واکشی‌ها را موازی کرده و رسیدگی به خطاها را ترکیب کند و به یک پیام خطای کلی "Failed to fetch data" بسنده کند، که اطلاعات خاصی در مورد منبع خطا ارائه نمی‌دهد. همچنین ممکن است از یک ordersByUser (دیکشنری برای گروه‌بندی سفارش‌ها) استفاده کند که اگرچه کارآمد است، اما ممکن است با محدودیت‌های خاص شما (مانند نیاز به Stream کردن نتایج) همخوانی نداشته باشد.

    ✅ پرامپت 2 (هدف‌گرا): "تابع getCombinedData بالا را برای حذف کدهای تکراری و بهبود عملکرد بازآرایی کن. به طور خاص: (1) از تکرار منطق (Logic) واکشی برای کاربران و سفارش‌ها خودداری کن – شاید از یک تابع کمکی (Helper) یا واکشی آن‌ها با هم استفاده کن. (2) در صورت امکان هر دو لیست را به صورت موازی واکشی کن. (3) رسیدگی به خطای هر واکشی را حفظ کن (می‌خواهیم بدانیم کدام فراخوانی شکست خورد). (4) ترکیب داده‌ها را بهبود ببخش، احتمالاً با استفاده از یک ساختار کارآمدتر برای جستجو به جای یک حلقه تو در تو (Nested Loop). کد بازآرایی شده را با کامنت‌هایی که تغییرات را توضیح می‌دهند، ارائه کن."
    تحلیل: این پرامپت مستقیماً به تمام اهداف مشخص شده رسیدگی می‌کند. کد به صورت تمیزتر و سریع‌تر بازآرایی شده و پیام‌های خطای جداگانه را همانطور که درخواست شده بود، حفظ کرده است. توضیح هوش مصنوعی نیز هر یک از نکات لیست شده را تأیید می‌کند که نشان می‌دهد دستورالعمل‌های پرامپت را با دقت دنبال کرده است. این یک نتیجه عالی است زیرا ما، به عنوان پرامپت‌نویس، معنای "بازآرایی" را در این زمینه تعریف کردیم. با این کار، هوش مصنوعی را برای تولید راه‌حلی که با حداقل رفت و برگشت با نیازهای ما مطابقت دارد، هدایت کردیم. در این پاسخ، هوش مصنوعی به درستی از Promise.all برای واکشی موازی استفاده کرده، بررسی‌های خطای جداگانه برای usersResponse.ok و ordersResponse.ok را حفظ کرده و برای ترکیب داده‌ها از orders.reduce برای ساخت ordersByUser و سپس از users.map استفاده کرده است که روشی کارآمدتر از حلقه تو در تو است.

    نکات اضافی برای بازآرایی
    • بازآرایی در مراحل: اگر کد بسیار بزرگ است یا لیست بلندی از تغییرات دارید، می‌توانید آن‌ها را یک به یک انجام دهید. به عنوان مثال، ابتدا از هوش مصنوعی بخواهید "برای خوانایی بازآرایی کن" (تمرکز بر تغییر نام، تقسیم توابع)، سپس بعداً "الگوریتم را در این تابع بهینه کن". این کار از بارگذاری بیش از حد مدل با دستورالعمل‌های زیاد جلوگیری می‌کند و به شما امکان می‌دهد هر تغییر را گام به گام تأیید کنید.
    • درخواست رویکردهای جایگزین: شاید اولین بازآرایی هوش مصنوعی کار کند اما در مورد زاویه‌ای متفاوت کنجکاو باشید. می‌توانید بپرسید: "آیا می‌توانی آن را به روشی دیگر بازآرایی کنی، شاید با استفاده از سبک برنامه‌نویسی تابعی (Functional Programming Style) (مثلاً متدهای آرایه (Array Methods) به جای حلقه‌ها)؟" یا "در اینجا به جای رویکرد تکراری (Iterative Approach) از بازگشت (Recursion) استفاده کنی، فقط برای مقایسه؟" به این ترتیب، می‌توانید راه‌حل‌های مختلف را ارزیابی کنید.
    • ترکیب بازآرایی با توضیح برای یادگیری الگوها: از هوش مصنوعی به عنوان یک ابزار یادگیری استفاده کنید. اگر کد را به روشی هوشمندانه بازآرایی می‌کند، خروجی و توضیح آن را مطالعه کنید. ممکن است یک API یا تکنیک جدید (مانند استفاده از reduce برای ساخت یک نقشه (Map)) را کشف کنید که قبلاً از آن استفاده نکرده بودید. این یکی از دلایل درخواست توضیحات است: پاسخ را به یک آموزش کوچک تبدیل می‌کند و درک شما را از بهترین شیوه‌ها تقویت می‌کند.
    • اعتبارسنجی (Validation) و تست (Testing): پس از هر بازآرایی تولید شده توسط هوش مصنوعی، همیشه تست‌های خود را اجرا کنید یا کد را با ورودی‌های نمونه امتحان کنید. هوش مصنوعی ممکن است سهواً باگ‌های ظریفی را معرفی کند، به خصوص اگر پرامپت یک محدودیت مهم را مشخص نکرده باشد. به عنوان مثال، اگر در بازآرایی ما، کد اصلی عمداً خطاهای واکشی را برای لاگ‌گیری (Logging) جدا می‌کرد اما ما لاگ‌گیری را ذکر نکردیم، خطای ترکیبی ممکن است کمتر مفید باشد. وظیفه ماست که آن را در بازبینی (Review) شناسایی کنیم. هوش مصنوعی می‌تواند با نوشتن تست‌ها نیز کمک کند – می‌توانید بپرسید: "چند تست واحد (Unit Tests) برای تابع بازآرایی شده تولید کن" تا مطمئن شوید که همانند قبل بر روی ورودی‌های مورد انتظار رفتار می‌کند.

  • وحید نصیری در ۱۴۰۴/۰۳/۰۶ ۲۰:۴۴
    الگوهای پرامپت‌نویسی برای پیاده‌سازی قابلیت‌های جدید در برنامه‌نویسی

    هوش مصنوعی (AI) به عنوان ابزاری قدرتمند برای کمک به برنامه‌نویسان در نوشتن کدهای جدید از پایه یا ادغام قابلیت‌های تازه در پایگاه‌های کد (codebase) موجود، نقش فزاینده‌ای ایفا می‌کند. این کمک می‌تواند از تولید کدهای بویلرپلیت (boilerplate) برای یک کامپوننت (component) ری‌اکت (React) گرفته تا نوشتن یک نقطه پایانی (API endpoint) جدید در یک برنامه اکسپرس (Express) را شامل شود. چالش اصلی در این وظایف، ماهیت باز آن‌هاست، به این معنی که راه‌های متعددی برای پیاده‌سازی یک قابلیت وجود دارد. مهندسی پرامپت (Prompt Engineering) برای تولید کد، به معنای هدایت هوش مصنوعی برای تولید کدهایی است که با نیازها و سبک برنامه‌نویسی شما همخوانی دارد. در ادامه، استراتژی‌هایی برای دستیابی به این هدف ارائه شده است.

    استراتژی‌های هدایت هوش مصنوعی در تولید کد
    یکی از مؤثرترین رویکردها، شروع با دستورالعمل‌های سطح بالا و سپس جزئی‌تر شدن است. در ابتدا، آنچه را که می‌خواهید بسازید، به زبان ساده و کلی بیان کنید و در صورت لزوم، آن را به وظایف کوچک‌تر تقسیم کنید. به عنوان مثال، برای افزودن قابلیت نوار جستجو (search bar) به یک برنامه وب (web app) موجود، می‌توانید ابتدا پرامپت (prompt) دهید: "طرحی برای افزودن قابلیت جستجو که لیست محصولات را بر اساس نام در برنامه ری‌اکت من فیلتر می‌کند، ارائه دهید. محصولات از یک API دریافت می‌شوند." هوش مصنوعی ممکن است یک برنامه گام به گام ارائه دهد، مانند: "1. افزودن یک فیلد ورودی (input field) برای عبارت جستجو. 2. افزودن استیت (state) برای نگهداری عبارت جستجو. 3. فیلتر کردن لیست محصولات بر اساس عبارت جستجو. 4. اطمینان از عدم حساسیت به حروف بزرگ و کوچک (case-insensitive)." پس از دریافت این طرح، می‌توانید با پرامپت‌های متمرکز، هر یک از مراحل را پیگیری کنید، مثلاً: "اکنون، مرحله 1 را پیاده‌سازی کنید: یک کامپوننت SearchBar با یک ورودی که استیت searchQuery را به‌روزرسانی می‌کند، ایجاد کنید." تقسیم یک قابلیت به بخش‌های کوچک‌تر، تضمین می‌کند که هر پرامپت مشخص و پاسخ‌های هوش مصنوعی قابل مدیریت باشد و روند توسعه تکراری (iterative development) را شبیه‌سازی می‌کند.

    ارائه زمینه یا کد مرجع مرتبط به هوش مصنوعی در پیاده‌سازی قابلیت‌های جدید بسیار کمک می‌کند. اگر در حال افزودن یک قابلیت به یک پروژه موجود هستید، نشان دادن نحوه انجام کارهای مشابه در آن پروژه بسیار مفید است. برای مثال، اگر از قبل یک کامپوننت مشابه دارید، می‌توانید بگویید: "این یک کامپوننت UserList موجود است (کد...). اکنون یک کامپوننت ProductList مشابه آن ایجاد کنید، اما شامل یک نوار جستجو باشد." هوش مصنوعی الگوها (مانند استفاده از کتابخانه‌های خاص یا قراردادهای سبک‌نویسی) را تشخیص داده و آن‌ها را اعمال خواهد کرد. باز نگه داشتن فایل‌های مرتبط یا ارجاع به آن‌ها در پرامپت، زمینه‌ای را فراهم می‌کند که منجر به پیشنهادهای کدهای خاص‌تر و سازگارتر با پروژه می‌شود. همچنین، اگر پروژه شما از یک سبک کدنویسی یا معماری خاص (مانند Redux برای مدیریت استیت یا یک فریم‌ورک (framework) CSS خاص) استفاده می‌کند، آن را ذکر کنید، مثلاً: "ما از Redux برای مدیریت استیت استفاده می‌کنیم – استیت جستجو را در Redاکس استور (Redux store) ادغام کنید." یک مدل آموزش‌دیده، کدی را تولید خواهد کرد که با الگوهای Redux سازگار است. این کار در واقع به هوش مصنوعی می‌آموزد که محیط پروژه شما چگونه است تا بتواند خروجی را متناسب با آن تنظیم کند. حتی اگر چیزی را از ابتدا شروع می‌کنید اما رویکرد ترجیحی دارید، می‌توانید آن را نیز ذکر کنید: "من می‌خواهم این را با استفاده از سبک برنامه‌نویسی تابعی (functional programming style) پیاده‌سازی کنم (بدون استیت خارجی، با استفاده از متدهای آرایه)." یا "اطمینان حاصل کنید که الگوی MVC را دنبال کرده و منطق را در کنترلر (controller) قرار دهید، نه در ویو (view)."

    استفاده از کامنت‌ها (comments) و TODOها به عنوان پرامپت‌های درون خطی (inline prompts) یک گردش کار (workflow) مؤثر است، به ویژه هنگام کار مستقیم در یک محیط توسعه یکپارچه (IDE) با ابزارهایی مانند Copilot. در یک بک‌اند (backend) Node.js، می‌توانید بنویسید: // TODO: Validate the request payload (ensure name and email are provided) و سپس خط بعدی را شروع کنید. Copilot اغلب قصد شما را درک کرده و یک بلوک کد برای انجام آن اعتبارسنجی (validation) تولید می‌کند. این روش مؤثر است زیرا کامنت شما عملاً یک پرامپت زبان طبیعی (natural language prompt) است. با این حال، همیشه آماده باشید تا کد تولید شده را در صورت سوءتفسیر هوش مصنوعی ویرایش کنید.

    ارائه مثال‌هایی از ورودی/خروجی (input/output) یا کاربرد مورد انتظار نیز بسیار مفید است. اگر از هوش مصنوعی می‌خواهید یک تابع جدید را پیاده‌سازی کند، یک مثال سریع از نحوه استفاده از آن یا یک مورد آزمایشی (test case) ساده را نیز در پرامپت خود بگنجانید. به عنوان مثال: "تابعی به نام formatPrice(amount) در جاوااسکریپت (JavaScript) پیاده‌سازی کنید که یک عدد (مانند 2.5) را می‌گیرد و یک رشته (string) قالب‌بندی شده به دلار آمریکا (مانند '$2.50') را برمی‌گرداند. به عنوان مثال، formatPrice(2.5) باید '$2.50' را برگرداند." با ارائه این مثال، هوش مصنوعی را مجبور می‌کنید تابعی سازگار با آن تولید کند. بدون مثال، هوش مصنوعی ممکن است قالب‌بندی یا ارز دیگری را فرض کند که می‌تواند تفاوت ظریفی اما مهم باشد. در یک محیط وب (web context): "یک میان‌افزار (middleware) اکسپرس پیاده‌سازی کنید که درخواست‌ها را ثبت می‌کند. به عنوان مثال، یک درخواست GET به /users باید 'GET /users' را در کنسول (console) ثبت کند." این امر خروجی مورد انتظار را شفاف می‌کند.

    هنگامی که نتیجه مورد نظر شما نیست، پرامپت را با جزئیات یا محدودیت‌های بیشتر بازنویسی کنید. این اتفاق که اولین تلاش برای تولید یک قابلیت جدید به هدف نخورد، رایج است. شاید کد اجرا می‌شود اما مناسب نیست، یا یک نیاز را از دست داده است. به جای ناامید شدن، با هوش مصنوعی مانند یک توسعه‌دهنده تازه‌کار رفتار کنید که پیش‌نویس اول را ارائه کرده است – اکنون باید بازخورد دهید. به عنوان مثال، "راه حل کار می‌کند اما من ترجیح می‌دهم که به جای حلقه for از متد داخلی array filter استفاده کنید." یا "آیا می‌توانید کامپوننت تولید شده را بازسازی کنید تا از React Hooks برای استیت به جای یک کامپوننت کلاس (class component) استفاده کند؟ پایگاه کد ما همگی کامپوننت‌های تابعی هستند." همچنین می‌توانید محدودیت‌های جدیدی اضافه کنید: "همچنین، اطمینان حاصل کنید که تابع در زمان O(n) یا بهتر اجرا می‌شود، زیرا n می‌تواند بزرگ باشد." این پرامپت‌نویسی تکراری بسیار قدرتمند است. نکته مهم این است که پس از یک بار تلاش دست از کار نکشید. مشخص کنید که در پرامپت چه چیزی کمبود داشت یا به اشتباه درک شد و آن را شفاف کنید. این جوهره مهندسی پرامپت است – هر تغییر می‌تواند مدل را به آنچه در ذهن دارید نزدیک‌تر کند.

    مثال پیاده‌سازی قابلیت: ساخت یک کامپوننت ری‌اکت با کمک هوش مصنوعی
    فرض کنید یک برنامه ری‌اکت (React application) داریم و می‌خواهیم یک کامپوننت جدید اضافه کنیم: یک لیست محصول با فیلتر جستجو و یک منوی کشویی (dropdown) مرتب‌سازی. این یک قابلیت نسبتاً معمول در یک برنامه وب است. در اینجا، برای ایجاز، بر روی پرامپت‌نویسی برای قابلیت جستجو در این کامپوننت تمرکز می‌کنیم.
    پرامپت اولیه (درخواست قابلیت): "یک کامپوننت تابعی ری‌اکت به نام ProductList ایجاد کنید که لیستی از محصولات را نمایش می‌دهد و شامل یک ورودی متنی برای فیلتر کردن محصولات بر اساس نام است. این کامپوننت باید: آرایه‌ای از محصولات را از /api/products دریافت کند (فرض کنید یک آرایه JSON از {id, name, ...} برمی‌گرداند)، آن‌ها را در استیت ذخیره کند، و به کاربر اجازه دهد تا در یک کادر جستجو تایپ کند تا محصولات نمایش داده شده را بر اساس نام فیلتر کند (مطابقت بدون حساسیت به حروف بزرگ و کوچک). لیست فیلتر شده را در یک ساده با نام محصولات نمایش دهید. شامل مدیریت خطای اولیه (مانند نمایش پیام خطا در صورت عدم موفقیت فراخوانی API) و یک استیت بارگذاری (loading state) در حین دریافت اطلاعات باشد."
    این یک پرامپت طولانی اما بسیار خاص است که به یک مدل زبان بزرگ (LLM) داده می‌شود.
    پاسخ هوش مصنوعی (خلاصه‌ای از آنچه ممکن است تولید کند): هوش مصنوعی احتمالاً یک کامپوننت ProductList تولید می‌کند که شامل: وارد کردن React, useState, useEffect است؛ استیت‌هایی برای products, search, loading, error تعریف می‌کند؛ از useEffect برای دریافت محصولات از /api/products به صورت ناهمزمان (async) استفاده می‌کند، شامل مدیریت خطا و استیت بارگذاری است؛ تابعی به نام handleSearchChange برای به‌روزرسانی استیت جستجو دارد؛ محصولات را بر اساس عبارت جستجو (بدون حساسیت به حروف بزرگ و کوچک) فیلتر می‌کند؛ و در نهایت، رندر (render) کامپوننت شامل نمایش استیت‌های بارگذاری و خطا، یک input برای جستجو، و یک ul برای نمایش محصولات فیلتر شده است. (احتمالاً همراه با کامنت‌هایی (comments) در کد که هر بخش را توضیح می‌دهند، اگر درخواست شده باشد.)

    تحلیل نتیجه و ملاحظات برای بهبود پرامپت:
    فرض کنید کد فوق بازگشته است، اما پروژه ما از یک کانتکست (context) یا یک مخزن سراسری (global store) برای دریافت داده‌ها استفاده می‌کند، به جای دریافت مستقیم در کامپوننت. این چیزی است که ما در ابتدا مشخص نکرده بودیم. هوش مصنوعی انتخابی را برای دریافت داده‌ها در useEffect انجام داده است. اگر ما ترجیح می‌دهیم از یک هوک (hook) سفارشی (custom hook) یا کانتکست استفاده کنیم، باید در پرامپت خود به آن اشاره می‌کردیم. بنابراین می‌توانیم پرامپت خود را اصلاح کنیم: "در واقع، در برنامه ما از یک هوک سفارشی useProducts() استفاده می‌کنیم که قبلاً دریافت داده‌ها را انجام می‌دهد. لطفاً کامپوننت را بازسازی کنید تا به جای فراخوانی مستقیم Workspace، از هوک useProducts استفاده کند." هوش مصنوعی سپس تنظیمات لازم را انجام می‌دهد، احتمالاً فرض می‌کند که useProducts یک آبجکت شامل products, loading, error را برمی‌گرداند و کامپوننت را بر این اساس ساده‌تر می‌کند.
    یک بهبود دیگر: شاید متوجه شویم که یک منوی کشویی مرتب‌سازی نیز می‌خواهیم (که در ابتدا ذکر نکردیم). اکنون می‌توانیم مکالمه را گسترش دهیم: "بسیار عالی، اکنون یک منوی کشویی برای مرتب‌سازی محصولات بر اساس نام (A-Z یا Z-A) اضافه کنید. این منو باید به کاربر اجازه دهد تا صعودی یا نزولی را انتخاب کند و لیست باید علاوه بر فیلتر کردن، بر این اساس مرتب شود." از آنجایی که هوش مصنوعی زمینه کد موجود را دارد، می‌تواند یک استیت مرتب‌سازی اضافه کرده و رندر را تنظیم کند. ما یک نیاز جدید و واضح را ارائه کردیم و هوش مصنوعی سعی خواهد کرد آن را برآورده کند، احتمالاً با اضافه کردن چیزی شبیه به: const [sortOrder, setSortOrder] = useState('asc'); و یک ورودی select برای sortOrder و مرتب‌سازی filteredProducts قبل از رندر: const sortedProducts = [...filteredProducts].sort((a, b) => { if (sortOrder === 'asc') return a.name.localeCompare(b.name); else return b.name.localeCompare(a.name); }); (به علاوه رابط کاربری (UI) منوی کشویی).
    با تکرار به این شیوه، قابلیت به قابلیت، یک چرخه توسعه با هوش مصنوعی را شبیه‌سازی می‌کنیم. این روش بسیار مؤثرتر از تلاش برای پرامپت‌نویسی برای کل کامپوننت پیچیده با تمام قابلیت‌های آن در یک مرحله اولیه است. این کار اشتباهات را کاهش می‌دهد و امکان اصلاحات در میانه راه را فراهم می‌کند. اگر هوش مصنوعی یک اشتباه ظریف مرتکب شود (مثلاً فراموش کند فیلتر جستجو را بدون حساسیت به حروف بزرگ و کوچک کند)، کافی است به آن اشاره کنیم: "جستجو را بدون حساسیت به حروف بزرگ و کوچک کنید." هوش مصنوعی فیلتر را برای استفاده از مقایسه حروف کوچک (که در خروجی ما قبلاً انجام شده بود، اما اگر نبود آن را اصلاح می‌کرد) تنظیم خواهد کرد.
    این مثال نشان می‌دهد که پیاده‌سازی قابلیت‌ها با هوش مصنوعی، تماماً در مورد توسعه افزایشی (incremental development) و بهبود پرامپت است. هر پرامپت مانند یک کامیت (commit) در فرآیند توسعه شماست.

    نکات اضافی برای پیاده‌سازی قابلیت‌ها
    در برخی مواقع، بهتر است اجازه دهید هوش مصنوعی ساختار اولیه (scaffold) را تولید کند، سپس شما جزئیات خاص را پر کنید. به عنوان مثال، می‌توانید از هوش مصنوعی بخواهید: "اسکلت یک مسیر (route) اکسپرس Node.js را برای ثبت نام کاربر با اعتبارسنجی و مدیریت خطا تولید کنید." هوش مصنوعی ممکن است یک مسیر عمومی با جای‌گیرنده‌ها (placeholders) تولید کند. سپس می‌توانید قوانین اعتبارسنجی واقعی یا فراخوانی‌های پایگاه داده (database calls) را که خاص برنامه شما هستند، پر کنید. این روش باعث می‌شود هوش مصنوعی شما را از نوشتن کدهای بویلرپلیت نجات دهد و شما می‌توانید منطق سفارشی (custom logic) را در صورت حساسیت مدیریت کنید.
    هنگام تولید یک قابلیت، می‌توانید از هوش مصنوعی بخواهید تا موارد لبه (edge cases) را در نظر بگیرد: "چه موارد لبه‌ای را باید برای این قابلیت در نظر بگیریم (و آیا می‌توانید آن‌ها را در کد مدیریت کنید)؟" برای مثال، در مثال جستجو، یک مورد لبه ممکن است این باشد که "اگر محصولات هنوز بارگذاری نشده باشند، وقتی کاربر تایپ می‌کند چه می‌شود؟" (اگرچه کد ما این را از طریق استیت بارگذاری مدیریت می‌کند) یا "اگر دو محصول نام یکسانی داشته باشند چه می‌شود؟" (مشکل بزرگی نیست اما شاید لازم باشد ذکر شود). هوش مصنوعی می‌تواند مواردی مانند مدیریت نتایج خالی، لیست‌های بسیار بزرگ (که ممکن است نیاز به دی‌بونس (debounce) برای ورودی جستجو داشته باشند) و غیره را ذکر کند. این روشی برای استفاده از آموزش هوش مصنوعی در مورد مشکلات رایج است.

    توسعه مبتنی بر داکیومنت‌نویسی (Documentation-driven development) یک رویکرد هوشمندانه است که برخی از توسعه‌دهندگان از آن استفاده می‌کنند؛ ابتدا یک داک‌استرینگ (docstring) یا مثال کاربرد را می‌نویسند و سپس از هوش مصنوعی می‌خواهند تابع را متناسب با آن پیاده‌سازی کند. به عنوان مثال:
    /**
     * Returns the nth Fibonacci number.
     * @param {number} n - The position in Fibonacci sequence (0-indexed).
     * @returns {number} The nth Fibonacci number.
     * * Example: fibonacci(5) -> 5  (sequence: 0,1,1,2,3,5,…)
     */
    function fibonacci(n) {
      // ... implementation
    }
    اگر کامنت و امضای تابع (function signature) بالا را بنویسید، یک مدل زبان بزرگ (LLM) ممکن است پیاده‌سازی را به درستی پر کند، زیرا کامنت دقیقاً آنچه را که باید انجام شود توضیح می‌دهد و حتی یک مثال ارائه می‌دهد. این تکنیک تضمین می‌کند که ابتدا قابلیت را به صورت نوشتاری (که به طور کلی یک تمرین خوب است) شفاف می‌کنید، و سپس هوش مصنوعی از آن به عنوان مشخصات (spec) برای نوشتن کد استفاده می‌کند.

    • هادی مزارعی در ۱۴۰۴/۰۳/۰۷ ۰۹:۴۱
      به نظرم رسید یکبار پاسخ یک سوالم از هوش مصنوعی هنوز جای کار داره. مجدد قطعه کد را با همراه کامنت‌های فارسی براش ارسال کردم و اعلام کردم که کامنت رو ابتدا از فارسی به انگلیسی ترجمه کنه و بعد با توجه به سوال اول و مطالعه کامنت، کد را Refactor کنه. حالا نتیجه دلخواه تولید شد. یا مثلا زمانی که چندین بار اعلام کردم بازخورد کدهای تولید شده را در ادامه گفتگوی جاری اعلام میکنم، یاد گرفته چک لیست ساده‌ای از وضعیت اجرای کد ارائه میکنه که در زمان اعلام بازخورد، حتما اطلاعاتی در اون زمینه ارائه کنم.
  • وحید نصیری در ۱۴۰۴/۰۳/۰۶ ۲۰:۵۲
    الگوهای نامناسب در پرامپت‌نویسی و راهکارهای اجتناب از آن‌ها

    در توسعه نرم‌افزار و کار با مدل‌های هوش مصنوعی، کیفیت پرامپت‌ها (Prompts) نقش حیاتی در دریافت پاسخ‌های دقیق و مفید ایفا می‌کند. این مطلب به بررسی الگوهای نامناسب رایج (Anti-Patterns) در پرامپت‌نویسی و چگونگی رفع آن‌ها می‌پردازد تا برنامه‌نویسان دات‌نت بتوانند تعاملات مؤثرتری با مدل‌های هوش مصنوعی داشته باشند.

    پرامپت مبهم (The Vague Prompt)
    پرامپت مبهم حالتی است که کاربر اطلاعات کافی به مدل هوش مصنوعی نمی‌دهد، مانند پرسیدن «چرا تابع (function) من کار نمی‌کند؟» بدون ارائه جزئیات بیشتر. این ابهام باعث می‌شود مدل مجبور به حدس زدن زمینه (context) شود و اغلب پاسخ‌هایی کلی یا نامرتبط ارائه دهد. برای حل این مشکل، باید اطلاعات و جزئیات بیشتری به پرامپت اضافه کرد. به عنوان مثال، ارائه پیام‌های خطا (error messages)، بخش‌هایی از کد (code excerpt)، یا توضیح خروجی مورد انتظار در مقابل خروجی واقعی (expected vs. actual outcome) می‌تواند بسیار کمک‌کننده باشد. یک روش خوب این است که پرامپت خود را مرور کنید و از خود بپرسید: «آیا این سوال می‌تواند در ده‌ها سناریو (scenario) مختلف کاربرد داشته باشد؟» اگر پاسخ مثبت است، پرامپت بیش از حد مبهم است و باید آن را تا جایی خاص (specific) کرد که تنها در سناریوی شما قابل اعمال باشد.

    پرامپت با بار زیاد (The Overloaded Prompt)
    این الگو نقطه مقابل پرامپت مبهم است، یعنی از مدل هوش مصنوعی خواسته می‌شود همزمان کارهای زیادی را انجام دهد. به عنوان مثال، «یک برنامه (app) کامل Node.js با احراز هویت (authentication)، فرانت‌اند (front-end) در React و اسکریپت‌های (scripts) استقرار (deployment) تولید کن.» یا حتی در مقیاس کوچک‌تر، «این 5 باگ (bug) را رفع کن و این 3 ویژگی (feature) را هم اضافه کن.» در چنین مواردی، مدل ممکن است تلاش کند همه درخواست‌ها را برآورده کند، اما نتیجه احتمالا نامرتب یا ناقص خواهد بود و یا ممکن است برخی از قسمت‌های درخواست نادیده گرفته شوند. حتی اگر مدل همه موارد را پوشش دهد، پاسخ طولانی خواهد بود و بررسی آن دشوارتر می‌شود. راه حل این است که وظایف را تقسیم (split) کنید. باید اولویت‌بندی کرد و هر بار یک کار را انجام داد. این کار باعث می‌شود پیدا کردن اشتباهات آسان‌تر شود و مدل تمرکز خود را حفظ کند. اگر متوجه شدید که در دستورالعمل‌های خود از چندین «و» (and) استفاده می‌کنید، بهتر است درخواست را به پرامپت‌های جداگانه یا مراحل متوالی (sequential steps) تقسیم کنید.

    عدم وجود سوال (Missing the Question)
    گاهی اوقات کاربران مقدار زیادی اطلاعات ارائه می‌دهند، اما هرگز به وضوح سوالی نمی‌پرسند یا مشخص نمی‌کنند که چه چیزی نیاز دارند. به عنوان مثال، فقط یک بخش بزرگ از کد را کپی کرده و می‌گویند: «این کد من است.» این کار می‌تواند مدل هوش مصنوعی را سردرگم کند، زیرا نمی‌داند شما چه می‌خواهید. همیشه باید یک درخواست واضح (clear ask) در پرامپت گنجانده شود، مانند «هر گونه باگ در کد بالا را شناسایی کن»، «توضیح بده این کد چه کاری انجام می‌دهد» یا «TODOها را در کد تکمیل کن». یک پرامپت باید هدفمند باشد. اگر فقط متن بدون سوال یا دستورالعمل ارائه دهید، مدل ممکن است فرضیات (assumptions) نادرستی داشته باشد (مانند خلاصه‌سازی کد به جای رفع اشکال آن). مطمئن شوید که مدل می‌داند چرا شما کدی را به آن نشان داده‌اید. حتی یک افزودن ساده مانند «چه مشکلی در این کد وجود دارد؟» یا «لطفاً اجرای این تابع را ادامه بده.» به آن جهت می‌دهد.

    معیارهای موفقیت مبهم (Vague Success Criteria)
    این مورد ظریف‌تر است؛ گاهی اوقات ممکن است بهینه‌سازی (optimization) یا بهبودی را درخواست کنید، اما تعریف نکنید که موفقیت چگونه به نظر می‌رسد. به عنوان مثال، «این تابع را سریع‌تر کن.» سریع‌تر بر اساس کدام معیار؟ اگر مدل هوش مصنوعی محدودیت‌های عملکرد (performance constraints) شما را نداند، ممکن است چیزی را که اهمیتی ندارد، به صورت جزئی بهینه کند (micro-optimize) یا از رویکردی (approach) استفاده کند که از نظر تئوری سریع‌تر است اما در عمل ناچیز به شمار می‌رود. یا «این کد را تمیزتر کن» – «تمیزتر» یک مفهوم ذهنی (subjective) است. این مشکل با بیان صریح اهداف (goals) مانند «کاهش تکرار (duplication)» یا «بهبود نام متغیرها (variable names)» حل می‌شود. راه حل: بهبود را کمی یا کیفی کنید. به عنوان مثال، «این تابع را برای اجرا در زمان خطی (linear time) بهینه کن (نسخه فعلی از نوع درجه دوم (quadratic) است)» یا «این را بازآرایی (refactor) کن تا متغیرهای سراسری (global variables) حذف شوند و به جای آن از یک کلاس (class) استفاده شود.» اساساً، در مورد اینکه با بازآرایی یا ویژگی (feature) چه مشکلی را حل می‌کنید، صریح باشید. اگر آن را بیش از حد باز بگذارید، مدل هوش مصنوعی ممکن است مشکلی متفاوت از آنچه شما به آن اهمیت می‌دهید را حل کند.

    نادیده گرفتن درخواست و یا خروجی هوش مصنوعی (Ignoring AI’s Clarification or Output)
    گاهی اوقات مدل هوش مصنوعی ممکن است با یک سوال روشن‌کننده (clarifying question) یا فرضیه (assumption) پاسخ دهد. به عنوان مثال: «آیا از کامپوننت‌های (components) کلاس React استفاده می‌کنید یا کامپوننت‌های تابعی (functional components)؟» یا «من فرض می‌کنم ورودی یک رشته (string) است – لطفاً تأیید کنید.» اگر این موارد را نادیده بگیرید و فقط درخواست خود را تکرار کنید، فرصت بهبود پرامپت را از دست می‌دهید. مدل هوش مصنوعی در حال سیگنال دادن است که به اطلاعات بیشتری نیاز دارد. همیشه به سوالات آن پاسخ دهید یا پرامپت خود را اصلاح کنید تا آن جزئیات را در بر گیرد. علاوه بر این، اگر خروجی مدل هوش مصنوعی به وضوح اشتباه است (مثلاً سوال را اشتباه متوجه شده است)، فقط همان پرامپت را عیناً تکرار نکنید. لحظه‌ای مکث کنید و عبارت‌بندی (wording) خود را تنظیم کنید. شاید پرامپت شما عبارتی مبهم (ambiguous phrase) داشت یا چیزی ضروری را حذف کرده بود. با آن مانند یک مکالمه (conversation) رفتار کنید – اگر یک انسان اشتباه متوجه می‌شد، شما به گونه‌ای متفاوت توضیح می‌دادید؛ همین کار را برای مدل هوش مصنوعی نیز انجام دهید.

    سبک متغیر یا ناسازگاری (Varying Style or Inconsistency)
    اگر مدام نحوه سوال پرسیدن را تغییر دهید یا فرمت‌های (formats) مختلف را به صورت همزمان مخلوط کنید، مدل ممکن است سردرگم شود. به عنوان مثال، تغییر بین حالت اول شخص (first-person) و سوم شخص (third-person) در دستورالعمل‌ها، یا مخلوط کردن شبه‌کد (pseudocode) با کد واقعی (actual code) به روشی گیج‌کننده. سعی کنید یک سبک ثابت (consistent style) را در یک پرامپت حفظ کنید. اگر مثال‌هایی ارائه می‌دهید، مطمئن شوید که به وضوح مشخص شده‌اند (از علامت‌های نقل قول (triple backticks) Markdown برای کد، و نقل قول (quotes) برای مثال‌های ورودی/خروجی (input/output) استفاده کنید). سازگاری به مدل کمک می‌کند تا هدف (intent) شما را به درستی تجزیه کند. همچنین، اگر سبک ترجیحی دارید (مثلاً سینتکس (syntax) ES6 در مقابل ES5)، به طور مداوم آن را ذکر کنید، در غیر این صورت مدل ممکن است در یک پرامپت یک روش و در پرامپت بعدی روش دیگری را پیشنهاد دهد.

    ارجاعات مبهم (Vague References) مانند "کد بالا"
    هنگام استفاده از چت، اگر بگویید «تابع بالا» یا «خروجی قبلی»، مطمئن شوید که ارجاع (reference) واضح است. اگر مکالمه طولانی باشد و بگویید «کد بالا را بازآرایی کن»، مدل هوش مصنوعی ممکن است مسیر را گم کند یا بخش کد اشتباهی را برای بازآرایی انتخاب کند. ایمن‌تر است که یا کد را دوباره نقل قول کنید یا نام تابع مورد نظر برای بازآرایی را به طور خاص ذکر کنید. مدل‌ها پنجره توجه (attention window) محدودی دارند، و اگرچه بسیاری از مدل‌های زبان بزرگ (LLMs) می‌توانند به بخش‌های قبلی مکالمه اشاره کنند، ارائه مجدد زمینه (context) صریح (explicit) می‌تواند به جلوگیری از سردرگمی کمک کند. این امر به ویژه اگر زمان (یا چندین پیام) از نمایش کد گذشته باشد، صادق است.

    رویکرد تاکتیکی برای بازنویسی پرامپت‌ها در صورت عدم موفقیت
    اگر پاسخ مدل هوش مصنوعی مطابق انتظار نبود، یک رویکرد تاکتیکی برای بازنویسی پرامپت‌ها وجود دارد:
    ابتدا مشخص کنید چه چیزی در پاسخ مدل هوش مصنوعی کم یا نادرست بود. آیا مشکل متفاوتی را حل کرد؟ آیا خطا یا راه‌حلی تولید کرد که مناسب نیست؟ به عنوان مثال، شاید شما راه‌حلی در TypeScript درخواست کردید اما مدل جاوااسکریپت (JavaScript) ساده ارائه داد. یا یک راه‌حل بازگشتی (recursive) نوشت در حالی که شما صراحتاً یک راه‌حل تکراری (iterative) می‌خواستید. باید عدم تطابق (discrepancy) را دقیقاً مشخص کنید.
    سپس، آن نیاز را در یک پرامپت جدید اضافه یا تأکید کنید. می‌توانید بگویید: «راه‌حل باید در TypeScript باشد، نه جاوااسکریپت. لطفاً توضیحات نوع (type annotations) را شامل شود.» یا «من اشاره کردم که یک راه‌حل تکراری می‌خواهم – لطفاً از بازگشت (recursion) اجتناب کن و به جای آن از یک حلقه (loop) استفاده کن.» گاهی اوقات استفاده از عباراتی مانند «توجه (Note):» یا «مهم (Important):» در پرامپت برای برجسته کردن محدودیت‌های کلیدی (key constraints) کمک‌کننده است (مدل احساسات (emotions) ندارد، اما برخی از عبارت‌بندی‌ها را نشان‌دهنده اهمیت می‌داند). به عنوان مثال: «مهم: برای این کار از هیچ کتابخانه (library) خارجی استفاده نکنید.» یا «توجه: کد باید در مرورگر (browser) اجرا شود، بنابراین هیچ API (Application Programming Interface) خاص Node را شامل نشود.»
    در صورت نیاز، درخواست را بیشتر تفکیک (break down) کنید. اگر مدل هوش مصنوعی بارها در یک درخواست پیچیده شکست می‌خورد، ابتدا سعی کنید یک بخش کوچک‌تر را درخواست کنید. یا سوالی بپرسید که ممکن است وضعیت را روشن کند: «آیا متوجه می‌شوی منظور من از X چیست؟» مدل ممکن است آنچه را که فکر می‌کند شما منظور دارید، بازنویسی (paraphrase) کند و شما می‌توانید آن را در صورت اشتباه بودن تصحیح کنید. این همان فرادادپرامپت‌نویسی (meta-prompting) است – بحث در مورد خود پرامپت – و گاهی اوقات می‌تواند سوء تفاهم‌ها (misunderstandings) را حل کند.
    در نهایت، اگر رشته گفتگو گیر کرده است، شروع مجدد را در نظر بگیرید. گاهی اوقات پس از چندین تلاش، مکالمه ممکن است به یک حالت سردرگمی برسد. شروع یک جلسه جدید (یا پاک کردن تاریخچه چت (chat history) برای لحظه‌ای) و پرامپت از ابتدا با یک درخواست اصلاح‌شده (refined ask) که بر اساس شکست‌های قبلی فرموله کرده‌اید، می‌تواند کمک‌کننده باشد. مدل از تکرار (repetition) ناراحت نمی‌شود، و یک زمینه تازه (fresh context) می‌تواند هرگونه سردرگمی انباشته شده از پیام‌های قبلی را از بین ببرد.
    با آگاهی از این الگوهای نامناسب و راهکارهای آن‌ها، در تنظیم سریع پرامپت‌های خود بسیار سریع‌تر خواهید شد. مهندسی پرامپت (Prompt engineering) برای توسعه‌دهندگان (developers) یک فرآیند تکراری (iterative) و بازخوردمحور (feedback-driven) است (همانطور که هر کار برنامه‌نویسی (programming task) نیز هست). خبر خوب این است که اکنون ابزارها و مثال‌های زیادی در جعبه ابزار (toolkit) خود دارید تا از آن‌ها استفاده کنید.