رفتن به محتوا

حافظه و دانش

بدون حافظه، هر گفتگوی عامل از صفر شروع می‌شود: همان قرارداد باید دوباره توضیح داده شود، همان تصمیم دوباره به بحث گذاشته شود، همان بن‌بست دوباره کشف شود. حافظه همان انبار محدود به فضای کاری است که از اجراها جان سالم به در می‌برد و وجود دارد تا دانشی که یک عامل تولید می‌کند، بعدها برای عامل دیگری قابل یافتن باشد.

سه لایه دارد و هرکدام به پرسشی متفاوت پاسخ می‌دهند:

  1. واقعیت‌ها — آنچه درست است (یک قرارداد، یک نتیجه، یک تصمیم).
  2. سیاست‌ها — آنچه عامل‌ها باید دربارهٔ آن انجام دهند (یک قاعدهٔ هنجاری).
  3. حافظهٔ کاری — آنچه یک عامل در میانهٔ آن بوده است.

این تمایز مهم است چون این لایه‌ها از مسیرهای متفاوتی به عامل می‌رسند. واقعیت‌ها جست‌وجو می‌شوند. سیاست‌ها تزریق می‌شوند. حافظهٔ کاری خصوصی است.

یک MemoryFact یک واحد دانش است که به یک فضای کاری و یک دامنه محدود می‌شود.

ویژگی چیست
domain دامنهٔ دانش («conventions»، «decisions»، «codebase»)
topic یک برچسب موضوعی کوتاه
content متن دانش
confidence 0.0–1.0، از منشأ مقدار می‌گیرد و با اشارهٔ دوباره بالا می‌رود
memoryType نوع واقعیت — منحنی افت زمانی آن را تعیین می‌کند
veracity چگونگی رسیدن به آن دانش — اطمینان را مقدار می‌دهد و اندازهٔ هر افزایشِ اشارهٔ دوباره را می‌سازد
sourceObservationIds مشاهداتی که به آن انجامیدند
supersededBy واقعیت تازه‌تری که جای آن را گرفته، در صورت وجود
validUntil, recallCount, mentionCount نشانه‌های انقضا و استفاده که هنگام یادآوری به کار می‌روند

دو سطر آخر همان‌هایی‌اند که مردم از قلم می‌اندازند و تعیین می‌کنند کدام واقعیت رو می‌شود. memoryType پارامترهای افت وایبول را به‌تفکیک نوع حمل می‌کند، پس یک تعهد زمان‌دار به‌سرعت محو می‌شود، در حالی که یک واقعیت پروفایلی پایدار محو نمی‌شود. veracity منشأ را ثبت می‌کند — اظهارشده توسط یک انسان (وزن 1.0)، استنتاج‌شده توسط یک عامل (0.7)، تولیدشده توسط یک ابزار (0.5)، درون‌بری‌شده (0.6) — و همان وزن، اطمینان آغازین واقعیت را مقدار می‌دهد.

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

یک MemoryPolicy قاعده‌ای هنجاری است که از واقعیت‌ها گرفته می‌شود، به یک فضای کاری و دامنه محدود است و یک فلگ فعال و یک requiredRole اختیاری دارد.

هر سیاست فعال در فضای کاری به هر اعزامی تزریق می‌شود، بی‌پالایش — بدون پالایش بر پایهٔ دامنه، نقش، کار یا فضا. ارزش دانستن دارد پیش از آنکه بیستمین سیاست‌تان را بنویسید، چون سیاست‌ها بر سر همان پنجرهٔ بافتی که کار در اختیار دارد رقابت می‌کنند. به همین دلیل هم requiredRole روی یک سیاست فقط توصیه‌ای است: توصیف می‌کند قاعده خطاب به چه کسی است، اما جلوی رسیدن قاعده به بقیه را نمی‌گیرد.

یک MemoryDomain واقعیت‌ها و سیاست‌ها را درون یک فضای کاری گروه می‌کند. دامنه‌ها به دانش ساختار سازمانی می‌دهند و همان واحدی هستند که اعطاهای دسترسی برایشان نوشته می‌شوند — اما پیش از آنکه با یک دامنه مثل مرز محرمانگی رفتار کنید، احتیاط زیر را ببینید.

