บล็อก

ทำให้รอบการทำงานของเอเจนต์ที่มีรูปจำนวนมากอยู่ในหน่วยความจำ

รอบการทำงานของเอเจนต์ในโปรดักชันหน่วยความจำหมดที่ 952 MB ขณะที่กำลังตัดสินค้าออกจากสแกนแคตตาล็อกหกไฟล์และดูภาพที่ตัดแล้ว ไม่ได้มีการรั่วไหลเพียงจุดเดียว แต่มีสามจุด การเรียกโมเดลแต่ละครั้งส่งรูปของรอบนั้นซ้ำด้วยขนาดเต็ม ไลบรารีที่เราใช้เรียกโมเดลเก็บคำขอทุกคำขอไว้จนรอบจบ และระบบ tracing ของเฟรมเวิร์กเอเจนต์เก็บอินพุตของทุกการเรียก รวมถึงรูป ตลอดทั้งรอบ เราแก้ทั้งสามจุด: รูปถูกย่อก่อนส่ง และรูปของแต่ละการเรียกจะถูกปล่อยทันทีที่การเรียกนั้นเสร็จ

เอเจนต์เห็นรูปอย่างไร

เมื่อคุณสร้างบน Mythex เอเจนต์จะทำงานภายในแซนด์บ็อกซ์บนคลาวด์ของโปรเจกต์คุณ มันดูรูปได้ เช่น ภาพหน้าจอที่คุณแนบ mockup ไฟล์ในโปรเจกต์ หรือรูปที่มันเพิ่งสร้างเอง โดยส่งรูปไปยังโมเดลพร้อมกับการสนทนา

รอบ คือทุกอย่างที่เอเจนต์ทำเพื่อตอบข้อความหนึ่งจากคุณ ภายในรอบ เอเจนต์เรียกโมเดลหลายครั้ง: คิด เรียกเครื่องมือ ดูผลลัพธ์ แล้วคิดอีกครั้ง การเรียกแต่ละครั้งจะส่งการสนทนาที่ผ่านมาทั้งหมด ซึ่งรวมถึงรูปของรอบนั้นที่เข้ารหัสเป็นข้อความ (base64 ทำให้มีขนาดใหญ่ขึ้นประมาณหนึ่งในสาม)

รอบที่ล่มกำลังทำสิ่งที่สมเหตุสมผล มันรับสแกนแคตตาล็อกหกไฟล์ ขนาดราว 2.4 MB ต่อไฟล์ ตัดสินค้าแต่ละชิ้นออกมา และอ่านภาพที่ตัดแล้วกลับมาเพื่อตรวจ นั่นคือการเรียกโมเดลจำนวนมาก โดยแต่ละครั้งมีรูปขนาดใหญ่หลายรูป

สาเหตุที่หนึ่ง: ทุกการเรียกส่งรูปขนาดเต็มซ้ำ

การเรียกโมเดลแต่ละครั้งสร้างเนื้อหาคำขอใหม่ด้วยรูปของรอบที่ขนาดเต็ม ราว 20 MB ของ base64 ต่อการเรียก เนื้อหาถูกสร้างเป็นสตริงเดียวในหน่วยความจำของเอเจนต์ ดังนั้นทุกการเรียกจึงจัดสรรอีกราว 20 MB

การส่งขนาดเต็มไม่ได้ให้ประโยชน์อะไรเลย โมเดลจะย่อรูปลงเหลือราว 1,300 พิกเซลด้านยาวเองอยู่แล้ว พิกเซลที่เกินมีแต่จะเปลืองหน่วยความจำและเวลาอัปโหลด

