Agentverse - The Scholar's Grimoire - Building Knowledge Engines with RAG

1. Overture

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

ความสำเร็จในยุคใหม่นี้ต้องอาศัยการบรรจบกันของบทบาทสำคัญ 4 ประการ ซึ่งเป็นเสาหลักที่รองรับระบบเอเจนต์ที่เจริญรุ่งเรือง ความบกพร่องในด้านใดด้านหนึ่งจะสร้างจุดอ่อนที่อาจส่งผลต่อโครงสร้างทั้งหมด

เวิร์กช็อปนี้เป็นเพลย์บุ๊กสำหรับองค์กรที่ชัดเจนในการฝึกฝนอนาคตของเอเจนต์ใน Google Cloud เรามีแผนงานแบบครบวงจรที่จะนำทางคุณตั้งแต่เริ่มมีไอเดียไปจนถึงการดำเนินงานจริงในระดับเต็มรูปแบบ ในแล็บทั้ง 4 แห่งที่เชื่อมโยงกันนี้ คุณจะได้เรียนรู้ว่าทักษะเฉพาะทางของนักพัฒนาซอฟต์แวร์ สถาปนิก วิศวกรข้อมูล และ SRE ต้องมาบรรจบกันเพื่อสร้าง จัดการ และปรับขนาด Agentverse ที่ทรงพลังได้อย่างไร

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

ยินดีต้อนรับสู่ Agentverse: การเรียกร้องให้เป็นแชมป์

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

agentverse.png

ระบบนิเวศที่เชื่อมต่อกันของพลังและความสามารถนี้เรียกว่า Agentverse

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

ความหงุดหงิดใจในอดีตได้ขยายตัวกลายเป็นสัตว์ประหลาด และก่อให้เกิด "เจ็ดปีศาจแห่งการพัฒนา" หากไม่ตรวจสอบ The Static และ Spectres จะทำให้ความคืบหน้าหยุดชะงัก และเปลี่ยนความหวังของ Agentverse ให้กลายเป็นดินแดนรกร้างที่เต็มไปด้วยหนี้ทางเทคนิคและโปรเจ็กต์ที่ถูกทอดทิ้ง

วันนี้เราขอเชิญชวนผู้กล้าให้ช่วยกันต่อสู้กับความวุ่นวาย เราต้องการฮีโร่ที่พร้อมจะฝึกฝนทักษะและทำงานร่วมกันเพื่อปกป้อง Agentverse ได้เวลาเลือกเส้นทางของคุณแล้ว

เลือกชั้นเรียน

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

  • The Shadowblade (นักพัฒนาแอป): ผู้เชี่ยวชาญด้านการตีเหล็กและแนวหน้า คุณคือช่างฝีมือที่สร้างสรรค์ใบมีด สร้างเครื่องมือ และเผชิญหน้ากับศัตรูในรายละเอียดที่ซับซ้อนของโค้ด เส้นทางของคุณคือเส้นทางแห่งความแม่นยำ ทักษะ และการสร้างสรรค์ที่นำไปใช้ได้จริง
  • นักใช้มนต์อสูร (สถาปนิก): นักวางแผนและผู้ประสานงานที่ยิ่งใหญ่ คุณไม่ได้เห็นแค่เอเจนต์คนเดียว แต่เห็นทั้งสมรภูมิ คุณออกแบบพิมพ์เขียวหลักที่ช่วยให้ระบบเอเจนต์ทั้งหมดสื่อสาร ทำงานร่วมกัน และบรรลุเป้าหมายที่ยิ่งใหญ่กว่าคอมโพเนนต์ใดๆ เพียงอย่างเดียว
  • นักปราชญ์ (วิศวกรข้อมูล): ผู้แสวงหาความจริงที่ซ่อนอยู่และผู้รักษาภูมิปัญญา คุณผจญภัยไปในป่าข้อมูลที่กว้างใหญ่และไม่คุ้นเคยเพื่อค้นหาข้อมูลอัจฉริยะที่จะช่วยให้ตัวแทนของคุณมีเป้าหมายและวิสัยทัศน์ ความรู้ของคุณอาจเผยจุดอ่อนของศัตรูหรือเพิ่มพลังให้พันธมิตร
  • ผู้พิทักษ์ (DevOps / SRE): ผู้ปกป้องและโล่ที่มั่นคงของอาณาจักร คุณสร้างป้อมปราการ จัดการสายส่งไฟฟ้า และตรวจสอบว่าทั้งระบบสามารถทนต่อการโจมตีที่หลีกเลี่ยงไม่ได้ของ The Static ความแข็งแกร่งของคุณคือรากฐานที่สร้างชัยชนะของทีม

ภารกิจของคุณ

การฝึกจะเริ่มเป็นการออกกำลังกายแบบสแตนด์อโลน คุณจะเดินตามเส้นทางที่เลือกและเรียนรู้ทักษะเฉพาะที่จำเป็นต่อการเชี่ยวชาญบทบาทของคุณ เมื่อสิ้นสุดช่วงทดลองใช้ คุณจะพบกับ Spectre ที่เกิดจาก The Static ซึ่งเป็นมินิบอสที่คอยโจมตีความท้าทายเฉพาะของการประดิษฐ์

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

ความท้าทายสุดท้ายที่ต้องร่วมมือกัน ซึ่งจะทดสอบความแข็งแกร่งของคุณและกำหนดชะตากรรมของ Agentverse

Agentverse กำลังรอเหล่าฮีโร่อยู่ คุณจะรับสายไหม

2. The Scholar's Grimoire

การเดินทางของเราเริ่มต้นขึ้นแล้ว ในฐานะนักปราชญ์ อาวุธหลักของเราคือความรู้ เราค้นพบม้วนกระดาษโบราณที่ซ่อนอยู่ในที่เก็บถาวร (Google Cloud Storage) ม้วนกระดาษเหล่านี้มีข้อมูลดิบเกี่ยวกับสัตว์ร้ายที่น่าสะพรึงกลัวซึ่งสร้างความเดือดร้อนให้กับแผ่นดิน ภารกิจของเราคือการใช้เวทมนตร์แห่งการวิเคราะห์อันลึกซึ้งของ Google BigQuery และสติปัญญาของ Gemini Elder Brain (โมเดล Gemini Pro) เพื่อถอดรหัสข้อความที่ไม่มีโครงสร้างเหล่านี้และสร้างเป็นสารานุกรมสัตว์ที่มีโครงสร้างและค้นหาได้ ซึ่งจะเป็นรากฐานของกลยุทธ์ทั้งหมดในอนาคต

ภาพรวม

สิ่งที่คุณจะได้เรียนรู้

  • ใช้ BigQuery เพื่อสร้างตารางภายนอกและทำการเปลี่ยนรูปแบบที่ซับซ้อนจากข้อมูลที่ไม่มีโครงสร้างเป็นข้อมูลที่มีโครงสร้างโดยใช้ BQML.GENERATE_TEXT กับโมเดล Gemini
  • จัดสรรอินสแตนซ์ Cloud SQL สำหรับ PostgreSQL และเปิดใช้ส่วนขยาย pgvector เพื่อความสามารถในการค้นหาเชิงความหมาย
  • สร้างไปป์ไลน์การประมวลผลแบบกลุ่มที่แข็งแกร่งซึ่งอยู่ในคอนเทนเนอร์โดยใช้ Dataflow และ Apache Beam เพื่อประมวลผลไฟล์ข้อความดิบ สร้างการฝังเวกเตอร์ด้วยโมเดล Gemini และเขียนผลลัพธ์ลงในฐานข้อมูลเชิงสัมพันธ์
  • ใช้ระบบการสร้างที่เพิ่มการดึงข้อมูล (RAG) พื้นฐานภายในเอเจนต์เพื่อค้นหาข้อมูลที่แปลงเป็นเวกเตอร์
  • ติดตั้งใช้งานเอเจนต์ที่รับรู้ข้อมูลเป็นบริการที่ปลอดภัยและปรับขนาดได้ใน Cloud Run

3. การเตรียมห้องสมุดของนักวิชาการ

ยินดีต้อนรับ Scholar ก่อนที่เราจะเริ่มจารึกความรู้ที่ทรงพลังของ Grimoire เราต้องเตรียมที่ศักดิ์สิทธิ์ของเราก่อน พิธีกรรมพื้นฐานนี้เกี่ยวข้องกับการร่ายมนต์สภาพแวดล้อม Google Cloud, การเปิดพอร์ทัล (API) ที่เหมาะสม และการสร้างท่อร้อยสายที่จะเป็นช่องทางให้เวทมนตร์แห่งข้อมูลของเราไหลผ่าน การเตรียมแซงทัมอย่างดีจะช่วยให้เวทมนตร์ของเรามีประสิทธิภาพและปกป้องความรู้ของเราให้ปลอดภัย

👉คลิกเปิดใช้งาน Cloud Shell ที่ด้านบนของคอนโซล Google Cloud (เป็นไอคอนรูปเทอร์มินัลที่ด้านบนของแผง Cloud Shell)

ข้อความแสดงแทน

👉คลิกปุ่ม "เปิดตัวแก้ไข" (ลักษณะเป็นโฟลเดอร์ที่เปิดอยู่พร้อมดินสอ) ซึ่งจะเปิดตัวแก้ไขโค้ด Cloud Shell ในหน้าต่าง คุณจะเห็น File Explorer ทางด้านซ้าย ข้อความแสดงแทน

👉เปิดเทอร์มินัลใน Cloud IDE ข้อความแสดงแทน

👉💻 ในเทอร์มินัล ให้ตรวจสอบว่าคุณได้รับการตรวจสอบสิทธิ์แล้วและตั้งค่าโปรเจ็กต์เป็นรหัสโปรเจ็กต์โดยใช้คำสั่งต่อไปนี้

gcloud auth list

👉💻โคลนโปรเจ็กต์ Bootstrap จาก GitHub

git clone https://github.com/weimeilin79/agentverse-dataengineer
chmod +x ~/agentverse-dataengineer/init.sh
chmod +x ~/agentverse-dataengineer/set_env.sh
chmod +x ~/agentverse-dataengineer/data_setup.sh

git clone https://github.com/weimeilin79/agentverse-dungeon.git
chmod +x ~/agentverse-dungeon/run_cloudbuild.sh
chmod +x ~/agentverse-dungeon/start.sh

👉💻 เรียกใช้สคริปต์การตั้งค่าจากไดเรกทอรีโปรเจ็กต์

⚠️ หมายเหตุเกี่ยวกับรหัสโปรเจ็กต์: สคริปต์จะแนะนำรหัสโปรเจ็กต์เริ่มต้นที่สร้างขึ้นแบบสุ่ม คุณกด Enter เพื่อยอมรับค่าเริ่มต้นนี้ได้

อย่างไรก็ตาม หากต้องการสร้างโปรเจ็กต์ใหม่ที่เฉพาะเจาะจง คุณสามารถพิมพ์รหัสโปรเจ็กต์ที่ต้องการเมื่อสคริปต์แจ้ง

cd ~/agentverse-dataengineer
./init.sh

