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

Run-Log-Distill: حذف خطاهای تکراری با استفاده از فایل‌های کالبدشکافی

·۲۱ تیر ۱۴۰۵۱۷ دقیقه مطالعه۱ بازدید
راهنما
اجرای کد، ثبت لاگ، استخراج دانش: حافظه‌ای خودبهبودیافته برای توسعه با هوش مصنوعی
اجرای کد، ثبت لاگ، استخراج دانش: حافظه‌ای خودبهبودیافته برای توسعه با هوش مصنوعی
اشتراک‌گذاری
واقعاً چه چیز جدید است؟

معرفی مکانیسم Run-Log-Distill برای تبدیل لاگ‌های خام جلسه به قوانین معماری دائمی؛ تفکیک صریح بین حافظه اپیزودیک (Sessional) و حافظه معنایی (Project Law).

تصور کنید یک برنامه‌نویس ساعت‌ها وقت صرف رفع یک باگ پیچیده در 공유 وضعیت (state-sharing) در تاریخ ۱۲ جولای ۲۰۲۶ می‌کند، اما در جلسه بعدی، به محض اینکه پنجره زمینه (Context Window) ریست می‌شود، عامل هوش مصنوعی دقیقاً همان خطا را دوباره تکرار می‌کند. این «فراموشی» سیستماتیک در جلسات کدنویسی امروز، جایی است که مدل‌ها با اعتمادبه‌نفس کامل، اشتباهات قبلی را در همان کدبیس بازتولید می‌کنند. برای حل این مشکل، چارچوب جدیدی به نام Run → Log → Distill معرفی شده است تا حافظه‌ای پایدار و تکامل‌یافته ایجاد کند که هم‌گام با کدبیس رشد کند.

من در حال حاضر یک فروشگاه Full-stack با استفاده از GraphQL (ترکیب Next.js + Keystone 6 + PostgreSQL) می‌سازم و تقریباً تمام مراحل را از طریق جلسات کمک‌گرفته از هوش مصنوعی در Claude Code پیش می‌برم. بعد از چند جلسه، از این فراموشی خسته شدم و تصمیم گرفتم خودِ گردش‌کار را تغییر دهم. این الگو در حال حاضر در سراسر صنعت در حال بازتعریف است؛ ابزارهایی در حال عرضه ویژگی‌های بومی هستند، مانند حافظه خودکار در Claude Code، حافظه‌های Cursor Memories و Devin's Cascade Memories. استفاده از این حافظه‌های محلی برای جلوگیری از بازنشانی زمینه گامی حیاتی در جهت پایداری جلسات توسعه است. عامل‌هایی که روی شکست‌های خود تأمل می‌کنند و در تلاش بعدی آن‌ها را می‌خوانند، در چارچوب‌هایی مثل Reflexion یا مفهوم «مهندسی ترکیبی» (compounding engineering) تعریف شده‌اند.

توسعه مدرن با کمک هوش مصنوعی بر پایه فایل‌های زمینه پایدار مثل CLAUDE.md یا قوانین Cursor است. اما این فایل‌ها معمولاً حقایق ایستا (Static) را نگه می‌دارند؛ مثلاً اینکه سرور توسعه را چگونه اجرا کنیم، تست‌ها کجا قرار دارند یا پوشه‌ها چه معنایی دارند. این فایل‌ها نمی‌توانند «حافظه معنایی» را ثبت کنند؛ یعنی دلایلی که چرا یک ریفکتور خاص انجام شد تا جلسه بعدی آن را لغو نکند، یا اینکه کدام الگوی به‌ظاهر بی‌خطر باعث کرش در محیط عملیاتی شد و دقیقاً چه دستوری برای تشخیص آن لازم است. این نقص باعث می‌شود عامل مجبور شود در حالی که زمینه هنوز در پنجره فعال است، ترنسکریپت‌هایی از کارهای خود بنویسد.

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

مکانیسم WAL و فشرده‌سازی

