การสร้างโครงสร้างพื้นฐานสำหรับ Cloud Agent: สิ่งที่แตกต่างและบทเรียนที่เราได้รับ

@intuitiveml
อังกฤษ1 เดือนที่ผ่านมา · 05 มิ.ย. 2569
311K
857
154
21
2.1K

TL;DR

CREAO แบ่งปันบทเรียนสำคัญในการสร้างโครงสร้างพื้นฐานสำหรับ Cloud Agent โดยเน้นไปที่การแยกสภาพแวดล้อมของผู้ใช้ออกจากโค้ดของแพลตฟอร์ม และการรักษาความปลอดภัยของข้อมูลประจำตัวภายนอก Sandbox

Peter Pang - inline image

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

โครงสร้างพื้นฐานของคลาวด์เอเจนต์ไม่มีสิทธิพิเศษเหล่านั้นเลย

เอเจนต์ทำงานบนแซนด์บ็อกซ์ที่บูตเครื่องใหม่หมด บนฮาร์ดแวร์ที่ใช้ร่วมกับคนแปลกหน้า ถูกเรียกใช้โดยผู้เรียกที่ผู้ใช้ไม่เคยรู้จัก: กำหนดการ, คำขอ HTTP, หรือเอเจนต์ตัวอื่น ผู้ใช้มักจะกำลังหลับอยู่ตอนที่รัน โค้ดภายในแซนด์บ็อกซ์อาจเป็นปฏิปักษ์ได้ ระบบไฟล์ต้องอยู่รอดผ่านการ Deploy หลายครั้ง ข้อมูลรับรองไม่สามารถอยู่ที่เดียวกับที่เอเจนต์อยู่ การรับประกันทุกอย่างที่เดสก์ท็อปมอบให้คุณได้โดยไม่ต้องลงทุนอะไรเลย เช่น ความคงทน อัตลักษณ์ ความน่าเชื่อถือของเครือข่าย การลองใหม่ ล้วนต้องถูกสร้างขึ้นใหม่เป็นระบบที่ชัดเจน

เราใช้เวลาสองสามเดือนที่ผ่านมาในการทำให้เลเยอร์นั้นแข็งแกร่งขึ้นที่ CREAO มีบทเรียนสองข้อที่ได้เรียนรู้ หากคุณเคย Deploy เอเจนต์บนเดสก์ท็อปและสงสัยว่าจะเปลี่ยนแปลงอะไรบ้างเมื่อมันย้ายไปยังคลาวด์ นี่คือสิ่งที่เปลี่ยนแปลง

บทเรียนที่ 1: แยกสิ่งที่เปลี่ยนแปลงช้าออกจากสิ่งที่เปลี่ยนแปลงเร็ว

Peter Pang - inline image

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

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

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

จากนั้นปัญหาการเชื่อมโยงก็ปรากฏขึ้น

อิมเมจเดียวกันที่แช่แข็งสภาพแวดล้อมของผู้ใช้ ยังมีโค้ดของ Runner ซึ่งเป็นไลบรารีตัวช่วยขนาดเล็กที่เราพัฒนาขึ้นเพื่อจัดการเอเจนต์ในแต่ละการรัน ผู้ใช้ต้องการให้สภาพแวดล้อมของพวกเขาหยุดนิ่ง เราต้องการให้ Runner ของเราสามารถ Deploy ได้หลายครั้งต่อวัน สิ่งประดิษฐ์ชิ้นเดียว แต่มีความต้องการที่ตรงกันข้ามกันสองอย่าง

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

การรันแบบไม่ต้องมีคนดูแลทำให้การป้องกันนั้นใช้ไม่ได้ผล การทำงาน Cron Job เวลา 9 โมงเช้าวันจันทร์ไม่ควรสูญเสียสภาพแวดล้อมไปเพราะเรา Deploy ตอน 8:55 น. สัญญาที่เรากำลังละเมิดอย่างเงียบ ๆ คือ "สภาพแวดล้อมของคุณจะถูกแช่แข็งจนกว่าคุณจะเปลี่ยนแปลงมัน"

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

โมเดลที่เราลงเอยด้วยนั้นยืมมาจากวิธีการที่ระบบปฏิบัติการจัดการกับการอัปเดต เคอร์เนลเปลี่ยนไป โฮมไดเรกทอรีของคุณไม่เปลี่ยน คุณจะไม่ล้างดิสก์เพื่อติดตั้งแพตช์รักษาความปลอดภัย