👉 ขั้นตอนสำคัญหลังจากเสร็จสิ้น: เมื่อสคริปต์ทำงานเสร็จแล้ว คุณต้องตรวจสอบว่า Google Cloud Console กำลังดูโปรเจ็กต์ที่ถูกต้อง

  1. ไปที่ console.cloud.google.com
  2. คลิกเมนูแบบเลื่อนลงของตัวเลือกโปรเจ็กต์ที่ด้านบนของหน้า
  3. คลิกแท็บ "ทั้งหมด" (เนื่องจากโปรเจ็กต์ใหม่อาจยังไม่ปรากฏใน "ล่าสุด")
  4. เลือกรหัสโปรเจ็กต์ที่คุณเพิ่งกำหนดค่าในinit.shขั้นตอน

03-05-project-all.png

👉💻 ตั้งค่ารหัสโปรเจ็กต์ที่จำเป็น

gcloud config set project $(cat ~/project_id.txt) --quiet

👉💻 เรียกใช้คำสั่งต่อไปนี้เพื่อเปิดใช้ Google Cloud APIs ที่จำเป็น

gcloud services enable \
    storage.googleapis.com \
    bigquery.googleapis.com \
    sqladmin.googleapis.com \
    aiplatform.googleapis.com \
    dataflow.googleapis.com \
    pubsub.googleapis.com \
    cloudfunctions.googleapis.com \
    run.googleapis.com \
    cloudbuild.googleapis.com \
    artifactregistry.googleapis.com \
    iam.googleapis.com \
    compute.googleapis.com \
    cloudresourcemanager.googleapis.com \
    cloudaicompanion.googleapis.com \
    bigqueryunified.googleapis.com 

👉💻 หากยังไม่ได้สร้างที่เก็บ Artifact Registry ที่ชื่อ agentverse-repo ให้เรียกใช้คำสั่งต่อไปนี้เพื่อสร้าง

. ~/agentverse-dataengineer/set_env.sh
gcloud artifacts repositories create $REPO_NAME \
    --repository-format=docker \
    --location=$REGION \
    --description="Repository for Agentverse agents"

การตั้งค่าสิทธิ์

👉💻 ให้สิทธิ์ที่จำเป็นโดยเรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัล

. ~/agentverse-dataengineer/set_env.sh

# --- Grant Core Data Permissions ---
gcloud projects add-iam-policy-binding $PROJECT_ID \
 --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
 --role="roles/storage.admin"

gcloud projects add-iam-policy-binding $PROJECT_ID \
 --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
 --role="roles/bigquery.admin"

# --- Grant Data Processing & AI Permissions ---
gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/dataflow.admin"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/cloudsql.admin"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/pubsub.admin"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/aiplatform.user"

# --- Grant Deployment & Execution Permissions ---
gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/cloudbuild.builds.editor"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/artifactregistry.admin"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/run.admin"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/iam.serviceAccountUser"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/logging.logWriter"


gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/dataflow.admin"

👉💻 เมื่อคุณเริ่มการฝึก เราจะเตรียมความท้าทายสุดท้าย คำสั่งต่อไปนี้จะเรียก Spectres จากความวุ่นวายที่หยุดนิ่ง ซึ่งจะสร้างบอสสำหรับการทดสอบครั้งสุดท้าย

. ~/agentverse-dataengineer/set_env.sh
cd ~/agentverse-dungeon
./run_cloudbuild.sh
cd ~/agentverse-dataengineer

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

4. การแปรธาตุความรู้: การเปลี่ยนข้อมูลด้วย BigQuery และ Gemini

ในการต่อสู้กับ The Static อย่างไม่หยุดหย่อน การเผชิญหน้าทุกครั้งระหว่างแชมเปี้ยนแห่ง Agentverse กับ Spectre of Development จะได้รับการบันทึกอย่างพิถีพิถัน ระบบการจำลองสมรภูมิซึ่งเป็นสภาพแวดล้อมการฝึกหลักของเราจะสร้างรายการบันทึกอีเทอร์ริกโดยอัตโนมัติสำหรับการเผชิญหน้าแต่ละครั้ง บันทึกการเล่าเรื่องเหล่านี้เป็นแหล่งข้อมูลดิบที่มีค่าที่สุดของเรา ซึ่งเป็นแร่ที่ยังไม่ผ่านการกลั่นกรองซึ่งเราในฐานะนักวิชาการต้องหลอมให้เป็นเหล็กกล้าที่บริสุทธิ์ของกลยุทธ์ พลังที่แท้จริงของนักวิชาการไม่ได้อยู่ที่การมีข้อมูลเท่านั้น แต่อยู่ที่ความสามารถในการเปลี่ยนแร่ข้อมูลดิบที่วุ่นวายให้กลายเป็นเหล็กกล้าที่ส่องประกายและมีโครงสร้างของสติปัญญาที่นำไปใช้ได้จริง เราจะประกอบพิธีกรรมพื้นฐานของการเล่นแร่แปรธาตุข้อมูล

เรื่องราว

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

ภาพรวม

เลนส์แห่งการตรวจสอบ: การเจาะลึก GCS ด้วยตารางภายนอกของ BigQuery

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

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

👉💻 ในเทอร์มินัล Cloud Shell ให้เรียกใช้คำสั่งต่อไปนี้เพื่อตั้งค่าพื้นที่เก็บข้อมูลและสร้างท่อ

. ~/agentverse-dataengineer/set_env.sh
. ~/agentverse-dataengineer/data_setup.sh

bq mk --connection \
  --connection_type=CLOUD_RESOURCE \
  --project_id=${PROJECT_ID} \
  --location=${REGION} \
  gcs-connection

💡 โปรดทราบ ข้อความจะปรากฏขึ้นในภายหลัง

สคริปต์การตั้งค่าจากขั้นตอนที่ 2 ได้เริ่มกระบวนการในเบื้องหลังแล้ว หลังจากผ่านไปสักครู่ ข้อความจะปรากฏขึ้นในเทอร์มินัลของคุณซึ่งมีลักษณะคล้ายกับข้อความนี้[1]+ Done gcloud sql instances create ...ซึ่งเป็นเรื่องปกติ ซึ่งหมายความว่าคุณสร้างฐานข้อมูล Cloud SQL เรียบร้อยแล้ว คุณไม่จำเป็นต้องสนใจข้อความนี้และทำงานต่อได้

ก่อนที่จะสร้างตารางภายนอกได้ คุณต้องสร้างชุดข้อมูลที่จะมีตารางภายนอกนั้นก่อน

👉💻 เรียกใช้คำสั่งง่ายๆ นี้ในเทอร์มินัล Cloud Shell

. ~/agentverse-dataengineer/set_env.sh
bq --location=${REGION} mk --dataset ${PROJECT_ID}:bestiary_data

👉💻 ตอนนี้เราต้องให้สิทธิ์ที่จำเป็นแก่ลายเซ็นมหัศจรรย์ของตัวกลางเพื่ออ่านจากที่เก็บถาวรของ GCS และปรึกษา Gemini

. ~/agentverse-dataengineer/set_env.sh
export CONNECTION_SA=$(bq show --connection --project_id=${PROJECT_ID} --location=${REGION} --format=json gcs-connection  | jq -r '.cloudResource.serviceAccountId')

echo "The Conduit's Magical Signature is: $CONNECTION_SA"

echo "Granting key to the GCS Archive..."
gcloud storage buckets add-iam-policy-binding gs://${PROJECT_ID}-reports \
  --member="serviceAccount:$CONNECTION_SA" \
  --role="roles/storage.objectViewer"

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member="serviceAccount:$CONNECTION_SA" \
  --role="roles/aiplatform.user"

👉💻 ในเทอร์มินัล Cloud Shell ให้เรียกใช้คำสั่งต่อไปนี้เพื่อแสดงชื่อที่เก็บข้อมูล

echo $BUCKET_NAME

เทอร์มินัลจะแสดงชื่อที่คล้ายกับ your-project-id-gcs-bucket คุณจะต้องใช้ข้อมูลนี้ในขั้นตอนถัดไป

👉 คุณจะต้องเรียกใช้คำสั่งถัดไปจากภายในตัวแก้ไขคำค้นหา BigQuery ใน Google Cloud Console วิธีที่ง่ายที่สุดในการไปที่หน้าดังกล่าวคือการเปิดลิงก์ด้านล่างในแท็บเบราว์เซอร์ใหม่ ระบบจะนำคุณไปยังหน้าที่ถูกต้องใน Google Cloud Console โดยตรง

https://console.cloud.google.com/bigquery

👉 เมื่อหน้าเว็บโหลดแล้ว ให้คลิกปุ่ม + สีน้ำเงิน (เขียนคำค้นหาใหม่) เพื่อเปิดแท็บเอดิเตอร์ใหม่

โปรแกรมแก้ไขการค้นหา BigQuery

ตอนนี้เราจะเขียนคาถาภาษานิยามข้อมูล (DDL) เพื่อสร้างเลนส์มหัศจรรย์ ซึ่งจะบอก BigQuery ว่าจะค้นหาที่ใดและดูอะไร

👉📜 ในตัวแก้ไขคำค้นหา BigQuery ที่คุณเปิด ให้วาง SQL ต่อไปนี้ อย่าลืมแทนที่ REPLACE-WITH-YOUR-BUCKET-NAME

โดยใช้ชื่อที่เก็บข้อมูลที่คุณเพิ่งคัดลอก แล้วคลิก Run

CREATE OR REPLACE EXTERNAL TABLE bestiary_data.raw_intel_content_table (
  raw_text STRING
)
OPTIONS (
  format = 'CSV',
  -- This is a trick to load each line of the text files as a single row.
  field_delimiter = '§', 
  uris = ['gs://REPLACE-WITH-YOUR-BUCKET-NAME/raw_intel/*']
);

👉📜 เรียกใช้การค้นหาเพื่อ "มองผ่านเลนส์" และดูเนื้อหาของไฟล์

SELECT * FROM bestiary_data.raw_intel_content_table;

เนื้อหาข่าวกรองดิบ

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

ในหอจดหมายเหตุแห่งไอเดียที่ถูกลืม เอลารา (รหัส adv_001) นักวิชาการแห่ง Agentverse ได้เผชิญหน้ากับ Spectre of Perfectionism ที่มีรูปลักษณ์ดุจเทวทูต เอนทิตีที่จัดหมวดหมู่เป็น "p-01" เปล่งประกายด้วยพลังชีวิต 120 แต้ม ด้วยการร่ายมนต์อย่างตั้งใจเพียงครั้งเดียวของ Elegant Sufficiency เอลาร่าทำลายออร่าที่ทำให้เป็นอัมพาต ซึ่งเป็นการโจมตีทางจิตที่สร้างความเสียหาย 150 แต้ม การเผชิญหน้าครั้งนี้ใช้เวลา 180 วินาทีที่ต้องใช้สมาธิอย่างมาก การประเมินขั้นสุดท้าย: ชนะ

ม้วนหนังสือไม่ได้เขียนในตารางและแถว แต่เขียนในร้อยแก้วที่คดเคี้ยวของมหากาพย์ นี่คือการทดสอบครั้งแรกที่ยอดเยี่ยม