این سیستم بر پایه لاگ پیش‌نویس (Write-Ahead Log یا WAL) است؛ مفهومی که از پایگاه‌های داده وام گرفته شده است. در این سیستم‌ها، افزودن اطلاعات به انتهای یک فایل (append)، سریع‌ترین و امن‌ترین عملیاتی است که یک دیسک می‌تواند انجام دهد؛ اگر پروسه‌ای در میانه‌ی نوشتن کرش کند، لاگ بازپخش شده و هیچ چیز گم نمی‌شود. نمونه‌های واقعی این سیستم عبارتند از:

  • PostgreSQL: که صراحتاً آن را WAL (در مسیر pg_wal) می‌نامد.
  • MySQL: که به آن redo log می‌گوید.
  • SQLite: که دارای یک حالت اختصاصی WAL است.

در این گردش‌کار، عامل یک دفترچه کار به عنوان WAL در مسیر docs/worklog/<date>-<plan-name>.md نگه می‌دارد. این فایل یک تخلیه زمانی (dump) خام، ارزان و پرجزئیات است که هیچ‌کس آن را به‌طور کامل دوباره نمی‌خواند. چون WAL برای نوشتن بهینه است اما برای خواندن دشوار است (زیرا یافتن وضعیت فعلی نیازمند بازپخش تاریخچه است)، مرحله «فشرده‌سازی» (Compaction) وارد می‌شود.

این فرآیند دقیقاً شبیه موتورهای log-structured مثل RocksDB، Cassandra یا فشرده‌سازی لاگ در Kafka است که در آن فایل‌های خام ادغام شده، موارد تکراری حذف و مقادیر بازنویسی شده دور ریخته می‌شوند. این رویکرد یادآور سیستم‌های پیشرفته‌ای است که با استریم لحظه‌ای لاگ‌ها سعی دارند زمان انتظار برای دیباگ کدهای هوش مصنوعی را به حداقل برسانند. این مرحلهٔ تقطیر (Distillation) — شبیه تبدیل نفت خام به بنزین — یادداشت‌های خام را به فایلی به نام POST_MORTEM.md تبدیل می‌کند.

این فایل که نامش از روش SRE برای تحلیل بی‌سرزنش حوادث (blameless post-mortems) گرفته شده، به عنوان «حقوق رویه» پروژه عمل می‌کند. به جای پوشش یک حادثه واحد، این فایل تجمعی است و چهار نوع رکورد حیاتی را نگه می‌دارد:

  • تصمیمات معماری: ثبت دقیق تغییرات در ساختار کدبیس و «چرایی» پشت آن‌ها، تا جلسات آینده تصمیمات را لغو نکنند.
  • حفاظ‌های عملیاتی (Production Guardrails): استانداردهای سخت و شماره‌گذاری شده برای کدنویسی (مثلاً جایی که وضعیت‌های تغییرپذیر به‌طور قطعی ممنوع هستند). این‌ها از زبان امری مثل «ممنوع است» (FORBIDDEN) یا «باید» (MUST) استفاده می‌کنند که عامل‌ها بسیار بهتر از کلمات «ترجیحاً» یا «در نظر بگیرید» از آن‌ها پیروی می‌کنند.
  • تله‌ها و عیب‌یابی: سوابق هر تله‌ای که در آن افتاده‌اند، شامل علائم، علت ریشه‌ای و دستورات دقیق تشخیص مورد نیاز برای راهنمای تعمیر.
  • بک‌لاگ آینده: یک دفتر کل شماره‌گذاری شده از بدهی‌های فنی (Technical Debt) که آگاهانه به تعویق افتاده‌اند و نیاز به کار بیشتر دارند.

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

اجرای کارهای برنامه‌ریزی شده

برای کارهای پیچیده، یک خط‌لوله سه مرحله‌ای اجرا می‌شود. مرحله صفر، طراحی یک برنامه با گراف وابستگی تسک‌هاست. این گراف اغلب از طریق افزونه Superpowers در Claude Code (یک کتابخانه مهارت‌های جامعه‌محور) تولید می‌شود که مدل را مجبور می‌کند مسیر «طوفان فکری $\rightarrow$ طراحی $\rightarrow$ برنامه پیاده‌سازی» را طی کند. این گراف مشخص می‌کند کدام آیتم‌ها مسدودکننده هستند و کدام‌ها «بردهای سریع» مستقل‌اند و اجرای کاملاً تکرارشونده را ممکن می‌کند. برای مثال، در ریفکتور یک فروشگاه، ابتدا باید یک store factory وجود داشته باشد تا صفحات بتوانند به آن مهاجرت کنند، اما خودِ صفحات می‌توانند به‌طور مستقل مهاجرت کنند.

