Day 3B: Tool Calling — Complete Function Calling Guide (Gemini)
สรุปย่อ
ประเด็นสำคัญจากวิดีโอ
- **ช่อง:** Adspolitan Knowledge Studio · **ความยาว:** ~21 นาที · **ลิงก์:** https://www.youtube.com/watch?v=2MdS3LuAc5w
# สรุป: Day 3B: Tool Calling — Complete Function Calling Guide (Gemini) - **ช่อง:** Adspolitan Knowledge Studio · **ความยาว:** ~21 นาที · **ลิงก์:** https://www.youtube.com/watch?v=2MdS3LuAc5w ## ประเด็นหลัก - แม้ชื่อวิดีโอจะระบุเรื่อง Tool Calling แต่เนื้อหาจริงของ codelab นี้คือ memory management (การจัดการหน่วยความจำระยะยาว) ใน ADK — แยกจาก session ซึ่งเป็นหน่วยความจำระยะสั้นแบบบทสนทนาเดียว - Memory ให้ความสามารถที่ session เดี่ยวๆ ทำไม่ได้: จดจำข้ามบทสนทนา สกัดข้อมูลอย่างชาญฉลาด ค้นหาเชิงความหมาย และเก็บข้อมูลถาวร - Memory workflow มี 3 ขั้นหลัก: Initialize (สร้าง service ผ่าก runner) → Ingest (ย้ายข้อมูล session ด้วย add_session_to_memory) → Retrieve (ค้นหาด้วย search_memory) - Notebook ใช้ InMemory memory service (จับคู่คียเวิร์ด ไม่เก็บถาวร) ส่วน production ควรใช้ Vertex AI Memory Bank (กลั่นข้อมูลด้วย LLM + semantic search + คลาวด์ถาวร) ซึ่งจะสอนใน Day 5 - การดึงข้อมูลความจำมี 2 โหมด: load_memory แบบ reactive (ทำงานเมื่อถูกเรียก) และ preload_memory แบบ proactive (เตรียมข้อมูลไว้ล่วงหน้า) - การค้นหา memory ตั้งอยู่บนข้อเท็จจริงจริงๆ ที่เก็บไว้ เอเจนต์จึง hallucinate ความจำที่ไม่มีอยู่ไม่ได้ - Callbacks ของ ADK เป็นฟังก์ชันที่ทำงานอัตโนมัติตามจังหวะต่างๆ ของเอเจนต์ (before/after agent, before/after model, before/after tool, on model error) เหมาะกับ logging, observability และการบันทึก memory อัตโนมัติ - ใช้ after_agent_callback + callback_context ทำ autosave บทสนทนาหลังจบทุก turn รวมกับ preload_memory ทำให้การจัดเก็บและดึงข้อมูลเป็นอัตโนมัติทั้งหมด โดยไม่ต้องเรียกด้วยมือเลย - ความถี่ในการบันทึก memory มี 3 แบบ: ทุก turn (เรียลไทม์), หลังจบบทสนทนา (ลด API calls / batch), เป็นช่วงๆ (บทสนทนายาว) - เก็บข้อมูลดิบทั้งหมดไม่ scale (50 ข้อความ = 10,000 tokens) — ต้องใช้ memory consolidation สกัดเฉพาะข้อเท็จจริงสำคัญทิ้ง noise ทิ้ง ผลลัพธ์คือเก็บน้อยลง ดึงเร็วขึ้น ตอบแม่นขึ้น - Consolidation เปลี่ยนภาษาธรรมชาติเป็นข้อมูลมีโครงสร้าง เช่น "แพ้ถั่ว กินอะไรที่มีถั่วไม่ได้" → แพ้ถั่ว/ถั่วต้นไม้/หลีกเลี่ยงอย่างสมบูรณ์ และ managed service อย่าง Vertex AI ทำให้อัตโนมัติโดยใช้ API เดิม ## ความเห็นสรุป วิดีโอนี้เดินตาม notebook ไปทีละขั้นอย่างละเอียด เหมาะกับผู้เริ่มต้นที่อยากเข้าใจว่าระบบความจำระยะยาวของเอเจนต์ทำงานอย่างไร ตั้งแต่ manual workflow ไปจนถึง automation ด้วย callbacks ครับ จุดที่ควรระวังคือชื่อวิดีโอกับเนื้อหาจริงไม่ตรงกัน (Tool Calling แต่สอน Memory) และตัวอย่างทั้งหมดใช้ InMemory service ซึ่งไม่เก็บข้อมูลถาวร ผู้ดูควรต่อยอดไปดู Day 5 เรื่อง Vertex AI Memory Bank ครับ
คำแปลเต็ม
แปลตามบทสนทนาต้นฉบับ ปรับเป็นภาษาไทยธรรมชาติ
ในวิดีโอนี้เราจะไปดูกันใน codelab ที่สองของ assignment ใน Day 3 ครับ ผมจะกดที่ Explore เพื่อให้มันพาเราไปที่ notebook แล้วเราจะทำสำเนาไว้เป็น notebook แบบแก้ไขได้ของเราเอง เพื่อใช้เดินผ่าน assignment นี้ไปด้วยกันนะครับ
ใน assignment นี้เราจะคุยกันเรื่อง memory management หรือการจัดการหน่วยความจำครับ เรามีอยู่สองแบบ แบบแรกคือ session (เซสชัน) และอีกแบบคือ memory (หน่วยความจำระยะยาว) session เป็นหน่วยความจำระยะสั้นที่ครอบคลุมแค่บทสนทนาเดียว ส่วนในวิดีโอนี้เราจะโฟกัสที่ memory ซึ่งเป็นความรู้ระยะยาวที่ใช้งานข้ามหลายบทสนทนาครับ ตัวอย่างที่เขาให้มาก็คือให้คิดว่ามันเหมือนกับ software engineer ครับ
ทีนี้ทำไมต้องมี memory ล่ะครับ memory มีความสามารถที่ session อย่างเดียวทำไม่ได้ ไม่ว่าจะเป็นการจดจำข้ามบทสนทนา การสกัดข้อมูลอย่างชาญฉลาด การค้นหาเชิงความหมาย และการเก็บข้อมูลแบบถาวรครับ มีอีกตัวอย่างหนึ่งคือการคุยกับ personal assistant ถ้ามีแค่ session เอเจนต์จะจำได้แค่สิ่งที่เราพูดในช่วงสิบนาทีที่ผ่านมา แต่ถ้ามี memory มันจะจำความชอบและบทสนทนาของเราจากสัปดาห์ที่แล้วได้ด้วยครับ
สิ่งที่เราจะเรียนในแบบฝึกหัดนี้คือ การตั้งค่า memory service และเชื่อมเข้ากับเอเจนต์ การย้ายข้อมูล session ไปเก็บในหน่วยความจำ การค้นหาและดึงข้อมูลความจำกลับมา การทำให้การจัดเก็บและดึงข้อมูลเป็นแบบอัตโนมัติ และการเข้าใจเรื่อง memory consolidation (การกลั่นข้อมูลในหน่วยความจำ) ครับ นี่คือภาพรวมเชิงแนวคิดนะครับ ข้อควรทราบคือ notebook นี้ใช้บริการ InMemory memory service เพื่อการเรียนรู้ แต่ในงานจริงที่ใช้ production สิ่งที่ต้องใช้คือ Vertex AI Memory Bank ซึ่งจะได้เจอกันใน assignment ของ Day 5 ครับ Vertex AI Memory Bank ให้บริการกลั่นข้อมูลด้วย LLM การค้นหาเชิงความหมาย และการจัดเก็บแบบถาวรบนคลาวด์ ส่วน InMemory memory service ทำได้แค่การจับคู่คำคียเวิร์ด และไม่เก็บข้อมูลถาวรครับ
เอาล่ะ เริ่มกันเลย ส่วนของ step หนึ่งผมจะรีบผ่านๆ ไป เพราะเราทำขั้นตอนนี้ซ้ำกันมาในทุกแบบฝึกหัดแล้ว เลือกหนึ่ง เราสร้าง API key สำเร็จแล้ว และตั้งค่าเรียบร้อยแล้ว ต่อไปเราจะ import ส่วนประกอบของ ADK (Agent Development Kit — ชุดเครื่องมือพัฒนาเอเจนต์ของ Google) เรามี load_memory และ preload_memory และมี memory service ด้วย แต่ใน production เราจะใช้ Vertex AI Memory Bank ตามที่บอกไปก่อนหน้านี้ครับ ฉะนั้นตรงนี้เราใช้ InMemory memory service แต่พอขึ้น production ให้ใช้ Vertex Memory Bank ครับ
เยี่ยม import ส่วนประกอบของ ADK สำเร็จแล้ว ขั้นต่อไปคือกำหนด helper function อันนี้ก็ทำเสร็จแล้ว จากนั้นสร้าง retry config ก็เสร็จเรียบร้อย เรามาดู section สองกันต่อเลย ซึ่งก็คือ memory workflow ครับ
ทีนี้ใน section สอง มาทำความเข้าใจ workflow ของ memory กันก่อน การจะเชื่อม memory เข้ากับเอเจนต์ของเรามีอยู่สามขั้นตอนหลักคือ Initialize Ingest และ Retrieve ครับ ขั้น Initialize คือเราสร้าง memory service แล้วส่งให้เอเจนต์ผ่านตัว runner ขั้นที่สองคือ Ingest ที่เราย้ายข้อมูลของ session เข้าสู่ memory โดยใช้ฟังก์ชัน add_session_to_memory ส่วนขั้นที่สามคือ Retrieve ที่เราค้นหาข้อมูลความจำที่เก็บไว้ด้วยฟังก์ชัน search_memory ครับ นี่คือหน้าตาของ memory workflow ของเรา แล้วเดี๋ยวเราจะไล่ดูรายละเอียดทีละขั้น ตั้งแต่ Initialize Ingest ไปจนถึง Retrieve กันครับ
Section สามคือการตั้งค่า memory service ครับ การ initialize memory คืออะไร ตรงนี้เรามีบริการแบบ built-in สำหรับงาน prototyping และ testing เช่นการจับคู่คำคียเวิร์ด แต่ไม่มีการเก็บข้อมูลถาวร ส่วนแบบที่สองคือ Vertex AI Memory Bank ซึ่งเป็นบริการคลาวด์แบบ managed มีการกลั่นข้อมูลด้วย LLM และการค้นหาเชิงความหมาย และแบบที่สามคือการ implement เอง เราสามารถสร้างของตัวเองจากฐานข้อมูลผ่าน managed service ซึ่งเป็นวิธีที่แนะนำครับ โดยสรุป ADK มี memory service implementation ให้เลือกใช้หลายแบบ ผ่าน interface ที่ชื่อ BaseMemoryService ครับ สำหรับ notebook นี้เราจะใช้แบบแรกตามที่บอกไปแล้ว เอาล่ะมาสร้าง memory กัน อันนี้เสร็จแล้ว ต่อไปเป็นการเพิ่ม memory เข้ากับเอเจนต์ตามที่นิยามไว้
โอเค ตอนนี้เรามี instructions ที่บอกว่าให้ตอบคำถามด้วยคำง่ายๆ เราได้เพิ่ม memory ตรงนี้แล้ว เอเจนต์ถูกสร้างเรียบร้อย ขั้นต่อไปคือสร้าง runner ครับ ตัว runner ต้องการ service ทั้งสองตัวเพื่อเปิดใช้งานฟังก์ชันที่เกี่ยวกับ memory ครับ ตัวแรกคือ session service ที่จัดการเธรดของบทสนทนาและ events และตัวที่สองคือ memory service ที่ให้การจัดเก็บหน่วยความจำระยะยาว ทั้งสอง service ทำงานร่วมกัน session เก็บบทสนทนา ส่วน memory เก็บความรู้เพื่อดึงกลับมาใช้ข้าม session ครับ เรามารันกัน เอเจนต์และ runner ถูกสร้างแล้วพร้อมการรองรับ memory ครับ
ตรงนี้มีโน้ตสำคัญเรื่อง configuration กับ usage ครับ การเพิ่ม memory service เข้ากับ runner ทำให้ memory พร้อมใช้สำหรับเอเจนต์ แต่มันไม่ได้ใช้งานอัตโนมัติ เราต้องกำหนดอย่างชัดเจน คือบอกให้มัน ingest ข้อมูลผ่าน session และเปิดใช้งานการดึงข้อมูลโดยให้ memory tools อย่าง load_memory หรือ preload_memory กับเอเจนต์ ซึ่งเราจะทำในขั้นถัดไปครับ
ทีนี้อีกเรื่องหนึ่งคือเรื่องตัวเลือก implementation ของ memory service ครับ อันนี้เราใช้ InMemory memory service และใน production เราจะใช้แบบที่พูดถึงไปแล้วครับ
Section สี่คือการนำข้อมูล session เข้าสู่ memory ครับ ระหว่างรันโค้ดนี้ สิ่งที่เกิดขึ้นคือในระหว่างการย้ายข้อมูล ตัว session จะทำ intelligent consolidation คือสกัดเอาเฉพาะข้อเท็จจริงสำคัญ แล้วทิ้งส่วนที่เป็นแค่ความยุ่งยากของบทสนทนาทิ้งไปครับ อันนี้เสร็จแล้ว เราได้คำถามว่า my favorite color is blue green ชอบสีน้ำเงินอมเขียว แล้วขอให้เขียนบทกวี haiku (ไฮกู) เกี่ยวกับสีนั้นหน่อย โดยใช้ conversation ID เป็น 01 ครับ แล้วมันตอบว่าเป็นสีที่สวยงามเหมือนมหาสมุทรกับต้นไม้ สงบและกลมกลืนกันดีครับ
ทีนี้เราจะมาตรวจสอบว่าบทสนทนานี้ถูกเก็บจริงหรือเปล่า และมันถูกเก็บอย่างไร ลองดูนะครับ มันบอกว่า session มีข้อความของ user เกี่ยวกับสีที่ชอบ และเรามี event ตรงนี้ที่มีคำว่า beautiful อยู่ เสร็จแล้วครับ ตรงนี้คือ method หลักในการนำบทสนทนาเข้าสู่ memory store เพื่อให้ค้นหาได้ในอนาคต ก็คือการเพิ่ม session เข้าไปใน memory ด้วยวิธีนี้ครับ
ขั้นต่อไปคือการเปิดใช้งานการดึงข้อมูล memory ในเอเจนต์ ครับ มีอยู่สองวิธีคือ load กับ preload โดย load_memory เป็นแบบ reactive คือทำงานเมื่อถูกเรียก ส่วน preload เป็นแบบ proactive คือเตรียมข้อมูลไว้ก่อนครับ ทีนี้เราจะเพิ่ม load_memory tool เข้ากับเอเจนต์ ผมรันอันนี้เลย ใช้ข้อมูลชุดเดิมกัน ตัว tool คือ load_memory และ instruction คือให้ตอบคำถามของ user ด้วยคำง่ายๆ และให้ใช้ load_memory tool เมื่อต้องการนึกถึงบทสนทนาที่ผ่านมา ครับ เราจะอัปเดต runner แล้วทดสอบกัน
User ถามว่าสีที่ฉันชอบคือสีอะไร โมเดลตอบว่าสีที่คุณชอบคือสีน้ำเงินอมเขียวครับ ต่อไปเราจะทดสอบ manual workflow ให้ครบ เรารันอันนี้แล้วบอกว่าวันเกิดของฉันคือวันที่ 15 มีนาคม โดยตั้งชื่อ session เป็น session วันเกิดอันดับหนึ่ง มันตอบว่ารับทราบ ฉันจะจำไว้ครับ ทีนี้เราจะบันทึกข้อมูลนี้แบบ manual อีกครั้ง session วันเกิดถูกบันทึกเข้า memory แล้ว ต่อไปเราจะดึงข้อมูลนี้กลับมาดูว่ามันได้ผลหรือเปล่า ผมใช้ session วันเกิดอันดับสอง ถามว่าวันเกิดของฉันคือเมื่อไหร่ มันตอบว่าวันเกิดของคุณคือวันที่ 15 มีนาคม ครับ
ตรงนี้เอเจนต์ได้รับคำถามว่าวันเกิดของฉันคือเมื่อไหร่ มันรู้ว่าคำถามนี้ต้องใช้บริบทจากบทสนทนาที่ผ่านมา เอเจนต์จึงเรียกใช้ load_memory แล้วมันคืนค่าบทสนทนาก่อนหน้าที่มีวันที่ 15 มีนาคมอยู่ อันนี้เสร็จเรียบร้อยครับ ทีนี้ถ้าอยากลองเล่นดู เรามี load_memory อยู่แล้ว ตอนนี้ลองสลับเป็น preload ดูครับ ในส่วนของ tool ตรงที่เขียนว่า load_memory ให้เปลี่ยนเป็น preload_memory แล้วรันดูว่าจะเกิดอะไรขึ้นครับ
เอาล่ะ มาลองกัน ถ้าต้องการผมจะเอาโค้ดส่วน retrieval มาวางตรงนี้เลย กำลังแทนที่อยู่ครับ อ๊ะขอโทษที ตรงนี้ต้องแก้ด้วย นี่ไง color test ดูดีเลยใช่ไหมครับ ทั้งสอง session ถูกบันทึกแล้ว เรากำลังรันส่วนนี้อยู่ ทุกอย่างเข้าที่ ทุกอย่างสมบูรณ์ครับ แม้จะใช้ preload แต่มันก็ยังค้นหาใน memory ได้เหมือนกันครับ
นอกเหนือจากกฎของเอเจนต์ เรายังเรียกใช้ search memory ตรงๆ ในโค้ดของเราได้ด้วยครับ วิธีนี้มีประโยชน์สำหรับการ debug การสร้าง analytics dashboard และการทำ custom memory management ครับ ตัวฟังก์ชัน search_memory จะรับ text query แล้วคืนค่า SearchMemoryResponse ที่มีรายการ memories ที่ตรงกันครับ โค้ดง่ายมาก มี user ID แล้วก็ print ผลลัพธ์ออกมาดูว่าเราคุยอะไรกันมาแล้วบ้าง ผลออกมามี memories ที่เกี่ยวข้องหกรายการครับ มีสีที่ชอบคือน้ำเงินอมเขียว มี haiku เกี่ยวกับสีนั้น แล้วก็มีวันที่ 15 กับคำว่ารับทราบจะจำไว้ มันแค่แสดงบทสนทนาทั้งหมดให้เราดูครับ
ทีนี้ถ้าอยากลอง ให้ลองเล่น search พวกนี้ดูเพื่อทำความเข้าใจว่าการจับคู่คียเวิร์ดทำงานอย่างไร เราสามารถถามว่า user ชอบสีอะไร และคำถามอื่นๆ ในลักษณะนี้ แล้วดูว่าแชตบอตตอบอย่างไร หรือมัน hallucinate (สร้างความจำเท็จ) หรือเปล่า แต่ประเด็นสำคัญคือการค้นหา memory นั้นตั้งอยู่บนข้อเท็จจริงครับ เอเจนต์จึงไม่สามารถ hallucinate ความจำที่ไม่มีอยู่จริงได้ครับ ส่วนการค้นหาทำงานอย่างไร memory service แบบนี้ทำการจับคู่คียเวิร์ด ส่วนใน Vertex AI Memory Bank ซึ่งเราจะได้ทำในแบบฝึกหัดของ Day 5 จะใช้การค้นหาเชิงความหมายด้วย embeddings ครับ อันนี้เสร็จแล้ว
ต่อไป section หกคือการทำ memory storage ให้อัตโนมัติครับ ตอนนี้เราเรียก add_session_to_memory ด้วยตนเองมาตลอดเพื่อย้ายข้อมูลไปเก็บระยะยาว แต่ระบบ production ต้องการให้เรื่องนี้เกิดขึ้นเองอัตโนมัติ ดังนั้นเราจึงแนะนำ callbacks (ฟังก์ชันเรียกกลับ) ครับ ระบบ callback ของ ADK ให้เรา hook เข้าไปยังจังหวะสำคัญๆ ของการทำงาน callback เป็นฟังก์ชัน Python ที่เรานิยามแล้วผูกเข้ากับเอเจนต์ ADK จะเรียกมันเองโดยอัตโนมัติในแต่ละขั้นตอน ทำหน้าที่เหมือน checkpoint ระหว่างการทำงานของเอเจนต์ครับ จะคิดซะว่า callback เป็น event listener ในวงจรชีวิตของเอเจนต์ก็ได้ครับ เมื่อเอเจนต์ประมวลผลคำขอหนึ่งๆ มันจะผ่านหลายขั้นตอน ตั้งแต่รับ input เรียก LLM เรียกใช้ tools ไปจนถึงสร้างคำตอบ callback ทำให้เราแทรก logic ที่กำหนดเองเข้าไปในแต่ละขั้นตอนเหล่านี้ได้ โดยไม่ต้องแก้โค้ดหลักของเอเจนต์ครับ
callback มีประเภทอะไรบ้าง มี before_agent_callback ที่รันก่อนที่เอเจนต์จะเริ่มประมวลผลคำขอ มี after_agent_callback ที่รันหลังเอเจนต์จบ turn ของตัวเอง แล้วก็มี before และ after ที่อยู่รอบๆ ตำแหน่งการเรียกใช้ tool มี before_model_callback และ after_model_callback ที่อยู่รอบๆ การเรียก LLM และมี on_model_error_callback ที่ทำงานเมื่อเกิด error ครับ use case ที่พบบ่อยคือ logging และ observability (การติดตามการทำงาน) เช่นดูว่าเอเจนต์ทำอะไรบ้าง การบันทึกลง memory การตรวจสอบแบบกำหนดเอง การกรองข้อมูล หรือการเฝ้าดูประสิทธิภาพ ครับ อยากรู้เรื่อง callback เพิ่มเติมไปอ่านได้ที่ documentation นี้ครับ ผมจะใส่ลิงก์ไว้ในคำอธิบายของวิดีโอด้วยเช่นกัน
นี่คือวิธีที่มันทำงานครับ ถ้าอยากเข้าใจประเภทของ callback เหล่านี้ before callback รันก่อนที่เอเจนต์จะประมวลผลคำขอ after ตัวหลังจะรันหลังเอเจนต์จบ turn ของตัวเอง แล้วก็ before_tool_callback กับ after_tool_callback ตรงนี้เลยครับ อันนี้อยู่รอบๆ การเรียกใช้ tool และตัว model แบบ before และ after ก็คืออยู่รอบๆ การเรียก LLM ครับ ไดอะแกรมนี้อธิบายประเภทของ callback และการทำงานของมันให้เราเข้าใจครับ นี่คือก่อนเอเจนต์ประมวลผล นี่คือหลังเอเจนต์ทำเสร็จ ส่วนนี้คือการเรียกใช้ tool และส่วนนี้คือการล้อมรอบการเรียก LLM ครับ
ต่อไปคือการจัดเก็บ memory อัตโนมัติด้วย callbacks ครับ สำหรับการจัดเก็บอัตโนมัติเราจะใช้ after_agent_callback ครับ ฟังก์ชันนี้จะทำงานทุกครั้งที่เอเจนต์จบ turn แล้วเรียก add_session เพื่อเรียก add_session_to_memory เพื่อบันทึกบทสนทนาโดยอัตโนมัติครับ แต่ความท้าทายคือฟังก์ชัน callback จะเข้าถึง memory service และ session ปัจจุบันได้อย่างไร สำหรับเรื่องนั้นเรามี callback context ครับ เมื่อเรานิยามฟังก์ชัน callback ขึ้นมา ADK จะส่งพารามิเตอร์พิเศษที่เรียกว่า callback_context เข้ามาให้อัตโนมัติ ตัว callback context นี้ให้การเข้าถึง memory service และส่วนประกอบ runtime อื่นๆ ครับ เราจะใช้มันใน callback ของเราเพื่อเข้าถึง memory service และ session ปัจจุบัน เพื่อบันทึกบทสนทนาอัตโนมัติหลังจบทุก turn ครับ เราไม่ต้องสร้าง context นี้เอง ADK เป็นคนสร้างแล้วส่งเข้า callback ให้อัตโนมัติเมื่อมันทำงาน เราไม่ต้องห่วงว่ามันทำงานอย่างไรครับ
ขั้นต่อไปคือสร้างเอเจนต์ที่รวมการจัดเก็บอัตโนมัติเข้ากับ preload_memory ครับ สำหรับการจัดเก็บอัตโนมัติ เราต้องสร้างเอเจนต์ที่ผสมการจัดเก็บอัตโนมัติกับการดึงข้อมูลอัตโนมัติ การจัดเก็บอัตโนมัติก็คือ after_agent_callback ที่บันทึกบทสนทนา ส่วน preload_memory จะโหลดข้อมูลความจำครับ ทำอย่างไรล่ะครับ มีเอเจนต์ตรงนี้ instruction คือตอบคำถามของ user เครื่องมือคือ preload_memory และ callback คือ autosave_memory ซึ่งบันทึกหลังจบทุก turn ครับ เรามารันกัน สิ่งที่เกิดขึ้นโดยอัตโนมัติคือหลังจากเอเจนต์ตอบกลับทุกครั้ง callback จะทำงาน และข้อมูลของ session จะถูกย้ายเข้า memory โดยไม่ต้องเรียก add_session_to_memory ด้วยตนเองเลยครับ
ต่อไปสร้าง runner แล้วทดสอบเอเจนต์ครับ เราสร้าง runner เสร็จแล้ว ทีนี้มาทดสอบเอเจนต์กัน เรามี test หนึ่งกับ test สอง อันแรกคือผมให้ของขวัญเป็นของเล่นใหม่แก่หลานชายในวันเกิดปีแรกของเขา มันตอบว่าเยี่ยมมาก หวังว่าหลานชายของคุณจะสนุกกับของเล่นนะครับ อันที่สองคือผมให้อะไรหลานชายไป มันตอบว่าคุณให้ของเล่นใหม่แก่หลานชายในวันเกิดปีแรกของเขาครับ
แล้วเพิ่งเกิดอะไรขึ้นล่ะครับ บทสนทนาแรกพูดถึงของขวัญให้หลานชาย ดังนั้น callback จึงบันทึกลง memory โดยอัตโนมัติ ส่วนบทสนทนาที่สองเป็น session ใหม่ ถามเรื่องของขวัญ preload_memory จึงดึงข้อมูลความจำกลับมาอัตโนมัติ แล้วเอเจนต์ก็ตอบถูกต้องครับ ดังนั้นจึงมีการเรียกใช้ memory ด้วยมือเป็นศูนย์ครั้ง นี่คือการจัดการหน่วยความจำแบบอัตโนมัติครับ
ควรบันทึก memory บ่อยแค่ไหน คือควรบันทึก session ลง memory บ่อยแค่ไหน มีตัวเลือกอยู่ดังนี้ครับ คือหลังจบทุก turn หลังจบบทสนทนา และเป็นช่วงๆ ตามระยะเวลา ควรบันทึกหลังจบทุก turn เมื่อต้องการอัปเดต memory แบบเรียลไทม์ ส่วนแบบหลังจบบทสนทนาเหมาะเมื่อทำ batch processing หรือต้องการลดจำนวน API calls และแบบเป็นช่วงๆ เหมาะกับบทสนทนาที่ยาวๆ ครับ เรารู้กันมาแล้วนะครับ
ต่อไปคือ section เจ็ดเรื่อง memory consolidation ครับ ในส่วนนี้เราจะเข้าใจข้อจำกัดของการเก็บข้อมูลดิบ สิ่งที่เราเก็บมาตลอดคือทุกข้อความของ user ทุกคำตอบของเอเจนต์ และทุก tool call ปัญหาคือถ้ามี 50 ข้อความในหนึ่ง session มันจะเท่ากับ 10,000 tokens แล้วทั้ง 50 ข้อความก็ถูกเก็บลง memory หมดเลย ตัวค้นหาจะคืนค่าทั้ง 50 ข้อความ และเอเจนต์ต้องประมวลผล 10,000 tokens ซึ่งมัน scale ไม่ไหวครับ เราจำเป็นต้องมี consolidation ดังนั้น memory consolidation จึงเข้ามามีบทบาทตรงนี้ครับ หมายความคือสกัดเอาเฉพาะข้อเท็จจริงสำคัญ แล้วทิ้ง noise ของบทสนทนาทิ้งไปครับ
การเก็บข้อมูลดิบจะหน้าตาประมาณนี้ครับ จากตัวอย่างก่อนหน้าของเรา มันเก็บข้อความทั้งสี่ที่ซ้ำซ้อนและยืดยาว เพราะเห็นได้ว่ามันพูดซ้ำกัน หลังทำ consolidation ข้อมูลที่สกัดได้คือ user ชอบสีน้ำเงินอมเขียว หมายความว่ามันเก็บเพียงข้อเท็จจริงเดียวที่กระชับจากข้อมูลดิบทั้งก้อนครับ ประโยชน์คือใช้พื้นที่จัดเก็บน้อยลง ดึงข้อมูลเร็วขึ้น และคำตอบแม่นยำขึ้นครับ จากตัวอย่าง session ของเรา สิ่งที่ได้ก็คือแบบนี้ครับ
subsection ถัดไปคือ consolidation ทำงานอย่างไร ในส่วนของแนวคิด เราจะไม่เขียนโค้ดส่วนนี้กันนะครับ เริ่มจาก event ดิบของ session ตัว language model จะวิเคราะห์บทสนทนา สกัดข้อเท็จจริงสำคัญ จัดเก็บความจำที่กระชับ และผสานเข้ากับความจำเดิมที่มีอยู่ โดยขจัดข้อมูลที่ซ้ำกันออกครับ ตัวอย่างของการแปลงข้อมูลเช่น ผมแพ้ถั่ว กินอะไรที่มีถั่วไม่ได้เลย ผลลัพธ์ที่ได้คือความจำแบบมีโครงสร้างว่า แพ้ถั่ว ถั่วต้นไม้ ระดับความรุนแรง หลีกเลี่ยงอย่างสมบูรณ์ ครับ ภาษาธรรมชาติจึงถูกแปลงเป็นข้อมูลที่มีโครงสร้างและนำไปใช้ได้จริงครับ
ส่วนถัดไปพูดถึงขั้นต่อไปของ memory consolidation ครับ ประเด็นสำคัญที่ต้องจำคือ managed memory service จัดการ consolidation ให้อัตโนมัติ ตรงนี้เราใช้ API เดิม ใช้ method ของ memory ตัวเดิม สิ่งที่ต่างคือสิ่งที่เกิดขึ้นเบื้องหลังครับ memory service แบบนี้เก็บ event ดิบๆ ส่วน Vertex AI Memory Bank จะกลั่นข้อมูลอย่างชาญฉลาดก่อนจัดเก็บครับ ถ้าอยากเรียนรู้เพิ่มเติมเรื่อง memory consolidation ซึ่งเราจะได้ศึกษาต่อในห้าวันถัดไป สามารถไปอ่านหน้า guide นี้ได้ครับ
นี่คือสรุปสิ่งที่เราทำในแบบฝึกหัดนี้ครับ เราได้เรียนรู้การเพิ่ม memory การจัดเก็บข้อมูล การค้นหา memory การดึงข้อมูลในเอเจนต์ และ memory consolidation ครับ หวังว่าแนวคิดจะชัดเจนสำหรับคุณนะครับ ถ้ายังไม่ชัดก็ลองดูวิดีโออีกหนึ่งหรือสองรอบ แล้วจะเข้าใจง่ายขึ้นในทุกครั้งที่ดูครับ และเมื่อจบ Day 3 แล้ว โปรดไปดูวิดีโอของ Day 4 ซึ่งพูดถึงการ implement observability และ evaluation ของเอเจนต์ ซึ่งสำคัญมาก เพราะมันช่วยให้มั่นใจว่าเอเจนต์ทำงานตามที่ตั้งใจไว้จริงๆ ใน production ครับ ขอบคุณครับ
หมายเหตุการแปล
ความโปร่งใสเกี่ยวกับความไม่แน่นอนในต้นฉบับ
- ไม่มีการใช้สัญลักษณ์ระบุเสียงไม่ชัดเจน (0 จุด) — ทุก segment เข้าใจความหมายได้ครบ
อภิธานศัพท์เทคนิค
คำศัพท์และชื่อผลิตภัณฑ์ที่คงรูปภาษาอังกฤษ
| ศัพท์ | คำแปล / คำอธิบาย |
|---|---|
| memory management | การจัดการหน่วยความจำระยะยาวของเอเจนต์ |
| session | เซสชัน — หน่วยความจำระยะสั้น ครอบคลุมบทสนทนาเดียว |
| memory | หน่วยความจำระยะยาว ใช้ข้ามหลายบทสนทนา |
| ADK (Agent Development Kit) | ชุดเครื่องมือพัฒนาเอเจนต์ของ Google |
| notebook | สมุดบันทึกโค้ดแบบโต้ตอบได้ (เช่นของ Kaggle/Colab) |
| codelab | ห้องปฏิบัติการโค้ด แบบฝึกหัดปฏิบัติจริง |
| InMemory memory service | บริการความจำชั่วคราวเก็บในหน่วยความจำโปรแกรม ใช้จับคู่คียเวิร์ด ไม่เก็บถาวร เหมาะกับการเรียน/ทดลอง |
| Vertex AI Memory Bank | บริการความจำระยะยาวบนคลาวด์ของ Google มีกลั่นข้อมูลด้วย LLM การค้นหาเชิงความหมาย และเก็บข้อมูลถาวร |
| semantic search | การค้นหาเชิงความหมาย ต่างจากการจับคู่คียเวิร์ดทั่วไป |
| embeddings | เวกเตอร์แทนความหมายของข้อความ ใช้สำหรับค้นหาเชิงความหมาย |
| consolidation | การกลั่นข้อมูล สกัดเฉพาะข้อเท็จจริงสำคัญจากบทสนทนา ทิ้งส่วนที่ซ้ำซ้อน |
| runner | ตัวขับเคลื่อนการทำงานของเอเจนต์ จัดการ session service และ memory service |
| session service | บริการจัดการเธรดบทสนทนาและ events |
| add_session_to_memory | ฟังก์ชันย้ายข้อมูล session เข้าสู่หน่วยความจำระยะยาว |
| search_memory | ฟังก์ชันค้นหาความจำที่เก็บไว้ |
| load_memory | เครื่องมือดึงข้อมูลความจำแบบ reactive (ทำงานเมื่อถูกเรียก) |
| preload_memory | เครื่องมือดึงข้อมูลความจำแบบ proactive (เตรียมไว้ล่วงหน้า) |
| callback | ฟังก์ชันเรียกกลับที่ ADK เรียกอัตโนมัติตามจังหวะการทำงานของเอเจนต์ |
| callback context | บริบทพิเศษที่ ADK ส่งให้ callback ใช้เข้าถึง memory service และ runtime |
| after_agent_callback | callback ที่ทำงานหลังเอเจนต์จบ turn |
| before_agent_callback | callback ที่ทำงานก่อนเอเจนต์เริ่มประมวลผลคำขอ |
| before/after_model_callback | callback รอบๆ การเรียก LLM |
| before/after_tool_callback | callback รอบๆ การเรียกใช้ tool |
| on_model_error_callback | callback ที่ทำงานเมื่อโมเดลเกิด error |
| observability | ความสามารถในการติดตามดูการทำงานของระบบ |
| evaluation | การประเมินผลการทำงานของเอเจนต์ |
| hallucinate / hallucination | อาการโมเดลสร้างข้อมูลเท็จที่ไม่มีอยู่จริง |
| production | สภาพแวดล้อมจริงที่ระบบใช้งานจริง (ต่างจากการทดลอง) |
| prototyping | การสร้างต้นแบบเพื่อทดลอง |
| haiku | ไฮกู — บทกวีสั้นญี่ปุ่น ใช้เป็นตัวอย่างในแบบฝึกหัด |
| BaseMemoryService | interface หลักของ memory service ใน ADK |
| SearchMemoryResponse | ชนิดผลลัพธ์ที่ได้จากการค้นหา memory |
| logging | การบันทึก log การทำงานของระบบ |
| token | หน่วยนับข้อความที่โมเดลประมวลผล |
ซับไตเติ้ลภาษาไทย
ดาวน์โหลดหรือดูซับทั้งหมด
1 00:00:00,000 --> 00:00:03,652 ในวิดีโอนี้เราจะไปดูกันใน codelab ที่สองของ 2 00:00:03,652 --> 00:00:07,218 assignment ใน Day 3 ครับ ผมจะกดที่ Explore 3 00:00:07,218 --> 00:00:09,766 เพื่อให้มันพาเราไปที่ notebook 4 00:00:09,766 --> 00:00:12,483 แล้วเราจะทำสำเนาไว้เป็น notebook
เปิดดูซับไตเติ้ลทั้งหมด (388 segments)
1 00:00:00,000 --> 00:00:03,652 ในวิดีโอนี้เราจะไปดูกันใน codelab ที่สองของ 2 00:00:03,652 --> 00:00:07,218 assignment ใน Day 3 ครับ ผมจะกดที่ Explore 3 00:00:07,218 --> 00:00:09,766 เพื่อให้มันพาเราไปที่ notebook 4 00:00:09,766 --> 00:00:12,483 แล้วเราจะทำสำเนาไว้เป็น notebook 5 00:00:12,483 --> 00:00:15,625 แบบแก้ไขได้ของเราเอง เพื่อใช้เดินผ่าน 6 00:00:15,625 --> 00:00:19,277 assignment นี้ไปด้วยกันนะครับ ใน assignment 7 00:00:19,277 --> 00:00:22,504 นี้เราจะคุยกันเรื่อง memory management 8 00:00:22,504 --> 00:00:26,241 หรือการจัดการหน่วยความจำครับ เรามีอยู่สองแบบ 9 00:00:26,241 --> 00:00:30,147 แบบแรกคือ session (เซสชัน) และอีกแบบคือ memory 10 00:00:30,147 --> 00:00:32,525 (หน่วยความจำระยะยาว) session 11 00:00:32,525 --> 00:00:36,686 เป็นหน่วยความจำระยะสั้นที่ครอบคลุมแค่บทสนทนาเดียว 12 00:00:36,686 --> 00:00:39,658 ส่วนในวิดีโอนี้เราจะโฟกัสที่ memory 13 00:00:39,658 --> 00:00:43,904 ซึ่งเป็นความรู้ระยะยาวที่ใช้งานข้ามหลายบทสนทนาครับ 14 00:00:43,904 --> 00:00:47,725 ตัวอย่างที่เขาให้มาก็คือให้คิดว่ามันเหมือนกับ 15 00:00:47,725 --> 00:00:51,547 software engineer ครับ ทีนี้ทำไมต้องมี memory 16 00:00:51,547 --> 00:00:54,774 ล่ะครับ memory มีความสามารถที่ session 17 00:00:54,774 --> 00:00:56,302 อย่างเดียวทำไม่ได้ 18 00:00:56,302 --> 00:00:58,850 ไม่ว่าจะเป็นการจดจำข้ามบทสนทนา 19 00:00:58,850 --> 00:01:02,756 การสกัดข้อมูลอย่างชาญฉลาด การค้นหาเชิงความหมาย 20 00:01:02,756 --> 00:01:05,049 และการเก็บข้อมูลแบบถาวรครับ 21 00:01:05,049 --> 00:01:08,361 มีอีกตัวอย่างหนึ่งคือการคุยกับ personal 22 00:01:08,361 --> 00:01:10,569 assistant ถ้ามีแค่ session 23 00:01:10,569 --> 00:01:14,985 เอเจนต์จะจำได้แค่สิ่งที่เราพูดในช่วงสิบนาทีที่ผ่านมา 24 00:01:14,985 --> 00:01:16,259 แต่ถ้ามี memory 25 00:01:16,259 --> 00:01:21,184 มันจะจำความชอบและบทสนทนาของเราจากสัปดาห์ที่แล้วได้ด้วยครับ 26 00:01:21,184 --> 00:01:25,006 สิ่งที่เราจะเรียนในแบบฝึกหัดนี้คือ การตั้งค่า 27 00:01:25,006 --> 00:01:28,233 memory service และเชื่อมเข้ากับเอเจนต์ 28 00:01:28,233 --> 00:01:31,714 การย้ายข้อมูล session ไปเก็บในหน่วยความจำ 29 00:01:31,714 --> 00:01:34,432 การค้นหาและดึงข้อมูลความจำกลับมา 30 00:01:34,432 --> 00:01:38,338 การทำให้การจัดเก็บและดึงข้อมูลเป็นแบบอัตโนมัติ 31 00:01:38,338 --> 00:01:41,650 และการเข้าใจเรื่อง memory consolidation 32 00:01:41,650 --> 00:01:44,537 (การกลั่นข้อมูลในหน่วยความจำ) ครับ 33 00:01:44,537 --> 00:01:48,104 นี่คือภาพรวมเชิงแนวคิดนะครับ ข้อควรทราบคือ 34 00:01:48,104 --> 00:01:51,926 notebook นี้ใช้บริการ InMemory memory service 35 00:01:51,926 --> 00:01:55,832 เพื่อการเรียนรู้ แต่ในงานจริงที่ใช้ production 36 00:01:55,832 --> 00:01:59,144 สิ่งที่ต้องใช้คือ Vertex AI Memory Bank 37 00:01:59,144 --> 00:02:02,795 ซึ่งจะได้เจอกันใน assignment ของ Day 5 ครับ 38 00:02:02,795 --> 00:02:06,702 Vertex AI Memory Bank ให้บริการกลั่นข้อมูลด้วย 39 00:02:06,702 --> 00:02:08,740 LLM การค้นหาเชิงความหมาย 40 00:02:08,740 --> 00:02:12,307 และการจัดเก็บแบบถาวรบนคลาวด์ ส่วน InMemory 41 00:02:12,307 --> 00:02:15,958 memory service ทำได้แค่การจับคู่คำคียเวิร์ด 42 00:02:15,958 --> 00:02:19,610 และไม่เก็บข้อมูลถาวรครับ เอาล่ะ เริ่มกันเลย 43 00:02:19,610 --> 00:02:22,412 ส่วนของ step หนึ่งผมจะรีบผ่านๆ ไป 44 00:02:22,412 --> 00:02:26,318 เพราะเราทำขั้นตอนนี้ซ้ำกันมาในทุกแบบฝึกหัดแล้ว 45 00:02:26,318 --> 00:02:29,545 เลือกหนึ่ง เราสร้าง API key สำเร็จแล้ว 46 00:02:29,545 --> 00:02:33,027 และตั้งค่าเรียบร้อยแล้ว ต่อไปเราจะ import 47 00:02:33,027 --> 00:02:36,594 ส่วนประกอบของ ADK (Agent Development Kit — 48 00:02:36,594 --> 00:02:40,161 ชุดเครื่องมือพัฒนาเอเจนต์ของ Google) เรามี 49 00:02:40,161 --> 00:02:43,812 load_memory และ preload_memory และมี memory 50 00:02:43,812 --> 00:02:47,634 service ด้วย แต่ใน production เราจะใช้ Vertex 51 00:02:47,634 --> 00:02:51,115 AI Memory Bank ตามที่บอกไปก่อนหน้านี้ครับ 52 00:02:51,115 --> 00:02:54,682 ฉะนั้นตรงนี้เราใช้ InMemory memory service 53 00:02:54,682 --> 00:02:58,588 แต่พอขึ้น production ให้ใช้ Vertex Memory Bank 54 00:02:58,588 --> 00:03:01,645 ครับ เยี่ยม import ส่วนประกอบของ ADK 55 00:03:01,645 --> 00:03:05,382 สำเร็จแล้ว ขั้นต่อไปคือกำหนด helper function 56 00:03:05,382 --> 00:03:09,203 อันนี้ก็ทำเสร็จแล้ว จากนั้นสร้าง retry config 57 00:03:09,203 --> 00:03:13,025 ก็เสร็จเรียบร้อย เรามาดู section สองกันต่อเลย 58 00:03:13,025 --> 00:03:16,931 ซึ่งก็คือ memory workflow ครับ ทีนี้ใน section 59 00:03:16,931 --> 00:03:20,838 สอง มาทำความเข้าใจ workflow ของ memory กันก่อน 60 00:03:20,838 --> 00:03:22,366 การจะเชื่อม memory 61 00:03:22,366 --> 00:03:26,018 เข้ากับเอเจนต์ของเรามีอยู่สามขั้นตอนหลักคือ 62 00:03:26,018 --> 00:03:29,415 Initialize Ingest และ Retrieve ครับ ขั้น 63 00:03:29,415 --> 00:03:32,557 Initialize คือเราสร้าง memory service 64 00:03:32,557 --> 00:03:36,378 แล้วส่งให้เอเจนต์ผ่านตัว runner ขั้นที่สองคือ 65 00:03:36,378 --> 00:03:39,945 Ingest ที่เราย้ายข้อมูลของ session เข้าสู่ 66 00:03:39,945 --> 00:03:43,596 memory โดยใช้ฟังก์ชัน add_session_to_memory 67 00:03:43,596 --> 00:03:45,804 ส่วนขั้นที่สามคือ Retrieve 68 00:03:45,804 --> 00:03:49,626 ที่เราค้นหาข้อมูลความจำที่เก็บไว้ด้วยฟังก์ชัน 69 00:03:49,626 --> 00:03:53,107 search_memory ครับ นี่คือหน้าตาของ memory 70 00:03:53,107 --> 00:03:54,381 workflow ของเรา 71 00:03:54,381 --> 00:03:58,288 แล้วเดี๋ยวเราจะไล่ดูรายละเอียดทีละขั้น ตั้งแต่ 72 00:03:58,288 --> 00:04:01,854 Initialize Ingest ไปจนถึง Retrieve กันครับ 73 00:04:01,854 --> 00:04:05,591 Section สามคือการตั้งค่า memory service ครับ 74 00:04:05,591 --> 00:04:08,054 การ initialize memory คืออะไร 75 00:04:08,054 --> 00:04:11,365 ตรงนี้เรามีบริการแบบ built-in สำหรับงาน 76 00:04:11,365 --> 00:04:13,319 prototyping และ testing 77 00:04:13,319 --> 00:04:15,357 เช่นการจับคู่คำคียเวิร์ด 78 00:04:15,357 --> 00:04:18,923 แต่ไม่มีการเก็บข้อมูลถาวร ส่วนแบบที่สองคือ 79 00:04:18,923 --> 00:04:22,745 Vertex AI Memory Bank ซึ่งเป็นบริการคลาวด์แบบ 80 00:04:22,745 --> 00:04:25,462 managed มีการกลั่นข้อมูลด้วย LLM 81 00:04:25,462 --> 00:04:29,029 และการค้นหาเชิงความหมาย และแบบที่สามคือการ 82 00:04:29,029 --> 00:04:30,133 implement เอง 83 00:04:30,133 --> 00:04:33,445 เราสามารถสร้างของตัวเองจากฐานข้อมูลผ่าน 84 00:04:33,445 --> 00:04:36,842 managed service ซึ่งเป็นวิธีที่แนะนำครับ 85 00:04:36,842 --> 00:04:40,578 โดยสรุป ADK มี memory service implementation 86 00:04:40,578 --> 00:04:44,060 ให้เลือกใช้หลายแบบ ผ่าน interface ที่ชื่อ 87 00:04:44,060 --> 00:04:47,287 BaseMemoryService ครับ สำหรับ notebook 88 00:04:47,287 --> 00:04:51,193 นี้เราจะใช้แบบแรกตามที่บอกไปแล้ว เอาล่ะมาสร้าง 89 00:04:51,193 --> 00:04:54,930 memory กัน อันนี้เสร็จแล้ว ต่อไปเป็นการเพิ่ม 90 00:04:54,930 --> 00:04:58,327 memory เข้ากับเอเจนต์ตามที่นิยามไว้ โอเค 91 00:04:58,327 --> 00:05:00,365 ตอนนี้เรามี instructions 92 00:05:00,365 --> 00:05:04,016 ที่บอกว่าให้ตอบคำถามด้วยคำง่ายๆ เราได้เพิ่ม 93 00:05:04,016 --> 00:05:07,583 memory ตรงนี้แล้ว เอเจนต์ถูกสร้างเรียบร้อย 94 00:05:07,583 --> 00:05:10,980 ขั้นต่อไปคือสร้าง runner ครับ ตัว runner 95 00:05:10,980 --> 00:05:12,254 ต้องการ service 96 00:05:12,254 --> 00:05:16,075 ทั้งสองตัวเพื่อเปิดใช้งานฟังก์ชันที่เกี่ยวกับ 97 00:05:16,075 --> 00:05:19,217 memory ครับ ตัวแรกคือ session service 98 00:05:19,217 --> 00:05:22,019 ที่จัดการเธรดของบทสนทนาและ events 99 00:05:22,019 --> 00:05:24,567 และตัวที่สองคือ memory service 100 00:05:24,567 --> 00:05:28,134 ที่ให้การจัดเก็บหน่วยความจำระยะยาว ทั้งสอง 101 00:05:28,134 --> 00:05:31,955 service ทำงานร่วมกัน session เก็บบทสนทนา ส่วน 102 00:05:31,955 --> 00:05:35,267 memory เก็บความรู้เพื่อดึงกลับมาใช้ข้าม 103 00:05:35,267 --> 00:05:38,834 session ครับ เรามารันกัน เอเจนต์และ runner 104 00:05:38,834 --> 00:05:42,061 ถูกสร้างแล้วพร้อมการรองรับ memory ครับ 105 00:05:42,061 --> 00:05:45,543 ตรงนี้มีโน้ตสำคัญเรื่อง configuration กับ 106 00:05:45,543 --> 00:05:49,109 usage ครับ การเพิ่ม memory service เข้ากับ 107 00:05:49,109 --> 00:05:52,591 runner ทำให้ memory พร้อมใช้สำหรับเอเจนต์ 108 00:05:52,591 --> 00:05:54,884 แต่มันไม่ได้ใช้งานอัตโนมัติ 109 00:05:54,884 --> 00:05:58,535 เราต้องกำหนดอย่างชัดเจน คือบอกให้มัน ingest 110 00:05:58,535 --> 00:06:00,064 ข้อมูลผ่าน session 111 00:06:00,064 --> 00:06:03,800 และเปิดใช้งานการดึงข้อมูลโดยให้ memory tools 112 00:06:03,800 --> 00:06:06,943 อย่าง load_memory หรือ preload_memory 113 00:06:06,943 --> 00:06:10,085 กับเอเจนต์ ซึ่งเราจะทำในขั้นถัดไปครับ 114 00:06:10,085 --> 00:06:13,142 ทีนี้อีกเรื่องหนึ่งคือเรื่องตัวเลือก 115 00:06:13,142 --> 00:06:16,369 implementation ของ memory service ครับ 116 00:06:16,369 --> 00:06:19,935 อันนี้เราใช้ InMemory memory service และใน 117 00:06:19,935 --> 00:06:23,417 production เราจะใช้แบบที่พูดถึงไปแล้วครับ 118 00:06:23,417 --> 00:06:26,899 Section สี่คือการนำข้อมูล session เข้าสู่ 119 00:06:26,899 --> 00:06:29,362 memory ครับ ระหว่างรันโค้ดนี้ 120 00:06:29,362 --> 00:06:33,098 สิ่งที่เกิดขึ้นคือในระหว่างการย้ายข้อมูล ตัว 121 00:06:33,098 --> 00:06:36,325 session จะทำ intelligent consolidation 122 00:06:36,325 --> 00:06:38,958 คือสกัดเอาเฉพาะข้อเท็จจริงสำคัญ 123 00:06:38,958 --> 00:06:43,458 แล้วทิ้งส่วนที่เป็นแค่ความยุ่งยากของบทสนทนาทิ้งไปครับ 124 00:06:43,458 --> 00:06:47,025 อันนี้เสร็จแล้ว เราได้คำถามว่า my favorite 125 00:06:47,025 --> 00:06:50,337 color is blue green ชอบสีน้ำเงินอมเขียว 126 00:06:50,337 --> 00:06:53,055 แล้วขอให้เขียนบทกวี haiku (ไฮกู) 127 00:06:53,055 --> 00:06:56,706 เกี่ยวกับสีนั้นหน่อย โดยใช้ conversation ID 128 00:06:56,706 --> 00:06:57,805 เป็น 01 ครับ 129 00:06:57,805 --> 00:07:02,136 แล้วมันตอบว่าเป็นสีที่สวยงามเหมือนมหาสมุทรกับต้นไม้ 130 00:07:02,136 --> 00:07:04,005 สงบและกลมกลืนกันดีครับ 131 00:07:04,005 --> 00:07:08,420 ทีนี้เราจะมาตรวจสอบว่าบทสนทนานี้ถูกเก็บจริงหรือเปล่า 132 00:07:08,420 --> 00:07:11,987 และมันถูกเก็บอย่างไร ลองดูนะครับ มันบอกว่า 133 00:07:11,987 --> 00:07:15,639 session มีข้อความของ user เกี่ยวกับสีที่ชอบ 134 00:07:15,639 --> 00:07:19,545 และเรามี event ตรงนี้ที่มีคำว่า beautiful อยู่ 135 00:07:19,545 --> 00:07:22,093 เสร็จแล้วครับ ตรงนี้คือ method 136 00:07:22,093 --> 00:07:25,320 หลักในการนำบทสนทนาเข้าสู่ memory store 137 00:07:25,320 --> 00:07:29,141 เพื่อให้ค้นหาได้ในอนาคต ก็คือการเพิ่ม session 138 00:07:29,141 --> 00:07:31,774 เข้าไปใน memory ด้วยวิธีนี้ครับ 139 00:07:31,774 --> 00:07:35,510 ขั้นต่อไปคือการเปิดใช้งานการดึงข้อมูล memory 140 00:07:35,510 --> 00:07:38,907 ในเอเจนต์ ครับ มีอยู่สองวิธีคือ load กับ 141 00:07:38,907 --> 00:07:42,304 preload โดย load_memory เป็นแบบ reactive 142 00:07:42,304 --> 00:07:45,871 คือทำงานเมื่อถูกเรียก ส่วน preload เป็นแบบ 143 00:07:45,871 --> 00:07:48,928 proactive คือเตรียมข้อมูลไว้ก่อนครับ 144 00:07:48,928 --> 00:07:51,645 ทีนี้เราจะเพิ่ม load_memory tool 145 00:07:51,645 --> 00:07:54,108 เข้ากับเอเจนต์ ผมรันอันนี้เลย 146 00:07:54,108 --> 00:07:57,844 ใช้ข้อมูลชุดเดิมกัน ตัว tool คือ load_memory 147 00:07:57,844 --> 00:08:01,071 และ instruction คือให้ตอบคำถามของ user 148 00:08:01,071 --> 00:08:04,298 ด้วยคำง่ายๆ และให้ใช้ load_memory tool 149 00:08:04,298 --> 00:08:07,610 เมื่อต้องการนึกถึงบทสนทนาที่ผ่านมา ครับ 150 00:08:07,610 --> 00:08:10,667 เราจะอัปเดต runner แล้วทดสอบกัน User 151 00:08:10,667 --> 00:08:12,875 ถามว่าสีที่ฉันชอบคือสีอะไร 152 00:08:12,875 --> 00:08:16,697 โมเดลตอบว่าสีที่คุณชอบคือสีน้ำเงินอมเขียวครับ 153 00:08:16,697 --> 00:08:19,924 ต่อไปเราจะทดสอบ manual workflow ให้ครบ 154 00:08:19,924 --> 00:08:23,660 เรารันอันนี้แล้วบอกว่าวันเกิดของฉันคือวันที่ 155 00:08:23,660 --> 00:08:27,227 15 มีนาคม โดยตั้งชื่อ session เป็น session 156 00:08:27,227 --> 00:08:30,199 วันเกิดอันดับหนึ่ง มันตอบว่ารับทราบ 157 00:08:30,199 --> 00:08:33,851 ฉันจะจำไว้ครับ ทีนี้เราจะบันทึกข้อมูลนี้แบบ 158 00:08:33,851 --> 00:08:37,587 manual อีกครั้ง session วันเกิดถูกบันทึกเข้า 159 00:08:37,587 --> 00:08:38,687 memory แล้ว 160 00:08:38,687 --> 00:08:42,933 ต่อไปเราจะดึงข้อมูลนี้กลับมาดูว่ามันได้ผลหรือเปล่า 161 00:08:42,933 --> 00:08:45,480 ผมใช้ session วันเกิดอันดับสอง 162 00:08:45,480 --> 00:08:48,113 ถามว่าวันเกิดของฉันคือเมื่อไหร่ 163 00:08:48,113 --> 00:08:52,019 มันตอบว่าวันเกิดของคุณคือวันที่ 15 มีนาคม ครับ 164 00:08:52,019 --> 00:08:56,435 ตรงนี้เอเจนต์ได้รับคำถามว่าวันเกิดของฉันคือเมื่อไหร่ 165 00:08:56,435 --> 00:09:00,511 มันรู้ว่าคำถามนี้ต้องใช้บริบทจากบทสนทนาที่ผ่านมา 166 00:09:00,511 --> 00:09:03,059 เอเจนต์จึงเรียกใช้ load_memory 167 00:09:03,059 --> 00:09:06,625 แล้วมันคืนค่าบทสนทนาก่อนหน้าที่มีวันที่ 15 168 00:09:06,625 --> 00:09:09,598 มีนาคมอยู่ อันนี้เสร็จเรียบร้อยครับ 169 00:09:09,598 --> 00:09:12,910 ทีนี้ถ้าอยากลองเล่นดู เรามี load_memory 170 00:09:12,910 --> 00:09:16,391 อยู่แล้ว ตอนนี้ลองสลับเป็น preload ดูครับ 171 00:09:16,391 --> 00:09:19,873 ในส่วนของ tool ตรงที่เขียนว่า load_memory 172 00:09:19,873 --> 00:09:22,336 ให้เปลี่ยนเป็น preload_memory 173 00:09:22,336 --> 00:09:26,242 แล้วรันดูว่าจะเกิดอะไรขึ้นครับ เอาล่ะ มาลองกัน 174 00:09:26,242 --> 00:09:29,214 ถ้าต้องการผมจะเอาโค้ดส่วน retrieval 175 00:09:29,214 --> 00:09:33,036 มาวางตรงนี้เลย กำลังแทนที่อยู่ครับ อ๊ะขอโทษที 176 00:09:33,036 --> 00:09:35,923 ตรงนี้ต้องแก้ด้วย นี่ไง color test 177 00:09:35,923 --> 00:09:38,725 ดูดีเลยใช่ไหมครับ ทั้งสอง session 178 00:09:38,725 --> 00:09:41,783 ถูกบันทึกแล้ว เรากำลังรันส่วนนี้อยู่ 179 00:09:41,783 --> 00:09:45,519 ทุกอย่างเข้าที่ ทุกอย่างสมบูรณ์ครับ แม้จะใช้ 180 00:09:45,519 --> 00:09:48,322 preload แต่มันก็ยังค้นหาใน memory 181 00:09:48,322 --> 00:09:51,718 ได้เหมือนกันครับ นอกเหนือจากกฎของเอเจนต์ 182 00:09:51,718 --> 00:09:54,521 เรายังเรียกใช้ search memory ตรงๆ 183 00:09:54,521 --> 00:09:56,474 ในโค้ดของเราได้ด้วยครับ 184 00:09:56,474 --> 00:09:59,956 วิธีนี้มีประโยชน์สำหรับการ debug การสร้าง 185 00:09:59,956 --> 00:10:03,522 analytics dashboard และการทำ custom memory 186 00:10:03,522 --> 00:10:07,004 management ครับ ตัวฟังก์ชัน search_memory 187 00:10:07,004 --> 00:10:09,297 จะรับ text query แล้วคืนค่า 188 00:10:09,297 --> 00:10:12,779 SearchMemoryResponse ที่มีรายการ memories 189 00:10:12,779 --> 00:10:16,430 ที่ตรงกันครับ โค้ดง่ายมาก มี user ID แล้วก็ 190 00:10:16,430 --> 00:10:20,337 print ผลลัพธ์ออกมาดูว่าเราคุยอะไรกันมาแล้วบ้าง 191 00:10:20,337 --> 00:10:24,073 ผลออกมามี memories ที่เกี่ยวข้องหกรายการครับ 192 00:10:24,073 --> 00:10:27,130 มีสีที่ชอบคือน้ำเงินอมเขียว มี haiku 193 00:10:27,130 --> 00:10:29,933 เกี่ยวกับสีนั้น แล้วก็มีวันที่ 15 194 00:10:29,933 --> 00:10:31,801 กับคำว่ารับทราบจะจำไว้ 195 00:10:31,801 --> 00:10:34,858 มันแค่แสดงบทสนทนาทั้งหมดให้เราดูครับ 196 00:10:34,858 --> 00:10:37,660 ทีนี้ถ้าอยากลอง ให้ลองเล่น search 197 00:10:37,660 --> 00:10:42,586 พวกนี้ดูเพื่อทำความเข้าใจว่าการจับคู่คียเวิร์ดทำงานอย่างไร 198 00:10:42,586 --> 00:10:46,322 เราสามารถถามว่า user ชอบสีอะไร และคำถามอื่นๆ 199 00:10:46,322 --> 00:10:50,144 ในลักษณะนี้ แล้วดูว่าแชตบอตตอบอย่างไร หรือมัน 200 00:10:50,144 --> 00:10:53,456 hallucinate (สร้างความจำเท็จ) หรือเปล่า 201 00:10:53,456 --> 00:10:56,258 แต่ประเด็นสำคัญคือการค้นหา memory 202 00:10:56,258 --> 00:10:58,721 นั้นตั้งอยู่บนข้อเท็จจริงครับ 203 00:10:58,721 --> 00:11:01,353 เอเจนต์จึงไม่สามารถ hallucinate 204 00:11:01,353 --> 00:11:03,816 ความจำที่ไม่มีอยู่จริงได้ครับ 205 00:11:03,816 --> 00:11:07,128 ส่วนการค้นหาทำงานอย่างไร memory service 206 00:11:07,128 --> 00:11:10,780 แบบนี้ทำการจับคู่คียเวิร์ด ส่วนใน Vertex AI 207 00:11:10,780 --> 00:11:14,686 Memory Bank ซึ่งเราจะได้ทำในแบบฝึกหัดของ Day 5 208 00:11:14,686 --> 00:11:18,507 จะใช้การค้นหาเชิงความหมายด้วย embeddings ครับ 209 00:11:18,507 --> 00:11:21,904 อันนี้เสร็จแล้ว ต่อไป section หกคือการทำ 210 00:11:21,904 --> 00:11:25,811 memory storage ให้อัตโนมัติครับ ตอนนี้เราเรียก 211 00:11:25,811 --> 00:11:27,594 add_session_to_memory 212 00:11:27,594 --> 00:11:31,245 ด้วยตนเองมาตลอดเพื่อย้ายข้อมูลไปเก็บระยะยาว 213 00:11:31,245 --> 00:11:32,774 แต่ระบบ production 214 00:11:32,774 --> 00:11:36,086 ต้องการให้เรื่องนี้เกิดขึ้นเองอัตโนมัติ 215 00:11:36,086 --> 00:11:38,464 ดังนั้นเราจึงแนะนำ callbacks 216 00:11:38,464 --> 00:11:42,370 (ฟังก์ชันเรียกกลับ) ครับ ระบบ callback ของ ADK 217 00:11:42,370 --> 00:11:46,192 ให้เรา hook เข้าไปยังจังหวะสำคัญๆ ของการทำงาน 218 00:11:46,192 --> 00:11:48,569 callback เป็นฟังก์ชัน Python 219 00:11:48,569 --> 00:11:51,626 ที่เรานิยามแล้วผูกเข้ากับเอเจนต์ ADK 220 00:11:51,626 --> 00:11:54,938 จะเรียกมันเองโดยอัตโนมัติในแต่ละขั้นตอน 221 00:11:54,938 --> 00:11:57,146 ทำหน้าที่เหมือน checkpoint 222 00:11:57,146 --> 00:12:00,543 ระหว่างการทำงานของเอเจนต์ครับ จะคิดซะว่า 223 00:12:00,543 --> 00:12:02,921 callback เป็น event listener 224 00:12:02,921 --> 00:12:05,469 ในวงจรชีวิตของเอเจนต์ก็ได้ครับ 225 00:12:05,469 --> 00:12:08,016 เมื่อเอเจนต์ประมวลผลคำขอหนึ่งๆ 226 00:12:08,016 --> 00:12:11,668 มันจะผ่านหลายขั้นตอน ตั้งแต่รับ input เรียก 227 00:12:11,668 --> 00:12:15,489 LLM เรียกใช้ tools ไปจนถึงสร้างคำตอบ callback 228 00:12:15,489 --> 00:12:17,018 ทำให้เราแทรก logic 229 00:12:17,018 --> 00:12:20,584 ที่กำหนดเองเข้าไปในแต่ละขั้นตอนเหล่านี้ได้ 230 00:12:20,584 --> 00:12:24,321 โดยไม่ต้องแก้โค้ดหลักของเอเจนต์ครับ callback 231 00:12:24,321 --> 00:12:27,803 มีประเภทอะไรบ้าง มี before_agent_callback 232 00:12:27,803 --> 00:12:31,369 ที่รันก่อนที่เอเจนต์จะเริ่มประมวลผลคำขอ มี 233 00:12:31,369 --> 00:12:35,191 after_agent_callback ที่รันหลังเอเจนต์จบ turn 234 00:12:35,191 --> 00:12:38,163 ของตัวเอง แล้วก็มี before และ after 235 00:12:38,163 --> 00:12:39,262 ที่อยู่รอบๆ 236 00:12:39,262 --> 00:12:46,481 ตำแหน่งการเรียกใช้ tool มี before_model_callback และ after_model_callback ที่อยู่รอบๆ 237 00:12:46,481 --> 00:12:50,047 การเรียก LLM และมี on_model_error_callback 238 00:12:50,047 --> 00:12:53,189 ที่ทำงานเมื่อเกิด error ครับ use case 239 00:12:53,189 --> 00:12:56,416 ที่พบบ่อยคือ logging และ observability 240 00:12:56,416 --> 00:13:00,323 (การติดตามการทำงาน) เช่นดูว่าเอเจนต์ทำอะไรบ้าง 241 00:13:00,323 --> 00:13:03,719 การบันทึกลง memory การตรวจสอบแบบกำหนดเอง 242 00:13:03,719 --> 00:13:07,371 การกรองข้อมูล หรือการเฝ้าดูประสิทธิภาพ ครับ 243 00:13:07,371 --> 00:13:11,108 อยากรู้เรื่อง callback เพิ่มเติมไปอ่านได้ที่ 244 00:13:11,108 --> 00:13:12,891 documentation นี้ครับ 245 00:13:12,891 --> 00:13:16,712 ผมจะใส่ลิงก์ไว้ในคำอธิบายของวิดีโอด้วยเช่นกัน 246 00:13:16,712 --> 00:13:18,835 นี่คือวิธีที่มันทำงานครับ 247 00:13:18,835 --> 00:13:22,232 ถ้าอยากเข้าใจประเภทของ callback เหล่านี้ 248 00:13:22,232 --> 00:13:23,506 before callback 249 00:13:23,506 --> 00:13:26,648 รันก่อนที่เอเจนต์จะประมวลผลคำขอ after 250 00:13:26,648 --> 00:13:30,045 ตัวหลังจะรันหลังเอเจนต์จบ turn ของตัวเอง 251 00:13:30,045 --> 00:13:32,677 แล้วก็ before_tool_callback กับ 252 00:13:32,677 --> 00:13:35,480 after_tool_callback ตรงนี้เลยครับ 253 00:13:35,480 --> 00:13:36,669 อันนี้อยู่รอบๆ 254 00:13:36,669 --> 00:13:42,104 การเรียกใช้ tool และตัว model แบบ before และ after ก็คืออยู่รอบๆ 255 00:13:42,104 --> 00:13:45,840 การเรียก LLM ครับ ไดอะแกรมนี้อธิบายประเภทของ 256 00:13:45,840 --> 00:13:49,407 callback และการทำงานของมันให้เราเข้าใจครับ 257 00:13:49,407 --> 00:13:51,530 นี่คือก่อนเอเจนต์ประมวลผล 258 00:13:51,530 --> 00:13:55,436 นี่คือหลังเอเจนต์ทำเสร็จ ส่วนนี้คือการเรียกใช้ 259 00:13:55,436 --> 00:13:59,258 tool และส่วนนี้คือการล้อมรอบการเรียก LLM ครับ 260 00:13:59,258 --> 00:14:02,570 ต่อไปคือการจัดเก็บ memory อัตโนมัติด้วย 261 00:14:02,570 --> 00:14:03,758 callbacks ครับ 262 00:14:03,758 --> 00:14:06,561 สำหรับการจัดเก็บอัตโนมัติเราจะใช้ 263 00:14:06,561 --> 00:14:08,684 after_agent_callback ครับ 264 00:14:08,684 --> 00:14:12,335 ฟังก์ชันนี้จะทำงานทุกครั้งที่เอเจนต์จบ turn 265 00:14:12,335 --> 00:14:15,053 แล้วเรียก add_session เพื่อเรียก 266 00:14:15,053 --> 00:14:16,836 add_session_to_memory 267 00:14:16,836 --> 00:14:19,724 เพื่อบันทึกบทสนทนาโดยอัตโนมัติครับ 268 00:14:19,724 --> 00:14:23,375 แต่ความท้าทายคือฟังก์ชัน callback จะเข้าถึง 269 00:14:23,375 --> 00:14:27,197 memory service และ session ปัจจุบันได้อย่างไร 270 00:14:27,197 --> 00:14:30,848 สำหรับเรื่องนั้นเรามี callback context ครับ 271 00:14:30,848 --> 00:14:34,330 เมื่อเรานิยามฟังก์ชัน callback ขึ้นมา ADK 272 00:14:34,330 --> 00:14:37,047 จะส่งพารามิเตอร์พิเศษที่เรียกว่า 273 00:14:37,047 --> 00:14:40,359 callback_context เข้ามาให้อัตโนมัติ ตัว 274 00:14:40,359 --> 00:14:43,756 callback context นี้ให้การเข้าถึง memory 275 00:14:43,756 --> 00:14:47,153 service และส่วนประกอบ runtime อื่นๆ ครับ 276 00:14:47,153 --> 00:14:50,635 เราจะใช้มันใน callback ของเราเพื่อเข้าถึง 277 00:14:50,635 --> 00:14:53,607 memory service และ session ปัจจุบัน 278 00:14:53,607 --> 00:14:57,513 เพื่อบันทึกบทสนทนาอัตโนมัติหลังจบทุก turn ครับ 279 00:14:57,513 --> 00:15:00,401 เราไม่ต้องสร้าง context นี้เอง ADK 280 00:15:00,401 --> 00:15:03,033 เป็นคนสร้างแล้วส่งเข้า callback 281 00:15:03,033 --> 00:15:05,156 ให้อัตโนมัติเมื่อมันทำงาน 282 00:15:05,156 --> 00:15:08,213 เราไม่ต้องห่วงว่ามันทำงานอย่างไรครับ 283 00:15:08,213 --> 00:15:12,969 ขั้นต่อไปคือสร้างเอเจนต์ที่รวมการจัดเก็บอัตโนมัติเข้ากับ 284 00:15:12,969 --> 00:15:16,790 preload_memory ครับ สำหรับการจัดเก็บอัตโนมัติ 285 00:15:16,790 --> 00:15:22,565 เราต้องสร้างเอเจนต์ที่ผสมการจัดเก็บอัตโนมัติกับการดึงข้อมูลอัตโนมัติ 286 00:15:22,565 --> 00:15:26,386 การจัดเก็บอัตโนมัติก็คือ after_agent_callback 287 00:15:26,386 --> 00:15:29,443 ที่บันทึกบทสนทนา ส่วน preload_memory 288 00:15:29,443 --> 00:15:32,755 จะโหลดข้อมูลความจำครับ ทำอย่างไรล่ะครับ 289 00:15:32,755 --> 00:15:36,322 มีเอเจนต์ตรงนี้ instruction คือตอบคำถามของ 290 00:15:36,322 --> 00:15:40,228 user เครื่องมือคือ preload_memory และ callback 291 00:15:40,228 --> 00:15:43,965 คือ autosave_memory ซึ่งบันทึกหลังจบทุก turn 292 00:15:43,965 --> 00:15:45,324 ครับ เรามารันกัน 293 00:15:45,324 --> 00:15:50,334 สิ่งที่เกิดขึ้นโดยอัตโนมัติคือหลังจากเอเจนต์ตอบกลับทุกครั้ง 294 00:15:50,334 --> 00:15:53,476 callback จะทำงาน และข้อมูลของ session 295 00:15:53,476 --> 00:15:56,533 จะถูกย้ายเข้า memory โดยไม่ต้องเรียก 296 00:15:56,533 --> 00:15:59,760 add_session_to_memory ด้วยตนเองเลยครับ 297 00:15:59,760 --> 00:16:02,987 ต่อไปสร้าง runner แล้วทดสอบเอเจนต์ครับ 298 00:16:02,987 --> 00:16:05,110 เราสร้าง runner เสร็จแล้ว 299 00:16:05,110 --> 00:16:08,677 ทีนี้มาทดสอบเอเจนต์กัน เรามี test หนึ่งกับ 300 00:16:08,677 --> 00:16:09,776 test สอง 301 00:16:09,776 --> 00:16:15,381 อันแรกคือผมให้ของขวัญเป็นของเล่นใหม่แก่หลานชายในวันเกิดปีแรกของเขา 302 00:16:15,381 --> 00:16:16,909 มันตอบว่าเยี่ยมมาก 303 00:16:16,909 --> 00:16:20,476 หวังว่าหลานชายของคุณจะสนุกกับของเล่นนะครับ 304 00:16:20,476 --> 00:16:23,024 อันที่สองคือผมให้อะไรหลานชายไป 305 00:16:23,024 --> 00:16:28,119 มันตอบว่าคุณให้ของเล่นใหม่แก่หลานชายในวันเกิดปีแรกของเขาครับ 306 00:16:28,119 --> 00:16:30,497 แล้วเพิ่งเกิดอะไรขึ้นล่ะครับ 307 00:16:30,497 --> 00:16:33,979 บทสนทนาแรกพูดถึงของขวัญให้หลานชาย ดังนั้น 308 00:16:33,979 --> 00:16:37,375 callback จึงบันทึกลง memory โดยอัตโนมัติ 309 00:16:37,375 --> 00:16:40,263 ส่วนบทสนทนาที่สองเป็น session ใหม่ 310 00:16:40,263 --> 00:16:42,895 ถามเรื่องของขวัญ preload_memory 311 00:16:42,895 --> 00:16:45,698 จึงดึงข้อมูลความจำกลับมาอัตโนมัติ 312 00:16:45,698 --> 00:16:47,990 แล้วเอเจนต์ก็ตอบถูกต้องครับ 313 00:16:47,990 --> 00:16:50,538 ดังนั้นจึงมีการเรียกใช้ memory 314 00:16:50,538 --> 00:16:52,321 ด้วยมือเป็นศูนย์ครั้ง 315 00:16:52,321 --> 00:16:55,888 นี่คือการจัดการหน่วยความจำแบบอัตโนมัติครับ 316 00:16:55,888 --> 00:16:59,285 ควรบันทึก memory บ่อยแค่ไหน คือควรบันทึก 317 00:16:59,285 --> 00:17:01,663 session ลง memory บ่อยแค่ไหน 318 00:17:01,663 --> 00:17:05,229 มีตัวเลือกอยู่ดังนี้ครับ คือหลังจบทุก turn 319 00:17:05,229 --> 00:17:08,456 หลังจบบทสนทนา และเป็นช่วงๆ ตามระยะเวลา 320 00:17:08,456 --> 00:17:12,023 ควรบันทึกหลังจบทุก turn เมื่อต้องการอัปเดต 321 00:17:12,023 --> 00:17:13,637 memory แบบเรียลไทม์ 322 00:17:13,637 --> 00:17:16,864 ส่วนแบบหลังจบบทสนทนาเหมาะเมื่อทำ batch 323 00:17:16,864 --> 00:17:20,175 processing หรือต้องการลดจำนวน API calls 324 00:17:20,175 --> 00:17:23,827 และแบบเป็นช่วงๆ เหมาะกับบทสนทนาที่ยาวๆ ครับ 325 00:17:23,827 --> 00:17:27,054 เรารู้กันมาแล้วนะครับ ต่อไปคือ section 326 00:17:27,054 --> 00:17:30,111 เจ็ดเรื่อง memory consolidation ครับ 327 00:17:30,111 --> 00:17:34,102 ในส่วนนี้เราจะเข้าใจข้อจำกัดของการเก็บข้อมูลดิบ 328 00:17:34,102 --> 00:17:37,584 สิ่งที่เราเก็บมาตลอดคือทุกข้อความของ user 329 00:17:37,584 --> 00:17:40,556 ทุกคำตอบของเอเจนต์ และทุก tool call 330 00:17:40,556 --> 00:17:43,868 ปัญหาคือถ้ามี 50 ข้อความในหนึ่ง session 331 00:17:43,868 --> 00:17:47,095 มันจะเท่ากับ 10,000 tokens แล้วทั้ง 50 332 00:17:47,095 --> 00:17:49,813 ข้อความก็ถูกเก็บลง memory หมดเลย 333 00:17:49,813 --> 00:17:52,445 ตัวค้นหาจะคืนค่าทั้ง 50 ข้อความ 334 00:17:52,445 --> 00:17:56,182 และเอเจนต์ต้องประมวลผล 10,000 tokens ซึ่งมัน 335 00:17:56,182 --> 00:18:00,088 scale ไม่ไหวครับ เราจำเป็นต้องมี consolidation 336 00:18:00,088 --> 00:18:02,466 ดังนั้น memory consolidation 337 00:18:02,466 --> 00:18:04,674 จึงเข้ามามีบทบาทตรงนี้ครับ 338 00:18:04,674 --> 00:18:07,986 หมายความคือสกัดเอาเฉพาะข้อเท็จจริงสำคัญ 339 00:18:07,986 --> 00:18:10,958 แล้วทิ้ง noise ของบทสนทนาทิ้งไปครับ 340 00:18:10,958 --> 00:18:14,100 การเก็บข้อมูลดิบจะหน้าตาประมาณนี้ครับ 341 00:18:14,100 --> 00:18:16,223 จากตัวอย่างก่อนหน้าของเรา 342 00:18:16,223 --> 00:18:19,620 มันเก็บข้อความทั้งสี่ที่ซ้ำซ้อนและยืดยาว 343 00:18:19,620 --> 00:18:22,507 เพราะเห็นได้ว่ามันพูดซ้ำกัน หลังทำ 344 00:18:22,507 --> 00:18:25,734 consolidation ข้อมูลที่สกัดได้คือ user 345 00:18:25,734 --> 00:18:27,348 ชอบสีน้ำเงินอมเขียว 346 00:18:27,348 --> 00:18:33,462 หมายความว่ามันเก็บเพียงข้อเท็จจริงเดียวที่กระชับจากข้อมูลดิบทั้งก้อนครับ 347 00:18:33,462 --> 00:18:36,349 ประโยชน์คือใช้พื้นที่จัดเก็บน้อยลง 348 00:18:36,349 --> 00:18:39,746 ดึงข้อมูลเร็วขึ้น และคำตอบแม่นยำขึ้นครับ 349 00:18:39,746 --> 00:18:41,954 จากตัวอย่าง session ของเรา 350 00:18:41,954 --> 00:18:45,776 สิ่งที่ได้ก็คือแบบนี้ครับ subsection ถัดไปคือ 351 00:18:45,776 --> 00:18:49,342 consolidation ทำงานอย่างไร ในส่วนของแนวคิด 352 00:18:49,342 --> 00:18:52,909 เราจะไม่เขียนโค้ดส่วนนี้กันนะครับ เริ่มจาก 353 00:18:52,909 --> 00:18:56,221 event ดิบของ session ตัว language model 354 00:18:56,221 --> 00:18:59,533 จะวิเคราะห์บทสนทนา สกัดข้อเท็จจริงสำคัญ 355 00:18:59,533 --> 00:19:01,401 จัดเก็บความจำที่กระชับ 356 00:19:01,401 --> 00:19:04,203 และผสานเข้ากับความจำเดิมที่มีอยู่ 357 00:19:04,203 --> 00:19:06,666 โดยขจัดข้อมูลที่ซ้ำกันออกครับ 358 00:19:06,666 --> 00:19:09,893 ตัวอย่างของการแปลงข้อมูลเช่น ผมแพ้ถั่ว 359 00:19:09,893 --> 00:19:12,016 กินอะไรที่มีถั่วไม่ได้เลย 360 00:19:12,016 --> 00:19:15,328 ผลลัพธ์ที่ได้คือความจำแบบมีโครงสร้างว่า 361 00:19:15,328 --> 00:19:18,215 แพ้ถั่ว ถั่วต้นไม้ ระดับความรุนแรง 362 00:19:18,215 --> 00:19:20,508 หลีกเลี่ยงอย่างสมบูรณ์ ครับ 363 00:19:20,508 --> 00:19:26,198 ภาษาธรรมชาติจึงถูกแปลงเป็นข้อมูลที่มีโครงสร้างและนำไปใช้ได้จริงครับ 364 00:19:26,198 --> 00:19:29,085 ส่วนถัดไปพูดถึงขั้นต่อไปของ memory 365 00:19:29,085 --> 00:19:32,737 consolidation ครับ ประเด็นสำคัญที่ต้องจำคือ 366 00:19:32,737 --> 00:19:36,388 managed memory service จัดการ consolidation 367 00:19:36,388 --> 00:19:40,210 ให้อัตโนมัติ ตรงนี้เราใช้ API เดิม ใช้ method 368 00:19:40,210 --> 00:19:41,738 ของ memory ตัวเดิม 369 00:19:41,738 --> 00:19:45,390 สิ่งที่ต่างคือสิ่งที่เกิดขึ้นเบื้องหลังครับ 370 00:19:45,390 --> 00:19:48,872 memory service แบบนี้เก็บ event ดิบๆ ส่วน 371 00:19:48,872 --> 00:19:50,655 Vertex AI Memory Bank 372 00:19:50,655 --> 00:19:54,052 จะกลั่นข้อมูลอย่างชาญฉลาดก่อนจัดเก็บครับ 373 00:19:54,052 --> 00:19:57,194 ถ้าอยากเรียนรู้เพิ่มเติมเรื่อง memory 374 00:19:57,194 --> 00:19:58,298 consolidation 375 00:19:58,298 --> 00:20:01,100 ซึ่งเราจะได้ศึกษาต่อในห้าวันถัดไป 376 00:20:01,100 --> 00:20:03,903 สามารถไปอ่านหน้า guide นี้ได้ครับ 377 00:20:03,903 --> 00:20:07,299 นี่คือสรุปสิ่งที่เราทำในแบบฝึกหัดนี้ครับ 378 00:20:07,299 --> 00:20:11,206 เราได้เรียนรู้การเพิ่ม memory การจัดเก็บข้อมูล 379 00:20:11,206 --> 00:20:14,688 การค้นหา memory การดึงข้อมูลในเอเจนต์ และ 380 00:20:14,688 --> 00:20:16,811 memory consolidation ครับ 381 00:20:16,811 --> 00:20:19,868 หวังว่าแนวคิดจะชัดเจนสำหรับคุณนะครับ 382 00:20:19,868 --> 00:20:23,519 ถ้ายังไม่ชัดก็ลองดูวิดีโออีกหนึ่งหรือสองรอบ 383 00:20:23,519 --> 00:20:26,831 แล้วจะเข้าใจง่ายขึ้นในทุกครั้งที่ดูครับ 384 00:20:26,831 --> 00:20:30,653 และเมื่อจบ Day 3 แล้ว โปรดไปดูวิดีโอของ Day 4 385 00:20:30,653 --> 00:20:34,134 ซึ่งพูดถึงการ implement observability และ 386 00:20:34,134 --> 00:20:37,022 evaluation ของเอเจนต์ ซึ่งสำคัญมาก 387 00:20:37,022 --> 00:20:41,777 เพราะมันช่วยให้มั่นใจว่าเอเจนต์ทำงานตามที่ตั้งใจไว้จริงๆ 388 00:20:41,777 --> 00:20:44,240 ใน production ครับ ขอบคุณครับ