วิธีแก้: ย่อครั้งเดียว ส่งเล็ก

  • รูปที่ใหญ่กว่า 400 KB ตอนนี้จะถูกแปลงเป็น JPEG ที่มีด้านยาวไม่เกิน 1,568 พิกเซล ก่อนส่ง รูปที่เล็กกว่าจะส่งตามเดิม
  • การแปลงใช้ ImageMagick ซึ่งมาพร้อมทุกแซนด์บ็อกซ์ของ Mythex และทำงานหนึ่งครั้งต่อไฟล์ รอบที่แสดงสแกนเดียวกันในทุกการเรียกจะใช้สำเนาที่ย่อแล้วซ้ำ แคชนี้ใช้คีย์เป็นพาธ ขนาด และเวลาแก้ไขของไฟล์ ไฟล์ที่ถูกแก้ไขจะถูกแปลงใหม่ และแคชมีขีดจำกัดขนาดของตัวเอง เพื่อไม่ให้มันกลายเป็นสิ่งที่ทำให้หน่วยความจำเต็ม
  • งบประมาณรูปสำหรับการเรียกโมเดลหนึ่งครั้งลดจาก 16 MB เป็น 6 MB

หกสแกนเดียวกันตอนนี้ใช้ 4.4 MB ต่อการเรียก แทนที่จะเป็น 19.7 MB

สาเหตุที่สอง: ไคลเอนต์โมเดลไม่ปล่อยคำขอ

ขนาดของแต่ละคำขอเป็นเพียงส่วนหนึ่ง หน่วยความจำยังเพิ่มขึ้นเรื่อย ๆ ตามการเรียกที่สะสม ในสภาพแวดล้อม staging ของเรา รอบแบบเดียวกันถือหน่วยความจำที่ยังใช้งานอยู่ 369 MB แม้หลังจาก garbage collection เต็มรูปแบบแล้ว ซึ่งคือจุดที่ทุกอย่างที่เข้าถึงไม่ได้จะถูกคืน การสุ่มตัวอย่าง heap ระบุว่าการเติบโตทั้งหมดอยู่ในส่วนของไลบรารีไคลเอนต์โมเดลที่เข้ารหัสเนื้อหาคำขอ

สาเหตุคือ abort listener เมื่อคุณกดหยุด abort signal ของรอบจะทำงาน และทุกคำขอที่ฟังอยู่จะยกเลิก เราส่ง signal ระดับรอบเดียวนั้นไปให้ทุกคำขอ ไลบรารีไคลเอนต์จะเพิ่มตัวฟัง “abort” ไปยัง signal ที่ได้รับ และไม่เคยลบออกเลย

ดังนั้นทุกคำขอของรอบจะยังถูกอ้างอิงจาก signal ของรอบตลอดเวลาที่รอบยังดำเนินอยู่ คือ listener ซึ่งถือ controller ซึ่งถือคำขอ ซึ่งถือเนื้อหาคำขอทั้งหมดพร้อมรูป

วิธีแก้: หนึ่ง signal ต่อคำขอ

ตอนนี้แต่ละคำขอได้ signal ของตัวเอง ซึ่งจะเชื่อมกับ signal ของรอบเฉพาะตอนที่คำขอนั้นกำลังทำงาน สำหรับการตอบกลับแบบสตรีม คือจนกว่าชิ้นสุดท้ายจะถูกอ่าน และจะถูกยกเลิกการเชื่อมทันทีหลังจากนั้น การกดหยุดยังคงไปถึงคำขอที่กำลังทำงานอยู่ แต่ signal ของรอบจะถือ listener เพียงหนึ่งตัวในแต่ละครั้ง

การทดสอบครอบคลุมทั้งสามส่วนนั้น:

  • หลังจาก 12 การเรียก จะไม่มี listener เหลือบน signal ของรอบ ก่อนแก้ไขมี 12
  • ตลอด 15 คำขอขนาดคำขอละ 8 MB หน่วยความจำคงที่ ก่อนแก้ไขมันเพิ่มขึ้น 128 MB
  • การกดหยุดยังคงยกเลิกคำขอที่กำลังสตรีมอยู่ได้ตรงกลาง

สาเหตุที่สาม: tracing เก็บอินพุตของทุกการเรียก