در مرحله اول (Run $\rightarrow$ Log)، عامل از یک ریتم سخت تعریف شده توسط یک «پرامپت اجرا» پیروی می‌کند. او در هر گام روی یک آیتم خاص کار می‌کند و برای هر آیتم این الگوریتم را اجرا می‌کند:

  1. [Maker]: نوشتن یا تغییر کد برای تسک مجزا و ایزوله فعلی.
  2. [Verifier]: اجرای یک دستور تأیید خاص (مانند npm test ، flutter test یا cargo check) برای اطمینان از اینکه هیچ چیز خراب نشده است.
  3. [Distill]: توقف و افزودن یک ورودی به دفترچه کار (WAL).
  4. [Report]: ارسال یک گزارش کوتاه و انتظار برای تأیید انسانی قبل از رفتن به آیتم بعدی.

این ورودی‌های دفترچه کار، پنج معیار را ثبت می‌کنند: حقایق تأیید شده، آنچه کار کرد، قوانین تقطیر شده برای گام‌های بعدی، تله‌های مواجه شده و تسک اتمیک بعدی. این تضمین می‌کند که قوانین و تله‌ها در حالی که زمینه «داغ» است ثبت شوند؛ زیرا یک Diff ساده از کد در روز بعد، دلیل انتخاب یک مسیر خاص را توضیح نمی‌دهد. هیچ چیزی تا زمان پاس شدن تست‌ها وارد دفترچه نمی‌شود و همین قانون، «لاگ کاری» را از «ترنسکریپت چت» جدا می‌کند.

به عنوان مثال، در رفع یک باگ اشتراک وضعیت، عامل کشف کرد که نتایج کوئری Keystone نمونه‌های کلاس (Class Instances) هستند. انتقال مستقیم آن‌ها به یک کامپوننت کلاینت باعث خطای «Only plain objects can be passed to Client Components» می‌شود. عامل این اصلاح — یعنی بسته‌بندی آن‌ها در toPlainObject() قبل از عبور از مرز RSC — را مستقیماً در WAL ثبت کرد تا تسک بعدی از آن استفاده کند. او همچنین یادداشت کرد که Selectorها باید مقادیر escalar یا رفرنس‌های پایدار برگردانند، زیرا یک object literal باعث ایجاد یک حلقه رندر بی‌نهایت (infinite re-render loop) شد.

پس از تأیید آخرین آیتم، مرحله دوم یعنی فشرده‌سازی آغاز می‌شود. یک پرامپت مدل را مجبور می‌کند تا لاگ‌ها را به POST_MORTEM.md تبدیل کرده و نقطه ورود را پاکسازی کند. خروجی این کار قوانین امری است، مانند:

  • قانون ۱: «اعلان یک شیء تغییرپذیر در سطح ماژول در Server Components یا Server Actions ممنوع است.» دلیل: ماژول‌های Next.js یک‌بار در هر پروسه مقداردهی می‌شوند و وضعیت را بین تمام کاربران به اشتراک می‌گذارند.
  • قانون ۳: «داده‌های سرور تنها به دو روش به کلاینت می‌رسند: (الف) یک store مخصوص هر درخواست که توسط صفحه با داده‌های initState ایجاد شده؛ (ب) props ساده.»

مدیریت جلسات خودبه‌خودی

همه کارهای برنامه‌ریزی شده نیستند. برخی از ارزشمندترین درس‌ها از جلسات خودبه‌خودی می‌آیند، مانند استقرار در محیط عملیاتی که به یک حماسه عیب‌یابی تبدیل می‌شود. یک مورد خاص در مورد کانتینری رخ داد که با خطای کلی «Container failed to start and listen on PORT=8080» شکست می‌خورد.