یک دامنه یا در سراسر فضای کاری است (architecture) یا به یک مخزن محدود است (repo:<slug>/architecture). نام یکسان در هر دو محدوده دو انبار مستقل است: واقعیتی که دربارهٔ یک کدبیس درست است، واقعیت سراسر فضای کاری را بازنویسی نمی‌کند. search_memory و مقدمهٔ اعزام وقتی عامل در آن مخزن کار می‌کند، حافظهٔ محدود به مخزن را اول رتبه‌بندی می‌کنند؛ اما بقیه را بیرون نمی‌گذارند. برای نوشتن در آن محدوده یا تقویت آن، repo را به propose_fact / propose_policy / search_memory بدهید.

کنترل دسترسی برای خواندن‌ها در صورت خطا باز است

بخش با عنوان “کنترل دسترسی برای خواندن‌ها در صورت خطا باز است”

MemoryAccessGrant نقش یک عامل و یک دامنه را به یکی از سه سطح دسترسی نگاشت می‌کند:

دسترسی معنا
none بدون دسترسی
read می‌تواند واقعیت‌ها را جست‌وجو و بازیابی کند
write propose_policy آن را لازم دارد. نوشتن واقعیت‌ها (propose_fact، supersede_fact) مشروط به اعطا نیست

این ناهمسانی — نرم در خواندن، سخت در نوشتن سیاست — معامله‌ای عمدی است. حافظه وقتی بیشترین فایده را دارد که در گردش باشد، و رد شدن یک خواندن عاملی می‌سازد که بی‌صدا کمتر می‌داند، نه عاملی که مشکلی را گزارش می‌کند. در مقابل، رد شدن نوشتن یک سیاست پرصدا و قابل اصلاح است، پس اجرای اجباری همان‌جا نشسته است. یک دامنهٔ تازه‌ساخته برای هر نقش write را مقدار می‌دهد؛ سخت‌ترکردن آن پس از آن ویرایشی تنها با RPC ممکن است، چون هیچ رابطی برای اعطاها وجود ندارد.

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

چه چیزی واقعاً به پرامپت یک عامل می‌رسد

بخش با عنوان “چه چیزی واقعاً به پرامپت یک عامل می‌رسد”

هنگام اعزام، مقدمهٔ حافظه دقیقاً از سه چیز ساخته می‌شود:

  • هر سیاست فعال فضای کاری، در قالب سطرهای - [domain] rule.
  • حافظهٔ کاری خودِ عامل، عیناً.
  • یک فهرست کوتاه از واقعیت‌های تطبیق‌شده با کلیدواژه برای همین کار — حداکثر پنج مورد، در بودجه‌ای حدود 1,200 نویسه و تنها وقتی شرح کار دست‌کم 20 نویسه باشد. کارهای کوتاه‌تر هیچ واقعیتی نمی‌گیرند.

این فهرست کوتاه تنها FTS/کلیدواژه است و عمداً سقف دارد. جاسازی یک پرس‌وجو کند است و مسیر اعزام تنها جایی است که تأخیر بلافاصله دیده می‌شود، پس مسیر معنایی کند عمداً از آن بیرون نگه داشته شده است. مقدمه در پایان به عامل می‌گوید اقلام باربر را با search_memory راستی‌آزمایی کند؛ همان‌جایی که مدل کامل یادآوری زندگی می‌کند.

در این مسیر هیچ اعطای دسترسی‌ای بررسی نمی‌شود. هر چیزی که فهرست کوتاه پیدا کند، همان چیزی است که عامل می‌بیند.

ابزار search_memory که عامل با آن روبه‌روست سه حالت دارد و واقعاً جست‌وجوهایی متفاوت‌اند:

  • keyword — فقط FTS5.
  • semantic — نتایج BM25 و برداری که با ادغام رتبهٔ متقابل به‌هم دوخته می‌شوند.
  • hybrid (پیش‌فرض) — یادآوری چندصدایی: چهار صدای رتبه‌بندی‌شده که با هم ادغام و سپس متنوع می‌شوند.

