ทำให้รอบงานยาวของเอเจนต์อยู่ในหน้าต่างบริบท
โมเดลอ่านได้ทีละจำนวนจำกัด นั่นคือหน้าต่างบริบทของมัน เอเจนต์ของ Mythex ทำงานยาว เช่น อ่านไฟล์จำนวนมาก รันคำสั่ง และมอบงานที่มีขอบเขตให้เอเจนต์ย่อย เราพบสามทางที่งานยาวพัง: เอเจนต์ย่อยเติบโตจนโมเดลปฏิเสธทุกคำขอ เอเจนต์ย่อยหยุดก่อนเวลาเพราะคิดว่าพื้นที่หมด และการนับโทเค็นของเราผิดมากสำหรับข้อความภาษารัสเซีย จีน และญี่ปุ่น นี่คือสิ่งที่เราเปลี่ยน
คำศัพท์ก่อน
- โทเค็น คือชิ้นส่วนที่โมเดลอ่าน ขีดจำกัดและค่าใช้จ่ายนับเป็นโทเค็น ไม่ใช่ตัวอักษรหรือคำ
- หน้าต่างบริบท คือจำนวนสูงสุดที่โมเดลอ่านได้ในคำขอหนึ่งครั้ง เรายังกำหนดงบประมาณ ของตัวเองให้ต่ำกว่าสำหรับแต่ละคำขอ เพื่อให้ค่าใช้จ่ายและความเร็วสมเหตุสมผล
- ผลลัพธ์จากเครื่องมือ คือสิ่งที่เอเจนต์ได้กลับมาจากเครื่องมือของมัน เช่น เนื้อหาของไฟล์ที่มันอ่าน หรือผลลัพธ์ของคำสั่งที่มันรัน ในงานยาว สิ่งเหล่านี้คือส่วนใหญ่ของสิ่งที่ถูกส่ง
- เอเจนต์ย่อย คือผู้ช่วยที่เอเจนต์หลักเริ่มขึ้นสำหรับงานที่แยกต่างหากได้ เช่น “ตรวจบทเหล่านี้เทียบกับบันทึก” มันได้รับคำสั่งหนึ่งข้อ แล้วทำงานผ่านการเรียกเครื่องมือหลายครั้งด้วยตัวเอง
ปัญหาที่ 1: เอเจนต์ย่อยเติบโตจนโมเดลปฏิเสธ
ทุกขั้นตอน เอเจนต์จะส่งการสนทนาที่ผ่านมาให้โมเดล เมื่อมันใหญ่เกิน โค้ดของเราจะตัดทอน แต่ตัดเฉพาะที่จุดเริ่มต้นของข้อความผู้ใช้ เพื่อไม่ให้การเรียกเครื่องมือและผลลัพธ์ถูกแยกออกจากกัน มันเก็บข้อความแรกไว้ เพิ่มหมายเหตุว่าการสนทนาก่อนหน้าถูกตัดทอน และเก็บรอบผู้ใช้ล่าสุดที่สมบูรณ์เท่าที่พอดี
เอเจนต์ย่อยมีข้อความผู้ใช้เพียงหนึ่งข้อความ คือคำสั่งของมัน ไม่มีจุดให้ตัด ดังนั้นมันจึงส่งประวัติทั้งหมดของตัวเองในทุกขั้นตอน ซึ่งเติบโตขึ้นทุกครั้ง จนคำขอใหญ่กว่าที่โมเดลรับได้เลย ราวหนึ่งล้านโทเค็น ในการทดสอบที่มีเอเจนต์ย่อยแบบนี้ 8 ตัว ทั้ง 8 ตัวถูกปฏิเสธ
วิธีแก้: ล้างผลลัพธ์เครื่องมือเก่าก่อน
ตอนนี้คำขอจะพอดีกับงบประมาณในสามขั้นตอน โดยลองแต่ละขั้นก็ต่อเมื่อขั้นก่อนหน้ายังไม่พอ:
- ล้างผลลัพธ์เครื่องมือที่เก่าที่สุด เนื้อหาของมันจะถูกแทนที่ด้วยหมายเหตุสั้น ๆ ว่าผลลัพธ์ถูกล้างเพื่อให้การสนทนาอยู่ในบริบทของโมเดล และเอเจนต์สามารถรันเครื่องมือนั้นใหม่หากต้องการ ไฟล์ที่อ่านเมื่อชั่วโมงก่อนมักเป็นสิ่งที่ใหญ่ที่สุดและมีประโยชน์น้อยที่สุดในคำขอ และไฟล์ยังอยู่ให้อ่านซ้ำได้ ผลลัพธ์ล่าสุดยังคงอยู่ครบ
- เก็บรอบผู้ใช้ที่สมบูรณ์ เหมือนเดิม: ข้อความแรก หมายเหตุ และรอบล่าสุดที่สมบูรณ์เท่าที่พอดี
- เก็บรอบการเรียกเครื่องมือที่สมบูรณ์ ภายในรอบยาวหนึ่งรอบ ซึ่งเป็นชนิดเดียวที่เอเจนต์ย่อยมี ให้เก็บข้อความแรก หมายเหตุ และรอบ “เรียกเครื่องมือ รับผลลัพธ์” ล่าสุดที่สมบูรณ์
สิ่งนี้เปลี่ยนเฉพาะสิ่งที่ถูกส่ง ประวัติที่เอเจนต์บันทึกไว้ยังเก็บทุกอย่าง ในการทดสอบเดียวกัน 0 จาก 8 ถูกปฏิเสธ และทั้ง 8 เสร็จสิ้น
ล้างเป็นชุด เพื่อให้แคชยังทำงาน
ผู้ให้บริการโมเดลสามารถนำงานของจุดเริ่มต้นคำขอกลับมาใช้ใหม่ได้ ถ้ามันเหมือนกับคำขอก่อนหน้า นั่นคือ prefix cache ถ้าเราล้างผลลัพธ์เพิ่มอีกหนึ่งรายการทุกการเรียก จุดเริ่มต้นของคำขอจะเปลี่ยนทุกครั้ง และแคชจะไม่ช่วยอะไรเลย
ดังนั้นผลลัพธ์เก่าที่สุดจะถูกล้างทีละสี่รายการ ไม่ใช่ทีละหนึ่ง ส่วนที่ถูกล้างจึงคงเดิมในหลายการเรียก ผลลัพธ์ที่ไม่ใหญ่กว่าหมายเหตุมากนักจะถูกปล่อยไว้ เพราะการล้างจะประหยัดได้แทบไม่เท่าไรและยังคงเปลี่ยนจุดเริ่มต้นของคำขอ ส่วนที่เก็บไว้ครบถูกตัดสินด้วยขนาด ไม่ใช่จำนวน: ผลลัพธ์ล่าสุดที่พอดีในหนึ่งในสี่ของงบประมาณจะถูกเก็บไว้ และอย่างน้อยหนึ่งรายการเสมอ เวอร์ชันก่อนหน้าเก็บหกรายการครบเสมอ ซึ่งเหมาะกับผลลัพธ์คำสั่งสั้น ๆ แต่เมื่อการอ่านไฟล์ยาว ทำให้งบประมาณส่วนใหญ่ยังเหลือให้ผลลัพธ์เก่า
ข้อผิดพลาดตอนนี้บอกสาเหตุ
คำขอที่โมเดลปฏิเสธว่าไม่ถูกต้องจะไม่ถูกลองใหม่อีกต่อไป เพราะการส่งคำขอเดิมซ้ำจะได้คำตอบเดิม ถ้าการสนทนายาวเกินไปสำหรับโมเดล ผู้ใช้จะเห็นว่า “การสนทนานี้ยาวเกินไปให้โมเดลอ่านในครั้งเดียว เริ่มแชทใหม่สำหรับขั้นตอนถัดไป ทุกอย่างที่สร้างไว้จนถึงตอนนี้จะยังอยู่” นั่นเป็นสิ่งที่ผู้ใช้ต้องจัดการ ไม่ใช่การล่มของระบบ จึงไม่ปลุกทีมของเรา
ปัญหาที่ 2: เอเจนต์หยุดเพื่อ “ประหยัดพื้นที่”
เอเจนต์ย่อยที่ถูกขอให้อ่านบทยาว 40 บท หยุดหลังจากอ่านไป 2 บท โดยบอกว่าอยากประหยัดพื้นที่ มันใช้ไปราว 100,000 โทเค็นจากงบประมาณ 400,000 โทเค็น
มันไม่มีทางรู้ว่าผลลัพธ์เก่าจะถูกล้างให้มันแล้ว ดังนั้นเราจึงบอกมัน คำสั่งของเอเจนต์ตอนนี้บอกว่า เมื่อการสนทนาโตเกินสิ่งที่โมเดลรับได้ ผลลัพธ์เครื่องมือเก่าที่สุดจะถูกล้าง และผลลัพธ์ล่าสุดจะยังอยู่ครบ ดังนั้นอย่าหยุดงานยาวเพื่อประหยัดพื้นที่ ให้ทำต่อไป และอ่านไฟล์ซ้ำหากต้องการสิ่งที่ถูกล้างไป
การแก้ไขที่โมเดลมองไม่เห็นจะไม่ใช่การแก้ไขจากมุมมองของโมเดล กลไกจะช่วยได้ก็ต่อเมื่อเอเจนต์เชื่อถือมัน
ปัญหาที่ 3: นับโทเค็นเหมือนทุกอย่างเป็นภาษาอังกฤษ
เราประมาณโทเค็นโดยไม่ได้รัน tokenizer โดยใช้จำนวนตัวอักษรหารด้วยสี่ นั่นเป็นกฎคร่าว ๆ ที่สมเหตุสมผลสำหรับภาษาอังกฤษ แต่ไม่ใช่สำหรับอักษรอื่น ภาษารัสเซียมีราว 2.2 ตัวอักษรต่อโทเค็น ส่วนภาษาจีนหรือญี่ปุ่นราวหนึ่งตัวอักษรต่อโทเค็น
ดังนั้นเอเจนต์ย่อยที่อ่านบทภาษารัสเซียจึงส่งคำขอราว 640,000 โทเค็น ขณะที่การประมาณของเราบอกว่าต่ำกว่างบประมาณ 400,000 การประมาณนั้นอาจทำให้คำขอเกินขีดจำกัดตายตัวของโมเดลได้ง่ายเช่นกัน
การประมาณตอนนี้นับตามอักษร: ASCII ธรรมดาที่สี่ตัวอักษรต่อโทเค็น จีน ญี่ปุ่น และเกาหลีที่หนึ่งตัวอักษร และทุกอย่างอื่น เช่น ซีริลลิก กรีก อาหรับ ตัวอักษรที่มีเครื่องหมายกำกับ และอีโมจิ ที่สองตัวอักษร ตั้งใจให้ประเมินสูงไว้ ในบทภาษารัสเซียบทหนึ่ง ตอนนี้ประมาณได้ 43,423 โทเค็น เทียบกับราว 44,600 ที่วัดได้จริง ก่อนหน้านี้บอกว่า 25,023 เนื่องจากข้อความไม่เปลี่ยนเมื่อเขียนแล้ว การประมาณของมันจึงคำนวณครั้งเดียวและจำไว้ ไม่ต้องคำนวณใหม่ทุกขั้นตอน
สิ่งที่เราได้เรียนรู้
- ตัดทอนตรงที่ขนาดอยู่จริง ในงานของเอเจนต์ นั่นคือผลลัพธ์เครื่องมือ ไม่ใช่ข้อความผู้ใช้
- บอกเอเจนต์เกี่ยวกับตาข่ายความปลอดภัยของตัวเอง ไม่อย่างนั้นมันจะวางแผนรอบขีดจำกัดที่ไม่ได้ใช้แล้ว
- “อักษร ÷ 4” คือสมมติฐานของภาษาอังกฤษ สิ่งใดก็ตามที่นับโทเค็นให้ผู้ใช้หลายภาษาต้องนับตามอักษร หรือใช้ tokenizer จริง
- ระวังแคช คำขอที่เปลี่ยนที่จุดเริ่มต้นทุกการเรียกจะมีค่าใช้จ่ายมากขึ้นและทำงานช้าลง
หากคุณกำลังสร้างฟีเจอร์ AI ในแอปของคุณเอง คู่มือของเราLLM คืออะไร และวิธีใช้ LLM APIs ครอบคลุมหน้าต่างบริบทและโทเค็นตั้งแต่ต้น ดูเพิ่มเติมเรื่องเอเจนต์ย่อยใน Mythex ได้ที่เอกสารเอเจนต์ย่อย