سه ساعت بررسی عمیق نشان داد که ایمیج مبتنی بر Alpine، موتورهای Prisma را با OpenSSL 1.1 لینک کرده بود، در حالی که Node 20 با OpenSSL 3 لینک می‌شود. این تضاد باعث می‌شد موتور کوئری در حین دست‌تکانی TLS با پایگاه‌داده عملیاتی دچار segfault شود. چون Postgres محلی TLS نداشت، این خطا در توسعه محلی نامرئی بود. راهکار، تغییر یک خط در Dockerfile (تغییر node:20-alpine به node:20-slim) بود.

چون برنامه‌ای پیش‌بینی نشده بود، دفترچه‌ای هم نوشته نشده بود. برای ثبت این مورد، از پرامپت «تقطیر یک جلسه خودبه‌خودی» قبل از بستن جلسه استفاده شد. این پرامپت کل پنجره زمینه فعلی و تاریخچه فایل‌های تغییر یافته را تحلیل می‌کند. نتیجه این شد که یک ورودی تله بسیار خاص (۳.۱۲) ایجاد شد که شامل تشخیص دقیق بود: «ایمیج را به‌صورت محلی با DATABASE_URL عملیاتی اجرا کرده و کل stderr را بخوانید». این درس بعداً به «حفاظ ۱۸» تبدیل شد: هر ایمیجی که با TLS به دیتابیس در محیط عملیاتی وصل می‌شود، باید قبل از استقرار در برابر یک دیتابیس TLS تست شود.

بستن حلقه

برای عملیاتی کردن این حافظه‌ها، نقطه ورود عامل (مانند CLAUDE.md) را بسیار سبک نگه می‌داریم. این فایل فقط شامل توصیف کوتاهی از پروژه، دستورات پایه و یک اشاره‌گر سخت اجباری در اولین خط است: «👉 مهم: قبل از نوشتن هر کد جدید، افزودن ویژگی‌ها یا ریفکتور، شما باید ابتدا POST_MORTEM.md را بخوانید و قوانین معماری و حفاظ‌های عملیاتی ثبت شده در آن را دقیقاً رعایت کنید».

این کار، کالبدشکافی را از یک مستند اختیاری به پیش‌شرط کدنویسی تبدیل می‌کند. نتیجه، عاملی است که به تاریخچه خودش استناد می‌کند. در یک مورد، عامل هنگام نوشتن یک تابع دسترسی به داده، بدون درخواست کاربر کامنتی اضافه کرد: «// خواندن خالص از DB: همگام‌سازی تامین‌کننده اینجا فراخوانی نمی‌شود... APIهای خارجی باید خارج از مسیر رندر بمانند (حفاظ ۴، بدهی فنی ۹). همگام‌سازی بر اساس نیاز از طریق POST /api/sync-supplier اجرا می‌شود».

حفاظ ۴ زمانی شکل گرفت که وابستگی فروشگاه به API یک تامین‌کننده B2B در حین رندر صفحه باعث سقوط کل سایت می‌شد وقتی API ناپایدار می‌شد. قانون جدید این است: APIهای خارجی فقط در حالت «بهترین تلاش» (best-effort) هستند، همگام‌سازی هرگز در مسیر رندر نیست — از try { sync } catch { log } استفاده کنید و سپس داده‌ها را از DB داخلی سرو کنید.

جزئیات پیاده‌سازی و محدودیت‌ها

برای حفظ کارایی سیستم، محدودیت‌های زیر اعمال شده است:

  • مکان لاگ: WAL باید خارج از فایل‌های زمینه خودکار (مثل CLAUDE.md) باشد. اگر لاگ‌ها آنجا بودند، هر جلسه توکن‌های زیادی را بابت لاگ‌های قدیمی پرداخت می‌کرد و نقطه ورود رقیق می‌شد. برای هر برنامه یک فایل مجزا استفاده شود، مانند docs/worklog/2026-07-08-per-request-store.md.
  • بایگانی: بعد از فشرده‌سازی، لاگ خام بایگانی می‌شود. Git تاریخچه را نگه می‌دارد اگر زمانی به مواد خام نیاز باشد.
  • برچسب‌گذاری: جلسات با برچسب‌هایی مثل [feature]، [refactor]، [redesign]، [deploy]، [debug] یا [mixed] علامت‌گذاری می‌شوند تا فشرده‌سازی‌های آینده در فایل پست-مورتوم آسان‌تر شود.