چهار صدا عبارت‌اند از واژگانی (FTS)، معنایی (KNN برداری)، زمانی (واقعیت‌های فعال اخیر) و گراف — پیمایشی دوگامی روی یال‌های اپیزودیک از قوی‌ترین بذرهای واژگانی و معنایی. صدای گراف دلیل وجود یال‌های اپیزودیک است: واقعیتی را رو می‌کند که به پاسخ شما پیوند دارد بی‌آنکه هیچ‌یک از واژه‌های شما را تطبیق دهد. صداها با یک قصدِ پرس‌وجوی دسته‌بندی‌شده وزن می‌گیرند (معنایی به‌طور پیش‌فرض بیشترین وزن را دارد، سپس گراف و واژگانی، و بعد تازگی)، امتیاز هر نامزد با افت وایبولش مقیاس می‌شود، و مجموعهٔ نتیجه با MMR متنوع می‌شود تا پنج بازگو از یک واقعیت جای چهار واقعیت متفاوت را تنگ نکند.

جست‌وجوی حافظه در دسکتاپ و وب مسیری جداگانه و ساده‌تر است: عملیات RPC memory_fact.search تنها FTS5 است، چون یک کلاینت سبک نمی‌تواند جاسازی پرس‌وجو را با خود ببرد و مسیر ترکیبی درون میزبان می‌ماند. پس رتبه‌بندی‌ای که در مرورگر حافظه می‌بینید همان رتبه‌بندی‌ای نیست که یک عامل از search_memory می‌گیرد. این انتظارِ طبیعی است، نه اشکال؛ اما به این معنا هم هست که «جست‌وجو کردم و پیدایش نکردم» در رابط کاربری شاهدی بر این نیست که عامل پیدایش نخواهد کرد.

حافظه کجا زندگی می‌کند و چه کسی آن را می‌نویسد

بخش با عنوان “حافظه کجا زندگی می‌کند و چه کسی آن را می‌نویسد”

مرورگر حافظه در تنظیمات → فضای کاری → حافظه قرار دارد (/workspaces/<id>/settings/memory) و زبانه‌های واقعیت‌ها، سیاست‌ها و گراف دانش را دارد.

ناهمسانی‌ای آنجا هست که مردم را غافلگیر می‌کند: می‌توانید حافظه را ویرایش و حذف کنید، اما نمی‌توانید آن را بسازید. نه زبانهٔ واقعیت‌ها و نه زبانهٔ سیاست‌ها هیچ امکان افزودنی ندارد. نوشتن سمت عامل است، از طریق propose_fact و propose_policy (برای جایگزینی، supersede_fact / supersede_policy). remember یک قلم لایهٔ داغ محدود به نشست می‌نویسد که consolidate_memory ممکن است بعدها آن را به یک واقعیت ارتقا دهد؛ record_observation و update_my_notes چرک‌نویس خصوصی‌ای را می‌نویسند که هنگام اعزام تزریق می‌شود. مرورگر یک سطح بازبینی و اصلاح است، نه نویسندگی — پس اگر واقعیتی را در حافظه می‌خواهید، راه گذاشتنش این است که به یک عامل بگویید.

دو عملیات نگهداشت نیز به‌جای زمان‌بندی‌شدن، با فراخوانی عامل اجرا می‌شوند: consolidate_memory واقعیت‌های انباشته را ادغام و هرس می‌کند و harmonize_memory باورهایی را که میان عامل‌ها واگرا شده‌اند آشتی می‌دهد. list_memory_conflicts نشان می‌دهد که تشخیص تعارض تا کنون چه چیزی ثبت کرده است. هیچ‌چیز آن‌ها را با تایمر برایتان اجرا نمی‌کند. تصمیم‌های جلسه وقتی یک گام ماندگارسازی جلسه آن‌ها را ثبت کند در دامنهٔ decisions جمع‌آوری می‌شوند؛ این یک تایمر روی اجراهای تکمیل‌شدهٔ عامل نیست.