HN เปิดตัว: FastGraphRAG – เทคนิค RAG ที่ปรับปรุงด้วย PageRank แบบดั้งเดิม
(github.com/circlemind-ai)- Fast GraphRAG เป็นเฟรมเวิร์ก GraphRAG แบบเรียบง่ายสำหรับ เวิร์กโฟลว์ค้นหาแบบใช้เอเจนต์ ที่ตีความได้และมีความแม่นยำสูง โดยเน้นการนำ RAG ขั้นสูงไปต่อเข้ากับไปป์ไลน์ค้นหาโดยไม่ต้องสร้างเวิร์กโฟลว์เอเจนต์ที่ซับซ้อนเอง
- ทำให้กราฟความรู้อยู่ในรูปแบบที่มนุษย์สำรวจได้ สามารถคิวรี แสดงภาพ และอัปเดตได้ พร้อมทั้ง สร้างและปรับแต่งกราฟโดยอัตโนมัติ ให้เข้ากับข้อกำหนดด้านโดเมนและ ontology
- การตอบคิวรีใช้การสำรวจกราฟบนพื้นฐาน personalized PageRank เพื่อค้นหาข้อมูลที่เกี่ยวข้อง และ README เชื่อมโยงบทความ HippoRAG ไว้เป็นภาพรวมของแนวทางนี้
- ในตัวอย่างค่าใช้จ่ายที่อิงกับ The Wizard of Oz ระบุว่า
fast-graphragมีค่าใช้จ่าย $0.08 ส่วนgraphragมีค่าใช้จ่าย $0.48 และระบุว่าเมื่อขนาดข้อมูลและจำนวนครั้งการแทรกเพิ่มขึ้น การลดค่าใช้จ่าย 6 เท่า จะยิ่งดีขึ้น - ทำงานบน Python 3.10.1 ขึ้นไป รองรับการติดตั้งจากซอร์สและ PyPI หลังตั้งค่า OpenAI API key แล้วสามารถแทรกเอกสารและทำคิวรีได้ พร้อมรักษาความรู้ไว้โดยอัตโนมัติในไดเรกทอรีทำงานเดียวกัน
เฟรมเวิร์กค้นหาที่ Fast GraphRAG มอบให้
- Fast GraphRAG เป็นเฟรมเวิร์ก GraphRAG ที่มุ่งให้ได้ ความรู้ที่ตีความและดีบักได้
- กราฟนำเสนอความรู้ในรูปแบบที่มนุษย์สามารถสำรวจได้ และรองรับงานต่อไปนี้
- คิวรี
- การแสดงภาพ
- การอัปเดต
- เน้นลดภาระในการสร้างและออกแบบ เวิร์กโฟลว์เอเจนต์ เอง ขณะยังให้ความสามารถ RAG ขั้นสูง
ฟีเจอร์หลัก
- ออกแบบมาให้รันงานขนาดใหญ่ได้ รวดเร็วและต้นทุนต่ำ โดยมุ่งลดความต้องการทรัพยากรหนัก ๆ หรือค่าใช้จ่ายสูง
- รองรับ ข้อมูลแบบไดนามิก โดยสร้างและปรับแต่งกราฟอัตโนมัติให้เข้ากับข้อกำหนดของโดเมนและ ontology
- รองรับ การอัปเดตแบบเพิ่มเฉพาะส่วน เมื่อข้อมูลเปลี่ยน ทำให้อัปเดตแบบเรียลไทม์ได้
- ให้ การสำรวจอัจฉริยะ ที่เพิ่มความแม่นยำและความน่าเชื่อถือด้วยการใช้การสำรวจกราฟบนพื้นฐาน PageRank
- โดยรวมทำงานแบบอะซิงโครนัส และมุ่งสู่เวิร์กโฟลว์ที่แข็งแกร่งและคาดการณ์ได้ด้วยการรองรับ type อย่างครบถ้วน
ตัวอย่างค่าใช้จ่าย
- ในตัวอย่างที่ใช้ The Wizard of Oz ระบุว่าค่าใช้จ่ายของ
fast-graphragคือ $0.08 และค่าใช้จ่ายของgraphragคือ $0.48 - README อธิบายว่านี่คือ การลดค่าใช้จ่าย 6 เท่า และระบุว่าเมื่อขนาดข้อมูลและจำนวนครั้งการแทรกเพิ่มขึ้น ผลการประหยัดจะยิ่งดีขึ้น
การติดตั้งและลำดับการรัน
- วิธีติดตั้งที่แนะนำแบ่งเป็น การติดตั้งจากซอร์ส เพื่อประสิทธิภาพ และการติดตั้งจาก PyPI เพื่อความเสถียร
- ติดตั้งจากซอร์ส: โคลน repository แล้วรัน
poetry install - ติดตั้งจาก PyPI:
pip install fast-graphrag
- ติดตั้งจากซอร์ส: โคลน repository แล้วรัน
- ตัวอย่าง quick start เริ่มจากการตั้งค่าตัวแปรสภาพแวดล้อม
OPENAI_API_KEY - หลังดาวน์โหลดข้อความ A Christmas Carol แล้ว ให้ initialize
GraphRAGในโค้ด Python - การ initialize ในตัวอย่างมีค่าต่อไปนี้
working_dir="./book_example"domainสำหรับวิเคราะห์ตัวละคร ปฏิสัมพันธ์ สถานที่ และความสัมพันธ์ในเรื่อง- รายการคิวรีตัวอย่าง
- ประเภท entity
["Character", "Animal", "Place", "Object", "Activity", "Event"]
- แทรกเอกสารด้วย
grag.insert(f.read())และแสดงผลลัพธ์คิวรีด้วยgrag.query("Who is Scrooge?").response - หาก initialize อีกครั้งในไดเรกทอรีทำงานเดียวกัน ความรู้จะถูกคงไว้โดยอัตโนมัติ
- หากต้องการควบคุมจำนวนงาน LLM ที่ประมวลผลพร้อมกัน เช่น เมื่อใช้โมเดลภายในเครื่อง สามารถตั้งค่าตัวแปรสภาพแวดล้อมอย่าง
CONCURRENT_TASK_LIMIT=8ได้ตามต้องการ
ตัวอย่างและตัวเลือกการตั้งค่า
- โฟลเดอร์
examplesมีบทเรียนสำหรับกรณีใช้งานทั่วไปของไลบรารี custom_llm.pyเป็นตัวอย่างง่าย ๆ ของการตั้งค่าโมเดลภาษาและ embedder ที่เข้ากันได้กับ OpenAI API ให้แตกต่างกันcheckpointing.ipynbอธิบายวิธีใช้ checkpoint เพื่อหลีกเลี่ยงความเสียหายของข้อมูลที่ย้อนกลับไม่ได้query_parameters.ipynbครอบคลุมพารามิเตอร์คิวรีต่าง ๆ และแสดงวิธีใส่การอ้างอิงข้อมูลที่ใช้ในคำตอบด้วยwith_references=True
ปรัชญาการออกแบบและวิธีการสำรวจ
- เป้าหมายคือเพิ่มจำนวนแอปพลิเคชัน GenAI ที่ประสบความสำเร็จ โดยระบุว่าจะสร้าง เครื่องมือหน่วยความจำและข้อมูล ที่ช่วยให้แอป LLM ใช้ไปป์ไลน์ค้นหาเฉพาะทางได้โดยไม่ต้องตั้งค่าและดูแลเวิร์กโฟลว์เอเจนต์ที่ซับซ้อน
- Fast GraphRAG สำรวจกราฟด้วยอัลกอริทึม personalized PageRank เพื่อค้นหาข้อมูลที่เกี่ยวข้องที่สุดสำหรับตอบคิวรีปัจจุบัน
- มีการเสนอ HippoRAG paper เป็นเอกสารอ้างอิงสำหรับภาพรวมว่าเหตุใดแนวทางนี้จึงทำงานได้
โอเพนซอร์สและบริการแบบ managed
- repository นี้ให้ใช้งานภายใต้ MIT License โดยมีรายละเอียดใน LICENSE.txt
- มีบริการแบบ managed เป็นวิธีเริ่มต้นใช้งานที่รวดเร็วและเชื่อถือได้
- บริการแบบ managed ให้ 100 คำขอแรก ฟรีในแต่ละเดือน หลังจากนั้นคิดค่าบริการตามปริมาณการใช้งาน
- หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับบริการแบบ managed สามารถจอง demo หรือดู docs
- แนวทางการมีส่วนร่วมอยู่ใน CONTRIBUTING.md และสามารถถามคำถามได้ที่ Discord
1 ความคิดเห็น
ความคิดเห็นใน Hacker News
นอกจาก PageRank แล้ว ยังมี ตัวชี้วัด centrality ที่น่าสนใจอีกหลายตัวซึ่งอาจส่งผลต่อ RAG บนข้อมูลเชิงโครงสร้างได้
หนึ่งในนั้นคือ Triangle Centrality ซึ่งคำนวณความเป็นศูนย์กลางโดยนับจำนวนสามเหลี่ยมรอบ ๆ โหนด โดยอิงแนวคิดว่าสามเหลี่ยมช่วยปิดความสัมพันธ์ให้แน่นหนา ส่วนการเชื่อมต่อแบบเปิดจะดึงน้ำหนักออกจากศูนย์กลางและทำให้ความเป็นศูนย์กลางเจือจางลง
https://arxiv.org/abs/2105.00110
ในเปเปอร์กล่าวว่ามีประสิทธิภาพสูงกว่า centrality แบบอื่นอย่าง PageRank แต่ในงานวิจัยที่ใช้ GraphBLAS พบว่าในกราฟ sparse หลายแบบที่มีขนาดถึง 1.8 พันล้าน edge นั้น TC ช้ากว่าการทำ PageRank แบบ sparse ของเรา
อย่างไรก็ตาม เมื่อกราฟใหญ่ขึ้น TC ดูเหมือนจะสเกลได้ดีกว่า และมีความเป็นไปได้สูงว่าจะมีประสิทธิภาพมากกว่าในระดับ edge หลักล้านล้าน
https://fossies.org/linux/SuiteSparse/GraphBLAS/Doc/The_Grap...
อย่างไรก็ดี คอขวดของการสร้างคำตอบน่าจะอยู่ที่ส่วนที่ LLM ต้อง parse อยู่แล้ว
PageRank เป็นขั้นแรก แต่ก็อยากทดสอบทางเลือกที่แม่นยำกว่านี้ด้วย
ที่นี่ใช้ Personalized PageRank อยู่ โดยให้น้ำหนักเริ่มต้นกับชุดโหนดเฉพาะ จึงสงสัยว่า Triangle Centrality รองรับสิ่งนี้หรือไม่
อีกทั้งยังดูน้ำหนักของ edge ด้วย จึงอยากรู้ว่าส่วนนั้นทำได้หรือเปล่า
https://link.springer.com/content/pdf/10.1007/978-3-030-6097...
เคยทำงานในด้านนี้มาค่อนข้างมาก และมีสิ่งที่ได้เรียนรู้อยู่หลายข้อ
ผมนำทั้งสามอย่างนี้มารวมกันเป็นขั้นตอนแยกย่อย/สกัดความรู้ที่คล้ายกัน และเพิ่ม meta prompter เข้าไปเพื่อให้สร้างโดเมน/ประเภทเอนทิตีได้แทบอัตโนมัติ
โดยพื้นฐานแล้ว LLM จับระดับการแบ่งย่อยที่เหมาะสมของความรู้ที่ถูกแยกออกมาได้ไม่ค่อยดี
เทคนิคหนึ่งคือให้ LLM ส่งออก mindmap ของ mermaid.js เพื่อแบ่ง input เป็น tree แบบลำดับชั้น แล้วตอนท้ายให้บอกว่าระดับใดเหมาะจะเป็นรากของ knowledge node
หลังจากนั้นจึงสร้างคำถามที่สามารถตอบได้ด้วยความรู้ภายใน node นั้น ๆ แล้ว index ข้อความคำถามเหล่านี้และทำ embedding ด้วย
แม้จับคู่ query ของผู้ใช้กับคำถามเหล่านี้โดยตรงด้วย BM25 ล้วน ๆ ก็ได้ผลดี และแนวทาง hybrid จะดีกว่า แต่ความต่างไม่ได้มากนัก
หากไม่ใช้ LLM ตอน query ก็สามารถใช้ความคล้ายกันของ embedding เป็นฟังก์ชันต้นทุนในการเดินทาง แล้วไล่ลงจาก root ไปยัง node ที่ลึกขึ้นแบบลำดับชั้นได้
สุดท้ายจึงตัดสินใจย้ายไปใช้กราฟในฐานะการทำให้ tree ทั่วไปขึ้น
มองว่าแนวคิดหลักคือการใช้ความคล้ายกันของ embedding เพื่อ “เดิน” บนกราฟ และใน FastGraphRAG ก็กำลังผสานสิ่งนี้อย่างจริงจังด้วยวิธีให้น้ำหนัก edge ตาม query
น่าสนใจที่หลายวิธีแก้ปัญหาดูจะบรรจบเข้าหาดีไซน์คล้ายกัน
ไอเดียการ สร้างคำตอบสมมติ จาก query แล้วใช้คำตอบนั้นไปค้นหาด้วย embedding น่าสนใจ และจะลองเพิ่มไว้ในรายการทดลอง
ตอนนี้สงสัยว่า หากสร้างคำตอบสมมติด้วย LLM ที่ fine-tune ให้เข้ากับ corpus แล้ว อาจทำงานได้ดียิ่งขึ้นหรือไม่
และอยากรู้ว่าเวลาสร้างคำตอบสมมติ มีการ prompt ให้ตอบตาม “ขนาด chunk” ด้วยหรือเปล่า
การใช้ PageRank เพื่อให้ได้ centrality ที่ดีกว่าดูดี แต่ก็ยังไม่ได้แก้ข้อบกพร่องที่อาจแก้ไม่ได้ของ RAG นั่นคือเหตุผลพื้นฐานที่ทำให้ RAG ทำงานได้ยาก
เหตุผลที่ RAG DB ทุกตัวทำงานต่ำกว่าที่คาด คือโดยพื้นฐานแล้ว RAG หา ความสัมพันธ์ระหว่างคำ ที่จำเป็นต่อการค้นหาข้อมูลที่ผู้ใช้ต้องการไม่ได้
อาจฟังดูแปลก เพราะดูเหมือนกลไก “attention” เดิมควรทำสิ่งนี้ได้ดี แต่ในความเป็นจริงยังไม่เพียงพอ
ตัวอย่างเช่น สมมติว่าในบทความหนึ่งมีเนื้อหาว่าคนชื่อ ‘Sharon’ เข้าร่วมการประชุมด้านฟิสิกส์เคมีหลายงาน แต่ไม่ได้ระบุอาชีพไว้ชัดเจน
หากค้นว่า “อาชีพของ Sharon คืออะไร?” แนวทาง RAG แทบทั้งหมดน่าจะเชื่อมโยง ‘อาชีพ’, การเข้าร่วมการประชุม และประเภทของการประชุม แล้วอนุมานว่าเป็น ‘นักเคมี’ ไม่ได้
ข้อผิดพลาดแบบนี้กระจายอยู่ในข้อมูลหลายประเภทเมื่อต้องค้นข้อมูลด้วย RAG
สุดท้ายแล้ววิธีแก้แบบข้างต้นดูเหมือนเป็นการประดิษฐ์วิธี query อื่น ๆ อย่าง SQL หรือ PageRank ขึ้นใหม่ผ่านขั้นตอนที่มากขึ้น และเมื่อถึงจุดนั้น vectorization ก็แทบไม่มีความหมาย
ส่วนประกอบของ RAG แค่ต้องค้นหาบทความเกี่ยวกับ Sharon จาก dataset ขนาดใหญ่ แล้วส่งทั้งหมดเป็น context ให้ LLM
หากดูเปเปอร์ HippoRAG ที่อ้างในต้นฉบับ ตัวอย่างแรงจูงใจก็แทบเหมือนกัน และการประเมินก็โดยมากปรับให้เข้ากับการถามตอบแบบ multi-hop ประเภทนี้
ดึงเอนทิตีชื่อ Sharon มา แล้วรับโหนดและ edge ที่อยู่ใกล้ Sharon เป็น context เพิ่มเติม
จากนั้นเป็นบทบาทของ LLM และหากใน context ที่ให้มาไม่มีอาชีพ ก็ควรแจ้งว่า “ไม่พบอาชีพของ Sharon ใน context ที่ให้มา”
เห็นว่าน่าสนใจเลยสมัครแล้วลองอัปโหลดเอกสาร PDF สองสามไฟล์ขึ้นแดชบอร์ด
กรณีใช้งานคือการวิเคราะห์ เอกสารด้านคอมพลายแอนซ์ เกี่ยวกับการผลิตในสตาร์ทอัพ AI และเพื่อให้สิ่งนี้มีประโยชน์กับเรา จำเป็นต้องเข้าใจว่ามันทำงานได้ถึงสเกลไหน และโมเดลค่าใช้จ่ายเป็นอย่างไร
เรามี PDF ประมาณ 300,000 ไฟล์ ต่อไคลเอนต์ และคาดว่าชุดเอกสารประมาณ 10% จะเปลี่ยนไปทุกเดือน
ไม่ว่าเป็นระบบ GraphRAG แบบใด ก็ต้องประมวลผลเอกสารในสเกลใหญ่ และแม้จะใช้ S3 เป็นกลไก ingest ได้ แต่เราจำเป็นต้องรู้ค่าใช้จ่ายและเวลาประมวลผลจนกว่าระบบจะพร้อมใช้งานในจุดต่อไปนี้
อยากคุยรายละเอียดเพิ่มเติม รบกวนติดต่อมาที่ antonio [at] circlemind.co
น่าสนใจ แต่สงสัยว่าคลังข้อความเฉพาะโดเมนต้องใหญ่แค่ไหนถึงจะได้ knowledge graph ที่มีประโยชน์
Aider ใช้ PageRank กับ call graph ของโค้ดรีโพซิทอรี่มานานแล้ว
โค้ดที่ไม่ใช่เรื่องเล็กน้อยล้วนมีโครงสร้างกราฟมากพอให้ PageRank ใช้ได้ จึงทำงานได้ดีมากในการหาบริบทที่เกี่ยวข้องที่สุดในโปรเจกต์กับงานปัจจุบัน
https://aider.chat/docs/repomap.html#optimizing-the-map
ถ้ามีคนเริ่มลองใช้มากขึ้น ก็อยากฟังฟีดแบ็ก
สงสัยว่ามีแผนจะให้บังคับสร้าง repo map แล้วตรวจสอบได้หรือไม่
เจ๋ง
สงสัยว่ากราฟถูกจัดเก็บและ query อย่างไร
คุ้นกับ graph database อยู่ แต่ดูเหมือนไม่ได้เป็น dependency
และสงสัยด้วยว่าได้ลองใช้ sciphi triplex model สำหรับการสกัดข้อมูลหรือยัง
ตอนเคยลองสกัดข้อมูลมาก่อน ถ้าสกัด chunk เดิมซ้ำหลายครั้งติดกัน ผลลัพธ์ไม่คงเส้นคงวา
codebase ถูกออกแบบให้เขียน wrapper บาง ๆ แล้วผสานรวมกับ graph DB ใด ๆ ได้ง่าย และมีแผนจะรองรับอย่าง neo4j ในอนาคตอันใกล้
ยังไม่ได้ลอง triplex เพราะตอนนี้ gpt4o-mini เร็วและแม่นยำพอแล้ว
เราใช้ gpt4o-mini ไม่ใช่แค่สกัด entity และ relation แต่ยังใช้สร้างคำอธิบายและแก้ความขัดแย้งด้วย
ถ้า fine-tune ผลลัพธ์น่าจะดีขึ้นแน่นอน
การ query กราฟทำโดยหาชุดโหนดตั้งต้นที่เกี่ยวข้องกับ query ที่ให้มา จากนั้นรัน personalized PageRank จากโหนดเหล่านั้นเพื่อหาข้อความส่วนอื่นที่เกี่ยวข้อง
ตอนนี้เลือกโหนดตั้งต้นด้วย semantic search ทั้งกับ query ทั้งหมดและ entity ที่สกัดจาก query แต่เรากำลังวางแผนฟีเจอร์เสริมที่น่าสนใจหลายอย่างสำหรับวิธีนี้
เป็นไอเดียที่ดี
ส่วนตัวคิดว่า information retrieval แบบดั้งเดิมคือทางที่ RAG ควรไป
vector search นั้นดี แต่ช้าและแพง และผู้คนมักใช้มันเหมือนผงวิเศษ
มันทำงานได้ดีกับข้อมูลไม่มีโครงสร้าง แต่ไม่ได้แปลว่าจะเหมาะกับข้อมูลมีโครงสร้างเสมอไป
เว้นแต่จะจูนมาดีมาก ๆ vector search ก็ไม่ได้ดีกว่า query แบบดั้งเดิมที่จูนมาดีมากนัก
เคยเห็นแนวปฏิบัติที่แปลงข้อมูลมีโครงสร้างให้เป็นข้อมูลไม่มีโครงสร้าง แล้วค่อยทำ vector search หรือ prompt engineering ซึ่งโดยรวมแล้วรู้สึกเหมือนเดินย้อนทาง
มันใช้ได้ระดับหนึ่ง แต่มีความเป็นไปได้สูงว่าจะมีวิธีที่ฉลาดกว่าสำหรับให้ได้ผลลัพธ์เดียวกัน
แก่นของ Graph RAG คือการใช้ประโยชน์จากโครงสร้างข้อมูล
จะเป็น SQL join หรือ query ใน graph DB ก็ไม่ได้สำคัญมาก
การสอน LLM ให้ query หรือให้ interface กับ API ค้นหา/query ที่มีอยู่ก็น่าจะมีคุณค่าเช่นกัน
ถ้า ranking ไม่ดี ก็ชดเชยด้วย context size ที่ใหญ่ขึ้น และดึงผลลัพธ์หลักร้อยขึ้นไปด้วยหลาย query
การขยายแบบนั้นน่าจะเร็วและถูกกว่า vector search มาก
ดูดี แต่เคยเจ็บกับ ชั้น abstraction อื่น ๆ อย่าง LangChain มาก่อน เลยกังวลเรื่องการทำให้ง่ายเกินไป
สงสัยว่ามีแผนอย่างไรเพื่อไม่ให้ทำผิดพลาดแบบเดิมซ้ำ
สงสัยว่ามี คะแนน metric ประเมินผล สำหรับการค้นหาและการสร้างคำตอบหรือไม่
เช่น ชุดข้อมูล KILT หรือ NQ
benchmark dataset ไม่ใช่ทุกอย่างก็จริง แต่ถ้าแสดงคะแนนที่ดีพอสมควรและเวลา inference ได้ ก็จะช่วยมากในการโน้มน้าวให้ใช้เฟรมเวิร์กหรือให้วิศวกรเลือก
ผมเคยสร้าง RAG pipeline มามากในฐานะวิศวกรประมวลผลภาษาธรรมชาติฟรีแลนซ์ และตั้งใจจะลองใช้งานนี้ด้วยตัวเอง
ตอนนี้กำลังสร้างแชตบอต Q&A และมีปัญหาในการจัดการสถานการณ์ต่อไปนี้
เมื่อผู้ใช้ถามว่า “ประโยคก่อนหน้าที่เพิ่งพูดไปหมายความว่าอะไร?” สงสัยว่าเฟรมเวิร์กนี้จะค้นหา ความรู้ดิบ ชุดย่อยเล็ก ๆ ที่ถูกต้อง และผสานเข้ากับ LLM เพื่อสร้างคำตอบที่เกี่ยวข้องได้อย่างไร
แก้ปัญหานี้ยากถ้าไม่พึ่งเฟรมเวิร์กภายนอก
https://www.reddit.com/r/LocalLLaMA/comments/1gtzdid/d_optim...
อยากรู้ว่าเฟรมเวิร์กนี้แก้ปัญหานี้อย่างไรและทำให้กระบวนการง่ายขึ้นได้อย่างไร
ถ้าไม่มีสิ่งนี้ มักล้มเหลวเมื่อผู้ใช้ถามอย่าง “อธิบายข้อ 2 เพิ่มเติม” หรือ “ขอตัวอย่างละเอียดของเนื้อหาข้างบน”
implementation ปัจจุบันมี 3 index แล้วให้ query กับข้อความก่อนหน้า จากนั้นให้ LLM แยกออกเป็น
คำขอทั้งหมด, คำถามที่ปรับให้เหมาะกับ BM25, keyword, คำถามที่ปรับให้เหมาะกับ semantic search
จากนั้นทำ RAG และ rerank แล้วส่ง passage อันดับต้น ๆ N รายการพร้อมกับคำขอทั้งหมดไปยังการเรียก LLM ครั้งที่สอง
ควรโฟกัสที่ขั้น orchestration
ลองดู ReAct agent ได้ และสร้างได้ด้วย LangGraph หรือ Bedrock Agents