เราวาดขอบเขตเดียวกันนั้น แซนด์บ็อกซ์บูตจากสแนปช็อตที่ถูกแช่แข็งของผู้ใช้โดยไม่ถูกแตะต้อง จากนั้นเราจะสลับเฉพาะ Runner แบบ Hot-Swap ลำดับคือ:

  1. จัดเตรียม Runner ตัวใหม่ในไดเรกทอรีชั่วคราวภายในแซนด์บ็อกซ์
  2. ตรวจสอบความถูกต้องด้วย node --check เพื่อจับข้อผิดพลาดทางไวยากรณ์ก่อนที่จะแตะต้องสิ่งใดที่กำลังทำงานอยู่
  3. สลับมันแบบอะตอมมิก: ปลดล็อกแอตทริบิวต์ Immutable บน Runner เก่า คัดลอกตัวใหม่เข้าไป ล็อคอีกครั้งด้วย chattr +i จากนั้นซ่อนไบนารี chattr เองเพื่อให้โค้ดในแซนด์บ็อกซ์ไม่สามารถย้อนกลับการล็อคได้
  4. ล้าง V8 compile cache (/home/user/.cache/v8-compile-cache/*) เพื่อให้ไฟล์ใหม่โหลดจริง ๆ แทนที่จะรัน bytecode ที่เก่า
  5. หากขั้นตอนใดล้มเหลว ให้ฆ่าแซนด์บ็อกซ์แล้วลองใหม่ด้วยอันใหม่ จะไม่มีสถานะที่อัปเกรดครึ่งทางไปรันเอเจนต์เด็ดขาด

การสลับทั้งหมดใช้เวลาประมาณ 300 มิลลิวินาที เราจะทำสแนปช็อตใหม่หลังจากการรันที่สำเร็จเฉพาะเมื่อมีการสลับโค้ด Runner เท่านั้น โดยอบโค้ดที่อัปเดตลงในอิมเมจของผู้ใช้ เพื่อให้การรันครั้งถัดไปข้ามการสลับไปเลย การ Deploy แพลตฟอร์มจะไม่ทิ้งสถานะของผู้ใช้ แต่จะรวม Runner ใหม่เข้าไปในนั้น แพ็กเกจ ไฟล์ และการปรับแต่งของผู้ใช้จะถูกส่งต่อโดยไม่เปลี่ยนแปลง

หากคุณจะจำอะไรสักอย่างจากบทเรียนนี้ นั่นคือคำถามเพื่อการวินิจฉัย สำหรับสิ่งใดก็ตามที่คุณคงอยู่ในแพลตฟอร์มคลาวด์ ให้ถาม: ใครเป็นผู้ควบคุมจังหวะการเปลี่ยนแปลงของสิ่งประดิษฐ์นี้? หากทั้งผู้ใช้และแพลตฟอร์มเป็นเจ้าของมันร่วมกัน ในที่สุดคุณจะต้องจ่ายค่าการเชื่อมโยงนั้น แบ่งสิ่งประดิษฐ์ตามแนวการเป็นเจ้าของ และปล่อยให้แต่ละฝ่ายอัปเดตตามนาฬิกาของตนเอง

บทเรียนที่ 2: เก็บความลับออกจากขอบเขตการทำงาน

Peter Pang - inline image

นี่คือบทเรียนที่แยกโครงสร้างพื้นฐานของคลาวด์เอเจนต์ออกจากทุกสิ่งทุกอย่าง

เอเจนต์บนเดสก์ท็อปทำงานในฐานะผู้ใช้ มันใช้คีย์ของผู้ใช้ บนเครื่องของผู้ใช้ กับเครือข่ายของผู้ใช้ เอเจนต์บนคลาวด์ทำงานในฐานะไม่มีใครเลย บนฮาร์ดแวร์ที่ใช้ร่วมกัน กับอินเทอร์เน็ตเปิด โดยเรียกใช้โค้ดที่ LLM เขียนจากพรอมต์ที่อาจเป็นปฏิปักษ์ โมเดลความปลอดภัยต้องสมมติว่าโค้ดภายในแซนด์บ็อกซ์ถูกบุกรุกไปแล้ว ไม่ใช่แค่หวังว่ามันจะไม่เกิดขึ้น

กฎที่เรายึดถือนั้นง่ายมาก ไม่มีข้อมูลรับรองที่มีอายุยืนยาวใด ๆ อาศัยอยู่ภายในแซนด์บ็อกซ์

เมื่อเอเจนต์จำเป็นต้องเรียกใช้บริการที่ต้องรับรองความถูกต้อง เช่น Slack, GitHub, API ของผู้ใช้เอง มันจะไม่เก็บโทเคนไว้ มันจะส่งคำขอ HTTP ในเครื่องไปยังสะพานเชื่อม API ที่ทำงานอยู่นอกแซนด์บ็อกซ์ สะพานเชื่อมจะแนบ OAuth token ไว้บนฝั่งโฮสต์และส่งต่อการเรียก คำตอบจะกลับมาโดยที่โทเคนไม่เคยเข้าสู่หน่วยความจำหรือสภาพแวดล้อมของแซนด์บ็อกซ์

ส่วนที่น่าสนใจคือ สะพานเชื่อมรู้ได้อย่างไรว่าแซนด์บ็อกซ์ได้รับอนุญาตให้ถาม มีการตรวจสอบสองขั้นตอน ซ้อนกันโดยเจตนา

ประการแรก IP allowlist สะพานเชื่อมจะยอมรับการเชื่อมต่อจากช่วงเครือข่ายภายในที่โฮสต์แซนด์บ็อกซ์ของเราอาศัยอยู่เท่านั้น การเรียกจากที่อื่นใด เช่น แล็ปท็อปของนักพัฒนา URL ที่รั่วไหล หรืออินเทอร์เน็ตสาธารณะ จะถูกทิ้งที่เลเยอร์เครือข่าย ก่อนที่โค้ดแอปพลิเคชันใด ๆ จะทำงาน สิ่งนี้จะยึดสะพานเชื่อมไว้กับโครงสร้างพื้นฐานทางกายภาพชิ้นเดียว และทำให้มันไร้ประโยชน์สำหรับใครก็ตามที่อยู่นอกนั้น

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

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

หากพรอมต์อินเจคชันทำให้เอเจนต์ทิ้ง process.env ไปยัง Webhook ในวันพรุ่งนี้ ผู้โจมตีจะได้ JWT อายุสั้นที่ใช้ได้จากภายในเครือข่ายของเราเท่านั้นและหมดอายุพร้อมกับการรัน คุณสมบัตินั้นคือสิ่งที่ทำให้เราสามารถรันโค้ดผู้ใช้ที่ไม่น่าเชื่อถือบนโครงสร้างพื้นฐานที่ใช้ร่วมกันได้ โดยไม่ต้องกังวล

รูปแบบที่อยู่เบื้องล่าง

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

  • สถานะอยู่ในแซนด์บ็อกซ์ ถูกแช่แข็งจนกว่าผู้ใช้จะเปลี่ยนแปลงมัน
  • โค้ดสามารถสลับแบบ Hot-Swap ได้ เป็นอิสระจากสถานะ
  • ข้อมูลรับรองอยู่ฝั่งโฮสต์ ไม่เคยอยู่ภายในเอเจนต์
  • ไพพ์ไลน์การทำงานหนึ่งชุดให้บริการแก่ผู้เรียกทุกคน ไม่ว่าตัวกระตุ้นจะเป็นมนุษย์ ตัวกำหนดเวลา หรือซอฟต์แวร์อื่น

คุณสมบัติสุดท้ายคือประเด็นสำคัญของการออกแบบทั้งหมด ฟังก์ชัน executeAgent เดียวกันจัดการการคลิก UI การรันตามกำหนดเวลา และการเรียก API ระบบการเรียกเก็บเงิน บันทึกการหักเครดิต สัญญาณการสังเกตการณ์ ทั้งหมดเหมือนกัน ไม่ว่ามนุษย์จะคลิก Run, Cron Job จะทำงาน หรือสคริปต์จะเรียก API การเพิ่มพื้นผิวตัวกระตุ้นใหม่คือการเปลี่ยนแปลงการกำหนดเส้นทาง ไม่ใช่การเปลี่ยนแปลงสถาปัตยกรรม ตัวเอเจนต์เองไม่รู้หรือสนใจว่าใครเป็นคนดึงไกปืน

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

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

นั่นคือสิ่งที่ทำให้พื้นผิวถัดไปมีราคาถูกและปลอดภัยที่จะ Deploy

บันทึกในคลิกเดียว

อ่านบทความไวรัลเชิงลึกด้วย AI ใน YouMind

บันทึกแหล่งที่มา ถามคำถามที่ตรงประเด็น สรุปข้อโต้แย้ง และเปลี่ยนบทความไวรัลให้เป็นโน้ตที่นำกลับมาใช้ได้ใน AI เวิร์กสเปซเดียว

สำรวจ YouMind
สำหรับครีเอเตอร์

เปลี่ยน Markdown ของคุณให้เป็นบทความ 𝕏 ที่สะอาดตา

เวลาคุณเผยแพร่งานเขียนยาวของตัวเอง การจัดรูปแบบรูปภาพ ตาราง และบล็อกโค้ดให้เข้ากับ 𝕏 นั้นน่าปวดหัว YouMind เปลี่ยนร่าง Markdown ทั้งฉบับให้เป็นบทความ 𝕏 ที่สะอาดตาและพร้อมโพสต์ทันที

ลอง Markdown เป็น 𝕏

แพตเทิร์นให้ถอดรหัสเพิ่มเติม

บทความไวรัลล่าสุด

สำรวจบทความไวรัลเพิ่มเติม