เราเพิ่งย้าย camelAI agent ออกจาก virtual machines เสร็จเรียบร้อย ตอนนี้ agent ทำงานภายใน Cloudflare Durable Object ระบบไฟล์ของมันอยู่ใน SQLite และ R2 และมันเขียน JavaScript แทน bash ทีมส่วนใหญ่รัน coding agents ใน Linux VM หรือ container sandbox แบบเต็มรูปแบบ และเราก็เคยทำเช่นกัน
เราต้องการออกจาก VMs เพราะการให้ผู้ใช้ทุกคนมีเครื่องที่เปิดตลอดเวลาพร้อมดิสก์ที่แนบมานั้นแพงเกินไปที่จะขยายขนาด ส่วนที่ยากคือ coding agents สมมติว่ามี Linux พวกมันถูกฝึกให้ใช้ bash และ harness ที่เราเปิดตัวตอนแรกต้องใช้ VM เต็มรูปแบบ ดังนั้นการมาถึงจุดนี้ต้องออกแบบใหม่สามครั้ง ข้อแลกเปลี่ยนคือตอนนี้ agent สามารถทำได้เฉพาะสิ่งที่เราสร้าง method ไว้อย่างชัดเจน ซึ่งฟังดูจำกัดแต่ก็ดีต่อผลิตภัณฑ์
ผม Miguel, CTO ของ camelAI โค้ดเบสของเราเพิ่งเปิดเป็นโอเพนซอร์ส ดังนั้นทุกอย่างในโพสต์นี้คือโค้ดที่คุณสามารถอ่านได้ที่ github.com/qaml-ai/camelAI ผมจะลิงก์ไปยังไฟล์ที่เกี่ยวข้องตลอดทาง นี่คือความก้าวหน้า
ขั้นตอนที่ศูนย์: ยุค VM
เราเปิดตัวบน Claude Code harness ซึ่งต้องใช้ virtual machine เต็มรูปแบบเพื่อทำงาน เราลองผู้ให้บริการ VM หลายราย ไม่มีรายไหนตรงตามข้อกำหนดด้านความคงทนและประสิทธิภาพ และสุดท้ายเราก็ สร้าง service container ของเราเอง โพสต์นั้นยังคงอยู่ แต่เราไม่ได้รันโครงสร้างพื้นฐานนั้นอีกแล้ว
service container ทำงานได้ แต่ก็หนักมาก การมี VM ที่เปิดตลอดเวลาสำหรับผู้ใช้ทุกคนนั้นแพง และการเก็บไฟล์ของผู้ใช้ทุกคนไว้ในดิสก์ที่เชื่อมต่อเร็วก็แพงเช่นกัน การขยายขนาดหมายถึงการขยายเครื่องจริงที่มีดิสก์จริง ซึ่งจะแพงเกินไปสำหรับจำนวนผู้ใช้ที่เราตั้งเป้าไว้ ดังนั้นแทนที่จะหาวิธีจัดการ VM อย่างชาญฉลาด เราจึงเริ่มออกแบบโดยไม่ต้องใช้ VM เลย
ขั้นตอนที่หนึ่ง: นำ agent ออกจาก VM
Claude Code harness แยกออกจาก VM ไม่ได้ ดังนั้นขั้นตอนแรกคือการสร้าง harness ของเราเอง เราสร้างมันบน pi ซึ่งเป็น coding agent โอเพนซอร์สของ Mario Zechner pi คือ stack ของ libraries ชั้นบนสุดสมมติว่าระบบปฏิบัติการปกติ แต่ชั้นล่างให้ primitives ของ agent เช่น agent loop และการจัดการสถานะ โดยไม่สนใจว่ามันจะรันที่ไหน เราไม่ได้เปลี่ยนโค้ด pi ใด ๆ เรานำชั้นล่างเหล่านั้นมาใช้และสร้าง harness ของเราเอง บนพื้นฐานของมัน โดยรันภายใน Cloudflare Durable Object แทนที่จะเป็นสภาพแวดล้อม Linux
Durable Object คือ instance คอมพิวต์แบบ stateful ขนาดเล็กที่สปินขึ้นบน edge ของ Cloudflare ใกล้กับผู้ใช้ที่สร้างมัน แต่ละเธรดแชทจะได้รับ Durable Object ของตัวเอง ซึ่งทำให้ latency ลดลงเมื่อเทียบกับการส่งทุกอย่างผ่าน VM host แบบรวมศูนย์
ในขั้นตอนนี้เรายังคงใช้ VMs แต่ agent ไม่ได้อยู่ภายในอีกต่อไป มันเรียกไปยัง VM ระยะไกลเมื่อต้องการรันคำสั่ง Anthropic อธิบายการแบ่งแบบเดียวกันนี้สำหรับ managed agents ของมัน สมองแยกจากมือ มันทำให้เรามีคุณสมบัติที่ดีบางอย่าง:
- agent เริ่มตอบสนองก่อนที่ VM จะตื่น เพราะมันไม่ต้องรอให้เครื่อง boot
- VM สามารถกลับไปพักในขณะที่ agent ยังทำงานต่อ หรือไม่ต้องตื่นเลยถ้าเทิร์นนั้นไม่ต้องการคำสั่งใด ๆ
- สมองเดียวสามารถควบคุมหลายมือ agent ตัวเดียวสามารถใช้งานหลาย VMs พร้อมกันได้
เราเรียกมือเหล่านั้นว่าโปรเจกต์ แต่ละโปรเจกต์มาพร้อมกับ VM สำหรับรันคำสั่งและ git repo ที่สร้างโดยโปรแกรมผ่าน Cloudflare Artifacts ซึ่งเป็นพื้นที่เก็บข้อมูลที่เข้ากันได้กับ git ที่คุณสามารถจัดเตรียมได้ทันทีจาก Worker agent ไม่รู้จริง ๆ ว่ามันรันอยู่นอก VM มันยังมี bash และทำงานเหมือน coding agent ทั่วไป
ปัญหาคือสิ่งนี้แก้ไขเฉพาะ latency เท่านั้น ไม่ใช่ต้นทุน เรายังมี VM ต่อผู้ใช้หนึ่งเครื่อง ดังนั้นเรายังมีปัญหาด้านต้นทุนและการขยายขนาดทั้งหมดจากดีไซน์ดั้งเดิม
ขั้นตอนที่สอง: เอา VM ออก
เวอร์ชันถัดไปยังคงโครงสร้างโปรเจกต์เดิม แต่ลบ VM ที่อยู่ข้างหลังออก ตอนนี้แต่ละโปรเจกต์ได้รับการสนับสนุนโดย ระบบไฟล์ที่อยู่ใน Durable Object โดยมี R2 อยู่เบื้องหลังสำหรับไฟล์ขนาดใหญ่
เราไม่ได้คิดค้นสิ่งนี้ ทีม agents ของ Cloudflare สร้าง Shell ซึ่งเป็นระบบไฟล์และ runtime สำหรับการรันคำสั่งทดลองสำหรับ Workers และเราใช้โค้ดของพวกเขาอย่างหนัก กลไกนั้นง่าย พื้นที่เก็บข้อมูลของ Durable Object คือฐานข้อมูล SQLite ที่มีขีดจำกัด 10 GB และแต่ละแถวมีขนาดสูงสุด ไฟล์ขนาดเล็กจะอยู่ในแถว SQLite โดยตรง ไฟล์ที่มีขนาดประมาณ 1.5 MB ขึ้นไปจะถูกเขียนไปยัง R2 และแถว SQLite จะเก็บเพียง pointer เท่านั้น สำหรับ agent มันดูเหมือนระบบไฟล์ปกติ แต่เบื้องหลังมันคือฐานข้อมูลและที่เก็บออบเจกต์ ดังนั้นความคงทนคือข้อมูลที่เก็บไว้ ไม่ใช่โครงสร้างพื้นฐานที่เราต้องทำให้คงอยู่
ประวัติเวอร์ชันยังคงทำงานผ่าน Artifacts ดังนั้นทุกโปรเจกต์จึงมีประวัติ git โดยที่เราไม่ต้องโฮสต์ git server
ขั้นตอนที่สาม: เอา bash ออก
การเอา bash ออกรู้สึกถึง drastic coding agents ถูกฝึกให้ใช้ bash และ bash คือเหตุผลที่ทุกคนรันพวกมันใน VMs ตั้งแต่แรก มันยังเป็นปัญหาที่เกินต้นทุนอีกด้วย agent ที่มี bash และการเข้าถึงเครือข่ายจำเป็นต้องมี credentials เพื่อทำสิ่งที่มีประโยชน์ และความพยายามของเราในการใช้ proxy URLs ที่ผ่านการรับรองความถูกต้องเริ่มซับซ้อนและบังคับใช้ได้ยาก
ดังนั้นเราจึงเอามันออก แทนที่จะเป็น bash agent เขียน JavaScript ซึ่งรันผ่าน Code Mode และ dynamic Worker loaders ของ Cloudflare แต่ละการรันทำงานใน V8 isolate ใหม่ที่บูทในหน่วยมิลลิวินาทีและใช้หน่วยความจำไม่กี่เมกะไบต์ sandbox มาพร้อมกับการเชื่อมต่อข้อมูลของผู้ใช้และ methods สำหรับทุกสิ่งที่แพลตฟอร์มทำได้ Credentials ไม่เคยเข้าสู่ sandbox agent เรียก methods ของการเชื่อมต่อ และการรับรองความถูกต้องเกิดขึ้นที่ฝั่งเรา
เมื่อคุณดูว่าจริง ๆ แล้ว agents ใช้ bash เพื่ออะไร การสูญเสียมันมีค่าใช้จ่ายน้อยกว่าที่คุณคิด ส่วนใหญ่เป็นการดำเนินการเกี่ยวกับไฟล์ ซึ่ง agent มีเครื่องมือดั้งเดิมสำหรับการนั้น เราให้ read, write, และ edit แก่มัน รวมถึง การใช้งาน grep และ glob ของเราเอง ซึ่งครอบคลุม 80-20 ส่วนที่เหลือเป็นคำสั่งเฉพาะสำหรับงานเฉพาะ และสิ่งเหล่านั้นกลายเป็น methods ที่ชัดเจน:
- wrangler deploy ผ่าน proxy กลายเป็น method deploy_project ที่เราควบคุมได้อย่างเต็มที่ เนื่องจากเรารู้แน่ชัดว่าเมื่อใดที่ deploy เกิดขึ้น เราสามารถเชื่อมต่อและเปิด live preview โดยอัตโนมัติ ก่อนหน้านี้เราต้องดม traffic wrangler ที่ถูก proxy เพื่อเดาว่าเธรดใดที่ deploy บางอย่าง
- การสร้างแอปของผู้ใช้และการรัน Python notebooks กลายเป็น methods ของตัวเอง ทั้งสอง backed โดย containers ที่มีอายุสั้น
เรายังคงใช้ containers สำหรับสองงานนี้เพราะพวกมันต้องการ Linux จริง ๆ แอปของผู้ใช้สร้างด้วย Vite, Tailwind, และ React Router และการเพิ่ม dependencies หมายถึงการรัน bun install เราพิจารณาการรัน builds ภายใน Worker เนื่องจากสิ่งที่สร้างขึ้นนั้นเป็น Worker เอง แต่เส้นทางนั้นไม่ได้รับการสนับสนุนอย่างดี และ Workers มีขีดจำกัดหน่วยความจำ 128 MB และ CPU เพียงเศษเสี้ยว Builds จะช้าและหลายโปรเจกต์จะเกินขีดจำกัดหน่วยความจำ ดังนั้นแทนที่จะเป็นเช่นนั้น build จะสปิน container ผ่าน Cloudflare Sandbox SDK คัดลอกโปรเจกต์เข้าไป รันงาน ส่งคืนผลลัพธ์ และปิด container การรัน notebooks ก็ทำงานในลักษณะเดียวกัน เรายังคงใช้ Linux เต็มรูปแบบ แต่เฉพาะสำหรับงานที่ต้องการจริง ๆ ไม่กี่วินาที
ข้อเสียที่ตรงไปตรงมาคือเราต้องคาดการณ์สิ่งที่ agent ต้องการ ด้วย bash มันสามารถหาคำตอบได้ด้วยตัวเอง ตอนนี้ ถ้าความสามารถบางอย่างหายไป เราต้องเพิ่มมัน ในทางปฏิบัติ แรงกดดันนี้ดีต่อผลิตภัณฑ์ เพราะมันบังคับให้เราคิดว่าผู้ใช้กำลังทำอะไรและสร้างเส้นทางระดับเฟิร์สคลาสสำหรับสิ่งนั้น แทนที่จะปล่อยให้ agent ปรับตัวเอาเอง
ยังมีประโยชน์ที่ไม่คาดคิดอีกด้วย bash เปิดกว้าง และโมเดลราคาถูกต่อสู้ในสภาพแวดล้อมที่เปิดกว้าง ด้วยชุด methods ที่ชัดเจนที่เล็กกว่า พวกมันทำงานได้ดีขึ้นอย่างเห็นได้ชัด ซึ่งเป็นสิ่งสำคัญเพราะการทำให้ camelAI ราคาถูกในการรันคือจุดประสงค์ของสถาปัตยกรรมนี้
ผลลัพธ์ที่เราได้
ตอนนี้ stack คือ Durable Objects สำหรับ agent และระบบไฟล์ของมัน, R2 สำหรับไฟล์ขนาดใหญ่, Artifacts สำหรับประวัติ git, pi เป็น harness, และ Code Mode กับ dynamic Workers สำหรับการรัน มัน deploy เหมือนกับแอป Cloudflare อื่น ๆ และไม่มี service container ภายนอกให้จัดการ
Dynamic Workers คิดค่าบริการต่อการรัน ไม่ใช่ต่อวินาทีของ uptime การรันนับพันครั้งมีค่าใช้จ่ายประมาณเท่ากับเวลาสองสามนาทีของ container time บนบริการที่เราเคยใช้ประเมิน Latency ต่ำเพราะทุกอย่างรันบน edge ใกล้ผู้ใช้ และการขยายขนาดเป็นปัญหาของ Cloudflare ไม่ใช่ของเรา
ผู้ใช้ยังคงสร้างและ deploy แอป full-stack ไปยัง live URLs และ agent ยังคงอ่าน เขียน grep และ deploy จากฝั่งผู้ใช้ ไม่มีอะไรเปลี่ยนแปลง
TL;DR
เราเริ่มต้นด้วย Claude Code harness บน VM service ที่สร้างเอง ซึ่งแพงและขยายขนาดยาก ขั้นแรกเราย้าย agent เองเข้าไปใน Cloudflare Durable Object และปล่อยให้มันควบคุม VMs ระยะไกล ซึ่งแก้ไข latency แต่ไม่ใช่ต้นทุน จากนั้นเราแทนที่ VMs ทั้งหมดด้วยระบบไฟล์ที่เก็บใน Durable Object SQLite และ R2 โดยอิงจากโปรเจกต์ Shell ของ Cloudflare พร้อมประวัติ git ผ่าน Cloudflare Artifacts สุดท้ายเราเอา bash ออกและให้ agent ใช้ JavaScript sandbox ผ่าน Code Mode และ dynamic Workers พร้อม methods ที่ชัดเจนสำหรับ deploys, builds, และ notebooks ผลลัพธ์คือราคาถูกลงหลายเท่า, latency ต่ำกว่า, ใช้งานง่ายกว่า และโมเดลเล็กกว่าขับเคลื่อนได้ง่ายกว่า ทั้งหมดเป็นโอเพนซอร์สที่ github.com/qaml-ai/camelAI