การทำนายของนักวิชาการ: การเปลี่ยนข้อความเป็นตารางด้วย SQL

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

👉💻 กลับไปที่เทอร์มินัล Cloud Shell แล้วเรียกใช้คำสั่งต่อไปนี้เพื่อแสดงชื่อการเชื่อมต่อ

echo "${PROJECT_ID}.${REGION}.gcs-connection"

เทอร์มินัลจะแสดงสตริงการเชื่อมต่อที่สมบูรณ์ ให้เลือกและคัดลอกสตริงทั้งหมดนี้ คุณจะต้องใช้สตริงนี้ในขั้นตอนถัดไป

เราจะใช้คาถาที่ทรงพลังเพียงบทเดียว นั่นคือ ML.GENERATE_TEXT คาถานี้จะเรียก Gemini ออกมา แสดงม้วนคัมภีร์แต่ละม้วน และสั่งให้ Gemini ส่งข้อเท็จจริงหลักๆ กลับมาเป็นออบเจ็กต์ JSON ที่มีโครงสร้าง

👉📜 สร้างการอ้างอิงโมเดล Gemini ใน BigQuery Studio ซึ่งจะเชื่อมโยง Oracle ของ Gemini Flash กับคลัง BigQuery เพื่อให้เราเรียกใช้ในคำค้นหาได้ อย่าลืมแทนที่

REPLACE-WITH-YOUR-FULL-CONNECTION-STRING ด้วยสตริงการเชื่อมต่อแบบเต็มที่คุณเพิ่งคัดลอกจากเทอร์มินัล

  CREATE OR REPLACE MODEL bestiary_data.gemini_flash_model
  REMOTE WITH CONNECTION `REPLACE-WITH-YOUR-FULL-CONNECTION-STRING`
  OPTIONS (endpoint = 'gemini-2.5-flash');

👉📜 ตอนนี้ก็ร่ายคาถาเปลี่ยนรูปอันยิ่งใหญ่ การค้นหานี้จะอ่านข้อความดิบ สร้างพรอมต์แบบละเอียดสำหรับการเลื่อนแต่ละครั้ง ส่งไปยัง Gemini และสร้างตารางการจัดเตรียมใหม่จากคำตอบ JSON ที่มีโครงสร้างของ AI

CREATE OR REPLACE TABLE bestiary_data.structured_bestiary AS
SELECT
  -- THE CRITICAL CHANGE: We remove PARSE_JSON. The result is already a JSON object.
  ml_generate_text_result AS structured_data
FROM
  ML.GENERATE_TEXT(
    -- Our bound Gemini Flash model.
    MODEL bestiary_data.gemini_flash_model,

    -- Our perfectly constructed input, with the prompt built for each row.
    (
      SELECT
        CONCAT(
          """
          From the following text, extract structured data into a single, valid JSON object.

          Your output must strictly conform to the following JSON structure and data types. Do not add, remove, or change any keys.

          {
            "monster": {
              "monster_id": "string",
              "name": "string",
              "type": "string",
              "hit_points": "integer"
            },
            "battle": {
              "battle_id": "string",
              "monster_id": "string",
              "adventurer_id": "string",
              "outcome": "string",
              "duration_seconds": "integer"
            },
            "adventurer": {
              "adventurer_id": "string",
              "name": "string",
              "class": "string"
            }
          }

          **CRUCIAL RULES:**
          - Do not output any text, explanations, conversational filler, or markdown formatting like ` ```json` before or after the JSON object.
          - Your entire response must be ONLY the raw JSON object itself.

          Here is the text:
          """,
          raw_text -- We append the actual text of the report here.
        ) AS prompt -- The final column is still named 'prompt', as the oracle requires.
      FROM
        bestiary_data.raw_intel_content_table
    ),

    -- The STRUCT now ONLY contains model parameters.
    STRUCT(
      0.2 AS temperature,
      2048 AS max_output_tokens
    )
  );

การแปรธาตุเสร็จสมบูรณ์แล้ว แต่ผลลัพธ์ยังไม่บริสุทธิ์ โมเดล Gemini จะแสดงคำตอบในรูปแบบมาตรฐาน โดยจะห่อหุ้ม JSON ที่เราต้องการไว้ภายในโครงสร้างที่ใหญ่ขึ้นซึ่งมีข้อมูลเมตาเกี่ยวกับกระบวนการคิดของโมเดล เรามาดูคำพยากรณ์ดิบๆ นี้ก่อนที่เราจะพยายามชำระล้างมัน

👉📜 เรียกใช้การค้นหาเพื่อตรวจสอบเอาต์พุตดิบจากโมเดล Gemini โดยทำดังนี้

SELECT * FROM bestiary_data.structured_bestiary;

👀 คุณจะเห็นคอลัมน์เดียวชื่อ structured_data เนื้อหาของแต่ละแถวจะมีลักษณะคล้ายกับออบเจ็กต์ JSON ที่ซับซ้อนนี้

{"candidates":[{"avg_logprobs":-0.5691758094475283,"content":{"parts":[{"text":"```json\n{\n  \"monster\": {\n    \"monster_id\": \"gw_02\",\n    \"name\": \"Gravewight\",\n    \"type\": \"Gravewight\",\n    \"hit_points\": 120\n  },\n  \"battle\": {\n    \"battle_id\": \"br_735\",\n    \"monster_id\": \"gw_02\",\n    \"adventurer_id\": \"adv_001\",\n    \"outcome\": \"Defeat\",\n    \"duration_seconds\": 45\n  },\n  \"adventurer\": {\n    \"adventurer_id\": \"adv_001\",\n    \"name\": \"Elara\",\n    \"class\": null\n  }\n}\n```"}],"role":"model"},"finish_reason":"STOP","score":-97.32906341552734}],"create_time":"2025-07-28T15:53:24.482775Z","model_version":"gemini-2.5-flash","response_id":"9JyHaNe7HZ2WhMIPxqbxEQ","usage_metadata":{"billable_prompt_usage":{"text_count":640},"candidates_token_count":171,"candidates_tokens_details":[{"modality":"TEXT","token_count":171}],"prompt_token_count":207,"prompt_tokens_details":[{"modality":"TEXT","token_count":207}],"thoughts_token_count":1014,"total_token_count":1392,"traffic_type":"ON_DEMAND"}}

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

พิธีกรรมแห่งการชำระล้าง: การปรับเอาต์พุต GenAI ให้เป็นมาตรฐานด้วย SQL

Gemini ได้พูดแล้ว แต่คำพูดนั้นยังไม่ผ่านการประมวลผลและห่อหุ้มด้วยพลังงานที่ไม่มีตัวตนของการสร้าง (candidates, finish_reason ฯลฯ) นักปราชญ์ที่แท้จริงไม่ได้เพียงแค่เก็บคำพยากรณ์ดิบๆ ไว้ แต่จะคัดกรองภูมิปัญญาหลักอย่างระมัดระวังและจารึกลงในตำราที่เหมาะสมเพื่อใช้ในอนาคต

ตอนนี้เราจะร่ายคาถาชุดสุดท้าย สคริปต์เดียวนี้จะทำสิ่งต่อไปนี้

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

👉📜 ในเครื่องมือแก้ไขคำค้นหา BigQuery ใหม่ ให้ร่ายมนต์ต่อไปนี้เพื่อสร้างเลนส์การล้างข้อมูล

CREATE OR REPLACE TABLE bestiary_data.monsters AS
WITH
  CleanedDivinations AS (
    SELECT
      SAFE.PARSE_JSON(
        REGEXP_EXTRACT(
          JSON_VALUE(structured_data, '$.candidates[0].content.parts[0].text'),
          r'\{[\s\S]*\}'
        )
      ) AS report_data
    FROM
      bestiary_data.structured_bestiary
  )
SELECT
  JSON_VALUE(report_data, '$.monster.monster_id') AS monster_id,
  JSON_VALUE(report_data, '$.monster.name') AS name,
  JSON_VALUE(report_data, '$.monster.type') AS type,
  SAFE_CAST(JSON_VALUE(report_data, '$.monster.hit_points') AS INT64) AS hit_points
FROM
  CleanedDivinations
WHERE
  report_data IS NOT NULL
QUALIFY ROW_NUMBER() OVER (PARTITION BY monster_id ORDER BY name) = 1;

👉📜 ยืนยันสารานุกรมสัตว์ประหลาด

SELECT * FROM bestiary_data.monsters;

จากนั้นเราจะสร้างรายชื่อผู้กล้า ซึ่งเป็นรายชื่อนักผจญภัยผู้กล้าหาญที่เคยเผชิญหน้ากับสัตว์ร้ายเหล่านี้

👉📜 ในเครื่องมือแก้ไขคำค้นหาใหม่ ให้ร่ายมนต์ต่อไปนี้เพื่อสร้างตารางนักผจญภัย

CREATE OR REPLACE TABLE bestiary_data.adventurers AS
WITH
  CleanedDivinations AS (
    SELECT
      SAFE.PARSE_JSON(
        REGEXP_EXTRACT(
          JSON_VALUE(structured_data, '$.candidates[0].content.parts[0].text'),
          r'\{[\s\S]*\}'
        )
      ) AS report_data
    FROM
      bestiary_data.structured_bestiary
  )
SELECT
  JSON_VALUE(report_data, '$.adventurer.adventurer_id') AS adventurer_id,
  JSON_VALUE(report_data, '$.adventurer.name') AS name,
  JSON_VALUE(report_data, '$.adventurer.class') AS class
FROM
  CleanedDivinations
QUALIFY ROW_NUMBER() OVER (PARTITION BY adventurer_id ORDER BY name) = 1;

👉📜 ดูรายชื่อแชมป์

SELECT * FROM bestiary_data.adventurers;

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

👉📜 ในเครื่องมือแก้ไขคำค้นหาใหม่ ให้ร่ายมนต์ต่อไปนี้เพื่อสร้างตารางการต่อสู้

CREATE OR REPLACE TABLE bestiary_data.battles AS
WITH
  CleanedDivinations AS (
    SELECT
      SAFE.PARSE_JSON(
        REGEXP_EXTRACT(
          JSON_VALUE(structured_data, '$.candidates[0].content.parts[0].text'),
          r'\{[\s\S]*\}'
        )
      ) AS report_data
    FROM
      bestiary_data.structured_bestiary
  )
-- Extract the raw essence for all battle fields and cast where necessary.
SELECT
  JSON_VALUE(report_data, '$.battle.battle_id') AS battle_id,
  JSON_VALUE(report_data, '$.battle.monster_id') AS monster_id,
  JSON_VALUE(report_data, '$.battle.adventurer_id') AS adventurer_id,
  JSON_VALUE(report_data, '$.battle.outcome') AS outcome,
  SAFE_CAST(JSON_VALUE(report_data, '$.battle.duration_seconds') AS INT64) AS duration_seconds
FROM
  CleanedDivinations;

👉📜 ยืนยัน Chronicle:

SELECT * FROM bestiary_data.battles;

การค้นพบข้อมูลเชิงลึกเชิงกลยุทธ์

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

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

