روز 02: LLM یک تابع بدون حالت است. بقیه چیزها تو هستی

من نسخه چهل خطی نقشه نگار را به پرونده دومی نشان دادم و از پیگیری آشکار پرسیدم: این یکی چه ارتباطی با آخرین پرونده دارد؟
از من پرسید که منظورم کدام فایل است.
اولین غریزه من این بود که چیزی را شکسته ام. پرچمی که انداخته بودم، شناسه جلسه ای که فراموش کرده بودم پاس کنم. من بیشتر از آن چیزی که راحت اعتراف کنم به دنبال آن بودم. بدون شناسه جلسه هرگز یکی وجود نخواهد داشت. نقطه پایانی نمیدانست که من نود ثانیه زودتر آن را فراخوانی کرده بودم، و هیچ مقدار پیکربندی آن را از بین نمیبرد.
هر قطعه حافظه ای که تا به حال در یک محصول هوش مصنوعی دیده اید، فردی است که در جایی تصمیم می گیرد قبل از POST چه چیزی را در یک آرایه قرار دهد. این تمام مکانیسم است. هنگامی که آن را ببینید، نمی توانید آن را نادیده بگیرید، و حجم شگفت انگیزی از واژگان مرموز نیست.
نسخه کوتاه
کد این روز: نقشه کش در روز 02
- مدل است تابع خالص آرایه ای که ارسال می کنید. چیزی بین درخواستها ذخیره نمیشود و هیچ چیزی که نمیتوانید پیکربندی کنید آن را تغییر میدهد.
- نسخه چهل خطی یک پیام ارسال کرد. اکنون لیستی را ارسال می کند و تماس گیرنده مالک این لیست است – بدون کتابخانه، بدون خدمات، بدون فیلد پنهان.
- اضافه شدن از پاسخ دستیار و همچنین پاسخ کاربر. حذف آن خطای ظریف تری نسبت به فراموشی ایجاد می کند.
- نماینده شما قبلاً دارد دقیقا یک قسمت از ایالتو یک فایل JSON است. اشکال زدایی با
catقبل از رسیدن به هر چیز دیگری - ارسال مجدد رونوشت است مربع: ده چرخش مساوی یک ورودی به ارزش پنجاه و پنج چرخش را از شما دریافت می کند نه ده.
- “حافظه” یک کلمه محصول است. هر پیاده سازی آن یک خط مشی است در مورد اینکه چه چیزی در آرایه قرار داده شودو انتخاب آن سیاست بخش عمده ای از بقیه این مجموعه است.
تعقیبی که به جایی نمی رسد
این نسخه ای است که ابتدا نوشتم و ارزش بررسی را دارد زیرا درست به نظر می رسد.
def turn(messages: list[dict[str, str]], content: str) -> str: # Broken. Do not ship this.
return ask(messages + [{"role": "user", "content": content}])
لیستی از پیام ها وارد می شود. یک پاسخ نمایش داده می شود. امضا مانند یک مکالمه خوانده می شود.
اما messages + [...] یک لیست dump می سازد، آن را می فرستد و رها می کند. لیست تماس گیرندگان هرگز لمس نمی شود، بنابراین هر تماس از یک مکان شروع می شود. این دقیقاً به این دلیل که نوع حاشیه نویسی دلالت بر تاریخ دارد در خواندن باقی می ماند – باید توجه داشته باشید که هیچ چیز هرگز رشد نمی کند.
نقطه پایانی که این رشته از آن استفاده می کند، نقطه پایانی تکمیل چت فرم OpenAI است و در این فرم درخواست مستقل است. هر چیزی که در آرایه قرار ندادید، اتفاق نیفتاد.
هیچ جلسه ای وجود ندارد. یک لیست وجود دارد.
راه حل سه خط است، و این تمام نکته روز است.
def turn(messages: list[dict[str, str]], content: str) -> str:
messages.append({"role": "user", "content": content})
reply = ask(messages)
messages.append({"role": "assistant", "content": reply})
return reply
او لیستی را که به او تحویل داده شده تغییر می دهد. این عمدی است: یک رونوشت وجود دارد، تماسگیرنده آن را نگه میدارد، و هر اضافه در تابعی اتفاق میافتد که در آن میتوانید یک نقطه شکست تعیین کنید.
اضافه دوم خطی است که مردم رها می کنند و حالت شکست آن بدتر از بی حافظه است. آن را کنار بگذارید، و مدل لیستی از سؤالات بدون پاسخ ضمیمه دریافت می کند – متنی که ظاهراً هرگز در آن صحبت نکرده است. بنابراین او دوباره به چیزهایی که قبلاً پاسخ داده است پاسخ می دهد، با نتیجه ای که دو نوبت پیش به آن رسیده بود در تناقض است و عموماً مانند مدلی عمل می کند که در استدلال بد است. قبل از اینکه آن را پیدا کنید، یک شب را صرف بازنویسی خط سیستم، دستورالعمل های ثابت در اولین پیام خواهید کرد.
ساختن هر دو اضافات به یک تابع یک سبک نیست. حالتی را که فقط نیمی از مبادله ثبت شده را حذف می کند.
دور تا دور turn، بقیه src/cartographer/agent.py کمتر از آنچه انتظار داشتید تغییر کرد الگوی دیروز می رود، جایگزین می شود SYSTEM، پیام سیستمی که هر لیست را باز می کند و به مدل می گوید که در حال نقشه برداری یک فایل ذخیره سازی است و باید به نام فایل های قبلی اشاره کند. ask بدن خود را نگه می دارد، اما اکنون کل لیست را می گیرد و به عنوان ارسال می کند messages فیلد بنابراین دیگر تصمیم نمی گیرد که مدل چه چیزی را ببیند. main هر بار در خط فرمان را به یک چرخش تبدیل می کند، سپس یک سوال نهایی می پرسد که فقط مدلی که هر فایل قبلی را در اختیار دارد می تواند به آن پاسخ دهد: اول کدام را می خوانید؟ tests/test_agent.py با تستی جایگزین می شود که تبادل می کند ask برای جعلی و ادعا می کند که هم ترتیب نقش ها و هم اینکه تماس دوم چهار پیام دیده است. یادداشتهای توسعهدهنده امروزی از هر خط عبور میکنند.
نماینده شما دقیقاً یک وضعیت دارد
از آنجایی که مدل تابع خالص این آرایه است، آرایه وضعیت کامل برنامه شما است. پس بنویس:
TRANSCRIPT.write_text(json.dumps(messages, indent=2))
این خط به پایان می رسد main، و transcript.json وارد کنید .gitignore، زیرا حاوی کل فایل های منبع است و در هر اجرا بازسازی می شود. این بالاترین ارزش پنج دقیقه در روز است و تقریباً هیچ درسی آن را نمیسازد. وقتی نتیجه اشتباه است، سؤالی که واقعاً باید به آن پاسخ دهید اینطور نیست چرا مدل اینو گفت. درست است چیزی که مدل دید. دقیقاً یک مصنوع وجود دارد که با آن مطابقت دارد و اکنون روی دیسک است.
تقریباً هر پاسخ بدی که در این مرحله دنبال میکردم در عرض سی ثانیه در این فایل قابل مشاهده بود: فایلی که هرگز اضافه نشد، منبعی که بهعنوان یک رشته خالی خوانده میشود، زیرا مسیر نسبت به دایرکتوری اشتباه بود، یک پیام سیستمی که توسط تخصیص بعدی پاک شد. هیچکدام از اینها مشکل مدل نیستند و تا زمانی که رونوشت را باز نکنید، همه آنها شبیه مشکلات مدل هستند.
همچنین اجراها را قابل پخش می کند. ورودی یک آرایه JSON است. شما می توانید آن را بایت به بایت دوباره ارسال کنید، یک پیام را تغییر دهید و دوباره ارسال کنید.
صورتحساب یک مثلث است نه یک خط
حالا اون قسمتی که گرون میشه هر تماس کل آرایه را حمل می کند، بنابراین شما برای حرکت اول دوباره در حرکت دوم و دوباره در حرکت سوم هزینه می پردازید.
اگر هر حرکت خشن اضافه می کند تی نشانه ها، تکه های متنی که مدل می خواند و گزارش می دهد، پرس و جو n*ام در مورد *nT واکشی می شود نشانه های ورودی و هزینه ها به طور کلی T·n(n+1)/2. ده چرخش مقادیر پنجاه و پنج چرخش وارد شده است. بیست انقلاب دویست و ده است. منحنی مثلثی است و مساحت آن از شما گرفته می شود.
برای دستیار چت که می تواند زنده بماند زیرا نوبت یک جمله است. برای عاملی که فایلهای منبع را میخواند، هر حرکت یک فایل کامل است، بنابراین تی بزرگ است و مثلث در تک رقمی ترسناک می شود ص. این یک مشکل اندازه گیری است قبل از اینکه یک مشکل طراحی باشد، که فردا خواهد بود.
سه استراتژی منصفانه وجود دارد و آنها علیه یکدیگر معامله می کنند:
| همه چیز را بفرست | نوبت های قدیمی تر را خلاصه کنید | اشاره گرها را نگه دارید، در صورت تقاضا دوباره بخوانید | |
|---|---|---|---|
| هزینه های ورودی برای n گردش مالی | با مربع رشد می کند | صاف بعد از گاز گرفتن کلاهک | مسطح، به علاوه یک تماس جستجو |
| آنچه را که رها می کنید | پنجره زمینه، سپس بودجه شما | جزئیاتی که شما نمی دانستید مهم است | رفت و برگشت و تاخیر |
| درست زمانی که | دوهای کوتاه و در حین مطالعه | چت که در آن نوبت های قدیمی چت است | محتوا روی دیسک است و بازخوانی آن ارزان است |
برای یک پایگاه کد، ستون سوم بدیهی است درست است – فضای ذخیره سازی همچنان در آنجا قرار دارد، و خواندن مجدد یک فایل، هزینه خواندن دیسک را دارد. این مسیری است که این پروژه در حال حرکت است، و بنابراین عامل در نهایت باید بتواند به جای اینکه به آنها داده شود، چیزهایی را برای خود بگیرد.
چه کار کنم؟
- رونوشت را به عنوان استدلال ارسال کنید. لحظه ای که به یک ویژگی پنهان یک شی تبدیل می شود، دیگر چیزی را که ارسال کرده اید نمی بینید.
- هر دو طرف را در یک تابع اضافه کنید. تبادل نیمه ضبط شده را غیرقابل ارائه کنید.
- در هر اجرا آرایه را روی دیسک تخلیه کنید، از روز اول این چهار خط است، و این تنها مشاهده شما تا مدت ها بعد است.
- توالی نقش ها را در یک آزمون تأیید کنید. معدن بررسی میکند که آیا دو چرخش سیستم، کاربر، دستیار، کاربر، دستیار تولید میکنند یا خیر – بلافاصله نسخه خراب بالا را میگیرد.
- کتابخانه حافظه را نصب نکنید در حالی که می توانید مشخص کنید به کدام ستون از آن جدول نیاز دارید. هر سه یک صفحه کد هستند. قسمت سخت انتخاب است و هیچ کتابخانه ای این کار را برای شما انجام نمی دهد.
اگر این مفید بود، کف زدن به افراد دیگر کمک میکند آن را پیدا کنند. من در مورد طرف دیگر آن کنجکاو هستم: طولانیترین مکالمه با ماموری که زنده نگه داشتهاید چه بوده است، و در نهایت چه چیزی را دور انداختید تا آن را در دسترس نگه دارید؟
تمام نظرات در این پست متعلق به من است. سناریوها ترکیبات تصویری هستند و نمونههای کد از یک پایگاه کد خاص مشتق نشدهاند.



