Anthropic เพิ่งเปิดตัวฟีเจอร์ generative UI แบบใหม่ใน Claude ที่ช่วยให้คุณเห็นแนวคิดและข้อมูลต่างๆ เป็นภาพในแชท ทำให้เข้าใจได้ง่ายกว่าข้อความธรรมดา !Image ผมเองก็กำลังมองหาโซลูชันที่คล้ายกันอยู่พอดี พอ Claude ปล่อยออกมา ก็รู้สึกว่าต้องเร่งทำงานให้เร็วขึ้น และในขณะเดียวกันก็สามารถย้อนวิศวกรรมแนวทางของพวกเขาเพื่อเป็นข้อมูลอ้างอิงได้ หลังจากใช้เวลาสองวันกับการสั่ง Codex และ Claude อย่างหนัก ผมก็ทำมันสำเร็จ! !https://pbs.twimg.com/amplify_video_thumb/2033112086713364480/img/EUmHCjsTK7tfnToZ.jpg ฟีเจอร์นี้ช่วยให้ AI สามารถวาดแผนภูมิแบบโต้ตอบได้โดยตรงในแชท พร้อมกับเอาต์พุตแบบสตรีมมิ่ง โดยจะเรนเดอร์ไปพร้อมกับการสร้าง ก่อนหน้านี้ เวลาขอให้ AI เขียนหน้าเว็บ คุณต้องรอให้โค้ดทั้งหมดถูกสร้างก่อนถึงจะเรนเดอร์ได้ ซึ่งใช้เวลานานมาก แต่ตอนนี้มันต่างออกไป คุณสามารถดูแผนภูมิถูกวาดทีละเส้นบน canvas โดยที่ SVG nodes โผล่ขึ้นมาทีละอัน กระบวนการสร้างนั้นสวยงาม และเมื่อสร้างเสร็จก็สามารถโต้ตอบได้ทันที ลองสัมผัสด้วยตัวเองได้ใน Agent Product ของผม, Code Pilot: https://github.com/op7418/CodePilot ในโพสต์นี้ ผมจะแนะนำการใช้งาน กระบวนการ implement ที่เฉพาะเจาะจง และข้อควรระวังบางประการ ## มีอะไรสนุกๆ ให้เล่นบ้าง? การวิเคราะห์ข้อมูล: ในที่สุดตัวเลขก็เข้าใจง่าย เช่น ให้มันวาดแผนภูมิสำหรับ "การประมาณต้นทุนรายวันของความขัดแย้งสหรัฐฯ-อิหร่าน" เมื่อก่อน AI จะให้ข้อความยาวเหยียดจนมองความสัมพันธ์ของตัวเลขยาก แต่ตอนนี้มันสร้างแผนภูมิออกมาโดยตรง ทำให้เห็นจำนวนเงินในแต่ละส่วนได้ชัดเจน ข้อความและแผนภูมิจะถูกเอาต์พุตพร้อมกัน อธิบายตรงไหนที่ต้องอธิบาย และวาดตรงไหนที่ต้องวาด !Image เครื่องมือเล็กๆ: สร้างเครื่องคิดเลขแบบโต้ตอบหรืออะไรทำนองนั้น ให้มันสร้างเครื่องคำนวณดอกเบี้ยทบต้น ลากแถบเลื่อนเพื่อเปลี่ยนจำนวนเงินเริ่มต้นหรือจำนวนปีลงทุน แผนภูมิและตัวเลขด้านล่างจะอัปเดตแบบเรียลไทม์ นี่ไม่ใช่ภาพนิ่ง แต่เป็นเครื่องมือแบบโต้ตอบจริงๆ การคำนวณสินเชื่อ การแปลงหน่วย และอะไรทำนองนี้ก็ทำได้หมด !Image ไดอะแกรมสถาปัตยกรรม: ของโปรดของโปรแกรมเมอร์ คุณสามารถให้มันช่วยวาดสถาปัตยกรรมของโปรเจกต์ หรือทำให้แผนการ implement เป็นภาพ ตัวอย่างเช่น ที่นี่ผมให้มันวาดโฟลว์ทั้งหมดจาก API ไปจนถึง JWT authentication การเปรียบเทียบฟีเจอร์ โฟลว์ชาร์ต และโครงสร้างแบบลำดับชั้นเป็นภาพกราฟิก ทำให้เข้าใจสถาปัตยกรรมได้เร็วกว่าการอ่านคำอธิบายที่เป็นข้อความมาก !Image วิเคราะห์ข้อมูลออนไลน์ อีกวิธีคือโยนลิงก์ GitHub repository ให้มัน มันจะดึงข้อมูลและทำการวิเคราะห์เป็นภาพ ตัวอย่างเช่น ผมส่งที่อยู่โปรเจกต์ของผมเอง CodePilot ให้มันวิเคราะห์ Stars, Forks, เทคสแต็ก, การออกแบบสถาปัตยกรรม และโมดูลหลัก ถูกวาดเป็นแผนภูมิทั้งหมด คุณสามารถเห็นภาพรวมของโปรเจกต์ได้ในพริบตา ดีกว่าอ่านข้อความยาวๆ เยอะ !Image คำอธิบายเชิงลึกแบบโต้ตอบ จุดแข็งที่สุดคือการผสานรวมกับโมเดลอย่างแน่นหนา ไม่ใช่แค่เอาต์พุตครั้งเดียวจบ คุณสามารถโต้ตอบกับไดอะแกรมที่สร้างขึ้น และขอคำอธิบายที่ละเอียดขึ้นได้ ตัวอย่างเช่น ที่นี่ผมให้มันอธิบายความสัมพันธ์ระหว่างมรสุมและกระแสน้ำในมหาสมุทร !Image ถ้าเราอยากรู้เพิ่มเติม เราสามารถคลิกปุ่มสำหรับกลไกกระแสน้ำในมหาสมุทร มันจะส่งคำสั่งไปยังโมเดลปัจจุบันโดยอัตโนมัติเพื่อสร้างไดอะแกรมของกลไกกระแสน้ำในมหาสมุทรต่อไป !Image แน่นอน เราสามารถทำการโต้ตอบที่ซับซ้อนกว่านี้ได้ เช่น การแสดงภาพสูตรฟิสิกส์และคณิตศาสตร์ทั่วไป ซึ่งมีประโยชน์มากสำหรับนักเรียน ทุกพารามิเตอร์สามารถควบคุมได้ผ่านแถบเลื่อนและช่องป้อนข้อมูล และแอนิเมชันจะเปลี่ยนทันที !Image รองรับโมเดลจีน เมื่อ implement ใน CodePilot แล้ว ไม่ได้จำกัดแค่ Claude เท่านั้น Kimi K2.5, Minimax M2.5 และโมเดลเนทีฟของ Anthropic ก็ทำงานได้ดี ผมว่ากราฟิกที่ K2.5 วาดออกมาสวยกว่า Sonnet 3.5 เสียอีก และการวิเคราะห์สถาปัตยกรรมก็ละเอียดมาก ถ้าคุณจะใช้ฟีเจอร์นี้ ผมแนะนำให้ลอง K2.5 ก่อนเลย โอเค นั่นคือการสาธิตโมเดลโดยประมาณ ถ้าคุณไม่สนใจว่ามัน implement มาอย่างไร คุณสามารถไปติดตั้ง CodePilot และสนุกกับมันได้เลย ## มัน implement มาอย่างไร? !Image Claude ทำอย่างไร Claude.ai อย่างเป็นทางการใช้กลไก tool_use โมเดลจะเรียกใช้เครื่องมือเฉพาะเพื่อเอาต์พุตเนื้อหาวิดเจ็ตที่มีโครงสร้าง และ frontend จะแยกวิเคราะห์พารามิเตอร์อินพุตของการเรียกใช้เครื่องมือเพื่อเรนเดอร์ โซลูชันนี้ใช้ได้ดีภายใต้สถาปัตยกรรมของ Claude.ai เอง แต่มันใช้ไม่ได้กับ CodePilot ด้วยสามเหตุผล: หนึ่ง ข้อจำกัดของ SDK CodePilot ใช้โหมด preset claude_code ของ Claude Agent SDK ซึ่งไม่อนุญาตให้ลงทะเบียนเครื่องมือที่กำหนดเอง SDK จะแสดงสตรีม text delta ดังนั้นจึงไม่สามารถขยายในระดับเครื่องมือได้ สอง ประสบการณ์สตรีมมิ่ง ผลลัพธ์ของ tool_use ต้องรอให้ input_json_delta เสร็จสิ้นก่อนถึงจะเรนเดอร์ได้ และมันไม่รองรับการเรนเดอร์ HTML แบบเพิ่มหน่วย ด้วย code fences HTML จะมาพร้อมกับสตรีมข้อความ ทำให้สามารถเรนเดอร์ไปพร้อมกับการสร้างได้ สาม การแยกการเรนเดอร์ Claude.ai ใช้ Shadow DOM เพื่อแยกส่วน เราเลือกใช้ sandbox iframe การแยกด้วย iframe นั้นละเอียดถี่ถ้วนกว่า—สภาพแวดล้อมการทำงานของ JS ที่เป็นอิสระอย่างสมบูรณ์ CSP ควบคุมการโหลดทรัพยากรอย่างแม่นยำ และไม่มีการรั่วไหลของสไตล์หรือการหลบหนีของสคริปต์ เราทำอย่างไร ทริกเกอร์: Code Fences โมเดลจะเอาต์พุต code fence Markdown พิเศษเพื่อทริกเกอร์การเรนเดอร์: ``show-widget {"title":"training_flow","widget_code":"<svg width=\"100%\" viewBox=\"0 0 680 400\">...</svg>"} ` รูปแบบนี้ใช้โหมด code fence ที่มีอยู่แล้วของ CodePilot (image-gen-request, batch-plan ฯลฯ) ซึ่งห่วงโซ่ parser ของ frontend รองรับโดยธรรมชาติ  **การเรนเดอร์: Sandbox Iframe** แต่ละวิดเจ็ตจะถูกเรนเดอร์ใน iframe ที่มี sandbox="allow-scripts" srcdoc ของ iframe คือหน้า receiver ที่ถูกสร้างขึ้นอย่างระมัดระวัง นโยบาย CSP อนุญาตให้สคริปต์ภายนอกจาก 4 CDN domains เท่านั้น และ connect-src 'none' ห้ามคำขอเครือข่ายทั้งหมด การอัปเดตเนื้อหาจะได้รับผ่าน postMessage ในระหว่างเฟสพรีวิวแบบสตรีมมิ่ง widget:update จะถูกส่งโดยไม่ต้องเรียกใช้สคริปต์ การเรนเดอร์ขั้นสุดท้ายจะส่ง widget:finalize ซึ่งจะเรียกใช้สคริปต์ ResizeObserver จะตรวจสอบการเปลี่ยนแปลงความสูงของเนื้อหาและรายงานกลับไปยังหน้าแม่ผ่าน postMessage คลิก <a> ทั้งหมดจะถูกสกัดกั้นและส่งต่อไปยังหน้าแม่เพื่อเปิดในหน้าต่างใหม่ การซิงค์ธีมอาศัยการตรวจสอบการเปลี่ยนแปลงคลาสบนหน้าแม่เพื่อสลับระหว่างโหมดมืด/สว่างแบบเรียลไทม์  **CSS Variable Bridging** นี่คือกุญแจสำคัญในการทำให้วิดเจ็ตกลมกลืนกับแอปด้วยสายตา CodePilot ใช้ CSS variables ในพื้นที่สี OKLCH แนวทางการออกแบบวิดเจ็ตของ Anthropic ใช้ชื่อตัวแปรมาตรฐาน เช่น --color-background-primary เลเยอร์ bridging จะฉีดค่าตัวแปรของ CodePilot เข้าไปใน :root ของ iframe เมื่อเริ่มต้น CSS ที่โมเดลเขียนตามแนวทางสามารถใช้สีของธีมปัจจุบันได้โดยตรง เมื่อสลับไปโหมดมืด หน้าแม่จะตรวจจับการเปลี่ยนแปลงคลาส คำนวณค่าตัวแปรใหม่ และส่งไปยัง iframe  **การเรนเดอร์แบบสตรีมมิ่ง** นี่คือส่วนที่ซับซ้อนที่สุดของการ implement ทั้งหมด โมเดลสร้าง token ทีละ token ในขณะใดก็ตาม โค้ดวิดเจ็ตที่ได้รับอาจเป็น JSON ที่ไม่สมบูรณ์ HTML ที่ไม่สมบูรณ์ หรือแท็ก <script> ที่ไม่สมบูรณ์ โฟลว์การประมวลผลมีดังนี้: Regex จับคู่ `show-widget เพื่อแยกแยะสถานะ "ยังไม่ปิด" และ "ปิดแล้ว" ค้นหาตำแหน่งเนื้อหาหลัง "widget_code":" ด้วยตนเองและ unescape ทีละอักขระ ไม่สามารถใช้ JSON.parse ได้เพราะ JSON ยังไม่เสร็จ เมื่อตรวจพบแท็ก <script> ที่ยังไม่ปิด ให้ตัดก่อน <script เพื่อหลีกเลี่ยงการแสดงโค้ด JavaScript เป็นข้อความที่มองเห็นได้ การดีบาวน์ 120ms ป้องกันไม่ให้ iframe อัปเดตบ่อยเกินไป เนื้อหาสตรีมมิ่งจะลบสคริปต์และตัวจัดการเหตุการณ์ทั้งหมด ไม่จำเป็นต้องมีการโต้ตอบในช่วงพรีวิว  **ขัดเกลาประสบการณ์: รายละเอียดที่ไม่ควรสังเกตเห็น** จากมุมมองของโค้ดหรือการ implement มันไม่ได้ซับซ้อนขนาดนั้น ความซับซ้อนอยู่ที่การขัดเกลาประสบการณ์ มีหลายจุดที่ส่งผลต่อประสบการณ์ และผู้ใช้ต้องไม่สังเกตเห็นรายละเอียดเหล่านั้นและกระบวนการสร้าง ซึ่งต้องจัดการแต่ละขั้นตอนแตกต่างกัน: 1. รายละเอียดที่ดูไม่เหมือนสตรีมมิ่ง 2. เนื้อหาที่ไม่ควรปรากฏ  **การหายไปของข้อความ** โมเดลจะเอาต์พุตข้อความนำก่อน ("Let me explain visually...") จากนั้นจึงเริ่ม fence วิดเจ็ต ทันทีที่ fence ปรากฏ ข้อความก่อนหน้านั้นจะหายไปทันทีและจะกลับมาเมื่อวิดเจ็ตเรนเดอร์เสร็จเท่านั้น สาเหตุคือ parseAllShowWidgets() จะคืนค่า array ว่างสำหรับข้อความธรรมดา เมื่อ fence เพิ่งปรากฏแต่ยังไม่ปิด ข้อความก่อน fence จะถูกส่งเข้าไปในฟังก์ชันนี้และถูกทิ้งไป วิธีแก้ไข: เมื่อข้อความก่อน fence ไม่มี fence วิดเจ็ตที่สมบูรณ์ ให้เรนเดอร์เป็น <MessageResponse> โดยตรง โดยข้ามฟังก์ชันการแยกวิเคราะห์ **การกระโดดของความสูง** ในขณะที่วิดเจ็ตเรนเดอร์เสร็จ พื้นที่แชททั้งหมดจะกระตุก ความสูงเริ่มต้นของ iframe คือ 0px เมื่อเนื้อหารายงานความสูงจริงครั้งแรก อาจเป็น 400px+ และ CSS transition ทำให้การเปลี่ยนแปลงนี้เกิดขึ้นใน 300ms ส่งผลให้เกิดการกระโดดที่สังเกตเห็นได้ วิธีแก้ไข: ปิดการใช้งาน CSS transition ชั่วคราวระหว่างการรายงานความสูงครั้งแรกเพื่อให้ความสูงเข้าที่ทันที การปรับความสูงในภายหลังจะใช้ smooth transitions **การกะพริบตอน Finalize** เมื่อวิดเจ็ตสลับจากพรีวิวแบบสตรีมมิ่งไปเป็นการเรนเดอร์ขั้นสุดท้าย เนื้อหาจะกะพริบ iframe receiver จะแทนที่ DOM ทั้งหมดด้วย root.innerHTML = html ระหว่างการ finalize แม้ว่าเนื้อหาใหม่และเก่าจะเหมือนกัน (วิดเจ็ต SVG ล้วน) เบราว์เซอร์ก็จะทริกเกอร์การวาดซ้ำหนึ่งเฟรม วิธีแก้ไข: ระหว่างการ finalize ขั้นแรกให้แยกวิเคราะห์ HTML ใหม่ลงในคอนเทนเนอร์ชั่วคราวและแยกองค์ประกอบสคริปต์ เปรียบเทียบ HTML ที่มองเห็น (ไม่มีสคริปต์) กับ DOM ปัจจุบัน—ถ้าเหมือนกัน ให้ข้ามการแทนที่ innerHTML และเพียงแค่ต่อท้ายสคริปต์เพื่อเรียกใช้ วิดเจ็ต SVG ล้วนจะได้การ finalize ที่ไม่มีการวาดซ้ำ **การกระโดดของ Scroll** แชทกำลังเลื่อนอัตโนมัติลงไปด้านล่าง จากนั้นก็กระโดดกลับขึ้นไปหลายร้อยพิกเซลแล้วกระโดดกลับมาอีกครั้ง เมื่อสตรีมมิ่งสิ้นสุด คอมโพเนนต์ StreamingMessage จะ unmount และคอมโพเนนต์ MessageItem จะ mount สิ่งเหล่านี้เป็นคอมโพเนนต์ React ที่แตกต่างกันโดยสิ้นเชิงสองตัว และ WidgetRenderer ภายในจะถูกทำลายและสร้างใหม่ ความสูง iframe ของอินสแตนซ์ใหม่เริ่มจาก 0 ทำให้พื้นที่เนื้อหาลดลงอย่างรวดเร็ว ซึ่งทริกเกอร์การปรับ scroll ใน use-stick-to-bottom วิธีแก้ไข: การแคชความสูงระดับโมดูล เมื่อใดก็ตามที่วิดเจ็ตรายงานความสูง มันจะถูกเขียนลงในแคชโดยใช้ 200 ตัวอักษรแรกของ widgetCode เป็นคีย์ อินสแตนซ์ WidgetRenderer ใหม่จะอ่านความสูงจากแคชระหว่างการเริ่มต้น useState ดังนั้น iframe จะเริ่มเรนเดอร์ที่ความสูงที่ถูกต้อง โดยไม่ต้องเปลี่ยนจาก 0→จริง **การรั่วไหลของโค้ดสคริปต์** เมื่อวิดเจ็ตที่มี Chart.js โหลด โค้ด JavaScript จำนวนมากจะแสดงที่ด้านล่าง แท็ก <script> ที่โมเดลเอาต์พุตมาถึงทีละอักขระ เมื่อแท็กเปิดมาถึงแต่แท็กปิดยังมาไม่ถึง sanitizeForStreaming จะลบแท็กเปิดออก แต่โค้ด JavaScript ภายในจะกลายเป็น text node เปล่าที่เรนเดอร์เป็นเนื้อหาที่มองเห็นได้ วิธีแก้ไข: หลังจากแยกโค้ดบางส่วนใน StreamingMessage ให้ตรวจสอบว่า <script สุดท้ายมี </script> ที่ตรงกันหรือไม่ ถ้าไม่มี ให้ตัดที่ตำแหน่ง <script แนวทางวิดเจ็ตระบุว่าสคริปต์จะอยู่ท้ายสุด ดังนั้นการตัดจึงไม่ส่งผลต่อเนื้อหาที่มองเห็น ระหว่างการตัด จะแสดง shimmer mask และแถบสถานะจะแสดง "กำลังเพิ่มแอนิเมชันแบบโต้ตอบให้กับการแสดงภาพ" **Iframe Ready Race Condition** ในบางกรณีที่พบไม่บ่อย วิดเจ็ตจะไม่เรนเดอร์เลย โดยคงความสูงไว้ที่ 0px WidgetRenderer ลงทะเบียนตัวฟังเหตุการณ์ข้อความผ่าน useEffect อย่างไรก็ตาม สคริปต์ receiver ของ iframe จะส่ง widget:ready ทันทีที่โหลด ถ้า iframe โหลดเร็วกว่าที่ React effect จะทำงาน widget:ready จะถูกส่งก่อนที่ตัวฟังจะถูกลงทะเบียน และ iframeReady จะไม่มีวันเป็น true วิธีแก้ไข: เพิ่ม callback onLoad ให้กับองค์ประกอบ iframe เป็นตัวสำรอง เมื่อ onLoad ทริกเกอร์ สคริปต์ receiver ต้องทำงานเสร็จแล้ว ซึ่งให้สัญญาณความพร้อมที่เชื่อถือได้ **ความเสถียรของ React Component Tree** วิดเจ็ตกะพริบในขณะที่ fence ปิด ปัญหาสองอย่างซ้อนทับกัน: วิดเจ็ตสตรีมมิ่งบางส่วนไม่มี React key และหลังจากปิดแล้ว จะได้รับ key="w-0" การเปลี่ยนแปลง key ทำให้เกิดการ remount นอกจากนี้ shimmer overlay ถูก implement ด้วย <div> ที่ห่อหุ้ม ซึ่งเปลี่ยนโครงสร้างของ component tree และทำให้เกิดการ remount อีกครั้ง วิธีแก้ไข: กำหนด key ที่เสถียรให้กับวิดเจ็ตบางส่วน (w-N โดยที่ N คือตำแหน่งที่คาดไว้ในอาร์เรย์ segments สุดท้าย) ซึ่งสอดคล้องกับ key หลังจากปิด ย้าย shimmer overlay ไว้ภายใน WidgetRenderer ควบคุมผ่าน prop showOverlay component tree จะคงเป็น <WidgetRenderer key="w-N"> ตลอด ## **ความคิดสุดท้าย** สำหรับระบบ generative UI ทั้งหมด ส่วนที่ยากไม่ใช่ "การทำให้ HTML ชิ้นหนึ่งทำงานใน iframe" นั่นมันง่าย ความซับซ้อนที่แท้จริงอยู่ที่การรักษา iframe นั้นให้มีเสถียรภาพทางสายตาในระหว่างการเปลี่ยนสถานะ เช่น สตรีมมิ่ง การสลับวงจรชีวิตของคอมโพเนนต์ และการเปลี่ยนธีม ทุกครั้งที่ "กะพริบ" "กระโดด" หรือ "หายไป" จำเป็นต้องเข้าใจการ reconciliation ของ React, rendering pipeline ของเบราว์เซอร์ และจังหวะเวลาของ postMessage` ผลลัพธ์สุดท้ายคือผู้ใช้เห็นแผนภูมิและไดอะแกรมแทรกอยู่ในคำตอบของโมเดลอย่างเป็นธรรมชาติ ราวกับว่ามันควรจะอยู่ที่นั่นตั้งแต่แรก วันนี้มีแค่นี้ครับ ถ้าคุณคิดว่ามีประโยชน์ ช่วยกดไลค์หรือแชร์ให้เพื่อนที่อาจต้องการได้นะครับ
ผมลองทำตามฟีเจอร์ Generative UI Interaction ที่เพิ่งเปิดตัวใหม่ของ Claude!
- การดู
- 265K
- ถูกใจ
- 446
- รีโพสต์
- 63
- ความคิดเห็น
- 34
- บุ๊กมาร์ก
- 815
TL;DR
บทความนี้ลงรายละเอียดเกี่ยวกับการจำลอง Generative UI ของ Claude ใน Code Pilot โดยครอบคลุมถึงความท้าทายทางเทคนิค เช่น การเรนเดอร์ sandbox iframe, การแยกวิเคราะห์ JSON แบบสตรีมมิ่ง และการปรับปรุง UX เพื่อให้มั่นใจว่าจะได้รับประสบการณ์ที่ราบรื่นและไม่มีอาการกระพริบของหน้าจอ
กำลังอ่านคำแปลภาษา ไทย