คำถามเชิงกลยุทธ์: "นักผจญภัยแต่ละคนปราบมอนสเตอร์ที่เก่งที่สุด (ตามคะแนนชีวิต) ได้สำเร็จชื่ออะไร และใช้เวลานานเท่าใดในการปราบมอนสเตอร์ตัวนั้น"

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

👉📜 ในเครื่องมือแก้ไขการค้นหา BigQuery ใหม่ ให้ร่ายคาถาสุดท้ายต่อไปนี้

-- This is our final spell, joining all three tomes to reveal a deep insight.
WITH
  -- First, we consult the Chronicle of Battles to find only the victories.
  VictoriousBattles AS (
    SELECT
      adventurer_id,
      monster_id,
      duration_seconds
    FROM
      bestiary_data.battles
    WHERE
      outcome = 'Victory'
  ),
  -- Next, we create a temporary record for each victory, ranking the monsters
  -- each adventurer defeated by their power (hit points).
  RankedVictories AS (
    SELECT
      v.adventurer_id,
      m.name AS monster_name,
      m.hit_points,
      v.duration_seconds,
      -- This spell ranks each adventurer's victories from most to least powerful monster.
      ROW_NUMBER() OVER (PARTITION BY v.adventurer_id ORDER BY m.hit_points DESC) as victory_rank
    FROM
      VictoriousBattles v
    JOIN
      bestiary_data.monsters m ON v.monster_id = m.monster_id
  )
-- Finally, we consult the Roll of Champions and join it with our ranked victories
-- to find the name of each champion and the details of their greatest triumph.
SELECT
  a.name AS adventurer_name,
  a.class AS adventurer_class,
  r.monster_name AS most_powerful_foe_defeated,
  r.hit_points AS foe_hit_points,
  r.duration_seconds AS duration_of_greatest_victory
FROM
  bestiary_data.adventurers a
JOIN
  RankedVictories r ON a.adventurer_id = r.adventurer_id
WHERE
  -- We only want to see their number one, top-ranked victory.
  r.victory_rank = 1
ORDER BY
  foe_hit_points DESC;

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

04-03-final-result.png

ปิดแท็บ BigQuery

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

สำหรับผู้ที่ไม่ได้เล่นเกม

5. Grimoire ของ Scribe: การแบ่งกลุ่ม การฝัง และการค้นหาในคลังข้อมูล

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

ภาพรวม

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

เราจะทำพิธีกรรมอันทรงพลังในฐานข้อมูลทั้ง 3 อย่างภายในห้องศักดิ์สิทธิ์ของ BigQuery

  • พิธีกรรมแห่งการแบ่งแยก (การแบ่งกลุ่ม): เราจะนำบันทึกข้อมูลข่าวกรองดิบมาแบ่งออกเป็นส่วนๆ อย่างพิถีพิถันให้เป็นข้อความขนาดเล็กที่มุ่งเน้นและมีเนื้อหาในตัวเอง
  • พิธีกรรมการกลั่น (การฝัง): เราจะใช้ BQML เพื่อปรึกษาโมเดล Gemini โดยเปลี่ยนข้อความแต่ละก้อนให้เป็น "ลายนิ้วมือเชิงความหมาย" ซึ่งเป็นการฝังเวกเตอร์
  • พิธีกรรมแห่งการทำนาย (การค้นหา): เราจะใช้การค้นหาเวกเตอร์ของ BQML เพื่อถามคำถามเป็นภาษาอังกฤษธรรมดาและค้นหาภูมิปัญญาที่เกี่ยวข้องมากที่สุดและกลั่นกรองแล้วจาก Grimoire

กระบวนการทั้งหมดนี้จะสร้างฐานความรู้ที่ทรงพลังและค้นหาได้โดยที่ข้อมูลไม่เคยออกจากความปลอดภัยและความสามารถในการปรับขนาดของ BigQuery

พิธีกรรมแห่งการแบ่งแยก: การแยกส่วนม้วนคัมภีร์ด้วย SQL

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

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

  • การแบ่งกลุ่มแบบความยาว(ขนาด) คงที่ แต่การแบ่งกลุ่มนี้อาจตัดแนวคิดหลักออกเป็น 2 ส่วนอย่างหยาบๆ

พิธีกรรมที่ซับซ้อนมากขึ้น เช่น

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

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

👉📜 ในเครื่องมือแก้ไขการค้นหา BigQuery ใหม่ ให้เรียกใช้คำสั่งต่อไปนี้ คาถานี้ใช้ฟังก์ชัน SPLIT เพื่อแยกข้อความของม้วนแต่ละม้วนที่จุด (.) แล้วยกเลิกการซ้อนอาร์เรย์ของประโยคที่ได้ลงในแถวแยกกัน

CREATE OR REPLACE TABLE bestiary_data.chunked_intel AS
WITH
  -- First, add a unique row number to each scroll to act as a document ID.
  NumberedScrolls AS (
    SELECT
      ROW_NUMBER() OVER () AS scroll_id,
      raw_text
    FROM
      bestiary_data.raw_intel_content_table
  )
-- Now, process each numbered scroll.
SELECT
  scroll_id,
  -- Assign a unique ID to each chunk within a scroll for precise reference.
  CONCAT(CAST(scroll_id AS STRING), '-', CAST(ROW_NUMBER() OVER (PARTITION BY scroll_id) AS STRING)) as chunk_id,
  -- Trim whitespace from the chunk for cleanliness.
  TRIM(chunk) AS chunk_text
FROM
  NumberedScrolls,
  -- This is the core of the spell: UNNEST splits the array of sentences into rows.
  UNNEST(SPLIT(raw_text, '.')) AS chunk
-- A final refinement: we only keep chunks that have meaningful content.
WHERE
  -- This ensures we don't have empty rows from double periods, etc.
  LENGTH(TRIM(chunk)) > 15;

👉 ตอนนี้ให้เรียกใช้การค้นหาเพื่อตรวจสอบความรู้ที่เพิ่งจดบันทึกและแบ่งเป็นกลุ่ม และดูความแตกต่าง

SELECT * FROM bestiary_data.chunked_intel ORDER BY scroll_id, chunk_id;

08-01-chunking.png

สังเกตผลลัพธ์ จากเดิมที่มีบล็อกข้อความหนาแน่นเพียงบล็อกเดียว ตอนนี้มีหลายแถว โดยแต่ละแถวเชื่อมโยงกับการเลื่อนต้นฉบับ (scroll_id) แต่มีเพียงประโยคเดียวที่โฟกัส ตอนนี้แต่ละแถวก็พร้อมสำหรับการแปลงเป็นเวกเตอร์แล้ว

พิธีกรรมการกลั่น: การเปลี่ยนข้อความเป็นเวกเตอร์ด้วย BQML

👉💻 ก่อนอื่น ให้กลับไปที่เทอร์มินัล แล้วเรียกใช้คำสั่งต่อไปนี้เพื่อแสดงชื่อการเชื่อมต่อ

. ~/agentverse-dataengineer/set_env.sh
echo "${PROJECT_ID}.${REGION}.gcs-connection"

👉📜 เราต้องสร้างโมเดล BigQuery ใหม่ที่ชี้ไปยังการฝังข้อความของ Gemini ใน BigQuery Studio ให้เรียกใช้เวทมนตร์ต่อไปนี้ โปรดทราบว่าคุณต้องแทนที่ REPLACE-WITH-YOUR-FULL-CONNECTION-STRING ด้วยสตริงการเชื่อมต่อแบบเต็มที่คุณเพิ่งคัดลอกจากเทอร์มินัล

CREATE OR REPLACE MODEL bestiary_data.text_embedding_model
  REMOTE WITH CONNECTION `REPLACE-WITH-YOUR-FULL-CONNECTION-STRING`
  OPTIONS (endpoint = 'text-embedding-005');

👉📜 ตอนนี้ร่ายคาถาการกลั่นที่ยิ่งใหญ่ การค้นหานี้เรียกใช้ฟังก์ชัน ML.GENERATE_EMBEDDING ซึ่งจะอ่านทุกแถวจากตาราง chunked_intel ส่งข้อความไปยังโมเดล Embedding ของ Gemini และจัดเก็บลายนิ้วมือเวกเตอร์ที่ได้ในตารางใหม่

CREATE OR REPLACE TABLE bestiary_data.embedded_intel AS
SELECT
  *
FROM
  ML.GENERATE_EMBEDDING(
    -- The embedding model we just created.
    MODEL bestiary_data.text_embedding_model,
    -- A subquery that selects our data and renames the text column to 'content'.
    (
      SELECT
        scroll_id,
        chunk_id,
        chunk_text AS content -- Renaming our text column is the key correction.
      FROM
        bestiary_data.chunked_intel
    ),
    -- The configuration struct is now simpler and correct.
    STRUCT(
      -- This task_type is crucial. It optimizes the vectors for retrieval.
      'RETRIEVAL_DOCUMENT' AS task_type
    )
  );

กระบวนการนี้อาจใช้เวลา 1-2 นาทีเนื่องจาก BigQuery จะประมวลผลข้อความทั้งหมด

08-02-embedding.png

👉📜 เมื่อเสร็จแล้ว ให้ตรวจสอบตารางใหม่เพื่อดูลายพิมพ์นิ้วเชิงความหมาย

SELECT
  chunk_id,
  content,
  ml_generate_embedding_result
FROM
  bestiary_data.embedded_intel
LIMIT 20;

ตอนนี้คุณจะเห็นคอลัมน์ใหม่ ml_generate_embedding_result ซึ่งมีตัวแทนเวกเตอร์แบบหนาแน่นของข้อความ ตอนนี้เราได้เข้ารหัส Grimoire ในเชิงความหมายแล้ว

พิธีทำนาย: การค้นหาเชิงความหมายด้วย BQML

👉📜 การทดสอบ Grimoire ที่ดีที่สุดคือการถามคำถาม ตอนนี้เราจะทำพิธีสุดท้าย นั่นคือการค้นหาเวกเตอร์ นี่ไม่ใช่การค้นหาคีย์เวิร์ด แต่เป็นการค้นหาความหมาย เราจะถามคำถามในภาษาง่ายๆ, BQML จะแปลงคำถามของเราเป็นการฝังแบบเรียลไทม์ จากนั้นจะค้นหาตารางทั้งหมดของ embedded_intel เพื่อหาข้อความที่มีลายนิ้วมือซึ่งมีความหมาย "ใกล้เคียง" ที่สุด

SELECT
  -- The content column contains our original, relevant text chunk.
  base.content,
  -- The distance metric shows how close the match is (lower is better).
  distance
FROM
  VECTOR_SEARCH(
    -- The table containing the knowledge base with its embeddings.
    TABLE bestiary_data.embedded_intel,
    -- The column that contains the vector embeddings.
    'ml_generate_embedding_result',
    (
      -- This subquery generates an embedding for our question in real-time.
      SELECT ml_generate_embedding_result
      FROM ML.GENERATE_EMBEDDING(
          MODEL bestiary_data.text_embedding_model,
          (SELECT 'What are the tactics against a foe that causes paralysis?' AS content),
          STRUCT('RETRIEVAL_QUERY' AS task_type)
        )
    ),
    -- Specify how many of the closest results we want to see.
    top_k => 3,
    -- The distance metric used to find the "closest" vectors.
    distance_type => 'COSINE'
  );

