MemGPT - LLM ที่มีหน่วยความจำแบบแก้ไขได้ด้วยตนเองสำหรับบริบทไม่สิ้นสุด
(github.com/cpacker)- Letta เป็นโครงการสำหรับสร้าง AI ที่ใช้ หน่วยความจำขั้นสูง ซึ่งสามารถเรียนรู้และพัฒนาตนเองได้เมื่อเวลาผ่านไป
- วิธีใช้งานแบ่งเป็น Letta Code สำหรับรันเอเจนต์ในเทอร์มินัลบนเครื่อง และ Letta API สำหรับผสานเอเจนต์เข้ากับแอปพลิเคชัน
- CLI ต้องการ Node.js 18+ และติดตั้งด้วย
npm install -g @letta-ai/letta-codeจากนั้นรันlettaเพื่อใช้งานเอเจนต์ที่มีหน่วยความจำบนคอมพิวเตอร์ของคุณ - เอเจนต์ Letta Code ช่วยงานด้านการเขียนโค้ดและงานที่ทำได้บนคอมพิวเตอร์ รองรับ skills และ subagents พร้อมบันเดิล skills/subagents ที่สร้างไว้ล่วงหน้าสำหรับหน่วยความจำขั้นสูงและการเรียนรู้อย่างต่อเนื่อง
- Letta ไม่ยึดติดกับโมเดลใดโมเดลหนึ่ง โดย README แนะนำ Opus 4.5 และ GPT-5.2 เพื่อประสิทธิภาพสูงสุด และลิงก์ model leaderboard ไว้เป็นข้อมูลอ้างอิงด้านอันดับ
- Letta API ใช้สำหรับผสานเอเจนต์แบบมีสถานะเข้ากับแอปพลิเคชัน โดยมี agents API แบบฟีเจอร์ครบถ้วน รวมถึง SDK สำหรับ Python และ TypeScript
- แพ็กเกจ TypeScript/Node.js:
@letta-ai/letta-client - แพ็กเกจ Python:
letta-client - ตัวอย่างแสดงขั้นตอนการสร้างเอเจนต์และส่งข้อความโดยใช้
LETTA_API_KEYและ Letta API key
- แพ็กเกจ TypeScript/Node.js:
- การใช้งาน Letta และบริการ Letta ที่เกี่ยวข้องอยู่ภายใต้เงื่อนไขการยอมรับ privacy policy และ terms of service
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
พวกเราเป็นผู้เขียน MemGPT ถ้ามี คำถามเกี่ยวกับการใช้งาน/การ implement ก็ถามมาได้เลย
ถ้าอยากลองใช้เอง สามารถดูการแก้ไขหน่วยความจำทำงานได้ในบอต Discord บนเซิร์ฟเวอร์ MemGPT Discord (https://discord.gg/9GEQrxmVyE) เมื่อคุยกับบอต จะเห็นกระบวนการที่ MemGPT แก้ไขหน่วยความจำเพื่ออัปเดตโปรไฟล์เกี่ยวกับผู้ใช้และตัวมันเอง
ทั้งหมดเป็นโอเพนซอร์ส จึงรันในเครื่องได้จากโค้ดที่ https://github.com/cpacker/MemGPT ใน repository ยังมี ตัวอย่างที่เน้นเอกสาร สำหรับคุยกับ MemGPT เกี่ยวกับเอกสาร API ของ LlamaIndex ด้วย
สงสัยว่าทำไมถึงจัดการทุกอย่างใน context window เดียว เมื่อไม่กี่เดือนก่อนตอนทดลองสิ่งที่คล้ายกัน ผม parallelize ด้วยหลาย agent ในขั้นตอน preprocessing/postprocessing
เช่น context window หลักไม่รู้เลยว่ามีการสร้างหรือค้นคืนหน่วยความจำ postprocessor จะสร้างหน่วยความจำจากบทสนทนาโดยอัตโนมัติแล้วบันทึกไว้ และเก็บบทสนทนาทั้งหมดใน vector database ด้วย preprocessor จะฉีดหน่วยความจำและบริบทที่เกี่ยวข้องให้เข้ากับบทสนทนาโดยอัตโนมัติ แถมยังเขียน history ใหม่ให้จากมุมมองของ context window หลักเหมือนกับว่าหน่วยความจำนั้นมีมาตั้งแต่แรก
วิธีนี้ช่วยประหยัดพื้นที่ใน context window หลักที่ต้องใช้กับ system prompt ที่ไม่จำเป็นและอื่น ๆ ได้มาก
แนวทางโดยนัยคือ “LLM หลัก” หรือในแชตคือ “เธรดสนทนา” จะไม่รู้เรื่องการจัดการหน่วยความจำที่อยู่เบื้องหลัง การจัดการนี้อาจทำโดย “LLM สำหรับหน่วยความจำ”, สคริปต์แบบ rule-based, neural network ขนาดเล็ก ฯลฯ
แนวทางแบบชัดแจ้งคือแบบของ MemGPT ซึ่งใช้ LLM ตัวเดียวจัดการทั้งหมด งานวิจัยเดิมเกี่ยวกับการแชตหลาย session/ระยะยาวมักเป็นแนวทางโดยนัยที่มีขั้นตอนสร้างหน่วยความจำแยกต่างหาก และ memory store ของแชตบอตสำหรับผู้บริโภคก็น่าจะเป็นแบบโดยนัยเป็นส่วนใหญ่
การจัดการหน่วยความจำแบบชัดแจ้งต้องการการทำตามคำสั่งที่ซับซ้อน จึงคิดว่ายากสำหรับ LLM สาธารณะส่วนใหญ่ในตอนนี้ กำลังดูวิธีแก้ เช่น การ fine-tune โมเดลเปิด
trade-off ก็เป็นอย่างที่คุณพูด แนวทางโดยนัยไม่จำเป็นต้องใส่คำสั่งการจัดการหน่วยความจำทั้งหมดไว้ใน pre-prompt ของ LLM ข้อความระบบทั้งหมดของ MemGPT มีประมาณ 1,000 token ในทางกลับกัน เมื่อ LLM ทำงานได้ถูกต้อง การจัดการหน่วยความจำแบบชัดแจ้งทำให้ระบบโดยรวมเรียบง่ายกว่ามาก เพราะไม่มี overhead ในการจัดการ LLM หลายโมเดลบนเธรดแบบขนาน
ผมมองว่า LLM และการประมวลผลภาษาธรรมชาติอาจกลายเป็นอินเทอร์เฟซที่เป็นไปได้มากขึ้นสำหรับข้อมูลแบบมีโครงสร้าง เมื่อมีการสร้างข้อมูลในบริบททางธุรกิจเฉพาะ ก็จะดึงข้อมูล สร้าง embedding และสร้าง vector database
ใน postprocessing หลังจากโมเดลหลักตอบแล้ว postprocessor จะสร้างหน่วยความจำจากบทสนทนาโดยอัตโนมัติและบันทึกไว้ โดยเก็บบริบทสำคัญไว้แต่ไม่เพิ่มภาระงานนี้ให้โมเดลหลัก ส่วนหนึ่งของคำขอยังรัน business logic ที่เกี่ยวข้อง แล้วป้อนกลับเข้าระบบ
ใน preprocessing ก่อนส่งอินพุตใหม่ไปยังโมเดลหลัก จะตรวจสอบหน่วยความจำที่บันทึกไว้ ฉีดบริบทที่เกี่ยวข้อง และรัน logic ด้วย กล่าวคือ preprocessor จะให้ “การทบทวน” บทสนทนาก่อนหน้าแก่โมเดลหลัก เพื่อเตรียมให้ตอบได้สอดคล้องและมีข้อมูลมากขึ้น
เกี่ยวกับสิ่งที่เขียนไว้ในข้อจำกัด หาก variant ของ Llama 2 70B แม้จะ fine-tune มาเพื่อการเรียกฟังก์ชันแล้ว แต่ยังสร้างการเรียกฟังก์ชันผิด หรือ hallucinate ฟังก์ชันที่อยู่นอก schema ที่ให้มา ก็สามารถใช้ grammar-based sampling ได้
อย่างน้อยก็รับประกันได้ว่าการเรียกฟังก์ชันจะถูกต้องทางไวยากรณ์
[0] https://github.com/ggerganov/llama.cpp/tree/master/grammars
ตัวอย่างเช่น โมเดลขนาดใหญ่ที่ fine-tune ด้วยข้อมูลการเรียกฟังก์ชัน (https://huggingface.co/jondurbin/airoboros-l2-70b-2.1#agentf...) โดยทั่วไปก็ output JSON ที่ parse ได้ แต่ argument หรือชื่อฟังก์ชันผิด
เช่น ตอนพยายามเขียนข้อมูล แทนที่จะเรียก
working_context.appendที่ถูกต้องตามที่ระบุไว้ใน pre-prompt กลับ output การเรียกpersonal_diary.addซึ่งไม่ได้กำหนดไว้เลยเห็นแค่ชื่อเรื่องแล้วนึกว่าเป็นเทคนิคแก้ไขหน่วยความจำของ neural memory ใน LLM คือการเปลี่ยน หน่วยความจำระดับ weight ระหว่างสนทนา ไม่ใช่ context เช่นแนวทางอย่าง ROME [1]
พอรู้ว่าจริง ๆ แล้วเป็นงาน RAG ที่เจ๋งก็ดีใจ และอีกไม่นานผมจะทำ MemEditGPT เวอร์ชันของตัวเอง
[1] https://arxiv.org/abs/2202.05262
อย่างที่เข้าใจถูกแล้ว MemGPT ไม่ได้แก้ไข weight ของ LLM แบบ ROME “หน่วยความจำ” ที่พูดถึงใน MemGPT อยู่ระดับข้อความ/token ไม่ใช่ระดับ weight
แนวคิดหลักคือให้ LLM มีความสามารถในการแก้ไข scratchpad ของ working memory ที่คงอยู่ภายใน context และอ่าน/เขียน context ภายนอกผ่านฟังก์ชัน รายละเอียดสำคัญคือ เพื่อรับมือกับข้อจำกัดของ context ที่มีขนาดจำกัด การอ่านจึงทำเป็นหน้าเสมอ หรือก็คือเป็น chunk
MemGPT สามารถ chain ฟังก์ชันต่อกันเพื่ออ่านและเขียนซ้ำหลายครั้งจากอินพุตผู้ใช้เดียวได้ ดังนั้นจึงสามารถค้นหา database เอกสารขนาดใหญ่และรวบรวมข้อมูลจากหลายแหล่งเพื่อส่งคำตอบกลับมาได้ เหมือนตัวอย่างเอกสาร API ของ LlamaIndex ใน README
อยู่พักหนึ่งผมสงสัยว่า ChatGPT เวอร์ชันเว็บ (chat.openai.com ไม่ใช่ API) อาจทำงานแบบนี้ในการสนทนา แม้ในประวัติแชตที่ยาวมาก ก็รู้สึกว่าคุณภาพค่อย ๆ ลดลง มากกว่าจะลืมทุกอย่างไปในทันที
แน่นอนว่าในบริบทอาจมีเบาะแสมากกว่าที่ผมคิดก็ได้
ไม่ว่าอย่างไร ผมคิดว่าไอเดียแบบนี้มีโอกาสสูงที่จะกลายเป็น ฟีเจอร์พื้นฐาน ของแชตบอตทุกตัวในอนาคต
มันมีการสูญเสียข้อมูล และสุดท้ายก็จะเสียข้อมูลสำคัญไป แต่ประสิทธิภาพอาจค่อย ๆ ลดลงได้ค่อนข้างนุ่มนวล ใน MemGPT ยังใช้การสรุปแบบเรียกซ้ำโดยนัยทับบนการจัดการหน่วยความจำแบบชัดเจนทั้งหมดด้วย
ถ้าเคยทำงานที่น่าสนใจแม้เพียงเล็กน้อย เอาต์พุตจะถูกโน้มเอียงอย่างแรงโดยพรอมป์ต์ เนื่องจากมีเพียงตัวอย่างเดียวคือเอาต์พุต/ประวัติก่อนหน้า จึงสูญเสียข้อมูลบางส่วนแทนที่จะได้การแจกแจงความน่าจะเป็นที่ราบรื่น และเพราะอินพุตหลายแบบอาจแมปไปยังเอาต์พุตเดียวกันได้ จึงสูญเสียข้อมูลอีกบางส่วน
แต่พรอมป์ต์ในโลกจริงมักเป็นถ้อยคำที่ง่ายและสั้นที่สุดเท่าที่นึกออกเพื่อให้ได้ผลลัพธ์ที่ต้องการ ดังนั้นถ้า LLM ประเมินพรอมป์ต์นั้นได้ การตีความบริบทที่ขาดหายไปก็น่าจะถูกต้องพอสมควร กล่าวคือ ข้อมูลจำนวนมากที่ดูเหมือนหายไปยังคงอยู่ในเอาต์พุตของ LLM และแม้บริบทเก่าจะถูกดันออกไป ปริมาณข้อมูลที่สูญเสียในครั้งเดียวก็ไม่ได้มากเกินไป
มีเทคนิคง่าย ๆ มากมายในการทำหน่วยความจำแบบสูญเสียข้อมูล ตัวอย่างเช่น วิธี average pooling โทเคนแบบที่ sentence transformers ใช้ ผมไม่ค่อยแน่ใจว่าทำไมวิธีนี้ถึงไม่ค่อยถูกใช้ในการบีบบริบทจำนวนมากให้เป็นพรอมป์ต์ ที่จริงมันทำหน้าที่เป็น หน่วยความจำระยะกลาง ได้
จำชื่อไม่ได้ แต่มี ภาษาโปรแกรมเชิงลึกลับ อยู่แล้วที่สั่งคำสั่งได้แบบไม่เสถียร ถ้าออกแบบโปรแกรมอย่างระมัดระวัง ก็ทำให้ลำดับคำสั่งถูกรันด้วยความน่าเชื่อถืออย่าง 99%, 99.9% ได้
อีก 20 ปีต่อมา แนวทางเดียวกันนี้ถูกทำให้แพร่หลายในสายโครงสร้างพื้นฐานโดยไม่ประชดประชัน ภายใต้ชื่อ “chaos engineering”
อัปเดต: เพิ่งเปิดตัว แชตบอต Discord แบบถาวร ที่สร้างบน MemGPT ลองใช้ได้ที่นี่: https://discord.gg/9GEQrxmVyE
จากโค้ดบน GitHub สามารถรันเดโมแชตบอตในเครื่องได้ รวมถึงเดโมบอตถาม-ตอบเอกสารที่ให้ถาม MemGPT เกี่ยวกับเอกสาร API ได้ด้วย
ผมคิดว่าข้อจำกัดใหญ่ที่สุดของ LLM คือ หน้าต่างบริบท ความสามารถในการให้เหตุผลที่ยอดเยี่ยมก็มักติดข้อจำกัดของหน้าต่างบริบทในกรณีใช้งานจริง
เห็นด้วยกับคำอธิบายที่ว่า การสรุปแบบเรียกซ้ำเป็นวิธีง่าย ๆ ในการจัดการหน้าต่างบริบทที่ล้น แต่โดยเนื้อแท้แล้วมีการสูญเสียข้อมูล และสุดท้ายจะสร้างช่องโหว่ใหญ่ในหน่วยความจำของระบบ
แต่ MemGPT ก็ทำสิ่งเดียวกันและมีปัญหาเดียวกัน ต่างกันแค่นิดหน่อยตรงที่แทนที่จะสรุปทุกอย่างแบบเรียกซ้ำ มันเลือกค้นประวัติแล้วสร้างขึ้นมาใหม่ในแต่ละคำขอ ไอเดียนี้เจ๋ง
แต่ผมยังสงสัย แนวทางนี้พึ่งพาสมมติฐานพื้นฐานว่า บริบทเดิมเป็น บริบทที่สรุปได้ด้วยเอนโทรปีต่ำ และคำถามขึ้นอยู่กับประวัติเพียงบางส่วน
สำหรับแชตหรือกรณีอย่าง “ตอบคำถามจากชุดเอกสารขนาดใหญ่” อาจจะถูกต้อง แต่ในกรณีอย่างการสร้างโค้ด ซึ่งบริบทอัดแน่นด้วยข้อมูลที่ทิ้งไม่ได้ เช่น คำนิยาม API บางอย่าง และต้องใช้บริบทกว้าง ๆ อย่างคำนิยาม API จำนวนมาก สมมติฐานทั้งสองข้อล้วนผิด
โครงสร้างและการใช้งานน่าสนใจ และเดโมก็ยอดเยี่ยม แต่เสียดายที่งานวิจัยเกี่ยวกับการสรุปเหล่านี้ไม่ยอมรับข้อจำกัดพื้นฐานของแนวทางนี้
อย่างที่บอก คิวการสนทนาของ MemGPT ถูกจัดการด้วยการสรุปแบบเรียกซ้ำ เช่นเดียวกับงานวิจัยก่อนหน้าและการใช้งานแชตบอตจำนวนมาก แต่ยังมี หน่วยความจำของ LLM ในพื้นที่ “คงที่” ที่อ่าน/เขียนได้ ซึ่งไม่เกี่ยวกับการสรุปแบบเรียกซ้ำ และในบทความเรียกสิ่งนี้ว่า “บริบทการทำงาน”
ดังนั้น MemGPT จึงเข้าถึงได้ทั้งสรุปแบบเรียกซ้ำที่สร้างอัตโนมัติ และบริบทการทำงานที่ MemGPT ดูแลให้อัปเดตอยู่เสมออย่างจริงจัง
ทั้งสองอย่างนี้ยังแยกจากบริบทภายนอกของ MemGPT ที่ถูกนำเข้ามาในคิวการสนทนาด้วยการเรียกฟังก์ชันด้วย ในทุกตัวอย่าง การอ่านบริบทภายนอกไม่ได้ถูกบีบอัด และทำเป็นรายหน้าโดยไม่มีการสรุป
เมื่อการสรุปคิวถูกทริกเกอร์ MemGPT จะได้รับการแจ้งเตือนจากระบบ ดังนั้นถ้าต้องรักษารายละเอียดบางอย่างจากคิวการสนทนาไว้ ก็สามารถเขียนลงในบริบทการทำงานก่อนที่จะถูกลบหรือถูกสรุปได้
ในตัวอย่างเอเจนต์สนทนา บริบทการทำงานใช้เก็บข้อเท็จจริงสำคัญเกี่ยวกับผู้ใช้และเอเจนต์ เพื่อรักษาบทสนทนาให้สอดคล้องกัน บริบทการทำงานจะถูก LLM เห็นอยู่เสมอ จึงไม่จำเป็นต้องค้นหาแยกต่างหาก
ในงานถาม-ตอบเอกสาร บริบทการทำงานสามารถใช้ติดตามงาน/คำถามปัจจุบันและความคืบหน้าได้ สำหรับคำถามที่ซับซ้อน มันช่วยให้ MemGPT ติดตามรายละเอียดอย่างการค้นหาก่อนหน้าและคำขอหน้าก่อนหน้าได้