Snapshot ของ heap แสดงผู้ถือรายที่สาม คือประมาณ 6 MB ที่เก็บต่อการเรียกโมเดลหนึ่งครั้ง อันนี้มาจากการสตรีมเหตุการณ์ของเฟรมเวิร์กเอเจนต์ มันบันทึกทุกการเรียกโมเดลในรอบเป็นลูกของรอบพร้อมอินพุต จนกว่ารอบจะจบ รูปทุกรูปที่แนบกับทุกการเรียกจึงค้างอยู่ในหน่วยความจำไปด้วย

วิธีแก้: ล้างรูปเมื่อการเรียกคืนค่า

รูปจะแนบอยู่กับข้อความที่สร้างขึ้นสำหรับการเรียกโมเดลเฉพาะเท่านั้น และไม่เคยถูกเก็บไว้ในสถานะการสนทนาที่บันทึกไว้ ดังนั้นเมื่อการเรียกคืนค่าแล้ว จึงปลอดภัยที่จะล้างข้อมูลรูปในข้อความเหล่านั้น trace ยังคงเก็บบันทึกข้อความของการเรียก ส่วนพิกเซลจะหายไป

มีรายละเอียดหนึ่งที่สำคัญ: ต้องล้างรูปในที่เดิม เพราะ tracer อาจเข้าถึงข้อมูลรูปเดียวกันผ่านการอ้างอิงมากกว่าหนึ่งทางบนข้อความ การเปลี่ยนเป็นลิสต์ว่างใหม่จะทิ้งต้นฉบับ พร้อมพิกเซลทั้งหมด ไว้ให้เข้าถึงได้อยู่ สถานะการสนทนาที่บันทึกไว้จะไม่ถูกแก้ไขเลย

การทดสอบรันกราฟของเอเจนต์ภายใต้การสตรีมเหตุการณ์เดียวกันโดยมีรูป 4 MB ในทุกการเรียก ถ้าไม่มีการแก้ไข หน่วยความจำเพิ่มขึ้น 77 MB ตลอด 16 การเรียก เมื่อมีการแก้ไข หน่วยความจำคงที่

สิ่งที่เราได้เรียนรู้

  • ปัญหาหน่วยความจำอาจซ้อนกันเป็นชั้น สาเหตุแยกกันสามอย่างต่างเก็บรูปไว้นานเกินไป และทั้งสามต้องถูกกำจัดก่อนที่รอบจะอยู่ในหน่วยความจำได้
  • สิ่งที่คุณส่งให้ไลบรารีอาจถูกเก็บไว้ signal และ trace ต่างมีอายุยืนกว่าการเรียกที่ได้รับมา เมื่อหน่วยความจำเพิ่มขึ้นต่อการเรียก ให้ดูว่าการเรียกไปแตะต้องอ็อบเจกต์อายุยาวอะไรบ้าง
  • อย่าส่งสิ่งที่อีกฝ่ายจะทิ้งอยู่แล้ว พิกเซลที่โมเดลจะทิ้งอยู่ดีทำให้เราเสียหน่วยความจำทุกการเรียก
  • ทดสอบหน่วยความจำโดยตรง การแก้แต่ละอย่างมาพร้อมการทดสอบที่วัดการเติบโตของ heap หรือจำนวน listener ดังนั้นการถดถอยจะปรากฏเป็นตัวเลข ไม่ใช่การล่ม

นี่เป็นเรื่องหน่วยความจำที่สองจากเอเจนต์ในเวลาไม่นาน เรื่องแรกคือป้ายความคืบหน้าที่ส่งซ้ำ 41,000 ครั้ง หากคุณอยากรู้เพิ่มเติมว่าเอเจนต์คืออะไรและทำงานอย่างไร ดูคู่มือ AI agents และเอกสารแชท

Mythex · Pricing · สร้างอะไรก็ได้ด้วย AI · เทมเพลตเว็บไซต์และแอป · เปรียบเทียบ Mythex · อภิธานศัพท์การสร้างแอปด้วย AI · เครื่องมือฟรีสำหรับสร้างแอปด้วย AI · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Brasil) Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు Tagalog Türkçe Українська اردو Tiếng Việt 简体中文 繁體中文(香港) 繁體中文(台灣)