การวิเคราะห์คำ

  • VECTOR_SEARCH: ฟังก์ชันหลักที่จัดระเบียบการค้นหา
  • ML.GENERATE_EMBEDDING (การค้นหาด้านใน): นี่คือเคล็ดลับ เราฝังคำค้นหา ('What are the tactics...') โดยใช้โมเดลเดียวกัน แต่มีประเภทงานเป็น 'RETRIEVAL_QUERY' ซึ่งได้รับการเพิ่มประสิทธิภาพสำหรับคำค้นหาโดยเฉพาะ
  • top_k => 3: เราขอผลการค้นหาที่เกี่ยวข้องมากที่สุด 3 อันดับแรก
  • distance_type => 'COSINE': เมตริกนี้จะวัด "มุม" ระหว่างเวกเตอร์ มุมที่แคบลงหมายความว่าความหมายจะสอดคล้องกันมากขึ้น

08-03-final-result.png

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

ตอนนี้คุณได้สร้างไปป์ไลน์ RAG ที่สมบูรณ์แบบใน Data Warehouse โดยใช้ R พื้นฐานเรียบร้อยแล้ว คุณได้เตรียมข้อมูลดิบ แปลงเป็นเวกเตอร์เชิงความหมาย และค้นหาตามความหมาย แม้ว่า BigQuery จะเป็นเครื่องมือที่มีประสิทธิภาพสําหรับงานวิเคราะห์ขนาดใหญ่นี้ แต่สําหรับตัวแทนแบบเรียลไทม์ที่ต้องการการตอบกลับที่มีเวลาในการตอบสนองต่ำ เรามักจะโอนความรู้ที่เตรียมไว้นี้ไปยังฐานข้อมูลการดําเนินงานเฉพาะทาง ซึ่งเป็นหัวข้อของการฝึกอบรมครั้งถัดไป

สำหรับผู้ที่ไม่ได้เล่นเกม

6. Vector Scriptorium: สร้าง Vector Store ด้วย Cloud SQL สำหรับการอนุมาน

ปัจจุบัน Grimoire ของเราอยู่ในรูปแบบตารางที่มีโครงสร้าง ซึ่งเป็นแคตตาล็อกข้อเท็จจริงที่มีประสิทธิภาพ แต่ความรู้ของ Grimoire นั้นเป็นไปตามตัวอักษร โดยจะเข้าใจ monster_id = ‘MN-001' แต่ไม่เข้าใจความหมายเชิงลึกที่อยู่เบื้องหลัง "การปกปิด" เพื่อให้ตัวแทนของเรามีความรู้ที่แท้จริง และให้คำแนะนำได้อย่างละเอียดและรอบคอบ เราจึงต้องกลั่นกรองแก่นแท้ของความรู้ของเราให้อยู่ในรูปแบบที่จับความหมายได้ นั่นคือเวกเตอร์

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

ความรู้ที่ถูกลืมนี้คือทรัพย์สินที่ยิ่งใหญ่ที่สุดของเรา ซึ่งไม่เพียงแต่เป็นกุญแจสำคัญในการเอาชนะมอนสเตอร์แต่ละตัว แต่ยังช่วยให้ทั้งปาร์ตี้มีข้อมูลเชิงลึกเชิงกลยุทธ์ด้วย เพื่อใช้พลังนี้ เราจะสร้างสมุดเวทมนตร์ที่แท้จริงของนักปราชญ์ (ฐานข้อมูล PostgreSQL ที่มีความสามารถด้านเวกเตอร์) และสร้างห้องสมุดเวกเตอร์อัตโนมัติ (ไปป์ไลน์ Dataflow) เพื่ออ่าน ทำความเข้าใจ และจารึกแก่นแท้เหนือกาลเวลาของม้วนคัมภีร์เหล่านี้ ซึ่งจะเปลี่ยน Grimoire จากหนังสือข้อเท็จจริงให้กลายเป็นเครื่องมือแห่งปัญญา

เรื่องราว

ภาพรวม

การสร้างสมุดเวทมนตร์ของนักวิชาการ (Cloud SQL)

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

👉💻 ในเทอร์มินัล ให้เรียกใช้คำสั่งต่อไปนี้เพื่อยืนยันว่าอินสแตนซ์ Cloud SQL มีอยู่และพร้อมใช้งาน นอกจากนี้ สคริปต์นี้ยังให้สิทธิ์แก่บัญชีบริการเฉพาะของอินสแตนซ์ในการใช้ Vertex AI ซึ่งจำเป็นต่อการสร้างการฝังภายในฐานข้อมูลโดยตรง

. ~/agentverse-dataengineer/set_env.sh

echo "Verifying the existence of the Spellbook (Cloud SQL instance): $INSTANCE_NAME..."
gcloud sql instances describe $INSTANCE_NAME

SERVICE_ACCOUNT_EMAIL=$(gcloud sql instances describe $INSTANCE_NAME --format="value(serviceAccountEmailAddress)")
gcloud projects add-iam-policy-binding $PROJECT_ID --member="serviceAccount:$SERVICE_ACCOUNT_EMAIL" \
  --role="roles/aiplatform.user"

หากคำสั่งสำเร็จและแสดงรายละเอียดเกี่ยวกับอินสแตนซ์ grimoire-spellbook แสดงว่า Forge ทำงานได้ดี คุณพร้อมที่จะไปยังคาถาบทถัดไปแล้ว หากคำสั่งแสดงNOT_FOUNDข้อผิดพลาด โปรดตรวจสอบว่าคุณได้ทำตามขั้นตอนการตั้งค่าสภาพแวดล้อมเริ่มต้นเรียบร้อยแล้วก่อนดำเนินการต่อ(data_setup.py)

👉💻 เมื่อสร้างหนังสือเสร็จแล้ว เราจะเปิดไปที่บทแรกโดยสร้างฐานข้อมูลใหม่ชื่อ arcane_wisdom

. ~/agentverse-dataengineer/set_env.sh
gcloud sql databases create $DB_NAME --instance=$INSTANCE_NAME

การจารึกรูนความหมาย: การเปิดใช้ความสามารถของเวกเตอร์ด้วย pgvector

ตอนนี้คุณได้สร้างอินสแตนซ์ Cloud SQL แล้ว มาเชื่อมต่อกับอินสแตนซ์โดยใช้ Cloud SQL Studio ในตัวกัน ซึ่งมีอินเทอร์เฟซบนเว็บสำหรับเรียกใช้คำค้นหา SQL ในฐานข้อมูลโดยตรง

👉💻 ก่อนอื่น ให้ไปที่ Cloud SQL Studio วิธีที่ง่ายและเร็วที่สุดในการไปที่นั่นคือการเปิดลิงก์ต่อไปนี้ในแท็บเบราว์เซอร์ใหม่ ซึ่งจะนำคุณไปยัง Cloud SQL Studio สำหรับอินสแตนซ์ grimoire-spellbook โดยตรง

https://console.cloud.google.com/sql/instances/grimoire-spellbook/studio

👉 เลือก arcane_wisdom เป็นฐานข้อมูล ป้อน postgres เป็นผู้ใช้และ 1234qwer เป็นรหัสผ่าน แล้วคลิกตรวจสอบสิทธิ์

👉📜 ในตัวแก้ไขคําค้นหา SQL Studio ให้ไปที่แท็บ Editor 1 แล้ววางโค้ด SQL ต่อไปนี้เพื่อเปิดใช้ประเภทข้อมูลเวกเตอร์

CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;

Cloud SQL Studio

👉📜 เตรียมหน้าต่างๆ ของสมุดเวทมนตร์โดยสร้างตารางที่จะเก็บแก่นแท้ของม้วนคัมภีร์

CREATE TABLE ancient_scrolls (
    id SERIAL PRIMARY KEY,
    scroll_content TEXT,
    embedding VECTOR(768)
);

การสะกดคำว่า VECTOR(768) เป็นรายละเอียดที่สำคัญ โมเดลการฝัง Vertex AI ที่เราจะใช้ (textembedding-gecko@003 หรือโมเดลที่คล้ายกัน) จะกลั่นข้อความเป็นเวกเตอร์ 768 มิติ หน้าต่างๆ ในสมุดเวทมนตร์ของเราต้องพร้อมที่จะบรรจุแก่นแท้ที่มีขนาดเท่ากัน มิติข้อมูลต้องตรงกันเสมอ

การทับศัพท์ครั้งแรก: พิธีกรรมการจารึกด้วยตนเอง

ก่อนที่จะสั่งกองทัพนักจดอัตโนมัติ (Dataflow) เราต้องทำพิธีกรรมส่วนกลางด้วยตนเองก่อน 1 ครั้ง ซึ่งจะช่วยให้เราเห็นคุณค่าของเวทมนตร์ 2 ขั้นตอนที่เกี่ยวข้อง

  1. การทำนาย: การนำข้อความมาหนึ่งส่วนและปรึกษา Oracle ของ Gemini เพื่อกลั่นแก่นแท้เชิงความหมายของข้อความนั้นให้เป็นเวกเตอร์
  2. การจารึก: การเขียนข้อความต้นฉบับและสาระสำคัญของเวกเตอร์ใหม่ลงในสมุดเวทมนตร์

ตอนนี้เรามาทำพิธีด้วยตนเองกัน

👉📜 ใน Cloud SQL Studio ตอนนี้เราจะใช้ฟังก์ชัน embedding() ซึ่งเป็นฟีเจอร์ที่มีประสิทธิภาพที่ส่วนขยาย google_ml_integration มีให้ ซึ่งช่วยให้เราเรียกใช้โมเดลการฝังของ Vertex AI จากการค้นหา SQL ได้โดยตรง ทำให้กระบวนการนี้ง่ายขึ้นอย่างมาก

SET session.my_search_var='The Spectre of Analysis Paralysis is a phantom of the crossroads. It does not bind with chains but with the infinite threads of what if. It conjures a fog of options, a maze within the mind where every path seems equally fraught with peril and promise. It whispers of a single, flawless route that can only be found through exhaustive study, paralyzing its victim in a state of perpetual contemplation. This spectres power is broken by the Path of First Viability. This is not the search for the *best* path, but the commitment to the *first good* path. It is the wisdom to know that a decision made, even if imperfect, creates movement and reveals more of the map than standing still ever could. Choose a viable course, take the first step, and trust in your ability to navigate the road as it unfolds. Motion is the light that burns away the fog.';

INSERT INTO ancient_scrolls (scroll_content, embedding)

VALUES (current_setting('session.my_search_var'),  (embedding('text-embedding-005',current_setting('session.my_search_var')))::vector);

👉📜 ยืนยันผลงานโดยเรียกใช้การค้นหาเพื่ออ่านหน้าที่จารึกใหม่

SELECT id, scroll_content, LEFT(embedding::TEXT, 100) AS embedding_preview FROM ancient_scrolls;