محدودیت‌های ذاتی نیز وجود دارد. فایل POST_MORTEM.md با گذشت زمان رشد می‌کند (مثلاً بعد از ۵ جلسه به ۳۰۰ خط می‌رسد) و در نهایت خودش نیاز به فشرده‌سازی دارد تا روایت‌ها را دوباره به قوانین تبدیل کند. همچنین خطر «بیش‌برازش» (Overfitting) وجود دارد، جایی که یک راهکار موقت برای یک نسخه خاص از یک کتابخانه تبدیل به یک دکترین غلط می‌شود. با این حال، فرمت شماره‌گذاری شده به توسعه‌دهندگان اجازه می‌دهد قوانین قدیمی را به‌راحتی پیدا کرده و لغو کنند.

این روش با الگوی Memory Bank متفاوت است. در حالی که Memory Bank وضعیت پروژه (چه می‌سازیم، کجا متوقف شدیم) را بازسازی می‌کند، Run-Log-Distill حکمت مهندسی (چه چیزی نباید دوباره اتفاق بیفتد) را جمع می‌کند. این رویکرد با چارچوب‌های دانشگاهی مثل ExpeL (توسط Zhao و همکاران، ۲۰۲۳) همسو است که در آن عامل‌ها مسیرهای اجرا (trajectories) را جمع‌آوری می‌کنند تا بصیرت‌های زبان-طبیعی استخراج کنند، و همچنین با مفهوم «مهندسی ترکیبی» توسط Every که هر واحد کار، کار بعدی را آسان‌تر می‌کند.

در این مدل، انسان نقش سردبیر را دارد. با بازبینی قوانین تقطیر شده، برنامه‌نویس مانع از ایجاد «خرافات» در مدل می‌شود. این انضباط باعث می‌شود هوش از پنجره زمینه گذرا به یک دارایی دائمی و تحت کنترل نسخه (version-controlled) تبدیل شود. این سیستم وابسته به ابزار خاصی نیست؛ اگرچه با Claude Code تست شده، اما در Cursor، Windsurf یا هر IDE عامل‌محوری که از قوانین Markdown پشتیبانی کند، به طور یکسان کار می‌کند.

🚀 همین امروز روی یک پروژه موجود شروع کنید: در انتهای جلسه بعدی خود، پرامپت ۳ (تقطیر) را اجرا کنید و تا امشب اولین حفاظ‌های عملیاتی خود را خواهید داشت. پنج جلسه بعد، عامل شما آن‌ها را برای شما نقل می‌کند.

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

این روش با تکیه بر تجربه عملی در توسعه نرم‌افزار (SRE)، نرخ خطای تکراری را در پروژه‌های بزرگ کاهش می‌دهد. اعتبار این متد از همگرمی با معماری‌های شناختی (CoALA) و تجربه استقرار در ابزارهای پیشرو مانند Claude Code می‌آید.

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

برنامه‌نویسان ایرانی که از ابزارهای Cursor یا Claude استفاده می‌کنند، می‌توانند بدون نیاز به تغییر زیرساخت، این متد را با ایجاد چند فایل Markdown در پروژه خود پیاده کنند.

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

جایگزینی حافظه کوتاه‌مدت با یک «قانون‌نامه» تکاملی، نقطه عطفی در تبدیل AI از یک دستیار ساده به یک همکار ارشد است. این رویکرد در واقع با ایجاد یک لایه استخراج دانش (Knowledge Extraction) روی داده‌های خام جلسه، مشکل محدودیت پنجره زمینه را دور می‌زند. به نظر ما، این الگوی «تقطیر تجربه»، پیش‌زمینه لازم برای رسیدن به عامل‌هایی است که قادرند استانداردهای سازمان را بدون نیاز به Fine-tuning یاد بگیرند.

منابع

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

گفتگو

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

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

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

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

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

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

دات‌هوش

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

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