ساخت چت بات Markdown با بهینه سازی حافظه
هنگام ساخت یک چتبات با استفاده از NextJS و AI SDK، معمولاً میخواهید پاسخهای مدل را با فرمت Markdown نمایش دهید؛ برای این کار میتوان از کتابخانهای مانند react-markdown استفاده کرد. با این حال، این روش میتواند تأثیر منفی بر عملکرد داشته باشد، زیرا Markdown با دریافت هر توکن جدید از پاسخ استریمی، مجدداً رندر میشود.
با طولانیتر و پیچیدهتر شدن مکالمهها، این مشکل بهصورت نمایی افزایش مییابد، چرا که کل تاریخچهی گفتگو با دریافت هر توکن جدید مجدداً رندر میشود.
در این راهکار از memoization استفاده شده است؛ یک تکنیک بهینهسازی عملکرد که در آن، نتایج توابع پرهزینه ذخیره (cache) شده و در دفعات بعدی مجدداً استفاده میشوند تا از محاسبات غیرضروری جلوگیری شود. در این مورد خاص، بلوکهای Markdown که پردازش شدهاند، ذخیره میشوند تا هنگام دریافت توکنهای جدید، نیازی به پردازش و رندر مجدد آنها نباشد. این بدان معناست که وقتی یک بلوک بهطور کامل پردازش شد، بهجای بازتولید شدن، از نسخهی ذخیرهشدهی آن استفاده میشود. این رویکرد با حذف عملیات تکراریِ پردازش و رندر، بهطور چشمگیری عملکرد رندر در مکالمات طولانی را بهبود میبخشد.
سرور
در سمت سرور، از یک route handler ساده استفاده کنید که پاسخ LLM را بهصورت استریم به کلاینت ارسال میکند. قطعه کد زیر را در مسیر app/api/chat/route.ts، قرار دهید:
متغیرهای محیطی BASE_URL و LIARA_API_KEY همان baseUrl سرویس هوش مصنوعی لیارا و کلید API لیارا هستند که باید در بخش متغیرهای محیطی برنامه خود، آنها را تنظیم کنید.
کامپوننت Markdown با بهینهسازی حافظه
در گام بعد، یک کامپوننت Markdown با قابلیت memoization ایجاد کنید که متن خام Markdown را به بلوکهایی تقسیم کرده و تنها زمانی بهروزرسانی میشود که محتوای آن واقعاً تغییر کرده باشد. این کامپوننت، محتوای Markdown را با استفاده از کتابخانه marked به بلوکهایی مجزا تقسیم میکند (برای شناسایی عناصر مستقل Markdown)، سپس از ویژگیهای memoization در React استفاده میکند تا فرآیند رندر تنها برای بلوکهایی که واقعاً تغییر کردهاند انجام شود. این روش باعث میشود از رندر مجدد کل محتوا در هنگام دریافت توکنهای جدید جلوگیری شود و تنها بخشهای تغییریافته بروزرسانی شوند، که این کار بهطور قابل توجهی عملکرد را در گفتگوهای طولانی بهبود میبخشد.
در فایل components/memoized-markdown.tsx قطعه کد زیر را قرار دهید:
کلاینت
در نهایت، در سمت کلاینت، از هوک useChat برای مدیریت chat state و نمایش رابط کاربری چت استفاده کنید. برای نمایش محتوای پیامها با فرمت Markdown بدون کاهش عملکرد، میتوانید از کامپوننت MemoizedMarkdown بهره بگیرید. همچنین میتوانید فرم ارسال پیام را در یک کامپوننت جداگانه پیادهسازی کنید تا از رندرهای غیرضروری پیامهای چت جلوگیری شود. علاوه بر این، میتوانید از گزینهی آزمایشی experimental_throttle استفاده کنید تا بهروزرسانی دادهها را در بازههای زمانی مشخص محدود (throttle) کرده و بدینترتیب عملکرد رندرینگ را بهتر کنترل و بهینهسازی نمایید.
در فایل app/page.tsx قطعه کد زیر را قرار دهید:
chat state از طریق استفاده از یک مقدار id بین هر دو کامپوننت بهاشتراک گذاشته میشود. این کار امکان تفکیک فرم ارسال پیام و پیامهای چت به دو کامپوننت مجزا را فراهم میکند، در حالیکه state بین آنها کاملاً همگام و هماهنگ باقی میماند.
خروجی برنامه فوق:

پروژه فوق را میتوانید بهصورت کامل در گیتهاب لیارا، مشاهده کنید.