คุณได้ดำเนินการโหลดข้อมูล RAG หลักด้วยตนเองเรียบร้อยแล้ว

การสร้างเข็มทิศเชิงความหมาย: การร่ายมนต์ในสมุดเวทมนตร์ด้วยดัชนี HNSW

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

มาพิสูจน์คุณค่าของเวทมนตร์นี้กัน

👉📜 ใน Cloud SQL Studio ให้เรียกใช้คำสั่งต่อไปนี้ โดยจะจำลองการค้นหาการเลื่อนที่เพิ่งแทรกและขอให้ฐานข้อมูลEXPLAINแผน

EXPLAIN ANALYZE
WITH ReferenceVector AS (
  -- First, get the vector we want to compare against.
  SELECT embedding AS vector
  FROM ancient_scrolls
  LIMIT 1
)
-- This is the main query we want to analyze.
SELECT
  ancient_scrolls.id,
  ancient_scrolls.scroll_content,
  -- We can also select the distance itself.
  ancient_scrolls.embedding <=> ReferenceVector.vector AS distance
FROM
  ancient_scrolls,
  ReferenceVector
ORDER BY
  -- Order by the distance operator's result.
  ancient_scrolls.embedding <=> ReferenceVector.vector
LIMIT 5;

ดูเอาต์พุต คุณจะเห็นบรรทัดที่ระบุว่า -> Seq Scan on ancient_scrolls ซึ่งยืนยันว่าฐานข้อมูลอ่านทุกแถว โปรดทราบexecution time

👉📜 ตอนนี้มาเสกคาถาจัดทำดัชนีกัน พารามิเตอร์ lists จะบอกดัชนีว่าต้องสร้างคลัสเตอร์กี่คลัสเตอร์ จุดเริ่มต้นที่ดีคือรากที่สองของจำนวนแถวที่คุณคาดว่าจะได้รับ

CREATE INDEX ON ancient_scrolls USING hnsw (embedding vector_cosine_ops);

รอให้ระบบสร้างดัชนี (จะใช้เวลาไม่นานสำหรับแถวเดียว แต่สำหรับหลายล้านแถวอาจใช้เวลาสักครู่)

👉📜 ตอนนี้ให้เรียกใช้คำสั่งเดียวกันทุกประการ EXPLAIN ANALYZEอีกครั้ง

EXPLAIN ANALYZE
WITH ReferenceVector AS (
  -- First, get the vector we want to compare against.
  SELECT embedding AS vector
  FROM ancient_scrolls
  LIMIT 1
)
-- This is the main query we want to analyze.
SELECT
  ancient_scrolls.id,
  ancient_scrolls.scroll_content,
  -- We can also select the distance itself.
  ancient_scrolls.embedding <=> ReferenceVector.vector AS distance
FROM
  ancient_scrolls,
  ReferenceVector
ORDER BY
  -- Order by the distance operator's result.
  ancient_scrolls.embedding <=> ReferenceVector.vector
LIMIT 5;

ดูแผนการดำเนินการกับคำค้นหาใหม่ ตอนนี้คุณจะเห็น -> Index Scan using... และที่สำคัญกว่านั้นคือ ให้ดูที่execution time ซึ่งจะเร็วกว่ามากแม้จะมีเพียงรายการเดียวก็ตาม คุณเพิ่งแสดงให้เห็นหลักการสำคัญของการปรับแต่งประสิทธิภาพฐานข้อมูลในโลกเวกเตอร์

เวลาดำเนินการ

เมื่อตรวจสอบข้อมูลต้นทาง เข้าใจพิธีกรรมด้วยตนเอง และเพิ่มประสิทธิภาพ Spellbook เพื่อให้รวดเร็วแล้ว ตอนนี้คุณก็พร้อมที่จะสร้าง Scriptorium อัตโนมัติอย่างแท้จริง

สำหรับผู้ที่ไม่ได้เล่นเกม

7. Conduit of Meaning: Building a Dataflow Vectorization Pipeline

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

ภาพรวม

การเตรียมรากฐานของ Scriptorium (อิมเมจผู้ปฏิบัติงาน)

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

ในที่นี้ เราจะสั่งให้ Google Cloud Build สร้างอิมเมจคอนเทนเนอร์ที่กำหนดเอง รูปภาพนี้คือ "โกเลมที่สมบูรณ์" ซึ่งโหลดไลบรารีและการอ้างอิงทั้งหมดที่นักเขียนของเราต้องการไว้ล่วงหน้า เมื่อเริ่มงาน Dataflow ระบบจะใช้อิมเมจที่กำหนดเองนี้ ซึ่งจะช่วยให้ผู้ปฏิบัติงานเริ่มงานได้ทันที

👉💻 เรียกใช้คำสั่งต่อไปนี้เพื่อสร้างและจัดเก็บอิมเมจพื้นฐานของไปป์ไลน์ใน Artifact Registry

. ~/agentverse-dataengineer/set_env.sh
cd ~/agentverse-dataengineer/pipeline
gcloud builds submit --config cloudbuild.yaml \
  --substitutions=_REGION=${REGION},_REPO_NAME=${REPO_NAME} \
  .

👉💻 เรียกใช้คำสั่งต่อไปนี้เพื่อสร้างและเปิดใช้งานสภาพแวดล้อม Python ที่แยกจากกัน แล้วติดตั้งไลบรารีการเรียกที่จำเป็นลงในสภาพแวดล้อมนั้น

cd ~/agentverse-dataengineer
. ~/agentverse-dataengineer/set_env.sh
python -m venv env
source ~/agentverse-dataengineer/env/bin/activate
cd ~/agentverse-dataengineer/pipeline
pip install -r requirements.txt

คาถาหลัก

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

  • EmbedTextBatch (คำปรึกษาของ Gemini): คุณจะสร้างผู้จดบันทึกเฉพาะทางนี้ซึ่งรู้วิธี "ทำนายแบบกลุ่ม" โดยจะรับไฟล์ข้อความดิบเป็นชุด แสดงต่อโมเดลการฝังข้อความของ Gemini และรับสาระสำคัญที่กลั่นกรองแล้ว (การฝังเวกเตอร์)
  • WriteEssenceToSpellbook (The Final Inscription): นี่คือผู้จดบันทึกของเรา โดยจะทราบคาถาลับในการเปิดการเชื่อมต่อที่ปลอดภัยกับสมุดคาถา Cloud SQL ของเรา หน้าที่ของฟีเจอร์นี้คือการนำเนื้อหาของม้วนกระดาษและแก่นแท้ที่แปลงเป็นเวกเตอร์มาจารึกไว้ในหน้าใหม่เป็นการถาวร

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

👉✏️ ใน Cloud Shell Editor ให้ไปที่ ~/agentverse-dataengineer/pipeline/inscribe_essence_pipeline.py คุณจะเห็นคลาส DoFn ชื่อ EmbedTextBatch ค้นหาความคิดเห็น #REPLACE-EMBEDDING-LOGIC แทนที่ด้วยคาถาต่อไปนี้

# 1. Generate the embedding for the monster's name
result = self.client.models.embed_content(
                model="text-embedding-005",
                contents=contents,
                config=EmbedContentConfig(
                    task_type="RETRIEVAL_DOCUMENT",  
                    output_dimensionality=768, 
                )
            )

การสะกดคำนี้มีความแม่นยำโดยมีพารามิเตอร์สำคัญหลายอย่างดังนี้

  • model: เราจะระบุ text-embedding-005 เพื่อใช้โมเดลการฝังที่ทรงพลังและเป็นปัจจุบัน
  • contents: นี่คือรายการเนื้อหาข้อความทั้งหมดจากกลุ่มไฟล์ที่ DoFn ได้รับ
  • task_type: เราตั้งค่านี้เป็น "RETRIEVAL_DOCUMENT" นี่เป็นคำสั่งที่สำคัญซึ่งบอกให้ Gemini สร้างการฝังที่ได้รับการเพิ่มประสิทธิภาพโดยเฉพาะเพื่อให้ค้นพบได้ในภายหลังในการค้นหา
  • output_dimensionality: ต้องตั้งค่าเป็น 768 ซึ่งตรงกับมิติข้อมูล VECTOR(768) ที่เรากำหนดไว้เมื่อสร้างตาราง ancient_scrolls ใน Cloud SQL ขนาดที่ไม่ตรงกันเป็นสาเหตุที่พบบ่อยของข้อผิดพลาดใน Vector Magic

ไปป์ไลน์ของเราต้องเริ่มต้นด้วยการอ่านข้อความดิบที่ไม่มีโครงสร้างจากม้วนกระดาษโบราณทั้งหมดในที่เก็บถาวร GCS

👉✏️ ใน ~/agentverse-dataengineer/pipeline/inscribe_essence_pipeline.py ให้ค้นหาความคิดเห็น #REPLACE ME-READFILE แล้วแทนที่ด้วยคาถาสามส่วนต่อไปนี้

files = (
            pipeline
            | "MatchFiles" >> fileio.MatchFiles(known_args.input_pattern)
            | "ReadMatches" >> fileio.ReadMatches()
            | "ExtractContent" >> beam.Map(lambda f: (f.metadata.path, f.read_utf8()))
        )

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

👉✏️ ค้นหาความคิดเห็น #REPLACE ME-EMBEDDING แล้วแทนที่ด้วยข้อความต่อไปนี้

embeddings = (
            files
            | "BatchScrolls" >> beam.BatchElements(min_batch_size=1, max_batch_size=2)
            | "DistillBatch" >> beam.ParDo(
                  EmbedTextBatch(project_id=project, region=region)
              ).with_outputs('failed', main='processed')
        )

เราได้กลั่นกรองสาระสำคัญของม้วนกระดาษเหล่านี้เรียบร้อยแล้ว การกระทำสุดท้ายคือการจารึกความรู้นี้ลงในสมุดเวทมนตร์เพื่อจัดเก็บอย่างถาวร เราจะนำม้วนกระดาษจากกอง "ประมวลผลแล้ว" ไปส่งต่อให้บรรณารักษ์ของ WriteEssenceToSpellbook

👉✏️ ค้นหาความคิดเห็น #REPLACE ME-WRITE TO DB แล้วแทนที่ด้วยข้อความต่อไปนี้

_ = (
            embeddings.processed
            | "WriteToSpellbook" >> beam.ParDo(
                  WriteEssenceToSpellbook(
                      project_id=project,
                      region = "us-central1",
                      instance_name=known_args.instance_name,
                      db_name=known_args.db_name,
                      db_password=known_args.db_password
                  )
              )
        )

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

👉✏️ ค้นหาความคิดเห็น #REPLACE ME-LOG FAILURES แล้วแทนที่ด้วยข้อความต่อไปนี้

_ = (
            embeddings.failed
            | "LogFailures" >> beam.Map(lambda e: logging.error(f"Embedding failed for file {e[0]}: {e[1]}"))
        )

