Tool: read_file — อ่านไฟล์ใหญ่โดยไม่ระเบิด RAM ด้วยการ sample แทนอ่านทั้งไฟล์

bash เหมาะกับการค้นหรือดูข้อมูลเบื้องต้น ส่วน read_file ในบทความนี้เป็น tool ที่อ่านเนื้อหาจริงของไฟล์และส่งส่วนที่จำเป็นให้โมเดลใช้ โดยไม่โหลดไฟล์ขนาดใหญ่ทั้งหมดเข้าหน่วยความจำ
Tool นี้คืออะไร
อ่านไฟล์ text/markdown/code/PDF/Word/Excel/PowerPoint จาก path ที่รู้แล้ว คืนผลลัพธ์ไม่เกิน 5,000 ตัวอักษร — ไฟล์ที่ใหญ่กว่านี้จะถูกสุ่มตัวอย่าง (sample) กระจายทั่วไฟล์ ไม่ใช่อ่านแค่ส่วนต้น เพราะโมเดลขนาดเล็กมี context window จำกัด การยัดไฟล์เต็มเข้าไปทำไม่ได้อยู่แล้ว
Agent เรียก tool นี้เมื่อไร
Docstring ระบุชัดเจน:
Use this directly when the exact path is already known – given in the question, or already found by a previous rag_search call. Do not call rag_search again for a path you already have.
พูดง่ายๆ: read_file มาหลัง rag_search เสมอ ในสาย workflow ปกติ (rag_search หา path → read_file อ่านเนื้อหา) ไม่ใช้เมื่อยังไม่รู้ path ที่แน่นอน
ปัญหาที่แก้: ไฟล์ใหญ่ vs RAM 8GB
ทีมพัฒนาบันทึกปัญหาจริงไว้ (PLAN.md §9.1): เดิมระบบโหลดไฟล์ทั้งไฟล์เข้า memory ก่อน แล้วค่อยตัดมาแสดงแค่ 5,000 ตัวอักษร — วิธีนี้ใช้ได้กับไฟล์เล็ก แต่ไฟล์ข้อความ/PDF ขนาดใหญ่จริงบนเครื่องผู้ใช้ ทำให้ RAM พุ่งเกินจำเป็นทั้งที่สุดท้ายใช้แค่เศษเสี้ยวของสิ่งที่โหลดมา
ทางแก้คือสถาปัตยกรรมแบบ streaming สองรอบ (two-pass):
- Pass 1 — สแกนทั้งไฟล์แบบไม่เก็บเนื้อหา: นับความยาวรวม, นับจำนวนบรรทัด/unit ที่ไม่ว่าง, และสแกนหา credential-shaped content ไปพร้อมกัน — ทั้งหมดนี้โดยไม่เก็บข้อความไว้ใน memory เลย (อ่านทีละบรรทัด ทิ้งทันทีหลังประมวลผล)
- Pass 2 — อ่านซ้ำเฉพาะจุดที่เลือกไว้แล้ว: จาก index ที่สุ่มเลือกไว้ (ตาม algorithm เดิมที่ deterministic — ใช้ hash ของ path+ขนาดไฟล์เป็น seed เพื่อให้ผลลัพธ์เดิมทุกครั้งที่อ่านไฟล์เดิม) อ่านเฉพาะบรรทัด/หน้าที่ต้องใช้จริง
วิธีนี้ทำให้ไฟล์ขนาดหลาย MB ก็อ่านได้โดยใช้ RAM คงที่เกือบตลอด ไม่ใช่แปรผันตามขนาดไฟล์
PDF: สุ่มตัวอย่างเป็น “หน้า” ไม่ใช่ “บรรทัด”
จุดที่ต้องระวังเป็นพิเศษ: PDF ยาวๆ ถ้าสุ่มตัวอย่างแบบบรรทัดธรรมดา อาจได้บรรทัดจากหน้า 1 เก็บ marker ของหน้าไว้ แต่ marker ของหน้าอื่นๆ หายไปหมด ทำให้การอ่านที่ตั้งใจกระจายทั่วเอกสารกลับเห็นเหมือนอ่านแค่หน้าเดียว — ระบบจึงสุ่มเลือกทั้งบล็อกของหน้า (สูงสุด 8 หน้า กระจายเท่าๆ กันตั้งแต่หน้าแรกถึงหน้าสุดท้าย) แทนสุ่มบรรทัด รักษาความสมบูรณ์ของแต่ละหน้าที่เลือกไว้
PDF ที่เป็นภาพสแกน (ไม่มีข้อความให้ extract ตรงๆ) จะ fallback ไป OCR อัตโนมัติ ซึ่งถูกจำกัดไว้ไม่เกิน 30 หน้าอยู่แล้วโดยธรรมชาติของ OCR pipeline จึงไม่ต้องกังวลเรื่อง RAM เพิ่มเติมสำหรับกรณีนี้
อ่านช่วงบรรทัดเฉพาะ (line range) ก็ผ่าน pipeline เดียวกัน
ถ้าระบุ start_line/end_line มา ระบบยังคงใช้หลักการสองรอบเดิม: รอบแรกนับและสแกน secret เฉพาะในช่วงที่ขอ, รอบสองอ่านช่วงนั้นจริง — ถ้าช่วงที่ขอสั้นพอ (ไม่เกิน 5,000 ตัวอักษรหลังคำนวณ) จะคืนเต็มช่วง ถ้ายาวเกินก็สุ่มตัวอย่างในช่วงนั้นแทนเหมือนไฟล์ปกติ
ป้องกันข้อมูลลับหลุด — สแกนทั้งไฟล์ก่อนคืนอะไรออกไป
ไม่ว่าจะเป็นไฟล์ text ธรรมดาหรือ Office document จุดร่วมสำคัญคือ สแกนหา credential-shaped content ครอบคลุมทั้งไฟล์เสมอ ก่อนจะคืนผลลัพธ์อะไรออกไปแม้แต่ตัวอย่างสั้นๆ — และมีรายละเอียดที่ง่ายจะมองข้าม: เวลาต่อข้อความจากหลาย unit (เช่นหลายชีทใน Excel) เข้าด้วยกัน ระบบป้อนตัวคั่นระหว่าง unit เข้าตัวสแกนด้วย ไม่ใช่แค่ต่อข้อความดิบเข้าด้วยกันตรงๆ เพราะเคยพบว่าการต่อท้ายข้อความ unit หนึ่งเข้ากับหัวข้อความอีก unit โดยไม่มีตัวคั่น อาจทำให้ข้อความที่ปกติควรถูกตรวจจับได้ (เช่น api_key: xxx) หลุดผ่าน word-boundary check ของตัวสแกนไปได้
ทำไมเรื่องนี้ถึงสำคัญ
read_file แสดงให้เห็นว่าการรัน AI agent บนเครื่อง RAM จำกัดไม่ใช่แค่เรื่อง “เลือกโมเดลเล็ก” อย่างเดียว — โค้ดรอบๆ โมเดลก็ต้องถูกออกแบบให้ประหยัดหน่วยความจำตั้งแต่ระดับอัลกอริทึม (streaming แทน materialize ทั้งไฟล์) ไม่งั้นแม้โมเดลจะเล็กพอ แต่ tool ที่รองรับมันกลับเป็นคอขวดแทน
ความคิดเห็น
กำลังโหลดความคิดเห็น...