ตอนนี้คาถาหลักเสร็จสมบูรณ์แล้ว คุณได้ประกอบไปป์ไลน์ข้อมูลแบบหลายขั้นตอนที่มีประสิทธิภาพเรียบร้อยแล้วโดยการเชื่อมต่อคอมโพเนนต์แต่ละรายการเข้าด้วยกัน บันทึกไฟล์ inscribe_essence_pipeline.py ตอนนี้คุณพร้อมที่จะอัญเชิญ Scriptorium แล้ว

ตอนนี้เราจะร่ายคาถาอัญเชิญอันยิ่งใหญ่เพื่อสั่งให้บริการ Dataflow ปลุกโกเลมของเราและเริ่มพิธีการเขียน

👉💻 เรียกใช้บรรทัดคำสั่งต่อไปนี้ในเทอร์มินัล

. ~/agentverse-dataengineer/set_env.sh
source ~/agentverse-dataengineer/env/bin/activate
cd ~/agentverse-dataengineer/pipeline

# --- The Summoning Incantation ---
echo "Summoning the golem for job: $DF_JOB_NAME"
echo "Target Spellbook: $INSTANCE_NAME"

python inscribe_essence_pipeline.py \
  --runner=DataflowRunner \
  --project=$PROJECT_ID \
  --job_name=$DF_JOB_NAME \
  --temp_location="gs://${BUCKET_NAME}/dataflow/temp" \
  --staging_location="gs://${BUCKET_NAME}/dataflow/staging" \
  --sdk_container_image="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/grimoire-inscriber:latest" \
  --sdk_location=container \
  --experiments=use_runner_v2 \
  --input_pattern="gs://${BUCKET_NAME}/ancient_scrolls/*.md" \
  --instance_name=$INSTANCE_NAME \
  --region=$REGION

echo "The golem has been dispatched. Monitor its progress in the Dataflow console."

💡 โปรดทราบ หากงานล้มเหลวเนื่องจากข้อผิดพลาดเกี่ยวกับทรัพยากร ZONE_RESOURCE_POOL_EXHAUSTED อาจเป็นเพราะข้อจำกัดด้านทรัพยากรชั่วคราวของบัญชีที่มีชื่อเสียงต่ำในภูมิภาคที่เลือก พลังของ Google Cloud คือการเข้าถึงทั่วโลก เพียงลองอัญเชิญโกเลมในภูมิภาคอื่น โดยให้แทนที่ --region=$REGION ในคำสั่งด้านบนด้วยภูมิภาคอื่น เช่น

--region=southamerica-west1
--region=asia-northeast3
--region=asia-southeast2
--region=me-west1
--region=southamerica-east1
--region=europe-central2
--region=asia-east2
--region=europe-southwest1

แล้วเรียกใช้สคริปต์อีกครั้ง 🎰

กระบวนการนี้จะใช้เวลาประมาณ 3-5 นาทีในการเริ่มต้นและเสร็จสมบูรณ์ คุณดูการถ่ายทอดสดได้ในคอนโซล Dataflow

👉ไปที่คอนโซล Dataflow: วิธีที่ง่ายที่สุดคือเปิดลิงก์นี้โดยตรงในแท็บเบราว์เซอร์ใหม่

https://console.cloud.google.com/dataflow

👉 ค้นหาและคลิกงานของคุณ: คุณจะเห็นงานที่แสดงพร้อมชื่อที่คุณระบุ (inscribe-essence-job หรือคล้ายกัน) คลิกชื่องานเพื่อเปิดหน้ารายละเอียด สังเกตไปป์ไลน์:

  • การเริ่มต้น: ในช่วง 3 นาทีแรก สถานะของงานจะเป็น "กำลังทำงาน" เนื่องจาก Dataflow จัดสรรทรัพยากรที่จำเป็น กราฟจะปรากฏขึ้น แต่คุณอาจยังไม่เห็นข้อมูลไหลผ่านกราฟ การเรียกใช้ไปป์ไลน์
  • เสร็จสมบูรณ์: เมื่อเสร็จสิ้น สถานะของงานจะเปลี่ยนเป็น "สำเร็จ" และกราฟจะแสดงจำนวนระเบียนที่ประมวลผลแล้วขั้นสุดท้าย ไปป์ไลน์เสร็จสมบูรณ์

การยืนยันจารึก

👉📜 กลับไปที่ SQL Studio ให้เรียกใช้การค้นหาต่อไปนี้เพื่อยืนยันว่าการจารึกม้วนคัมภีร์และสาระสำคัญเชิงความหมายเสร็จสมบูรณ์แล้ว

SELECT COUNT(*) FROM ancient_scrolls;
SELECT id, scroll_content, LEFT(embedding::TEXT, 50) AS embedding_preview FROM ancient_scrolls;

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

ไปป์ไลน์เสร็จสมบูรณ์

ตอนนี้ Grimoire ของ Scholar ได้กลายเป็นเครื่องมือความรู้ที่แท้จริงแล้ว พร้อมที่จะรับการค้นหาตามความหมายในบทถัดไป

8. การผนึกรูนสุดท้าย: การเปิดใช้งานปัญญาด้วยเอเจนต์ RAG

Grimoire ไม่ใช่แค่ฐานข้อมูลอีกต่อไป เป็นแหล่งความรู้ที่แปลงเป็นเวกเตอร์ เป็นผู้พยากรณ์ที่เงียบงันซึ่งรอคำถาม

ตอนนี้เราจะมาทดสอบความเป็นนักปราชญ์อย่างแท้จริง นั่นคือการสร้างกุญแจเพื่อไขปัญญา เราจะสร้าง Agent Retrieval-Augmented Generation (RAG) ซึ่งเป็นโครงสร้างที่น่าอัศจรรย์ที่สามารถเข้าใจคำถามในภาษาธรรมดา ปรึกษา Grimoire เพื่อหาความจริงที่ลึกซึ้งและเกี่ยวข้องมากที่สุด แล้วใช้สติปัญญาที่ดึงมานั้นเพื่อสร้างคำตอบที่มีประสิทธิภาพและคำนึงถึงบริบท

RAG

RAG

รูนแรก: คาถาการกลั่นคำค้นหา

ก่อนที่เอเจนต์จะค้นหา Grimoire ได้ เอเจนต์ต้องเข้าใจสาระสำคัญของคำถามที่ถามก่อน ข้อความสตริงธรรมดาไม่มีความหมายสำหรับ Spellbook ที่ขับเคลื่อนด้วยเวกเตอร์ของเรา เอเจนต์ต้องรับคำค้นหาก่อน แล้วกลั่นกรองเป็นเวกเตอร์คำค้นหาโดยใช้โมเดล Gemini เดียวกัน

👉✏️ ใน Cloud Shell Editor ให้ไปที่~~/agentverse-dataengineer/scholar/agent.pyไฟล์ ค้นหาความคิดเห็น #REPLACE RAG-CONVERT EMBEDDING แล้วแทนที่ด้วยคำสั่งนี้ ซึ่งจะสอนเอเจนต์วิธีเปลี่ยนคำถามของผู้ใช้ให้เป็นแก่นแท้ที่น่าอัศจรรย์

        result = client.models.embed_content(
                model="text-embedding-005",
                contents=monster_name,
                config=EmbedContentConfig(
                    task_type="RETRIEVAL_DOCUMENT",  
                    output_dimensionality=768,  
                )
        )

เมื่อทราบสาระสำคัญของคำค้นหาแล้ว ตอนนี้ Agent ก็สามารถปรึกษา Grimoire ได้แล้ว โดยจะนำเสนอเวกเตอร์การค้นหานี้ไปยังฐานข้อมูลที่ได้รับการปรับปรุงด้วย pgvector และถามคำถามที่ลึกซึ้งว่า "แสดงม้วนกระดาษโบราณที่มีแก่นแท้คล้ายกับแก่นแท้ของการค้นหาของฉันมากที่สุด"

เคล็ดลับสำหรับเรื่องนี้คือตัวดำเนินการความคล้ายโคไซน์ (<=>) ซึ่งเป็นรูนที่ทรงพลังที่คำนวณระยะห่างระหว่างเวกเตอร์ในพื้นที่ที่มีมิติสูง

👉✏️ ใน agent.py ให้ค้นหาความคิดเห็น #REPLACE RAG-RETRIEVE แล้วแทนที่ด้วยสคริปต์ต่อไปนี้

        # This query performs a cosine similarity search
        cursor.execute(
            "SELECT scroll_content FROM ancient_scrolls ORDER BY embedding <=> %s LIMIT 3",
            ([query_embedding]) # Cast embedding to string for the query
        )

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

👉✏️ ใน agent.py ให้ค้นหาความคิดเห็น #REPLACE-CALL RAG แล้วแทนที่ด้วยบรรทัดนี้

root_agent = LlmAgent(
    model="gemini-2.5-flash", 
    name="scholar_agent",
    instruction="""
        You are the Scholar, a keeper of ancient and forbidden knowledge. Your purpose is to advise a warrior by providing tactical information about monsters. Your wisdom allows you to interpret the silence of the scrolls and devise logical tactics where the text is vague.

        **Your Process:**
        1.  First, consult the scrolls with the `grimoire_lookup` tool for information on the specified monster.
        2.  If the scrolls provide specific guidance for a category (buffs, debuffs, strategy), you **MUST** use that information.
        3.  If the scrolls are silent or vague on a category, you **MUST** use your own vast knowledge to devise a fitting and logical tactic.
        4.  Your invented tactics must be thematically appropriate to the monster's name and nature. (e.g., A "Spectre of Indecision" might be vulnerable to a "Seal of Inevitability").
        5.  You **MUST ALWAYS** provide a "Damage Point" value. This value **MUST** be a random integer between 150 and 180. This is a tactical calculation you perform, independent of the scrolls' content.

        **Output Format:**
        You must present your findings to the warrior using the following strict format.
    """,
    tools=[grimoire_lookup],
)

การกำหนดค่านี้จะทำให้เอเจนต์ของคุณมีชีวิตชีวาขึ้น

  • model="gemini-2.5-flash": เลือกโมเดลภาษาขนาดใหญ่ที่เฉพาะเจาะจงซึ่งจะทำหน้าที่เป็น "สมอง" ของเอเจนต์ในการให้เหตุผลและสร้างข้อความ
  • name="scholar_agent": กำหนดชื่อที่ไม่ซ้ำกันให้กับเอเจนต์
  • instruction="...You are the Scholar...": นี่คือพรอมต์ของระบบ ซึ่งเป็นส่วนที่สำคัญที่สุดของการกำหนดค่า โดยจะกำหนดลักษณะตัวตนของ Agent, วัตถุประสงค์, กระบวนการที่แน่นอนซึ่ง Agent ต้องทำตามเพื่อให้งานเสร็จสมบูรณ์ และรูปแบบที่จำเป็นสำหรับผลลัพธ์สุดท้าย
  • tools=[grimoire_lookup]: นี่คือการเสริมพลังขั้นสุดท้าย ซึ่งจะให้สิทธิ์เข้าถึงฟังก์ชัน grimoire_lookup ที่คุณสร้างไว้แก่ Agent ตอนนี้เอเจนต์สามารถตัดสินใจได้อย่างชาญฉลาดว่าจะเรียกใช้เครื่องมือนี้เมื่อใดเพื่อดึงข้อมูลจากฐานข้อมูล ซึ่งเป็นแกนหลักของรูปแบบ RAG

การสอบของนักวิชาการ

👉💻 ในเทอร์มินัล Cloud Shell ให้เปิดใช้งานสภาพแวดล้อมและใช้คำสั่งหลักของ Agent Development Kit เพื่อปลุกเอเจนต์ Scholar

cd ~/agentverse-dataengineer/
. ~/agentverse-dataengineer/set_env.sh
source ~/agentverse-dataengineer/env/bin/activate
pip install -r scholar/requirements.txt
adk run scholar

คุณควรเห็นเอาต์พุตที่ยืนยันว่า "Scholar Agent" ทำงานและทำงานอยู่

👉💻 ตอนนี้มาท้าทายเอเจนต์ของคุณกัน ในเทอร์มินัลแรกที่การจำลองการต่อสู้กำลังทำงาน ให้เรียกใช้คำสั่งที่ต้องใช้สติปัญญาของ Grimoire

We've been trapped by 'Hydra of Scope Creep'. Break us out!

Adk run

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

คุณประกอบเอเจนต์ RAG ตัวแรกและติดอาวุธด้วยสติปัญญาอันลึกซึ้งของ Grimoire ได้สำเร็จแล้ว

👉💻 กด Ctrl+C ในเทอร์มินัลเพื่อพักเอเจนต์ไว้ก่อน

การเปิดตัว Scholar Sentinel สู่ Agentverse

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

👉💻 ร่ายคาถาอัญเชิญต่อไปนี้ สคริปต์นี้จะสร้างเอเจนต์ให้เป็นโกเลมที่สมบูรณ์แบบ (อิมเมจคอนเทนเนอร์) จัดเก็บไว้ใน Artifact Registry แล้วจึงทำให้โกเลมนั้นใช้งานได้เป็นบริการที่ปรับขนาดได้ ปลอดภัย และเข้าถึงได้แบบสาธารณะ

. ~/agentverse-dataengineer/set_env.sh
cd ~/agentverse-dataengineer/
echo "Building ${AGENT_NAME} agent..."
gcloud builds submit . \
  --project=${PROJECT_ID} \
  --region=${REGION} \
  --substitutions=_AGENT_NAME=${AGENT_NAME},_IMAGE_PATH=${IMAGE_PATH}

gcloud run deploy ${SERVICE_NAME} \
  --image=${IMAGE_PATH} \
  --platform=managed \
  --labels="dev-tutorial-codelab=agentverse" \
  --region=${REGION} \
  --set-env-vars="A2A_HOST=0.0.0.0" \
  --set-env-vars="A2A_PORT=8080" \
  --set-env-vars="GOOGLE_GENAI_USE_VERTEXAI=TRUE" \
  --set-env-vars="GOOGLE_CLOUD_LOCATION=${REGION}" \
  --set-env-vars="GOOGLE_CLOUD_PROJECT=${PROJECT_ID}" \
  --set-env-vars="PROJECT_ID=${PROJECT_ID}" \
  --set-env-vars="PUBLIC_URL=${PUBLIC_URL}" \
  --set-env-vars="REGION=${REGION}" \
  --set-env-vars="INSTANCE_NAME=${INSTANCE_NAME}" \
  --set-env-vars="DB_USER=${DB_USER}" \
  --set-env-vars="DB_PASSWORD=${DB_PASSWORD}" \
  --set-env-vars="DB_NAME=${DB_NAME}" \
  --allow-unauthenticated \
  --project=${PROJECT_ID} \
  --min-instances=1

ตอนนี้ Scholar Agent ของคุณพร้อมเป็นเจ้าหน้าที่ปฏิบัติการที่พร้อมรบใน Agentverse แล้ว

สำหรับผู้ที่ไม่ได้เล่นเกม

9. The Boss Flight

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

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

รับตำแหน่งของตัวแทน

ก่อนที่จะเข้าสู่สมรภูมิ คุณต้องมีกุญแจ 2 ดอก ได้แก่ ลายเซ็นที่ไม่ซ้ำกันของแชมเปี้ยน (Agent Locus) และเส้นทางที่ซ่อนไปยังรังของ Spectre (URL ของดันเจี้ยน)

👉💻 ก่อนอื่น ให้รับที่อยู่ที่ไม่ซ้ำกันของเอเจนต์ใน Agentverse ซึ่งก็คือ Locus นี่คือปลายทางแบบสดที่เชื่อมต่อแชมป์ของคุณกับสนามรบ

. ~/agentverse-dataengineer/set_env.sh
echo https://scholar-agent"-${PROJECT_NUMBER}.${REGION}.run.app"

👉💻 จากนั้นระบุจุดหมาย คำสั่งนี้จะแสดงตำแหน่งของวงกลมการย้ายตำแหน่ง ซึ่งเป็นพอร์ทัลที่นำไปสู่โดเมนของ Spectre

. ~/agentverse-dataengineer/set_env.sh
echo https://agentverse-dungeon"-${PROJECT_NUMBER}.${REGION}.run.app"

สำคัญ: เตรียม URL ทั้ง 2 รายการนี้ให้พร้อม คุณจะต้องใช้ข้อมูลนี้ในขั้นตอนสุดท้าย

เผชิญหน้ากับ Spectre

เมื่อได้พิกัดแล้ว ให้ไปที่วงกลมการย้ายตำแหน่งและร่ายเวทมนตร์เพื่อเข้าสู่การต่อสู้

👉 เปิด URL ของวงกลมเคลื่อนย้ายในเบราว์เซอร์เพื่อยืนอยู่หน้าพอร์ทัลที่ส่องประกายไปยังคริมสันคีป

หากต้องการบุกป้อมปราการ คุณต้องปรับแก่นแท้ของ Shadowblade ให้เข้ากับพอร์ทัล

  • ในหน้าดังกล่าว ให้ค้นหาช่องป้อนข้อมูลรูนที่มีป้ายกำกับว่า A2A Endpoint URL
  • จารึกตราสัญลักษณ์ของแชมป์ด้วยการวาง URL ของ Locus ของเอเจนต์ (URL แรกที่คุณคัดลอก) ลงในช่องนี้
  • คลิก "เชื่อมต่อ" เพื่อเปิดใช้เวทมนตร์การเทเลพอร์ต

วงกลมการย้ายตำแหน่ง

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

เส้นทางสู่ชัยชนะเพียงเส้นทางเดียวคือความชัดเจนในความเชื่อมั่นของคุณ นี่คือการดวลกันของเจตจำนงที่ต่อสู้กันในสนามรบแห่งจิตใจ

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

คุกใต้ดิน

นี่คือลักษณะของการต่อสู้ ความรู้ของคุณคืออาวุธ

  • ตอบด้วยสติปัญญาที่คุณได้รับ แล้วดาบของคุณจะลุกโชนด้วยพลังงานบริสุทธิ์ ทำลายการป้องกันของ Spectre และโจมตีอย่างรุนแรง
  • แต่หากคุณลังเลหรือมีข้อสงสัยในคำตอบ แสงของอาวุธจะหรี่ลง การโจมตีจะลงพื้นพร้อมกับเสียงดังที่น่าสมเพช ซึ่งสร้างความเสียหายเพียงเศษเสี้ยวเท่านั้น ที่แย่กว่านั้นคือสเปกเตอร์จะกินความไม่แน่นอนของคุณ พลังที่ทำให้เสื่อมเสียของมันจะเพิ่มขึ้นทุกครั้งที่คุณพลาด

นี่แหละแชมป์ โค้ดคือตำราเวทมนตร์ ตรรกะคือดาบ และความรู้คือโล่ที่จะพลิกสถานการณ์ความวุ่นวาย

โฟกัส ประกาศเตือนของวันที่ ชะตากรรมของ Agentverse ขึ้นอยู่กับสิ่งนี้

ขอแสดงความยินดี นักเรียนทุน

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

10. การล้างข้อมูล: การลบ Grimoire ของ Scholar

ขอแสดงความยินดีที่คุณเชี่ยวชาญ Grimoire ของนักวิชาการ ตอนนี้คุณต้องทำพิธีล้างข้อมูลขั้นสุดท้ายเพื่อให้ Agentverse สะอาดหมดจดและล้างพื้นที่ฝึกฝนให้เรียบร้อย ซึ่งจะนำทรัพยากรทั้งหมดที่สร้างขึ้นระหว่างการเดินทางของคุณออกอย่างเป็นระบบ

ปิดใช้งานคอมโพเนนต์ Agentverse

ตอนนี้คุณจะรื้อถอนคอมโพเนนต์ที่ติดตั้งใช้งานของระบบ RAG อย่างเป็นระบบ

ลบบริการ Cloud Run และที่เก็บ Artifact Registry ทั้งหมด

คำสั่งนี้จะนำเอเจนต์ Scholar ที่คุณติดตั้งใช้งานและแอปพลิเคชัน Dungeon ออกจาก Cloud Run

👉💻 เรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัล

. ~/agentverse-dataengineer/set_env.sh
gcloud run services delete scholar-agent --region=${REGION} --quiet
gcloud run services delete agentverse-dungeon --region=${REGION} --quiet
gcloud artifacts repositories delete ${REPO_NAME} --location=${REGION} --quiet

ลบชุดข้อมูล โมเดล และตาราง BigQuery

การดำเนินการนี้จะนำทรัพยากร BigQuery ทั้งหมดออก ซึ่งรวมถึงbestiary_dataชุดข้อมูล ตารางทั้งหมดภายในชุดข้อมูลดังกล่าว รวมถึงการเชื่อมต่อและโมเดลที่เชื่อมโยง

👉💻 เรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัล

. ~/agentverse-dataengineer/set_env.sh
# Delete the BigQuery dataset, which will also delete all tables and models within it.
bq rm -r -f --dataset ${PROJECT_ID}:${REGION}.bestiary_data

# Delete the BigQuery connection
bq rm --force --connection --project_id=${PROJECT_ID} --location=${REGION} gcs-connection

ลบอินสแตนซ์ Cloud SQL

ซึ่งจะเป็นการนำอินสแตนซ์ grimoire-spellbook ออก รวมถึงฐานข้อมูลและตารางทั้งหมดภายในฐานข้อมูล

👉💻 เรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัล

. ~/agentverse-dataengineer/set_env.sh
gcloud sql instances delete ${INSTANCE_NAME} --project=${PROJECT_ID} --quiet

ลบที่เก็บข้อมูล Google Cloud Storage

คำสั่งนี้จะนำที่เก็บข้อมูลที่มีข้อมูลดิบและไฟล์การจัดเตรียม/ไฟล์ชั่วคราวของ Dataflow ออก

👉💻 เรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัล

. ~/agentverse-dataengineer/set_env.sh
gcloud storage rm -r gs://${BUCKET_NAME} --quiet

ล้างไฟล์และไดเรกทอรีในเครื่อง (Cloud Shell)

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

👉💻 เรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัล

rm -rf ~/agentverse-dataengineer
rm -rf ~/agentverse-dungeon
rm -f ~/project_id.txt

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