1. บทนำ
สวัสดี คุณสนใจตัวแทน ซึ่งเป็นผู้ช่วยตัวน้อยที่ทําสิ่งต่างๆ ให้คุณได้โดยไม่ต้องออกแรงเลยใช่ไหม ยอดเยี่ยม! แต่อย่าลืมว่าตัวแทนเพียงคนเดียวอาจไม่เพียงพอเสมอไป โดยเฉพาะเมื่อคุณจัดการกับโปรเจ็กต์ขนาดใหญ่และซับซ้อนมากขึ้น คุณอาจต้องใช้ทั้งทีม ด้วยเหตุนี้ ระบบหลายตัวแทนจึงเข้ามามีบทบาท
เมื่อใช้ LLM ตัวแทนจะมีความยืดหยุ่นอย่างไม่น่าเชื่อเมื่อเทียบกับการเขียนโค้ดแบบฮาร์ดโค้ดแบบเก่า แต่ข้อเสียคือ วิดีโอเหล่านี้มีความท้าทายที่ยากลำบากในตัวเอง และเราจะเจาะลึกเรื่องนี้ในเวิร์กช็อปนี้
สิ่งที่คุณจะได้รับจากหลักสูตรนี้เปรียบเสมือนการเพิ่มระดับทักษะการเป็นตัวแทนของคุณ
การสร้าง Agent ตัวแรกด้วย LangGraph: เราจะลงมือสร้าง Agent ของคุณเองโดยใช้ LangGraph ซึ่งเป็นเฟรมเวิร์กยอดนิยม คุณจะได้เรียนรู้วิธีสร้างเครื่องมือที่เชื่อมต่อกับฐานข้อมูล ใช้ประโยชน์จาก Gemini 2 API เวอร์ชันล่าสุดสำหรับการค้นหาบางอย่างบนอินเทอร์เน็ต และเพิ่มประสิทธิภาพพรอมต์และการตอบกลับ เพื่อให้ตัวแทนโต้ตอบกับ LLM และบริการที่มีอยู่ได้ เราจะแสดงวิธีการทำงานของการเรียกฟังก์ชันด้วย
การจัดระเบียบตัวแทนในแบบของคุณ: เราจะสำรวจวิธีต่างๆ ในการจัดระเบียบตัวแทน ตั้งแต่เส้นทางตรงๆ ที่เรียบง่ายไปจนถึงสถานการณ์แบบหลายเส้นทางที่ซับซ้อนมากขึ้น คุณสามารถลองนึกถึงว่าเป็นการกําหนดขั้นตอนของทีมตัวแทน
ระบบหลายตัวแทน: คุณจะได้ดูวิธีสร้างระบบที่ตัวแทนสามารถทํางานร่วมกันและทําสิ่งต่างๆ ให้เสร็จสิ้นได้ ทั้งหมดนี้ต้องขอบคุณสถาปัตยกรรมที่ขับเคลื่อนโดยเหตุการณ์
LLM Freedom – ใช้ LLM ที่เหมาะกับงานที่สุด: เราไม่ได้ยึดติดกับ LLM เพียงรูปแบบเดียว คุณจะเห็นวิธีใช้ LLM หลายรายการ โดยกำหนดบทบาทที่แตกต่างกันเพื่อเพิ่มความสามารถในการแก้ปัญหาโดยใช้ "รูปแบบการคิด" ที่ยอดเยี่ยม
เนื้อหาแบบไดนามิก ไม่เป็นไร ลองจินตนาการว่าตัวแทนของคุณสร้างเนื้อหาแบบไดนามิกที่ปรับให้เหมาะกับผู้ใช้แต่ละรายโดยเฉพาะแบบเรียลไทม์ เราจะแสดงวิธีให้คุณเห็น
ย้ายข้อมูลไปยังระบบคลาวด์ด้วย Google Cloud: เลิกเล่นโน้ตบุ๊กแล้ว เราจะแสดงวิธีออกแบบและติดตั้งใช้งานระบบหลายตัวแทนใน Google Cloud เพื่อให้พร้อมใช้งานจริง
โปรเจ็กต์นี้จะเป็นตัวอย่างที่ยอดเยี่ยมในการใช้เทคนิคทั้งหมดที่เราได้พูดถึง
2. สถาปัตยกรรม
การเป็นครูหรือทำงานด้านการศึกษาอาจให้รางวัลที่ยอดเยี่ยม แต่เราก็ต้องยอมรับว่าภาระงาน โดยเฉพาะการเตรียมงานทั้งหมดอาจเป็นเรื่องท้าทาย นอกจากนี้ มักจะมีเจ้าหน้าที่ไม่เพียงพอและการเรียนพิเศษก็อาจมีราคาแพง เราจึงเสนอผู้ช่วยสอนที่ทำงานด้วยระบบ AI เครื่องมือนี้จะช่วยแบ่งเบาภาระของนักการศึกษาและช่วยเติมเต็มช่องว่างที่เกิดจากปัญหาการขาดแคลนเจ้าหน้าที่และการไม่มีผู้สอนราคาไม่แพง
ผู้ช่วยสอนที่เป็น AI ของเราสามารถจัดทำแผนการสอนโดยละเอียด แบบทดสอบสนุกๆ สรุปแบบเสียงที่เข้าใจง่าย และงานแบบปรับเปลี่ยนในแบบของคุณ ซึ่งจะช่วยให้ครูมุ่งเน้นที่สิ่งที่ตนถนัดที่สุดได้ นั่นคือการเข้าถึงนักเรียนและช่วยให้นักเรียนรักการเรียนรู้
ระบบนี้มี 2 เว็บไซต์ เว็บไซต์หนึ่งสำหรับครูในการสร้างแผนบทเรียนสำหรับสัปดาห์ที่กําลังจะมาถึง
และอีก 1 บัญชีสำหรับนักเรียนเพื่อเข้าถึงแบบทดสอบ สรุปแบบเสียง และงาน
มาเริ่มดูสถาปัตยกรรมที่ขับเคลื่อน Aidemy ซึ่งเป็นผู้ช่วยสอนกัน ดังที่คุณเห็น เราได้แยกออกเป็นคอมโพเนนต์หลักหลายรายการที่ทำงานร่วมกันเพื่อให้เกิดผลลัพธ์นี้
องค์ประกอบและเทคโนโลยีสถาปัตยกรรมหลัก
Google Cloud Platform (GCP): เป็นส่วนกลางของทั้งระบบ
- Vertex AI: เข้าถึง LLM ของ Gemini ของ Google
- Cloud Run: แพลตฟอร์มแบบ Serverless สำหรับทำให้ตัวแทนและฟังก์ชันการทำงานแบบคอนเทนเนอร์ใช้งานได้
- Cloud SQL: ฐานข้อมูล PostgreSQL สำหรับข้อมูลหลักสูตร
- Pub/Sub และ Eventarc: รากฐานของสถาปัตยกรรมที่ทำงานตามเหตุการณ์ ซึ่งช่วยให้คอมโพเนนต์ต่างๆ สื่อสารกันได้แบบไม่พร้อมกัน
- พื้นที่เก็บข้อมูลระบบคลาวด์: จัดเก็บไฟล์งานและสรุปเสียง
- เครื่องมือจัดการข้อมูลลับ: จัดการข้อมูลเข้าสู่ระบบฐานข้อมูลอย่างปลอดภัย
- Artifact Registry: จัดเก็บอิมเมจ Docker สําหรับตัวแทน
- Compute Engine: ติดตั้งใช้งาน LLM ที่โฮสต์เองแทนการใช้โซลูชันของผู้ให้บริการ
LLM: "สมอง" ของระบบ
- โมเดล Gemini ของ Google: (Gemini 1.0 Pro, Gemini 2 Flash, Gemini 2 Flash Thinking, Gemini 1.5-pro) ใช้สำหรับการวางแผนบทเรียน การสร้างเนื้อหา การสร้าง HTML แบบไดนามิก คำอธิบายแบบทดสอบ และการรวมงาน
- DeepSeek: ใช้สำหรับงานที่เฉพาะเจาะจงในการสร้างงานแบบศึกษาด้วยตนเอง
LangChain และ LangGraph: เฟรมเวิร์กสําหรับการพัฒนาแอปพลิเคชัน LLM
- ช่วยให้สร้างเวิร์กโฟลว์ที่ซับซ้อนซึ่งมีหลายตัวแทนได้
- เปิดใช้การจัดการเครื่องมืออย่างชาญฉลาด (การเรียก API, การค้นหาฐานข้อมูล, การค้นหาบนเว็บ)
- ใช้สถาปัตยกรรมที่ทำงานตามเหตุการณ์เพื่อความสามารถในการปรับขนาดและความยืดหยุ่นของระบบ
โดยพื้นฐานแล้ว สถาปัตยกรรมของเรารวมความสามารถของ LLM เข้ากับ Structured Data และการสื่อสารที่ทำงานตามเหตุการณ์ ซึ่งทั้งหมดนี้ทำงานบน Google Cloud ซึ่งช่วยให้เราสร้างผู้ช่วยสอนที่ปรับขนาดได้ เชื่อถือได้ และมีประสิทธิภาพ
3. ก่อนเริ่มต้น
ในคอนโซล Google Cloud ให้เลือกหรือสร้างโปรเจ็กต์ Google Cloud ในหน้าตัวเลือกโปรเจ็กต์ ตรวจสอบว่าเปิดใช้การเรียกเก็บเงินสำหรับโปรเจ็กต์ Cloud แล้ว ดูวิธีตรวจสอบว่าเปิดใช้การเรียกเก็บเงินในโปรเจ็กต์หรือไม่
👉คลิกเปิดใช้งาน Cloud Shell ที่ด้านบนของคอนโซล Google Cloud (ไอคอนรูปเทอร์มินัลที่ด้านบนของแผง Cloud Shell) คลิกปุ่ม "เปิดเครื่องมือแก้ไข" (มีลักษณะเป็นโฟลเดอร์ที่เปิดอยู่พร้อมดินสอ) ซึ่งจะเปิดเครื่องมือแก้ไขโค้ด Cloud Shell ในหน้าต่าง คุณจะเห็นโปรแกรมสำรวจไฟล์ทางด้านซ้าย
👉คลิกปุ่มลงชื่อเข้าใช้ Cloud Code ในแถบสถานะด้านล่างดังที่แสดง ให้สิทธิ์ปลั๊กอินตามที่ระบุ หากเห็น Cloud Code - no project ในแถบสถานะ ให้เลือกรายการนั้นในเมนูแบบเลื่อนลง "เลือกโปรเจ็กต์ Google Cloud" แล้วเลือกโปรเจ็กต์ Google Cloud ที่เฉพาะเจาะจงจากรายการโปรเจ็กต์ที่คุณสร้างขึ้น
👉เปิดเทอร์มินัลใน IDE บนระบบคลาวด์
👉ในเทอร์มินัล ให้ตรวจสอบว่าคุณตรวจสอบสิทธิ์แล้วและตั้งค่าโปรเจ็กต์เป็นรหัสโปรเจ็กต์ของคุณโดยใช้คำสั่งต่อไปนี้
gcloud auth list
👉แล้วเรียกใช้
gcloud config set project <YOUR_PROJECT_ID>
👉เรียกใช้คําสั่งต่อไปนี้เพื่อเปิดใช้ Google Cloud API ที่จําเป็น
gcloud services enable compute.googleapis.com \
storage.googleapis.com \
run.googleapis.com \
artifactregistry.googleapis.com \
aiplatform.googleapis.com \
eventarc.googleapis.com \
sqladmin.googleapis.com \
secretmanager.googleapis.com \
cloudbuild.googleapis.com \
cloudresourcemanager.googleapis.com \
cloudfunctions.googleapis.com
การดำเนินการนี้อาจใช้เวลาสักครู่
เปิดใช้ฟีเจอร์ช่วยเขียนโค้ด Gemini ใน IDE ของ Cloud Shell
คลิกปุ่มความช่วยเหลือเกี่ยวกับโค้ดในแผงด้านซ้ายดังที่แสดง แล้วเลือกโปรเจ็กต์ Google Cloud ที่ถูกต้องอีกครั้งเป็นครั้งสุดท้าย หากระบบขอให้คุณเปิดใช้ Cloud AI Companion API โปรดเปิดใช้และดำเนินการต่อ เมื่อเลือกโปรเจ็กต์ Google Cloud แล้ว ให้ตรวจสอบว่าคุณเห็นข้อความสถานะ Cloud Code ในแถบสถานะ และเปิดใช้การช่วยเขียนโค้ดทางด้านขวาในแถบสถานะดังที่แสดงด้านล่างด้วย
การตั้งค่าสิทธิ์
👉ตั้งค่าสิทธิ์ของบัญชีบริการ
export PROJECT_ID=$(gcloud config get project)
export SERVICE_ACCOUNT_NAME=$(gcloud compute project-info describe --format="value(defaultServiceAccount)")
echo "Here's your SERVICE_ACCOUNT_NAME $SERVICE_ACCOUNT_NAME"
ให้สิทธิ์ 👉Cloud Storage (อ่าน/เขียน):
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/storage.objectAdmin"
👉Pub/Sub (เผยแพร่/รับ):
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/pubsub.publisher"
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/pubsub.subscriber"
👉Cloud SQL (อ่าน/เขียน):
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/cloudsql.editor"
👉Eventarc (รับเหตุการณ์):
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/iam.serviceAccountTokenCreator"
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/eventarc.eventReceiver"
👉Vertex AI (ผู้ใช้):
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/aiplatform.user"
👉ผู้จัดการข้อมูลลับ (อ่าน):
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/secretmanager.secretAccessor"
👉ตรวจสอบผลลัพธ์ในคอนโซล IAM
4. การสร้างตัวแทนแรก
ก่อนที่จะเจาะลึกระบบหลายเอเจนต์ที่ซับซ้อน เราต้องสร้างรากฐานที่สำคัญก่อน ซึ่งก็คือเอเจนต์ที่ใช้งานได้เพียงตัวเดียว ในส่วนนี้ เราจะเริ่มต้นด้วยการสร้างตัวแทน "ผู้ให้บริการหนังสือ" แบบง่าย ตัวแทนผู้ให้บริการหนังสือจะรับหมวดหมู่เป็นอินพุตและใช้ LLM ของ Gemini เพื่อสร้างสมุดภาพตัวแทน JSON ภายในหมวดหมู่นั้น จากนั้นจะแสดงหนังสือแนะนำเหล่านี้เป็นปลายทาง REST API
👉ในแท็บเบราว์เซอร์อื่น ให้เปิด Google Cloud Console ในเว็บเบราว์เซอร์ จากนั้นไปที่ "Cloud Run" ในเมนูการนำทาง (☰) คลิกปุ่ม "+ ... เขียนฟังก์ชัน"
👉ต่อไปเราจะกําหนดการตั้งค่าพื้นฐานของฟังก์ชัน Cloud Run ดังนี้
- ชื่อบริการ:
book-provider
- ภูมิภาค:
us-central1
- รันไทม์:
Python 3.12
- การตรวจสอบสิทธิ์:
Allow unauthenticated invocations
เป็น "เปิดใช้"
👉ปล่อยการตั้งค่าอื่นๆ เป็นค่าเริ่มต้น แล้วคลิกสร้าง ซึ่งจะนำคุณไปยังเครื่องมือแก้ไขซอร์สโค้ด
คุณจะเห็นไฟล์ main.py
และ requirements.txt
ที่ระบบป้อนข้อมูลไว้ล่วงหน้า
main.py
จะมีตรรกะทางธุรกิจของฟังก์ชัน ส่วน requirements.txt
จะมีแพ็กเกจที่จำเป็น
👉ตอนนี้เราพร้อมที่จะเขียนโค้ดแล้ว แต่ก่อนที่จะเจาะลึกลงไป มาดูกันว่าฟีเจอร์ช่วยเขียนโค้ดของ Gemini จะช่วยให้เราเริ่มต้นได้เร็วขึ้นไหม กลับไปที่เครื่องมือแก้ไข Cloud Shell แล้วคลิกไอคอน Gemini Code Assist จากนั้นวางคําขอต่อไปนี้ลงในช่องพรอมต์
Use the functions_framework library to be deployable as an HTTP function.
Accept a request with category and number_of_book parameters (either in JSON body or query string).
Use langchain and gemini to generate the data for book with fields bookname, author, publisher, publishing_date.
Use pydantic to define a Book model with the fields: bookname (string, description: "Name of the book"), author (string, description: "Name of the author"), publisher (string, description: "Name of the publisher"), and publishing_date (string, description: "Date of publishing").
Use langchain and gemini model to generate book data. the output should follow the format defined in Book model.
The logic should use JsonOutputParser from langchain to enforce output format defined in Book Model.
Have a function get_recommended_books(category) that internally uses langchain and gemini to return a single book object.
The main function, exposed as the Cloud Function, should call get_recommended_books() multiple times (based on number_of_book) and return a JSON list of the generated book objects.
Handle the case where category or number_of_book are missing by returning an error JSON response with a 400 status code.
return a JSON string representing the recommended books. use os library to retrieve GOOGLE_CLOUD_PROJECT env var. Use ChatVertexAI from langchain for the LLM call
จากนั้นเครื่องมือช่วยเขียนโค้ดจะสร้างโซลูชันที่เป็นไปได้ โดยให้ทั้งซอร์สโค้ดและไฟล์ข้อกำหนด requirements.txt
เราขอแนะนำให้คุณเปรียบเทียบโค้ดที่ Code Assist สร้างขึ้นกับโซลูชันที่ถูกต้องซึ่งผ่านการทดสอบแล้วซึ่งให้ไว้ด้านล่าง ซึ่งจะช่วยให้คุณประเมินประสิทธิภาพของเครื่องมือและระบุความคลาดเคลื่อนที่อาจเกิดขึ้นได้ แม้ว่าไม่ควรเชื่อ LLM อย่างสุ่มสี่สุ่มห้า แต่เครื่องมือช่วยเขียนโค้ดก็ถือเป็นเครื่องมือที่ยอดเยี่ยมในการสร้างต้นแบบอย่างรวดเร็วและสร้างโครงสร้างโค้ดเริ่มต้น และควรนำมาใช้เพื่อเริ่มต้นที่ดี
เนื่องจากเป็นเวิร์กช็อป เราจะดำเนินการกับรหัสที่ยืนยันแล้วที่ระบุไว้ด้านล่าง อย่างไรก็ตาม คุณลองใช้โค้ดที่เครื่องมือช่วยเขียนโค้ดสร้างขึ้นในเวลาว่างเพื่อทําความเข้าใจความสามารถและข้อจํากัดของเครื่องมือนี้ให้ดียิ่งขึ้นได้
👉กลับไปที่เครื่องมือแก้ไขซอร์สโค้ดของฟังก์ชัน Cloud Run (ในแท็บเบราว์เซอร์อื่น) แทนที่เนื้อหาที่มีอยู่ของ main.py
ด้วยโค้ดที่ระบุไว้ด้านล่างอย่างระมัดระวัง
import functions_framework
import json
from flask import Flask, jsonify, request
from langchain_google_vertexai import ChatVertexAI
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.prompts import PromptTemplate
from pydantic import BaseModel, Field
import os
class Book(BaseModel):
bookname: str = Field(description="Name of the book")
author: str = Field(description="Name of the author")
publisher: str = Field(description="Name of the publisher")
publishing_date: str = Field(description="Date of publishing")
project_id = os.environ.get("GOOGLE_CLOUD_PROJECT")
llm = ChatVertexAI(model_name="gemini-1.0-pro")
def get_recommended_books(category):
"""
A simple book recommendation function.
Args:
category (str): category
Returns:
str: A JSON string representing the recommended books.
"""
parser = JsonOutputParser(pydantic_object=Book)
question = f"Generate a random made up book on {category} with bookname, author and publisher and publishing_date"
prompt = PromptTemplate(
template="Answer the user query.\n{format_instructions}\n{query}\n",
input_variables=["query"],
partial_variables={"format_instructions": parser.get_format_instructions()},
)
chain = prompt | llm | parser
response = chain.invoke({"query": question})
return json.dumps(response)
@functions_framework.http
def recommended(request):
request_json = request.get_json(silent=True) # Get JSON data
if request_json and 'category' in request_json and 'number_of_book' in request_json:
category = request_json['category']
number_of_book = int(request_json['number_of_book'])
elif request.args and 'category' in request.args and 'number_of_book' in request.args:
category = request.args.get('category')
number_of_book = int(request.args.get('number_of_book'))
else:
return jsonify({'error': 'Missing category or number_of_book parameters'}), 400
recommendations_list = []
for i in range(number_of_book):
book_dict = json.loads(get_recommended_books(category))
print(f"book_dict=======>{book_dict}")
recommendations_list.append(book_dict)
return jsonify(recommendations_list)
👉แทนที่เนื้อหาของ requirements.txt ด้วยข้อมูลต่อไปนี้
functions-framework==3.*
google-genai==1.0.0
flask==3.1.0
jsonify==0.5
langchain_google_vertexai==2.0.13
langchain_core==0.3.34
pydantic==2.10.5
👉เราจะตั้งค่าจุดแรกเข้าของฟังก์ชันเป็น recommended
👉คลิกบันทึกและทําให้การเผยแพร่เพื่อทําให้การเผยแพร่ฟังก์ชัน รอให้กระบวนการติดตั้งใช้งานเสร็จสมบูรณ์ Cloud Console จะแสดงสถานะ การดำเนินการนี้อาจใช้เวลาสักครู่
👉เมื่อติดตั้งใช้งานแล้ว ให้กลับไปที่เครื่องมือแก้ไข Cloud Shell แล้วเรียกใช้สิ่งต่อไปนี้ในเทอร์มินัล
export PROJECT_ID=$(gcloud config get project)
export BOOK_PROVIDER_URL=$(gcloud run services describe book-provider --region=us-central1 --project=$PROJECT_ID --format="value(status.url)")
curl -X POST -H "Content-Type: application/json" -d '{"category": "Science Fiction", "number_of_book": 2}' $BOOK_PROVIDER_URL
ซึ่งควรแสดงข้อมูลหนังสือบางส่วนในรูปแบบ JSON
[
{"author":"Anya Sharma","bookname":"Echoes of the Singularity","publisher":"NovaLight Publishing","publishing_date":"2077-03-15"},
{"author":"Anya Sharma","bookname":"Echoes of the Quantum Dawn","publisher":"Nova Genesis Publishing","publishing_date":"2077-03-15"}
]
ยินดีด้วย คุณทำให้ฟังก์ชัน Cloud Run ใช้งานได้เรียบร้อยแล้ว ซึ่งเป็นหนึ่งในบริการที่เราจะใช้รวมเข้ากับการพัฒนาตัวแทน Aidemy
5. เครื่องมือการสร้าง: การเชื่อมต่อตัวแทนกับบริการและข้อมูล RESTFUL
มาดาวน์โหลดโปรเจ็กต์โครง Bootstrap กัน ตรวจสอบว่าคุณอยู่ใน Cloud Shell Editor ในเทอร์มินัล ให้เรียกใช้
git clone https://github.com/weimeilin79/aidemy-bootstrap.git
หลังจากเรียกใช้คําสั่งนี้ ระบบจะสร้างโฟลเดอร์ใหม่ชื่อ aidemy-bootstrap
ในสภาพแวดล้อม Cloud Shell
ในแผง Explorer ของเครื่องมือแก้ไข Cloud Shell (ปกติจะอยู่ทางด้านซ้าย) คุณควรเห็นโฟลเดอร์ที่สร้างเมื่อคุณโคลนที่เก็บ Git aidemy-bootstrap
เปิดโฟลเดอร์รูทของโปรเจ็กต์ใน Explorer คุณจะเห็นโฟลเดอร์ย่อย planner
ภายในโฟลเดอร์ดังกล่าว ให้เปิดโฟลเดอร์ย่อยนั้นด้วย
มาเริ่มสร้างเครื่องมือที่ตัวแทนของเราจะใช้เพื่อให้เป็นประโยชน์อย่างแท้จริงกัน อย่างที่ทราบกันดีว่า LLM นั้นถนัดในการหาเหตุผลและสร้างข้อความ แต่จำเป็นต้องเข้าถึงแหล่งข้อมูลภายนอกเพื่อทำงานในชีวิตจริงและให้ข้อมูลที่ถูกต้องและเป็นปัจจุบัน เครื่องมือเหล่านี้เปรียบเสมือน "เครื่องมืออเนกประสงค์" ของตัวแทน ซึ่งช่วยให้สามารถโต้ตอบกับโลกภายนอกได้
เมื่อสร้างตัวแทน คุณอาจเขียนโค้ดรายละเอียดต่างๆ ไว้อย่างเจาะจงมากเกินไป ซึ่งจะสร้างตัวแทนที่ไม่ยืดหยุ่น แต่การสร้างและใช้เครื่องมือจะช่วยให้ตัวแทนเข้าถึงตรรกะหรือระบบภายนอกได้ ซึ่งให้ประโยชน์ทั้ง LLM และการเขียนโปรแกรมแบบดั้งเดิม
ในส่วนนี้ เราจะสร้างรากฐานให้กับตัวแทนเครื่องมือวางแผน ซึ่งครูจะใช้เพื่อสร้างแผนการสอน ก่อนที่ตัวแทนจะเริ่มสร้างแผน เราต้องการกําหนดขอบเขตโดยให้รายละเอียดเพิ่มเติมเกี่ยวกับเรื่องและหัวข้อ เราจะสร้างเครื่องมือ 3 อย่าง ได้แก่
- การเรียก Restful API: การโต้ตอบกับ API ที่มีอยู่เพื่อดึงข้อมูล
- การค้นหาฐานข้อมูล: การดึงข้อมูล Structured Data จากฐานข้อมูล Cloud SQL
- Google Search: การเข้าถึงข้อมูลแบบเรียลไทม์จากเว็บ
การดึงข้อมูลหนังสือแนะนำจาก API
ก่อนอื่นมาสร้างเครื่องมือที่ดึงข้อมูลหนังสือแนะนำจาก book-provider API ที่เราติดตั้งใช้งานในส่วนก่อนหน้า ตัวอย่างนี้แสดงให้เห็นวิธีที่ตัวแทนใช้ประโยชน์จากบริการที่มีอยู่
ใน Cloud Shell Editor ให้เปิดโปรเจ็กต์ aidemy-bootstrap
ที่คุณโคลนไว้ในส่วนก่อนหน้า 👉แก้ไข book.py
ในโฟลเดอร์ planner
แล้ววางโค้ดต่อไปนี้
def recommend_book(query: str):
"""
Get a list of recommended book from an API endpoint
Args:
query: User's request string
"""
region = get_next_region();
llm = VertexAI(model_name="gemini-1.5-pro", location=region)
query = f"""The user is trying to plan a education course, you are the teaching assistant. Help define the category of what the user requested to teach, respond the categroy with no more than two word.
user request: {query}
"""
print(f"-------->{query}")
response = llm.invoke(query)
print(f"CATEGORY RESPONSE------------>: {response}")
# call this using python and parse the json back to dict
category = response.strip()
headers = {"Content-Type": "application/json"}
data = {"category": category, "number_of_book": 2}
books = requests.post(BOOK_PROVIDER_URL, headers=headers, json=data)
return books.text
if __name__ == "__main__":
print(recommend_book("I'm doing a course for my 5th grade student on Math Geometry, I'll need to recommend few books come up with a teach plan, few quizes and also a homework assignment."))
คำอธิบาย:
- recommend_book(query: str): ฟังก์ชันนี้จะรับการค้นหาของผู้ใช้เป็นอินพุต
- การโต้ตอบ LLM: ใช้ LLM เพื่อดึงหมวดหมู่จากการค้นหา ตัวอย่างนี้แสดงวิธีใช้ LLM เพื่อช่วยสร้างพารามิเตอร์สําหรับเครื่องมือ
- การเรียก API: ดำเนินการส่งคำขอ POST ไปยัง API ของผู้ให้บริการหนังสือ โดยส่งหมวดหมู่และจำนวนหนังสือที่ต้องการ
👉หากต้องการทดสอบฟังก์ชันใหม่นี้ ให้ตั้งค่าตัวแปรสภาพแวดล้อม แล้วเรียกใช้ ดังนี้
cd ~/aidemy-bootstrap/planner/
export BOOK_PROVIDER_URL=$(gcloud run services describe book-provider --region=us-central1 --project=$PROJECT_ID --format="value(status.url)")
👉ติดตั้งการอ้างอิงและเรียกใช้โค้ดเพื่อให้แน่ใจว่าใช้งานได้ โดยให้เรียกใช้คำสั่งต่อไปนี้
cd ~/aidemy-bootstrap/planner/
python -m venv env
source env/bin/activate
export PROJECT_ID=$(gcloud config get project)
pip install -r requirements.txt
python book.py
ละเว้นหน้าต่างป๊อปอัปคำเตือนของ Git
คุณควรเห็นสตริง JSON ที่มีหนังสือแนะนำซึ่งดึงมาจาก API ของผู้ให้บริการหนังสือ
[{"author":"Anya Sharma","bookname":"Echoes of the Singularity","publisher":"NovaLight Publishing","publishing_date":"2077-03-15"},{"author":"Anya Sharma","bookname":"Echoes of the Quantum Dawn","publisher":"Nova Genesis Publishing","publishing_date":"2077-03-15"}]
หากเห็นข้อความนี้ แสดงว่าเครื่องมือแรกทำงานได้อย่างถูกต้อง
เราใช้ภาษาที่เป็นธรรมชาติ ("ฉันกำลังเรียนหลักสูตร...") แทนที่จะเขียนการเรียก RESTful API ด้วยพารามิเตอร์ที่เฉพาะเจาะจง จากนั้นตัวแทนจะดึงข้อมูลพารามิเตอร์ที่จําเป็น (เช่น หมวดหมู่) โดยใช้ NLP อย่างชาญฉลาด ซึ่งจะแสดงให้เห็นว่าตัวแทนใช้ประโยชน์จากความเข้าใจภาษาธรรมชาติเพื่อโต้ตอบกับ API อย่างไร
👉นํารหัสการทดสอบต่อไปนี้ออกจาก book.py
if __name__ == "__main__":
print(recommend_book("I'm doing a course for my 5th grade student on Math Geometry, I'll need to recommend few books come up with a teach plan, few quizes and also a homework assignment."))
การดึงข้อมูลหลักสูตรจากฐานข้อมูล
ต่อไป เราจะสร้างเครื่องมือที่ดึงข้อมูลหลักสูตรที่มีโครงสร้างจากฐานข้อมูล Cloud SQL PostgreSQL ซึ่งช่วยให้ตัวแทนเข้าถึงแหล่งข้อมูลที่เชื่อถือได้สำหรับการวางแผนบทเรียน
👉เรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัลเพื่อสร้างอินสแตนซ์ Cloud SQL ชื่อ aidemy กระบวนการนี้อาจใช้เวลาสักครู่
gcloud sql instances create aidemy \
--database-version=POSTGRES_14 \
--cpu=2 \
--memory=4GB \
--region=us-central1 \
--root-password=1234qwer \
--storage-size=10GB \
--storage-auto-increase
👉ถัดไป ให้สร้างฐานข้อมูลชื่อ aidemy-db
ในอินสแตนซ์ใหม่
gcloud sql databases create aidemy-db \
--instance=aidemy
มายืนยันอินสแตนซ์ใน Cloud SQL ใน Google Cloud Console กัน คุณควรเห็นอินสแตนซ์ Cloud SQL ชื่อ aidemy
แสดงอยู่ คลิกชื่ออินสแตนซ์เพื่อดูรายละเอียด ในหน้ารายละเอียดอินสแตนซ์ Cloud SQL ให้คลิก "SQL Studio" ในเมนูการนำทางด้านซ้ายมือ ซึ่งจะเป็นการเปิดแท็บใหม่
คลิกเพื่อเชื่อมต่อกับฐานข้อมูล ลงชื่อเข้าใช้ SQL Studio
เลือก aidemy-db
เป็นฐานข้อมูล ป้อน postgres
เป็นผู้ใช้ และ 1234qwer
เป็นรหัสผ่าน
👉วางโค้ด SQL ต่อไปนี้ในตัวแก้ไขคําค้นหาของ SQL Studio
CREATE TABLE curriculums (
id SERIAL PRIMARY KEY,
year INT,
subject VARCHAR(255),
description TEXT
);
-- Inserting detailed curriculum data for different school years and subjects
INSERT INTO curriculums (year, subject, description) VALUES
-- Year 5
(5, 'Mathematics', 'Introduction to fractions, decimals, and percentages, along with foundational geometry and problem-solving techniques.'),
(5, 'English', 'Developing reading comprehension, creative writing, and basic grammar, with a focus on storytelling and poetry.'),
(5, 'Science', 'Exploring basic physics, chemistry, and biology concepts, including forces, materials, and ecosystems.'),
(5, 'Computer Science', 'Basic coding concepts using block-based programming and an introduction to digital literacy.'),
-- Year 6
(6, 'Mathematics', 'Expanding on fractions, ratios, algebraic thinking, and problem-solving strategies.'),
(6, 'English', 'Introduction to persuasive writing, character analysis, and deeper comprehension of literary texts.'),
(6, 'Science', 'Forces and motion, the human body, and introductory chemical reactions with hands-on experiments.'),
(6, 'Computer Science', 'Introduction to algorithms, logical reasoning, and basic text-based programming (Python, Scratch).'),
-- Year 7
(7, 'Mathematics', 'Algebraic expressions, geometry, and introduction to statistics and probability.'),
(7, 'English', 'Analytical reading of classic and modern literature, essay writing, and advanced grammar skills.'),
(7, 'Science', 'Introduction to cells and organisms, chemical reactions, and energy transfer in physics.'),
(7, 'Computer Science', 'Building on programming skills with Python, introduction to web development, and cyber safety.');
โค้ด SQL นี้จะสร้างตารางชื่อ curriculums
และแทรกข้อมูลตัวอย่างบางส่วน คลิกเรียกใช้เพื่อเรียกใช้โค้ด SQL คุณควรเห็นข้อความยืนยันที่ระบุว่าระบบดําเนินการตามคําสั่งเรียบร้อยแล้ว
👉ขยายเครื่องมือสํารวจ ค้นหาตารางที่สร้างขึ้นใหม่ แล้วคลิกค้นหา ซึ่งจะเปิดแท็บเครื่องมือแก้ไขใหม่ที่มี SQL ที่สร้างขึ้นให้คุณ
SELECT * FROM
"public"."curriculums" LIMIT 1000;
👉คลิกเรียกใช้
ตารางผลลัพธ์ควรแสดงแถวข้อมูลที่คุณแทรกไว้ในขั้นตอนก่อนหน้า ซึ่งยืนยันว่าตารางและข้อมูลสร้างขึ้นอย่างถูกต้อง
เมื่อคุณสร้างฐานข้อมูลที่มีข้อมูลตัวอย่างหลักสูตรที่ป้อนข้อมูลแล้ว เราจะสร้างเครื่องมือเพื่อดึงข้อมูลดังกล่าว
👉ในเครื่องมือแก้ไขโค้ดบนระบบคลาวด์ ให้แก้ไขไฟล์ curriculums.py
ในโฟลเดอร์ aidemy-bootstrap
แล้ววางโค้ดต่อไปนี้
def connect_with_connector() -> sqlalchemy.engine.base.Engine:
db_user = os.environ["DB_USER"]
db_pass = os.environ["DB_PASS"]
db_name = os.environ["DB_NAME"]
encoded_db_user = os.environ.get("DB_USER")
print(f"--------------------------->db_user: {db_user!r}")
print(f"--------------------------->db_pass: {db_pass!r}")
print(f"--------------------------->db_name: {db_name!r}")
ip_type = IPTypes.PRIVATE if os.environ.get("PRIVATE_IP") else IPTypes.PUBLIC
connector = Connector()
def getconn() -> pg8000.dbapi.Connection:
conn: pg8000.dbapi.Connection = connector.connect(
instance_connection_name,
"pg8000",
user=db_user,
password=db_pass,
db=db_name,
ip_type=ip_type,
)
return conn
pool = sqlalchemy.create_engine(
"postgresql+pg8000://",
creator=getconn,
pool_size=2,
max_overflow=2,
pool_timeout=30, # 30 seconds
pool_recycle=1800, # 30 minutes
)
return pool
def init_connection_pool() -> sqlalchemy.engine.base.Engine:
return (
connect_with_connector()
)
raise ValueError(
"Missing database connection type. Please define one of INSTANCE_HOST, INSTANCE_UNIX_SOCKET, or INSTANCE_CONNECTION_NAME"
)
def get_curriculum(year: int, subject: str):
"""
Get school curriculum
Args:
subject: User's request subject string
year: User's request year int
"""
try:
stmt = sqlalchemy.text(
"SELECT description FROM curriculums WHERE year = :year AND subject = :subject"
)
with db.connect() as conn:
result = conn.execute(stmt, parameters={"year": year, "subject": subject})
row = result.fetchone()
if row:
return row[0]
else:
return None
except Exception as e:
print(e)
return None
db = init_connection_pool()
คำอธิบาย:
- ตัวแปรสภาพแวดล้อม: โค้ดจะดึงข้อมูลเข้าสู่ระบบฐานข้อมูลและข้อมูลการเชื่อมต่อจากตัวแปรสภาพแวดล้อม (ดูข้อมูลเพิ่มเติมด้านล่าง)
- connect_with_connector(): ฟังก์ชันนี้ใช้เครื่องมือเชื่อมต่อ Cloud SQL เพื่อสร้างการเชื่อมต่อที่ปลอดภัยกับฐานข้อมูล
- get_curriculum(year: int, subject: str): ฟังก์ชันนี้จะรับปีและวิชาเป็นอินพุต ค้นหาตารางหลักสูตร และแสดงคำอธิบายหลักสูตรที่เกี่ยวข้อง
👉ก่อนเรียกใช้โค้ดได้ เราต้องตั้งค่าตัวแปรสภาพแวดล้อมบางอย่าง โดยให้เรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัล
export PROJECT_ID=$(gcloud config get project)
export INSTANCE_NAME="aidemy"
export REGION="us-central1"
export DB_USER="postgres"
export DB_PASS="1234qwer"
export DB_NAME="aidemy-db"
👉หากต้องการทดสอบ ให้เพิ่มโค้ดต่อไปนี้ต่อท้าย curriculums.py
if __name__ == "__main__":
print(get_curriculum(6, "Mathematics"))
👉เรียกใช้โค้ด
cd ~/aidemy-bootstrap/planner/
source env/bin/activate
python curriculums.py
คุณควรเห็นคำอธิบายหลักสูตรคณิตศาสตร์ชั้นประถมศึกษาปีที่ 6 ที่พิมพ์ลงในคอนโซล
Expanding on fractions, ratios, algebraic thinking, and problem-solving strategies.
หากเห็นคำอธิบายหลักสูตร แสดงว่าเครื่องมือฐานข้อมูลทำงานได้อย่างถูกต้อง หยุดสคริปต์โดยกด Ctrl+C
👉นํารหัสการทดสอบต่อไปนี้ออกจาก curriculums.py
if __name__ == "__main__":
print(get_curriculum(6, "Mathematics"))
👉ออกจากสภาพแวดล้อมเสมือน ให้เรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัล
deactivate
6. เครื่องมือสร้าง: เข้าถึงข้อมูลแบบเรียลไทม์จากเว็บ
สุดท้าย เราจะสร้างเครื่องมือที่ใช้การผสานรวม Gemini 2 กับ Google Search เพื่อเข้าถึงข้อมูลแบบเรียลไทม์จากเว็บ ซึ่งจะช่วยให้ตัวแทนทราบข้อมูลล่าสุดและให้ผลลัพธ์ที่เกี่ยวข้อง
การผสานรวม Gemini 2 กับ Google Search API ช่วยเพิ่มความสามารถของตัวแทนด้วยการแสดงผลการค้นหาที่แม่นยำและเกี่ยวข้องกับบริบทมากขึ้น ซึ่งช่วยให้ตัวแทนเข้าถึงข้อมูลล่าสุดและตอบกลับด้วยข้อมูลในชีวิตจริงได้ เพื่อลดการคาดเดา การผสานรวม API ที่ปรับปรุงแล้วยังช่วยให้การค้นหาเป็นภาษาธรรมชาติได้ง่ายขึ้นด้วย ซึ่งช่วยให้ตัวแทนสามารถกำหนดคำขอการค้นหาที่ซับซ้อนและละเอียดยิ่งขึ้น
ฟังก์ชันนี้จะรับข้อความค้นหา หลักสูตร วิชา และปีเป็นอินพุต และใช้ Gemini API และเครื่องมือ Google Search เพื่อดึงข้อมูลที่เกี่ยวข้องจากอินเทอร์เน็ต หากมองอย่างละเอียด คุณจะเห็นว่าแอปใช้ Google Generative AI SDK ในการเรียกใช้ฟังก์ชันโดยไม่ต้องใช้เฟรมเวิร์กอื่นๆ
👉แก้ไข search.py
ในโฟลเดอร์ aidemy-bootstrap
แล้ววางโค้ดต่อไปนี้
model_id = "gemini-2.0-flash-001"
google_search_tool = Tool(
google_search = GoogleSearch()
)
def search_latest_resource(search_text: str, curriculum: str, subject: str, year: int):
"""
Get latest information from the internet
Args:
search_text: User's request category string
subject: "User's request subject" string
year: "User's request year" integer
"""
search_text = "%s in the context of year %d and subject %s with following curriculum detail %s " % (search_text, year, subject, curriculum)
region = get_next_region()
client = genai.Client(vertexai=True, project=PROJECT_ID, location=region)
print(f"search_latest_resource text-----> {search_text}")
response = client.models.generate_content(
model=model_id,
contents=search_text,
config=GenerateContentConfig(
tools=[google_search_tool],
response_modalities=["TEXT"],
)
)
print(f"search_latest_resource response-----> {response}")
return response
if __name__ == "__main__":
response = search_latest_resource("What are the syllabus for Year 6 Mathematics?", "Expanding on fractions, ratios, algebraic thinking, and problem-solving strategies.", "Mathematics", 6)
for each in response.candidates[0].content.parts:
print(each.text)
คำอธิบาย:
- การกําหนดเครื่องมือ - google_search_tool: การรวมออบเจ็กต์ GoogleSearch ภายในเครื่องมือ
- search_latest_resource(search_text: str, subject: str, year: int): ฟังก์ชันนี้จะรับข้อความค้นหา หัวข้อ และปีเป็นอินพุต และใช้ Gemini API เพื่อทำการค้นหาใน Google โมเดล Gemini
- GenerateContentConfig: กำหนดว่าผู้ใช้มีสิทธิ์เข้าถึงเครื่องมือ GoogleSearch
โมเดล Gemini จะวิเคราะห์ search_text ภายในและพิจารณาว่าจะตอบคำถามได้โดยตรงหรือต้องใช้เครื่องมือ GoogleSearch นี่เป็นขั้นตอนสําคัญที่เกิดขึ้นภายในกระบวนการใช้เหตุผลของ LLM โมเดลได้รับการฝึกให้จดจำสถานการณ์ที่ต้องใช้เครื่องมือภายนอก หากโมเดลตัดสินใจใช้เครื่องมือ GoogleSearch ทาง Google Generative AI SDK จะจัดการการเรียกใช้จริง SDK จะนําการตัดสินของโมเดลและพารามิเตอร์ที่สร้างขึ้นไปส่งไปยัง Google Search API ส่วนนี้ซ่อนอยู่จากผู้ใช้ในโค้ด
จากนั้นโมเดล Gemini จะผสานรวมผลการค้นหาไว้ในคำตอบ โดยใช้ข้อมูลดังกล่าวเพื่อตอบคําถามของผู้ใช้ สร้างข้อมูลสรุป หรือดําเนินการอื่นๆ
👉หากต้องการทดสอบ ให้เรียกใช้โค้ดดังนี้
cd ~/aidemy-bootstrap/planner/
export PROJECT_ID=$(gcloud config get project)
source env/bin/activate
python search.py
คุณควรเห็นการตอบกลับของ Gemini Search API ที่มีผลการค้นหาที่เกี่ยวข้องกับ "หลักสูตรคณิตศาสตร์ชั้นปีที่ 5" เอาต์พุตที่แน่นอนจะขึ้นอยู่กับผลการค้นหา แต่จะเป็นออบเจ็กต์ JSON ที่มีข้อมูลเกี่ยวกับการค้นหา
หากเห็นผลการค้นหา แสดงว่าเครื่องมือ Google Search ทํางานได้อย่างถูกต้อง หยุดสคริปต์โดยกด Ctrl+C
👉และนำส่วนสุดท้ายในโค้ดออก
if __name__ == "__main__":
response = search_latest_resource("What are the syllabus for Year 6 Mathematics?", "Expanding on fractions, ratios, algebraic thinking, and problem-solving strategies.", "Mathematics", 6)
for each in response.candidates[0].content.parts:
print(each.text)
👉ออกจากสภาพแวดล้อมเสมือน ให้เรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัล
deactivate
ยินดีด้วย ตอนนี้คุณสร้างเครื่องมือที่มีประสิทธิภาพ 3 รายการสําหรับตัวแทนผู้วางแผนแล้ว ได้แก่ เครื่องมือเชื่อมต่อ API, เครื่องมือเชื่อมต่อฐานข้อมูล และเครื่องมือ Google Search เครื่องมือเหล่านี้จะช่วยให้ตัวแทนเข้าถึงข้อมูลและความสามารถที่จำเป็นในการสร้างแผนการสอนที่มีประสิทธิภาพได้
7. การจัดการโดยใช้ LangGraph
เมื่อสร้างเครื่องมือแต่ละรายการแล้ว ก็ถึงเวลาจัดระเบียบเครื่องมือเหล่านั้นโดยใช้ LangGraph ซึ่งจะช่วยให้เราสร้างตัวแทน "ผู้วางแผน" ที่มีความซับซ้อนมากขึ้น ซึ่งสามารถตัดสินใจอย่างชาญฉลาดว่าควรใช้เครื่องมือใดและเมื่อใด โดยอิงตามคําขอของผู้ใช้
LangGraph เป็นไลบรารี Python ที่ออกแบบมาเพื่อช่วยให้คุณสร้างแอปพลิเคชันที่มีสถานะและผู้ใช้หลายคนโดยใช้โมเดลภาษาขนาดใหญ่ (LLM) ได้ง่ายขึ้น ให้คิดว่าเป็นเฟรมเวิร์กสำหรับจัดการการสนทนาและเวิร์กโฟลว์ที่ซับซ้อนซึ่งเกี่ยวข้องกับ LLM, เครื่องมือ และตัวแทนอื่นๆ
แนวคิดสําคัญ
- โครงสร้างกราฟ: LangGraph แสดงตรรกะของแอปพลิเคชันเป็นกราฟที่มีทิศทาง โหนดแต่ละรายการในกราฟแสดงถึงขั้นตอนในกระบวนการ (เช่น การเรียก LLM, การเรียกใช้เครื่องมือ, การตรวจสอบแบบมีเงื่อนไข) ขอบกําหนดขั้นตอนการดําเนินการระหว่างโหนด
- สถานะ: LangGraph จะจัดการสถานะของแอปพลิเคชันขณะที่ดำเนินการผ่านกราฟ สถานะนี้อาจมีตัวแปรต่างๆ เช่น อินพุตของผู้ใช้ ผลลัพธ์ของการเรียกใช้เครื่องมือ เอาต์พุตกลางจาก LLM และข้อมูลอื่นๆ ที่ต้องเก็บไว้ระหว่างขั้นตอน
- โหนด: แต่ละโหนดแสดงการคํานวณหรือการโต้ตอบ ซึ่งอาจเป็นสิ่งต่อไปนี้
- โหนดเครื่องมือ: ใช้เครื่องมือ (เช่น ทำการค้นหาบนเว็บ ค้นหาฐานข้อมูล)
- โหนดฟังก์ชัน: เรียกใช้ฟังก์ชัน Python
- ขอบ: เชื่อมต่อโหนด ซึ่งจะกําหนดลําดับการดําเนินการ ซึ่งอาจเป็นสิ่งต่อไปนี้
- ขอบโดยตรง: ขอบที่แสดงการไหลจากโหนดหนึ่งไปยังอีกโหนดหนึ่งแบบไม่มีเงื่อนไข
- ขอบแบบมีเงื่อนไข: ขั้นตอนจะขึ้นอยู่กับผลลัพธ์ของโหนดแบบมีเงื่อนไข
เราจะใช้ LangGraph เพื่อติดตั้งใช้งานการประสานงาน มาแก้ไขไฟล์ aidemy.py
ในโฟลเดอร์ aidemy-bootstrap
เพื่อกำหนดตรรกะ LangGraph กัน 👉เพิ่มโค้ดติดตามต่อท้าย aidemy.py
tools = [get_curriculum, search_latest_resource, recommend_book]
def determine_tool(state: MessagesState):
llm = ChatVertexAI(model_name="gemini-2.0-flash-001", location=get_next_region())
sys_msg = SystemMessage(
content=(
f"""You are a helpful teaching assistant that helps gather all needed information.
Your ultimate goal is to create a detailed 3-week teaching plan.
You have access to tools that help you gather information.
Based on the user request, decide which tool(s) are needed.
"""
)
)
llm_with_tools = llm.bind_tools(tools)
return {"messages": llm_with_tools.invoke([sys_msg] + state["messages"])}
ฟังก์ชันนี้มีหน้าที่นำสถานะปัจจุบันของการสนทนา ระบุข้อความระบบให้กับ LLM แล้วขอให้ LLM สร้างคำตอบ LLM สามารถตอบกลับผู้ใช้โดยตรงหรือเลือกใช้เครื่องมือใดเครื่องมือหนึ่งที่มีอยู่ก็ได้
tools : รายการนี้แสดงชุดเครื่องมือที่ตัวแทนมีให้ใช้งาน ซึ่งมีฟังก์ชันเครื่องมือ 3 รายการที่เรากำหนดไว้ในขั้นตอนก่อนหน้า ได้แก่ get_curriculum
, search_latest_resource
และ recommend_book
llm.bind_tools(tools): "เชื่อมโยง" รายการเครื่องมือกับออบเจ็กต์ llm การเชื่อมโยงเครื่องมือจะบอก LLM ว่าเครื่องมือเหล่านี้พร้อมใช้งานและแจ้งข้อมูลเกี่ยวกับวิธีใช้เครื่องมือ (เช่น ชื่อของเครื่องมือ พารามิเตอร์ที่ยอมรับ และสิ่งที่เครื่องมือทํา)
เราจะใช้ LangGraph เพื่อติดตั้งใช้งานการประสานงาน 👉เพิ่มโค้ดต่อไปนี้ต่อท้าย aidemy.py
def prep_class(prep_needs):
builder = StateGraph(MessagesState)
builder.add_node("determine_tool", determine_tool)
builder.add_node("tools", ToolNode(tools))
builder.add_edge(START, "determine_tool")
builder.add_conditional_edges("determine_tool",tools_condition)
builder.add_edge("tools", "determine_tool")
memory = MemorySaver()
graph = builder.compile(checkpointer=memory)
config = {"configurable": {"thread_id": "1"}}
messages = graph.invoke({"messages": prep_needs},config)
print(messages)
for m in messages['messages']:
m.pretty_print()
teaching_plan_result = messages["messages"][-1].content
return teaching_plan_result
if __name__ == "__main__":
prep_class("I'm doing a course for year 5 on subject Mathematics in Geometry, , get school curriculum, and come up with few books recommendation plus search latest resources on the internet base on the curriculum outcome. And come up with a 3 week teaching plan")
คำอธิบาย:
StateGraph(MessagesState)
: สร้างออบเจ็กต์StateGraph
StateGraph
เป็นแนวคิดหลักใน LangGraph ซึ่งแสดงเวิร์กโฟลว์ของตัวแทนเป็นกราฟ โดยแต่ละโหนดในกราฟแสดงขั้นตอนในกระบวนการ ลองนึกถึงการกำหนดพิมพ์เขียวสำหรับวิธีที่ตัวแทนจะหาเหตุผลและดำเนินการ- ขอบแบบมีเงื่อนไข: มาจากโหนด
"determine_tool"
โดยอาร์กิวเมนต์tools_condition
น่าจะเป็นฟังก์ชันที่กําหนดขอบที่จะติดตามตามเอาต์พุตของฟังก์ชันdetermine_tool
ขอบแบบมีเงื่อนไขช่วยให้กราฟแตกแขนงตามการตัดสินใจของ LLM เกี่ยวกับเครื่องมือที่จะใช้ (หรือจะตอบกลับผู้ใช้โดยตรงหรือไม่) ตรงนี้เป็นจุดที่ "ความฉลาด" ของตัวแทนเข้ามามีบทบาท โดยสามารถปรับเปลี่ยนลักษณะการทํางานแบบไดนามิกตามสถานการณ์ - ลูป: เพิ่มขอบในกราฟที่เชื่อมต่อโหนด
"tools"
กลับไปที่โหนด"determine_tool"
ซึ่งจะสร้างลูปในกราฟ ช่วยให้ตัวแทนใช้เครื่องมือซ้ำๆ ได้จนกว่าจะรวบรวมข้อมูลได้เพียงพอที่จะทํางานให้เสร็จสมบูรณ์และมอบคําตอบที่ตรงใจ ลูปนี้สําคัญสําหรับงานที่ซับซ้อนซึ่งต้องใช้การหาเหตุผลและการรวบรวมข้อมูลหลายขั้นตอน
ตอนนี้มาทดสอบตัวแทนเครื่องมือวางแผนเพื่อดูว่าเครื่องมือนี้จัดระเบียบเครื่องมือต่างๆ อย่างไร
โค้ดนี้จะเรียกใช้ฟังก์ชัน prep_class ด้วยอินพุตที่เฉพาะเจาะจงของผู้ใช้ โดยจำลองคําขอสร้างแผนการสอนสําหรับชั้นประถมศึกษาปีที่ 5 วิชาคณิตศาสตร์เรขาคณิต โดยใช้หลักสูตร คําแนะนําหนังสือ และแหล่งข้อมูลล่าสุดบนอินเทอร์เน็ต
หากคุณปิดเทอร์มินัลหรือไม่ได้ตั้งค่าตัวแปรสภาพแวดล้อมแล้ว ให้เรียกใช้คําสั่งต่อไปนี้อีกครั้ง
export BOOK_PROVIDER_URL=$(gcloud run services describe book-provider --region=us-central1 --project=$PROJECT_ID --format="value(status.url)")
export PROJECT_ID=$(gcloud config get project)
export INSTANCE_NAME="aidemy"
export REGION="us-central1"
export DB_USER="postgres"
export DB_PASS="1234qwer"
export DB_NAME="aidemy-db"
👉เรียกใช้โค้ด
cd ~/aidemy-bootstrap/planner/
source env/bin/activate
pip install -r requirements.txt
python aidemy.py
ดูบันทึกในเทอร์มินัล คุณควรเห็นหลักฐานว่าตัวแทนเรียกใช้เครื่องมือทั้ง 3 อย่าง (ดูหลักสูตรของโรงเรียน รับคำแนะนำหนังสือ และค้นหาแหล่งข้อมูลล่าสุด) ก่อนที่จะให้แผนการสอนขั้นสุดท้าย ซึ่งแสดงให้เห็นว่าการจัดเตรียม LangGraph ทํางานอย่างถูกต้อง และตัวแทนใช้เครื่องมือทั้งหมดที่มีอยู่อย่างชาญฉลาดเพื่อตอบสนองคําขอของผู้ใช้
================================ Human Message =================================
I'm doing a course for year 5 on subject Mathematics in Geometry, , get school curriculum, and come up with few books recommendation plus search latest resources on the internet base on the curriculum outcome. And come up with a 3 week teaching plan
================================== Ai Message ==================================
Tool Calls:
get_curriculum (xxx)
Call ID: xxx
Args:
year: 5.0
subject: Mathematics
================================= Tool Message =================================
Name: get_curriculum
Introduction to fractions, decimals, and percentages, along with foundational geometry and problem-solving techniques.
================================== Ai Message ==================================
Tool Calls:
search_latest_resource (xxxx)
Call ID: xxxx
Args:
year: 5.0
search_text: Geometry
curriculum: {"content": "Introduction to fractions, decimals, and percentages, along with foundational geometry and problem-solving techniques."}
subject: Mathematics
================================= Tool Message =================================
Name: search_latest_resource
candidates=[Candidate(content=Content(parts=[Part(.....) automatic_function_calling_history=[] parsed=None
================================== Ai Message ==================================
Tool Calls:
recommend_book (93b48189-4d69-4c09-a3bd-4e60cdc5f1c6)
Call ID: 93b48189-4d69-4c09-a3bd-4e60cdc5f1c6
Args:
query: Mathematics Geometry Year 5
================================= Tool Message =================================
Name: recommend_book
[{.....}]
================================== Ai Message ==================================
Based on the curriculum outcome, here is a 3-week teaching plan for year 5 Mathematics Geometry:
**Week 1: Introduction to Shapes and Properties**
.........
หยุดสคริปต์โดยกด Ctrl+C
👉ตอนนี้ ให้แทนที่โค้ดทดสอบด้วยพรอมต์อื่นซึ่งต้องใช้เครื่องมืออื่น
if __name__ == "__main__":
prep_class("I'm doing a course for year 5 on subject Mathematics in Geometry, search latest resources on the internet base on the subject. And come up with a 3 week teaching plan")
หากคุณปิดเทอร์มินัลหรือไม่ได้ตั้งค่าตัวแปรสภาพแวดล้อมแล้ว ให้เรียกใช้คําสั่งต่อไปนี้อีกครั้ง
export BOOK_PROVIDER_URL=$(gcloud run services describe book-provider --region=us-central1 --project=$PROJECT_ID --format="value(status.url)")
export PROJECT_ID=$(gcloud config get project)
export INSTANCE_NAME="aidemy"
export REGION="us-central1"
export DB_USER="postgres"
export DB_PASS="1234qwer"
export DB_NAME="aidemy-db"
👉เรียกใช้โค้ดอีกครั้ง
cd ~/aidemy-bootstrap/planner/
source env/bin/activate
python aidemy.py
คุณสังเกตเห็นอะไรบ้างในครั้งนี้ ตัวแทนเรียกใช้เครื่องมือใด คุณควรเห็นว่าตัวแทนเรียกใช้เครื่องมือ search_latest_resource เท่านั้นในครั้งนี้ เนื่องจากพรอมต์ไม่ได้ระบุว่าต้องใช้เครื่องมืออีก 2 รายการ และ LLM ของเราฉลาดพอที่จะไม่เรียกใช้เครื่องมืออื่นๆ
================================ Human Message =================================
I'm doing a course for year 5 on subject Mathematics in Geometry, search latest resources on the internet base on the subject. And come up with a 3 week teaching plan
================================== Ai Message ==================================
Tool Calls:
get_curriculum (xxx)
Call ID: xxx
Args:
year: 5.0
subject: Mathematics
================================= Tool Message =================================
Name: get_curriculum
Introduction to fractions, decimals, and percentages, along with foundational geometry and problem-solving techniques.
================================== Ai Message ==================================
Tool Calls:
search_latest_resource (xxx)
Call ID: xxxx
Args:
year: 5.0
subject: Mathematics
curriculum: {"content": "Introduction to fractions, decimals, and percentages, along with foundational geometry and problem-solving techniques."}
search_text: Geometry
================================= Tool Message =================================
Name: search_latest_resource
candidates=[Candidate(content=Content(parts=[Part(.......token_count=40, total_token_count=772) automatic_function_calling_history=[] parsed=None
================================== Ai Message ==================================
Based on the information provided, a 3-week teaching plan for Year 5 Mathematics focusing on Geometry could look like this:
**Week 1: Introducing 2D Shapes**
........
* Use visuals, manipulatives, and real-world examples to make the learning experience engaging and relevant.
หยุดสคริปต์โดยกด Ctrl+C
👉นําโค้ดการทดสอบออกเพื่อให้ไฟล์ aidemy.py สะอาดอยู่เสมอ
if __name__ == "__main__":
prep_class("I'm doing a course for year 5 on subject Mathematics in Geometry, search latest resources on the internet base on the subject. And come up with a 3 week teaching plan")
เมื่อกําหนดตรรกะการทำงานของตัวแทนแล้ว มาเปิดเว็บแอปพลิเคชัน Flask กัน ซึ่งจะเป็นอินเทอร์เฟซแบบฟอร์มที่คุ้นเคยสำหรับครูในการโต้ตอบกับตัวแทน แม้ว่าการโต้ตอบกับแชทบ็อตจะเป็นเรื่องปกติสำหรับ LLM แต่เราเลือกใช้ UI แบบส่งแบบฟอร์มแบบดั้งเดิม เนื่องจากอาจใช้งานได้ง่ายกว่าสำหรับนักการศึกษาจำนวนมาก
หากคุณปิดเทอร์มินัลหรือไม่ได้ตั้งค่าตัวแปรสภาพแวดล้อมแล้ว ให้เรียกใช้คําสั่งต่อไปนี้อีกครั้ง
export BOOK_PROVIDER_URL=$(gcloud run services describe book-provider --region=us-central1 --project=$PROJECT_ID --format="value(status.url)")
export PROJECT_ID=$(gcloud config get project)
export INSTANCE_NAME="aidemy"
export REGION="us-central1"
export DB_USER="postgres"
export DB_PASS="1234qwer"
export DB_NAME="aidemy-db"
👉จากนั้นเปิด Web UI
cd ~/aidemy-bootstrap/planner/
source env/bin/activate
python app.py
มองหาข้อความเริ่มต้นในเอาต์พุตเทอร์มินัลของ Cloud Shell โดยปกติแล้ว Flask จะพิมพ์ข้อความที่ระบุว่ากำลังทำงานอยู่และพอร์ตที่ใช้
Running on http://127.0.0.1:8080
Running on http://127.0.0.1:8080
The application needs to keep running to serve requests.
👉จากเมนู "ตัวอย่างเว็บ" ให้เลือก "แสดงตัวอย่างบนพอร์ต 8080" Cloud Shell จะเปิดแท็บหรือหน้าต่างเบราว์เซอร์ใหม่ที่มีตัวอย่างเว็บของแอปพลิเคชัน
ในอินเทอร์เฟซของแอปพลิเคชัน ให้เลือก 5
สำหรับปี เลือกวิชา Mathematics
และพิมพ์ Geometry
ในคำขอส่วนเสริม
แทนที่จะรอการตอบกลับโดยไร้จุดหมาย ให้เปลี่ยนไปใช้เทอร์มินัลของ Cloud Editor คุณสามารถดูความคืบหน้าและเอาต์พุตหรือข้อความแสดงข้อผิดพลาดที่ฟังก์ชันสร้างขึ้นได้ในเทอร์มินัลของโปรแกรมจำลอง 😁
👉หยุดสคริปต์โดยกด Ctrl+C
ในเทอร์มินัล
👉ออกจากสภาพแวดล้อมเสมือนจริง
deactivate
8. การติดตั้งใช้งาน Agent วางแผนในระบบคลาวด์
สร้างและพุชอิมเมจไปยังรีจิสทรี
👉ได้เวลาทำให้โมเดลนี้ใช้งานได้บนระบบคลาวด์ ในเทอร์มินัล ให้สร้างที่เก็บอาร์ติแฟกต์เพื่อจัดเก็บอิมเมจ Docker ที่เรากำลังจะสร้าง
gcloud artifacts repositories create agent-repository \
--repository-format=docker \
--location=us-central1 \
--description="My agent repository"
คุณควรเห็นที่เก็บที่สร้างขึ้น [agent-repository]
👉เรียกใช้คําสั่งต่อไปนี้เพื่อสร้างอิมเมจ Docker
cd ~/aidemy-bootstrap/planner/
export PROJECT_ID=$(gcloud config get project)
docker build -t gcr.io/${PROJECT_ID}/aidemy-planner .
👉เราต้องติดแท็กรูปภาพอีกครั้งเพื่อให้โฮสต์ใน Artifact Registry แทน GCR และพุชรูปภาพที่ติดแท็กไปยัง Artifact Registry โดยทำดังนี้
export PROJECT_ID=$(gcloud config get project)
docker tag gcr.io/${PROJECT_ID}/aidemy-planner us-central1-docker.pkg.dev/${PROJECT_ID}/agent-repository/aidemy-planner
docker push us-central1-docker.pkg.dev/${PROJECT_ID}/agent-repository/aidemy-planner
เมื่อการพุชเสร็จสมบูรณ์แล้ว คุณสามารถตรวจสอบว่าระบบจัดเก็บรูปภาพใน Artifact Registry เรียบร้อยแล้ว ไปที่ Artifact Registry ในคอนโซล Google Cloud คุณควรเห็นรูปภาพ aidemy-planner
ภายในที่เก็บ agent-repository
การรักษาความปลอดภัยของข้อมูลเข้าสู่ระบบฐานข้อมูลด้วย Secret Manager
เราจะใช้ Google Cloud Secret Manager เพื่อจัดการและเข้าถึงข้อมูลเข้าสู่ระบบฐานข้อมูลอย่างปลอดภัย วิธีนี้จะช่วยป้องกันการกำหนดข้อมูลที่ละเอียดอ่อนไว้ในโค้ดแอปพลิเคชันอย่างถาวรและเพิ่มความปลอดภัย
👉เราจะสร้างข้อมูลลับแยกต่างหากสำหรับชื่อผู้ใช้ รหัสผ่าน และชื่อฐานข้อมูล แนวทางนี้ช่วยให้เราจัดการข้อมูลเข้าสู่ระบบแต่ละรายการได้อย่างอิสระ ในเทอร์มินัล ให้เรียกใช้คำสั่งต่อไปนี้
gcloud secrets create db-user
printf "postgres" | gcloud secrets versions add db-user --data-file=-
gcloud secrets create db-pass
printf "1234qwer" | gcloud secrets versions add db-pass --data-file=-
gcloud secrets create db-name
printf "aidemy-db" | gcloud secrets versions add db-name --data-file=-
การใช้เครื่องมือจัดการข้อมูลลับเป็นขั้นตอนสําคัญในการรักษาความปลอดภัยของแอปพลิเคชันและป้องกันไม่ให้ข้อมูลเข้าสู่ระบบที่ละเอียดอ่อนเปิดเผยโดยไม่ตั้งใจ โดยเป็นไปตามแนวทางปฏิบัติแนะนำด้านความปลอดภัยสำหรับการใช้งานระบบคลาวด์
ทำให้ใช้งานได้กับ Cloud Run
Cloud Run เป็นแพลตฟอร์มแบบ Serverless ที่มีการจัดการครบวงจรซึ่งช่วยให้คุณทำให้แอปพลิเคชันที่มีคอนเทนเนอร์ใช้งานได้อย่างรวดเร็วและง่ายดาย ซึ่งตัดการจัดการโครงสร้างพื้นฐานออก เพื่อให้คุณมุ่งเน้นเฉพาะการเขียนและทำให้โค้ดใช้งานได้ เราจะทําให้เครื่องมือวางแผนเป็นบริการ Cloud Run
👉ไปที่ "Cloud Run" ในคอนโซล Google Cloud คลิกDEPLOY CONTAINER แล้วเลือก SERVICE กำหนดค่าบริการ Cloud Run โดยทำดังนี้
- รูปภาพคอนเทนเนอร์: คลิก "เลือก" ในช่อง URL ค้นหา URL ของรูปภาพที่คุณพุชไปยัง Artifact Registry (เช่น us-central1-docker.pkg.dev/YOUR_PROJECT_ID/agent-repository/agent-planner/YOUR_IMG)
- ชื่อบริการ:
aidemy-planner
- ภูมิภาค: เลือกภูมิภาค
us-central1
- การตรวจสอบสิทธิ์: สําหรับวัตถุประสงค์ของเวิร์กช็อปนี้ คุณสามารถอนุญาต "อนุญาตการเรียกใช้ที่ไม่ผ่านการตรวจสอบสิทธิ์" สําหรับเวอร์ชันที่ใช้งานจริง คุณอาจต้องจํากัดการเข้าถึง
- แท็บคอนเทนเนอร์ (ขยายคอนเทนเนอร์ เครือข่าย):
- แท็บการตั้งค่า:
- ทรัพยากร
- หน่วยความจำ : 2GB
- ทรัพยากร
- แท็บตัวแปรและข้อมูลลับ:
- ตัวแปรสภาพแวดล้อม:
- เพิ่มชื่อ:
GOOGLE_CLOUD_PROJECT
และค่า: <YOUR_PROJECT_ID> - เพิ่มชื่อ:
BOOK_PROVIDER_URL
และค่า: <YOUR_BOOK_PROVIDER_FUNCTION_URL>
- เพิ่มชื่อ:
- ข้อมูลลับที่เปิดเผยเป็นตัวแปรสภาพแวดล้อม:
- เพิ่มชื่อ:
DB_USER
, ข้อมูลลับ: เลือกdb-user
และเวอร์ชัน:latest
- เพิ่มชื่อ:
DB_PASS
, ข้อมูลลับ: เลือกdb-pass
และเวอร์ชัน:latest
- เพิ่มชื่อ:
DB_NAME
, ข้อมูลลับ: เลือกdb-name
และเวอร์ชัน:latest
- เพิ่มชื่อ:
- ตัวแปรสภาพแวดล้อม:
- แท็บการตั้งค่า:
เรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัลหากต้องการเรียกข้อมูล YOUR_BOOK_PROVIDER_FUNCTION_URL
gcloud run services describe book-provider --region=us-central1 --project=$PROJECT_ID --format="value(status.url)"
ปล่อยค่าอื่นๆ เป็นค่าเริ่มต้น
👉คลิกสร้าง
Cloud Run จะทําให้บริการใช้งานได้
เมื่อติดตั้งใช้งานแล้ว ให้คลิกบริการเพื่อไปยังหน้ารายละเอียด คุณจะดู URL ที่ติดตั้งใช้งานได้ที่ด้านบน
ในอินเทอร์เฟซการสมัคร ให้เลือก 7
สำหรับปี เลือก Mathematics
เป็นเรื่อง และป้อน Algebra
ในช่องคำขอส่วนเสริม ซึ่งจะช่วยให้ตัวแทนมีบริบทที่จำเป็นในการสร้างแผนการสอนที่ปรับให้เหมาะกับนักเรียน
ยินดีด้วย คุณสร้างแผนการเรียนการสอนโดยใช้ตัวแทน AI ที่มีประสิทธิภาพของเราเรียบร้อยแล้ว ข้อมูลนี้แสดงให้เห็นถึงศักยภาพของตัวแทนในการลดภาระงานและปรับปรุงงานให้มีประสิทธิภาพมากขึ้น ซึ่งจะช่วยเพิ่มประสิทธิภาพและช่วยให้ชีวิตง่ายขึ้นสำหรับนักการศึกษาในที่สุด
9. ระบบหลายตัวแทน
เมื่อติดตั้งใช้งานเครื่องมือสร้างแผนการสอนเรียบร้อยแล้ว เรามามุ่งเน้นที่การสร้างพอร์ทัลของนักเรียนกัน พอร์ทัลนี้จะให้สิทธิ์นักเรียนเข้าถึงแบบทดสอบ สรุปแบบเสียง และงานที่เกี่ยวข้องกับหลักสูตร เนื่องด้วยขอบเขตของฟังก์ชันการทำงานนี้ เราจะใช้ประโยชน์จากความสามารถของระบบหลายตัวแทนเพื่อสร้างโซลูชันแบบโมดูลที่ปรับขนาดได้
ดังที่ได้กล่าวไปก่อนหน้านี้ ระบบหลายตัวแทนช่วยให้เราแบ่งภาระงานออกเป็นงานขนาดเล็กๆ เฉพาะทางที่ตัวแทนแต่ละคนจัดการได้ แทนที่จะใช้ตัวแทนเพียงคนเดียวจัดการทุกอย่าง แนวทางนี้มีข้อดีหลักๆ ดังนี้
การแยกส่วนและการบำรุงรักษา: สร้างตัวแทนขนาดเล็กที่เชี่ยวชาญเฉพาะด้านซึ่งมีภาระหน้าที่ที่ชัดเจนแทนการสร้างตัวแทนตัวเดียวที่ทําทุกอย่าง ความเป็นโมดูลนี้ช่วยให้ระบบเข้าใจ ดูแลรักษา และแก้ไขข้อบกพร่องได้ง่ายขึ้น เมื่อเกิดปัญหา คุณสามารถแยกปัญหานั้นไปยังตัวแทนที่เฉพาะเจาะจงได้โดยไม่ต้องสแกนไปทั่วทั้งฐานโค้ดขนาดใหญ่
ความสามารถในการปรับขนาด: การปรับขนาดตัวแทนที่ซับซ้อนเพียงตัวเดียวอาจเป็นปัญหาคอขวด ระบบตัวแทนหลายรายช่วยให้คุณปรับขนาดตัวแทนแต่ละรายตามความต้องการเฉพาะได้ เช่น หากตัวแทนรายหนึ่งจัดการคําขอจํานวนมาก คุณสามารถเริ่มอินสแตนซ์ของตัวแทนรายนั้นเพิ่มได้ง่ายๆ โดยไม่ส่งผลกระทบต่อระบบส่วนที่เหลือ
ความเชี่ยวชาญของทีม: ลองคิดในอีกแง่หนึ่งว่า คุณคงไม่ขอให้วิศวกรเพียงคนเดียวสร้างแอปพลิเคชันทั้งแอปตั้งแต่ต้น แต่คุณควรรวบรวมทีมผู้เชี่ยวชาญที่มีความเชี่ยวชาญด้านต่างๆ ในทํานองเดียวกัน ระบบหลายเอเจนต์ช่วยให้คุณใช้ประโยชน์จากจุดแข็งของ LLM และเครื่องมือต่างๆ ได้ โดยกําหนดให้เอเจนต์เหมาะกับงานหนึ่งๆ มากที่สุด
การพัฒนาแบบขนาน: ทีมต่างๆ สามารถทํางานกับตัวแทนคนละคนพร้อมกันได้ ซึ่งจะช่วยเร่งกระบวนการพัฒนา เนื่องจากตัวแทนแต่ละรายทำงานอิสระ การเปลี่ยนแปลงตัวแทนรายหนึ่งจึงมีแนวโน้มที่จะไม่ส่งผลกระทบต่อตัวแทนรายอื่นๆ
สถาปัตยกรรมที่ทำงานตามเหตุการณ์
เราจะใช้สถาปัตยกรรมที่ทำงานตามเหตุการณ์เพื่อให้ตัวแทนเหล่านี้สื่อสารและประสานงานได้อย่างมีประสิทธิภาพ ซึ่งหมายความว่าตัวแทนจะตอบสนองต่อ "เหตุการณ์" ที่เกิดขึ้นภายในระบบ
ตัวแทนจะสมัครรับข้อมูลเหตุการณ์บางประเภท (เช่น "สร้างแผนการสอนแล้ว" "สร้างงานแล้ว") เมื่อเกิดเหตุการณ์ขึ้น ตัวแทนที่เกี่ยวข้องจะได้รับการแจ้งเตือนและสามารถดำเนินการตามความเหมาะสม การแยกส่วนนี้ช่วยเพิ่มความยืดหยุ่น ความสามารถในการปรับขนาด และการตอบสนองแบบเรียลไทม์
ในการเริ่มต้น เราต้องมีวิธีออกอากาศเหตุการณ์เหล่านี้ เราจะตั้งค่าหัวข้อ Pub/Sub เพื่อดำเนินการนี้ มาเริ่มกันด้วยการสร้างหัวข้อชื่อ plan
👉ไปที่ Google Cloud Console pub/sub แล้วคลิกปุ่ม "สร้างหัวข้อ"
👉กำหนดค่าหัวข้อด้วยรหัส/ชื่อ plan
และยกเลิกการเลือก Add a default subscription
ปล่อยให้ค่าที่เหลือเป็นค่าเริ่มต้น แล้วคลิกสร้าง
หน้า Pub/Sub จะรีเฟรช และคุณควรเห็นหัวข้อที่สร้างขึ้นใหม่แสดงอยู่ในตาราง
ตอนนี้มาผสานรวมฟังก์ชันการเผยแพร่เหตุการณ์ Pub/Sub กับตัวแทนเครื่องมือวางแผนกัน เราจะเพิ่มเครื่องมือใหม่ที่ส่งเหตุการณ์ "แผน" ไปยังหัวข้อ Pub/Sub ที่เพิ่งสร้างขึ้น เหตุการณ์นี้จะส่งสัญญาณให้ตัวแทนคนอื่นๆ ในระบบ (เช่น ตัวแทนในพอร์ทัลของนักเรียน) ทราบว่ามีแผนการสอนใหม่ให้ใช้งาน
👉กลับไปที่ Cloud Code Editor แล้วเปิดไฟล์ app.py
ในโฟลเดอร์ planner
เราจะเพิ่มฟังก์ชันที่เผยแพร่กิจกรรม แทนที่
##ADD SEND PLAN EVENT FUNCTION HERE
กับ
def send_plan_event(teaching_plan:str):
"""
Send the teaching event to the topic called plan
Args:
teaching_plan: teaching plan
"""
publisher = pubsub_v1.PublisherClient()
print(f"-------------> Sending event to topic plan: {teaching_plan}")
topic_path = publisher.topic_path(PROJECT_ID, "plan")
message_data = {"teaching_plan": teaching_plan}
data = json.dumps(message_data).encode("utf-8")
future = publisher.publish(topic_path, data)
return f"Published message ID: {future.result()}"
- send_plan_event: ฟังก์ชันนี้จะรับแผนการสอนที่สร้างขึ้นเป็นอินพุต สร้างไคลเอ็นต์ผู้เผยแพร่โฆษณา Pub/Sub สร้างเส้นทางหัวข้อ แปลงแผนการสอนเป็นสตริง JSON และเผยแพร่ข้อความไปยังหัวข้อ
- รายการเครื่องมือ: ระบบจะเพิ่มฟังก์ชัน
send_plan_event
ลงในรายการเครื่องมือเพื่อให้ตัวแทนใช้งานได้
และภายในโฟลเดอร์เดียวกัน ในไฟล์ app.py
ให้👉อัปเดตพรอมต์เพื่อสั่งให้ตัวแทนส่งเหตุการณ์ของแผนการสอนไปยังหัวข้อ Pub/Sub หลังจากสร้างแผนการสอน แทนที่
### ADD send_plan_event CALL
โดยใช้ข้อมูลต่อไปนี้
send_plan_event(teaching_plan)
การเพิ่มเครื่องมือ send_plan_event และการแก้ไขพรอมต์ช่วยให้เราเปิดใช้ตัวแทนผู้วางแผนเพื่อเผยแพร่เหตุการณ์ไปยัง Pub/Sub ซึ่งช่วยให้คอมโพเนนต์อื่นๆ ของระบบตอบสนองต่อการสร้างแผนการสอนใหม่ได้ ตอนนี้เราจะมีระบบหลายตัวแทนที่ใช้งานได้ในส่วนต่อไปนี้
10. ส่งเสริมศักยภาพนักเรียนด้วยแบบทดสอบแบบออนดีมานด์
ลองนึกถึงสภาพแวดล้อมการเรียนรู้ที่นักเรียนสามารถเข้าถึงแบบทดสอบมากมายที่ปรับให้เหมาะกับแผนการเรียนเฉพาะของตน แบบทดสอบเหล่านี้จะให้ความคิดเห็นทันที รวมถึงคำตอบและคำอธิบาย ซึ่งจะช่วยส่งเสริมความเข้าใจเนื้อหาให้ลึกซึ้งยิ่งขึ้น นี่คือศักยภาพที่เราต้องการปลดล็อกด้วยพอร์ทัลแบบทดสอบที่ทำงานด้วยระบบ AI
เราจะสร้างคอมโพเนนต์การสร้างแบบทดสอบที่สามารถสร้างคำถามแบบหลายตัวเลือกตามเนื้อหาของแผนการเรียนการสอนเพื่อทำให้วิสัยทัศน์นี้กลายเป็นจริง
👉ในแผง Explorer ของ Cloud Code Editor ให้ไปที่โฟลเดอร์ portal
เปิดไฟล์ quiz.py
แล้วคัดลอกและวางโค้ดต่อไปนี้ไว้ที่ท้ายไฟล์
def generate_quiz_question(file_name: str, difficulty: str, region:str ):
"""Generates a single multiple-choice quiz question using the LLM.
```json
{
"question": "The question itself",
"options": ["Option A", "Option B", "Option C", "Option D"],
"answer": "The correct answer letter (A, B, C, or D)"
}
```
"""
print(f"region: {region}")
# Connect to resourse needed from Google Cloud
llm = VertexAI(model_name="gemini-1.5-pro", location=region)
plan=None
#load the file using file_name and read content into string call plan
with open(file_name, 'r') as f:
plan = f.read()
parser = JsonOutputParser(pydantic_object=QuizQuestion)
instruction = f"You'll provide one question with difficulty level of {difficulty}, 4 options as multiple choices and provide the anwsers, the quiz needs to be related to the teaching plan {plan}"
prompt = PromptTemplate(
template="Generates a single multiple-choice quiz question\n {format_instructions}\n {instruction}\n",
input_variables=["instruction"],
partial_variables={"format_instructions": parser.get_format_instructions()},
)
chain = prompt | llm | parser
response = chain.invoke({"instruction": instruction})
print(f"{response}")
return response
ในเอเจนต์ โปรแกรมจะสร้างโปรแกรมแยกวิเคราะห์เอาต์พุต JSON ที่ออกแบบมาโดยเฉพาะเพื่อทำความเข้าใจและจัดโครงสร้างเอาต์พุตของ LLM โดยใช้รูปแบบ QuizQuestion
ที่เรากําหนดไว้ก่อนหน้านี้เพื่อให้เอาต์พุตที่แยกวิเคราะห์เป็นไปตามรูปแบบที่ถูกต้อง (คําถาม ตัวเลือก และคําตอบ)
👉เรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัลเพื่อตั้งค่าสภาพแวดล้อมเสมือน ติดตั้งส่วนที่ใช้อ้างอิง และเริ่มการทำงานของ Agent
cd ~/aidemy-bootstrap/portal/
python -m venv env
source env/bin/activate
pip install -r requirements.txt
python app.py
ใช้ฟีเจอร์ตัวอย่างเว็บของ Cloud Shell เพื่อเข้าถึงแอปพลิเคชันที่ทำงานอยู่ คลิกลิงก์ "แบบทดสอบ" ในแถบนําทางด้านบนหรือจากการ์ดในหน้าดัชนี คุณควรเห็นแบบทดสอบที่สร้างขึ้นแบบสุ่ม 3 รายการแสดงอยู่สำหรับนักเรียน แบบทดสอบเหล่านี้อิงตามแผนการเรียนการสอนและแสดงให้เห็นถึงประสิทธิภาพของระบบการสร้างแบบทดสอบที่ทำงานด้วยระบบ AI
หากต้องการหยุดกระบวนการที่ทำงานอยู่ภายในเครื่อง ให้กด Ctrl+C
ในเทอร์มินัล
การคํานวณของ Gemini 2 สําหรับคําอธิบาย
โอเค เรามีแบบทดสอบ ซึ่งเป็นจุดเริ่มต้นที่ดี แต่จะเกิดอะไรขึ้นหากนักเรียนตอบผิด นั่นคือการเรียนรู้ที่แท้จริงใช่ไหม หากเราอธิบายได้ว่าทำไมคำตอบจึงผิดและวิธีหาคำตอบที่ถูกต้อง นักเรียนก็จะมีแนวโน้มที่จะจำคำตอบนั้นๆ ได้มากกว่า ทั้งยังช่วยคลายความกังวลและเพิ่มความมั่นใจให้ผู้ใช้ด้วย
ด้วยเหตุนี้ เราจึงจะเปิดตัวอาวุธหนักอย่างโมเดล "การคิด" ของ Gemini 2 ซึ่งก็เหมือนกับการให้เวลา AI คิดสักครู่ก่อนที่จะอธิบาย ซึ่งจะช่วยให้ระบบแสดงความคิดเห็นที่ละเอียดและดีขึ้น
เราอยากทราบว่าฟีเจอร์นี้จะช่วยนักเรียนได้หรือไม่ด้วยการให้ความช่วยเหลือ ตอบคำถาม และอธิบายอย่างละเอียด เราจะทดสอบด้วยเรื่องแคลคูลัส ซึ่งเป็นวิชาที่ขึ้นชื่อเรื่องความยาก
👉ขั้นแรก ให้ไปที่เครื่องมือแก้ไขโค้ดในระบบคลาวด์ ใน answer.py
ภายในโฟลเดอร์ portal
ให้แทนที่
def answer_thinking(question, options, user_response, answer, region):
return ""
โดยมีข้อมูลโค้ดต่อไปนี้
def answer_thinking(question, options, user_response, answer, region):
try:
llm = VertexAI(model_name="gemini-2.0-flash-001",location=region)
input_msg = HumanMessage(content=[f"Here the question{question}, here are the available options {options}, this student's answer {user_response}, whereas the correct answer is {answer}"])
prompt_template = ChatPromptTemplate.from_messages(
[
SystemMessage(
content=(
"You are a helpful teacher trying to teach the student on question, you were given the question and a set of multiple choices "
"what's the correct answer. use friendly tone"
)
),
input_msg,
]
)
prompt = prompt_template.format()
response = llm.invoke(prompt)
print(f"response: {response}")
return response
except Exception as e:
print(f"Error sending message to chatbot: {e}") # Log this error too!
return f"Unable to process your request at this time. Due to the following reason: {str(e)}"
if __name__ == "__main__":
question = "Evaluate the limit: lim (x→0) [(sin(5x) - 5x) / x^3]"
options = ["A) -125/6", "B) -5/3 ", "C) -25/3", "D) -5/6"]
user_response = "B"
answer = "A"
region = "us-central1"
result = answer_thinking(question, options, user_response, answer, region)
แอปนี้เป็นแอป Langchain ที่เรียบง่ายมาก ซึ่งจะเริ่มต้นโมเดล Gemini 2 Flash โดยเรากําหนดให้แอปทำหน้าที่เป็นครูที่มีประโยชน์และให้คําอธิบาย
👉เรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัล
cd ~/aidemy-bootstrap/portal/
python answer.py
คุณควรเห็นเอาต์พุตที่คล้ายกับตัวอย่างที่ให้ไว้ในวิธีการเดิม โมเดลปัจจุบันอาจให้คำอธิบายไม่ละเอียด
Okay, I see the question and the choices. The question is to evaluate the limit:
lim (x→0) [(sin(5x) - 5x) / x^3]
You chose option B, which is -5/3, but the correct answer is A, which is -125/6.
It looks like you might have missed a step or made a small error in your calculations. This type of limit often involves using L'Hôpital's Rule or Taylor series expansion. Since we have the form 0/0, L'Hôpital's Rule is a good way to go! You need to apply it multiple times. Alternatively, you can use the Taylor series expansion of sin(x) which is:
sin(x) = x - x^3/3! + x^5/5! - ...
So, sin(5x) = 5x - (5x)^3/3! + (5x)^5/5! - ...
Then, (sin(5x) - 5x) = - (5x)^3/3! + (5x)^5/5! - ...
Finally, (sin(5x) - 5x) / x^3 = - 5^3/3! + (5^5 * x^2)/5! - ...
Taking the limit as x approaches 0, we get -125/6.
Keep practicing, you'll get there!
ในไฟล์ answer.py ให้แทนที่ model_name จาก gemini-2.0-flash-001
เป็น gemini-2.0-flash-thinking-exp-01-21
ในฟังก์ชัน answer_thinking
ซึ่งจะเปลี่ยน LLM ให้ใช้เหตุผลมากขึ้น ซึ่งจะช่วยให้สร้างคำอธิบายได้ดียิ่งขึ้น แล้วเรียกใช้อีกครั้ง
👉เรียกใช้เพื่อทดสอบรูปแบบการคิดใหม่
cd ~/aidemy-bootstrap/portal/
source env/bin/activate
python answer.py
ต่อไปนี้คือตัวอย่างคำตอบจากโมเดลการคิดที่ละเอียดและครอบคลุมมากขึ้น โดยให้คำอธิบายแบบทีละขั้นตอนเกี่ยวกับวิธีแก้ปัญหาแคลคูลัส ซึ่งแสดงให้เห็นถึงความสามารถของโมเดล "การคิด" ในการสร้างคำอธิบายคุณภาพสูง คุณควรเห็นเอาต์พุตในลักษณะนี้
Hey there! Let's take a look at this limit problem together. You were asked to evaluate:
lim (x→0) [(sin(5x) - 5x) / x^3]
and you picked option B, -5/3, but the correct answer is actually A, -125/6. Let's figure out why!
It's a tricky one because if we directly substitute x=0, we get (sin(0) - 0) / 0^3 = (0 - 0) / 0 = 0/0, which is an indeterminate form. This tells us we need to use a more advanced technique like L'Hopital's Rule or Taylor series expansion.
Let's use the Taylor series expansion for sin(y) around y=0. Do you remember it? It looks like this:
sin(y) = y - y^3/3! + y^5/5! - ...
where 3! (3 factorial) is 3 × 2 × 1 = 6, 5! is 5 × 4 × 3 × 2 × 1 = 120, and so on.
In our problem, we have sin(5x), so we can substitute y = 5x into the Taylor series:
sin(5x) = (5x) - (5x)^3/3! + (5x)^5/5! - ...
sin(5x) = 5x - (125x^3)/6 + (3125x^5)/120 - ...
Now let's plug this back into our limit expression:
[(sin(5x) - 5x) / x^3] = [ (5x - (125x^3)/6 + (3125x^5)/120 - ...) - 5x ] / x^3
Notice that the '5x' and '-5x' cancel out! So we are left with:
= [ - (125x^3)/6 + (3125x^5)/120 - ... ] / x^3
Now, we can divide every term in the numerator by x^3:
= -125/6 + (3125x^2)/120 - ...
Finally, let's take the limit as x approaches 0. As x gets closer and closer to zero, terms with x^2 and higher powers will become very, very small and approach zero. So, we are left with:
lim (x→0) [ -125/6 + (3125x^2)/120 - ... ] = -125/6
Therefore, the correct answer is indeed **A) -125/6**.
It seems like your answer B, -5/3, might have come from perhaps missing a factor somewhere during calculation or maybe using an incorrect simplification. Double-check your steps when you were trying to solve it!
Don't worry, these limit problems can be a bit tricky sometimes! Keep practicing and you'll get the hang of it. Let me know if you want to go through another similar example or if you have any more questions! 😊
Now that we have confirmed it works, let's use the portal.
👉นําโค้ดทดสอบต่อไปนี้ออกจาก answer.py
if __name__ == "__main__":
question = "Evaluate the limit: lim (x→0) [(sin(5x) - 5x) / x^3]"
options = ["A) -125/6", "B) -5/3 ", "C) -25/3", "D) -5/6"]
user_response = "B"
answer = "A"
region = "us-central1"
result = answer_thinking(question, options, user_response, answer, region)
👉เรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัลเพื่อตั้งค่าสภาพแวดล้อมเสมือน ติดตั้งส่วนที่ใช้อ้างอิง และเริ่มการทำงานของ Agent
cd ~/aidemy-bootstrap/portal/
source env/bin/activate
python app.py
👉ใช้ฟีเจอร์ตัวอย่างเว็บของ Cloud Shell เพื่อเข้าถึงแอปพลิเคชันที่ทำงานอยู่ คลิกลิงก์ "แบบทดสอบ" ตอบแบบทดสอบทั้งหมดและตอบผิดอย่างน้อย 1 ข้อ แล้วคลิก "ส่ง"
แทนที่จะรอการตอบกลับโดยไร้จุดหมาย ให้เปลี่ยนไปใช้เทอร์มินัลของ Cloud Editor คุณสามารถดูความคืบหน้าและเอาต์พุตหรือข้อความแสดงข้อผิดพลาดที่ฟังก์ชันสร้างขึ้นได้ในเทอร์มินัลของโปรแกรมจำลอง 😁
หากต้องการหยุดกระบวนการที่ทำงานอยู่ภายในเครื่อง ให้กด Ctrl+C
ในเทอร์มินัล
11. การจัดการ Agent ด้วย Eventarc
จนถึงตอนนี้ พอร์ทัลของนักเรียนสร้างแบบทดสอบตามชุดแผนการสอนเริ่มต้น ซึ่งมีประโยชน์ แต่หมายความว่าเอเจนต์เครื่องมือวางแผนของเราและเเจนต์แบบทดสอบของพอร์ทัลไม่ได้สื่อสารกันจริงๆ คุณยังจำได้ไหมว่าเราเพิ่มฟีเจอร์ที่ตัวแทนผู้วางแผนเผยแพร่แผนการสอนที่สร้างขึ้นใหม่ไปยังหัวข้อ Pub/Sub ถึงเวลาเชื่อมต่อกับตัวแทนพอร์ทัลแล้ว
เราต้องการให้พอร์ทัลอัปเดตเนื้อหาแบบทดสอบโดยอัตโนมัติทุกครั้งที่มีการสร้างแผนการเรียนการสอนใหม่ โดยเราจะสร้างปลายทางในพอร์ทัลที่รับแผนใหม่เหล่านี้ได้
👉ในแผง Explorer ของ Cloud Code Editor ให้ไปที่โฟลเดอร์ portal
เปิดไฟล์ app.py
เพื่อแก้ไข เพิ่มโค้ดต่อไปนี้ระหว่าง ## เพิ่มโค้ดของคุณที่นี่
## Add your code here
@app.route('/new_teaching_plan', methods=['POST'])
def new_teaching_plan():
try:
# Get data from Pub/Sub message delivered via Eventarc
envelope = request.get_json()
if not envelope:
return jsonify({'error': 'No Pub/Sub message received'}), 400
if not isinstance(envelope, dict) or 'message' not in envelope:
return jsonify({'error': 'Invalid Pub/Sub message format'}), 400
pubsub_message = envelope['message']
print(f"data: {pubsub_message['data']}")
data = pubsub_message['data']
data_str = base64.b64decode(data).decode('utf-8')
data = json.loads(data_str)
teaching_plan = data['teaching_plan']
print(f"File content: {teaching_plan}")
with open("teaching_plan.txt", "w") as f:
f.write(teaching_plan)
print(f"Teaching plan saved to local file: teaching_plan.txt")
return jsonify({'message': 'File processed successfully'})
except Exception as e:
print(f"Error processing file: {e}")
return jsonify({'error': 'Error processing file'}), 500
## Add your code here
การสร้างใหม่และทำให้ใช้งานได้ใน Cloud Run
โอเค คุณจะต้องอัปเดตและทำให้ทั้งตัววางแผนและตัวแทนพอร์ทัลของเราใช้งานได้ใน Cloud Run อีกครั้ง ซึ่งจะช่วยให้มั่นใจได้ว่าอุปกรณ์จะมีโค้ดล่าสุดและได้รับการกําหนดค่าให้สื่อสารผ่านเหตุการณ์
👉ถัดไปเราจะสร้างและพุชรูปภาพตัวแทน planner อีกครั้งในเทอร์มินัล
cd ~/aidemy-bootstrap/planner/
export PROJECT_ID=$(gcloud config get project)
docker build -t gcr.io/${PROJECT_ID}/aidemy-planner .
export PROJECT_ID=$(gcloud config get project)
docker tag gcr.io/${PROJECT_ID}/aidemy-planner us-central1-docker.pkg.dev/${PROJECT_ID}/agent-repository/aidemy-planner
docker push us-central1-docker.pkg.dev/${PROJECT_ID}/agent-repository/aidemy-planner
👉เราจะทำแบบเดียวกัน โดยสร้างและพุชรูปภาพตัวแทน portal ดังนี้
cd ~/aidemy-bootstrap/portal/
export PROJECT_ID=$(gcloud config get project)
docker build -t gcr.io/${PROJECT_ID}/aidemy-portal .
export PROJECT_ID=$(gcloud config get project)
docker tag gcr.io/${PROJECT_ID}/aidemy-portal us-central1-docker.pkg.dev/${PROJECT_ID}/agent-repository/aidemy-portal
docker push us-central1-docker.pkg.dev/${PROJECT_ID}/agent-repository/aidemy-portal
ใน Artifact Registry คุณควรเห็นทั้งอิมเมจคอนเทนเนอร์ aidemy-planner
และ aidemy-portal
แสดงอยู่
👉กลับไปที่เทอร์มินัล แล้วเรียกใช้คำสั่งนี้เพื่ออัปเดตอิมเมจ Cloud Run สําหรับตัวแทนผู้วางแผน
export PROJECT_ID=$(gcloud config get project)
gcloud run services update aidemy-planner \
--region=us-central1 \
--image=us-central1-docker.pkg.dev/${PROJECT_ID}/agent-repository/aidemy-planner:latest
คุณควรเห็นเอาต์พุตในลักษณะนี้
OK Deploying... Done.
OK Creating Revision...
OK Routing traffic...
Done.
Service [aidemy-planner] revision [aidemy-planner-xxxxx] has been deployed and is serving 100 percent of traffic.
Service URL: https://aidemy-planner-xxx.us-central1.run.app
จด URL ของบริการไว้ ซึ่งเป็นลิงก์ไปยังตัวแทนแผนировщикที่ติดตั้งใช้งาน
👉เรียกใช้คำสั่งนี้เพื่อสร้างอินสแตนซ์ Cloud Run สำหรับตัวแทน portal
export PROJECT_ID=$(gcloud config get project)
gcloud run deploy aidemy-portal \
--image=us-central1-docker.pkg.dev/${PROJECT_ID}/agent-repository/aidemy-portal:latest \
--region=us-central1 \
--platform=managed \
--allow-unauthenticated \
--memory=2Gi \
--cpu=2 \
--set-env-vars=GOOGLE_CLOUD_PROJECT=${PROJECT_ID}
คุณควรเห็นเอาต์พุตในลักษณะนี้
Deploying container to Cloud Run service [aidemy-portal] in project [xxxx] region [us-central1]
OK Deploying new service... Done.
OK Creating Revision...
OK Routing traffic...
OK Setting IAM Policy...
Done.
Service [aidemy-portal] revision [aidemy-portal-xxxx] has been deployed and is serving 100 percent of traffic.
Service URL: https://aidemy-portal-xxxx.us-central1.run.app
จด URL ของบริการไว้ ซึ่งจะเป็นลิงก์ไปยังพอร์ทัลของนักเรียนที่ติดตั้งใช้งาน
การสร้างทริกเกอร์ Eventarc
แต่คำถามสำคัญคือ ปลายทางนี้จะได้รับการแจ้งเตือนอย่างไรเมื่อมีแผนใหม่รออยู่ในหัวข้อ Pub/Sub Eventarc จะช่วยแก้ปัญหานี้
Eventarc จะทำหน้าที่เป็นบริดจ์ที่คอยเฝ้าติดตามเหตุการณ์ที่เฉพาะเจาะจง (เช่น ข้อความใหม่ที่มาถึงในหัวข้อ Pub/Sub) และเรียกการดำเนินการเพื่อตอบสนองโดยอัตโนมัติ ในกรณีของเรา ฟีเจอร์นี้จะตรวจหาเมื่อมีการเผยแพร่แผนการเรียนการสอนใหม่ จากนั้นส่งสัญญาณไปยังปลายทางของพอร์ทัลเพื่อแจ้งให้ทราบถึงเวลาที่ควรอัปเดต
เมื่อ Eventarc จัดการการสื่อสารที่ทำงานตามเหตุการณ์ เราจึงเชื่อมต่อตัวแทนผู้วางแผนและตัวแทนพอร์ทัลได้อย่างราบรื่น ซึ่งสร้างระบบการเรียนรู้ที่ตอบสนองและเปลี่ยนแปลงได้จริง ฟีเจอร์นี้เหมือนกับการมีผู้ส่งข้อความอัจฉริยะที่ส่งแผนบทเรียนล่าสุดไปยังที่ที่ถูกต้องโดยอัตโนมัติ
👉ในคอนโซล ให้ไปที่ Eventarc
👉คลิกปุ่ม "+ สร้างทริกเกอร์"
กําหนดค่าทริกเกอร์ (ข้อมูลเบื้องต้น)
- ชื่อทริกเกอร์:
plan-topic-trigger
- ประเภททริกเกอร์: แหล่งที่มาของ Google
- ผู้ให้บริการเหตุการณ์: Cloud Pub/Sub
- ประเภทกิจกรรม:
google.cloud.pubsub.topic.v1.messagePublished
- ภูมิภาค:
us-central1
- หัวข้อ Cloud Pub/Sub : เลือก
plan
- ให้สิทธิ์บัญชีบริการที่มีบทบาท
roles/iam.serviceAccountTokenCreator
- ปลายทางของเหตุการณ์: Cloud Run
- บริการ Cloud Run: aidemy-portal
- เส้นทาง URL บริการ:
/new_teaching_plan
- ละเว้นข้อความ (ปฏิเสธสิทธิ์ใน "locations/me-central2" (หรืออาจไม่มีอยู่))
คลิก "สร้าง"
หน้าทริกเกอร์ Eventarc จะรีเฟรช และตอนนี้คุณควรเห็นทริกเกอร์ที่สร้างใหม่แสดงอยู่ในตาราง
👉จากนั้นไปที่เครื่องมือวางแผนและขอแผนการสอนใหม่ คราวนี้ให้ลองใช้ปี 5
เรื่อง science
กับ Add-no request atoms
เรียกใช้คำสั่งนี้ในเทอร์มินัลหากคุณลืมตำแหน่งของตัวแทนแผนировщик
gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep planner
จากนั้นรอ 1-2 นาที อีกครั้งความล่าช้านี้เกิดขึ้นเนื่องจากข้อจํากัดในการเรียกเก็บเงินของห้องทดลองนี้ ภายใต้สภาวะปกติจะไม่เกิดความล่าช้า
สุดท้าย ให้ไปที่พอร์ทัลของนักเรียน คุณควรเห็นว่าแบบทดสอบได้รับการอัปเดตและสอดคล้องกับแผนการสอนใหม่ที่คุณเพิ่งสร้างขึ้นแล้ว การดำเนินการนี้แสดงให้เห็นว่าการผสานรวม Eventarc ในระบบ Aidemy ประสบความสำเร็จ
เรียกใช้คำสั่งนี้ในเทอร์มินัลหากคุณลืมตำแหน่งของตัวแทนพอร์ทัล
gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep portal
ยินดีด้วย คุณสร้างระบบหลายตัวแทนใน Google Cloud โดยใช้สถาปัตยกรรมที่ทำงานตามเหตุการณ์เพื่อเพิ่มความยืดหยุ่นและความสามารถในการปรับขนาดได้แล้ว คุณวางรากฐานที่มั่นคงแล้ว แต่ยังมีอีกมากมายให้สำรวจ หากต้องการเจาะลึกประโยชน์ที่แท้จริงของสถาปัตยกรรมนี้ โปรดดูประสิทธิภาพของ Live API แบบหลายรูปแบบของ Gemini 2 และเรียนรู้วิธีใช้การประสานงานแบบเส้นทางเดียวด้วย LangGraph โดยไปที่บทถัดไป 2 บท
12. ไม่บังคับ: สรุปแบบเสียงด้วย Gemini
Gemini สามารถเข้าใจและประมวลผลข้อมูลจากแหล่งที่มาต่างๆ เช่น ข้อความ รูปภาพ และแม้แต่เสียง ซึ่งเปิดโอกาสใหม่ๆ มากมายสำหรับการเรียนรู้และการสร้างเนื้อหา ความสามารถในการ "เห็น" "ได้ยิน" และ "อ่าน" ของ Gemini ช่วยปลดล็อกประสบการณ์ของผู้ใช้ที่สร้างสรรค์และน่าสนใจอย่างแท้จริง
นอกจากการสร้างภาพหรือข้อความแล้ว ขั้นตอนสำคัญอีกอย่างหนึ่งในการเรียนรู้คือการสรุปและทบทวนอย่างมีประสิทธิภาพ ลองคิดดูว่าคุณจำเนื้อเพลงที่ติดหูได้ง่ายกว่าสิ่งที่อ่านในตำราเรียนบ่อยแค่ไหน เสียงเป็นสิ่งที่น่าจดจําได้อย่างไม่น่าเชื่อ ด้วยเหตุนี้ เราจึงจะใช้ประโยชน์จากความสามารถแบบมัลติโมเดลของ Gemini เพื่อสร้างสรุปเสียงของแผนการสอน ซึ่งจะช่วยให้นักเรียนมีวิธีทบทวนเนื้อหาที่สะดวกและน่าสนใจ ซึ่งอาจช่วยเพิ่มการจดจำและความเข้าใจผ่านการเรียนรู้ด้วยเสียง
เราต้องมีที่เก็บไฟล์เสียงที่สร้างขึ้น Cloud Storage เป็นโซลูชันที่ปรับขนาดได้และเชื่อถือได้
👉ไปที่พื้นที่เก็บข้อมูลในคอนโซล คลิก "ที่เก็บข้อมูล" ในเมนูด้านซ้ายมือ คลิกปุ่ม "+ สร้าง" ที่ด้านบน
👉กำหนดค่าที่เก็บข้อมูล
- ชื่อที่เก็บข้อมูล: aidemy-recap-<UNIQUE_NAME> สำคัญ: ตรวจสอบว่าคุณได้กำหนดชื่อที่เก็บข้อมูลที่ไม่ซ้ำกันซึ่งขึ้นต้นด้วย "aidemy-recap-" ชื่อที่ไม่ซ้ำกันนี้สำคัญมากในการหลีกเลี่ยงความขัดแย้งของชื่อเมื่อสร้างที่เก็บข้อมูล Cloud Storage
- ภูมิภาค:
us-central1
- คลาสพื้นที่เก็บข้อมูล: "มาตรฐาน" มาตรฐานเหมาะสำหรับข้อมูลที่เข้าถึงบ่อย
- การควบคุมการเข้าถึง: เลือก "การควบคุมการเข้าถึงแบบเดียวกัน" ที่เป็นค่าเริ่มต้นไว้ วิธีนี้ช่วยให้มีการควบคุมการเข้าถึงระดับที่เก็บข้อมูลที่สอดคล้องกัน
- ตัวเลือกขั้นสูง: สําหรับเวิร์กช็อปนี้ การตั้งค่าเริ่มต้นมักจะเพียงพอแล้ว คลิกปุ่มสร้างเพื่อสร้างที่เก็บข้อมูล
คุณอาจเห็นป๊อปอัปเกี่ยวกับการป้องกันการเข้าถึงแบบสาธารณะ เลือกช่องไว้แล้วคลิก Confirm
ตอนนี้คุณจะเห็นที่เก็บข้อมูลที่สร้างใหม่ในรายการที่เก็บข้อมูล โปรดจำชื่อที่เก็บข้อมูลไว้ เนื่องจากคุณจะต้องใช้ในภายหลัง
👉ในเทอร์มินัลของ Cloud Code Editor ให้เรียกใช้คําสั่งต่อไปนี้เพื่อให้สิทธิ์เข้าถึงที่เก็บข้อมูลแก่บัญชีบริการ
export COURSE_BUCKET_NAME=$(gcloud storage buckets list --format="value(name)" | grep aidemy-recap)
export SERVICE_ACCOUNT_NAME=$(gcloud compute project-info describe --format="value(defaultServiceAccount)")
gcloud storage buckets add-iam-policy-binding gs://$COURSE_BUCKET_NAME \
--member "serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role "roles/storage.objectViewer"
gcloud storage buckets add-iam-policy-binding gs://$COURSE_BUCKET_NAME \
--member "serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role "roles/storage.objectCreator"
👉ใน Cloud Code Editor ให้เปิด audio.py
ในโฟลเดอร์ course
วางโค้ดต่อไปนี้ที่ส่วนท้ายของไฟล์
config = LiveConnectConfig(
response_modalities=["AUDIO"],
speech_config=SpeechConfig(
voice_config=VoiceConfig(
prebuilt_voice_config=PrebuiltVoiceConfig(
voice_name="Charon",
)
)
),
)
async def process_weeks(teaching_plan: str):
region = "us-west1" #To workaround onRamp qouta limits
client = genai.Client(vertexai=True, project=PROJECT_ID, location=region)
clientAudio = genai.Client(vertexai=True, project=PROJECT_ID, location="us-central1")
async with clientAudio.aio.live.connect(
model=MODEL_ID,
config=config,
) as session:
for week in range(1, 4):
response = client.models.generate_content(
model="gemini-1.0-pro",
contents=f"Given the following teaching plan: {teaching_plan}, Extrace content plan for week {week}. And return just the plan, nothingh else " # Clarified prompt
)
prompt = f"""
Assume you are the instructor.
Prepare a concise and engaging recap of the key concepts and topics covered.
This recap should be suitable for generating a short audio summary for students.
Focus on the most important learnings and takeaways, and frame it as a direct address to the students.
Avoid overly formal language and aim for a conversational tone, tell a few jokes.
Teaching plan: {response.text} """
print(f"prompt --->{prompt}")
await session.send(input=prompt, end_of_turn=True)
with open(f"temp_audio_week_{week}.raw", "wb") as temp_file:
async for message in session.receive():
if message.server_content.model_turn:
for part in message.server_content.model_turn.parts:
if part.inline_data:
temp_file.write(part.inline_data.data)
data, samplerate = sf.read(f"temp_audio_week_{week}.raw", channels=1, samplerate=24000, subtype='PCM_16', format='RAW')
sf.write(f"course-week-{week}.wav", data, samplerate)
storage_client = storage.Client()
bucket = storage_client.bucket(BUCKET_NAME)
blob = bucket.blob(f"course-week-{week}.wav") # Or give it a more descriptive name
blob.upload_from_filename(f"course-week-{week}.wav")
print(f"Audio saved to GCS: gs://{BUCKET_NAME}/course-week-{week}.wav")
await session.close()
def breakup_sessions(teaching_plan: str):
asyncio.run(process_weeks(teaching_plan))
- การเชื่อมต่อสตรีมมิง: ขั้นแรก ระบบจะสร้างการเชื่อมต่อถาวรกับปลายทาง Live API ซึ่งแตกต่างจากการเรียก API มาตรฐานที่คุณส่งคําขอและได้รับการตอบกลับ การเชื่อมต่อนี้จะยังคงเปิดอยู่เพื่อแลกเปลี่ยนข้อมูลอย่างต่อเนื่อง
- การกำหนดค่าแบบมัลติโมด: ใช้การกำหนดค่าเพื่อระบุประเภทเอาต์พุตที่ต้องการ (ในกรณีนี้คือเสียง) และคุณยังระบุพารามิเตอร์ที่ต้องการใช้ได้ด้วย (เช่น การเลือกเสียง การเข้ารหัสเสียง)
- การประมวลผลแบบไม่พร้อมกัน: API นี้ทํางานแบบไม่พร้อมกัน ซึ่งหมายความว่าจะไม่บล็อกเทรดหลักขณะรอการสร้างเสียง การประมวลผลข้อมูลแบบเรียลไทม์และส่งเอาต์พุตเป็นกลุ่มๆ จะช่วยให้คุณได้รับประสบการณ์การใช้งานที่เกือบจะทันที
คำถามสำคัญคือ กระบวนการสร้างเสียงนี้ควรทำงานเมื่อใด เราต้องการให้สรุปเสียงพร้อมใช้งานทันทีที่สร้างแผนการสอนใหม่ เนื่องจากเราได้ใช้สถาปัตยกรรมที่ทำงานตามเหตุการณ์แล้วโดยการเผยแพร่แผนการสอนไปยังหัวข้อ Pub/Sub เราจึงสมัครใช้บริการหัวข้อนั้นได้โดยง่าย
อย่างไรก็ตาม เราไม่ได้สร้างแผนการสอนใหม่บ่อยนัก การมีตัวแทนทำงานอยู่ตลอดเวลาและรอแผนใหม่นั้นไม่มีประสิทธิภาพ ดังนั้นจึงควรใช้ตรรกะการสร้างเสียงนี้เป็นฟังก์ชัน Cloud Run
เมื่อทําให้การเผยแพร่เป็นฟังก์ชัน ฟังก์ชันจะหยุดทํางานจนกว่าจะมีการเผยแพร่ข้อความใหม่ไปยังหัวข้อ Pub/Sub เมื่อเกิดเหตุการณ์ดังกล่าว ระบบจะเรียกใช้ฟังก์ชันโดยอัตโนมัติ ซึ่งจะสร้างสรุปเสียงและจัดเก็บไว้ในที่เก็บข้อมูลของเรา
👉ในโฟลเดอร์ course
ในไฟล์ main.py
ไฟล์นี้จะกำหนดฟังก์ชัน Cloud Run ที่จะทริกเกอร์เมื่อมีแผนการสอนใหม่ โดยจะรับแผนและเริ่มสร้างสรุปเสียง เพิ่มข้อมูลโค้ดต่อไปนี้ที่ส่วนท้ายของไฟล์
@functions_framework.cloud_event
def process_teaching_plan(cloud_event):
print(f"CloudEvent received: {cloud_event.data}")
time.sleep(60)
try:
if isinstance(cloud_event.data.get('message', {}).get('data'), str): # Check for base64 encoding
data = json.loads(base64.b64decode(cloud_event.data['message']['data']).decode('utf-8'))
teaching_plan = data.get('teaching_plan') # Get the teaching plan
elif 'teaching_plan' in cloud_event.data: # No base64
teaching_plan = cloud_event.data["teaching_plan"]
else:
raise KeyError("teaching_plan not found") # Handle error explicitly
#Load the teaching_plan as string and from cloud event, call audio breakup_sessions
breakup_sessions(teaching_plan)
return "Teaching plan processed successfully", 200
except (json.JSONDecodeError, AttributeError, KeyError) as e:
print(f"Error decoding CloudEvent data: {e} - Data: {cloud_event.data}")
return "Error processing event", 500
except Exception as e:
print(f"Error processing teaching plan: {e}")
return "Error processing teaching plan", 500
@functions_framework.cloud_event: ตัวแปรตกแต่งนี้จะทําเครื่องหมายฟังก์ชันเป็นฟังก์ชัน Cloud Run ที่ CloudEvents จะทริกเกอร์
การทดสอบในเครื่อง
👉เราจะเรียกใช้สิ่งนี้ในสภาพแวดล้อมเสมือนและติดตั้งไลบรารี Python ที่จําเป็นสําหรับฟังก์ชัน Cloud Run
cd ~/aidemy-bootstrap/courses
export COURSE_BUCKET_NAME=$(gcloud storage buckets list --format="value(name)" | grep aidemy-recap)
python -m venv env
source env/bin/activate
pip install -r requirements.txt
👉โปรแกรมจำลองฟังก์ชัน Cloud Run ช่วยให้เราทดสอบฟังก์ชันในเครื่องได้ก่อนที่จะนำไปติดตั้งใช้งานใน Google Cloud เริ่มโปรแกรมจำลองในเครื่องโดยเรียกใช้คำสั่งต่อไปนี้
functions-framework --target process_teaching_plan --signature-type=cloudevent --source main.py
👉ขณะที่โปรแกรมจำลองทํางานอยู่ คุณสามารถส่ง CloudEvents ทดสอบไปยังโปรแกรมจำลองเพื่อจําลองการเผยแพร่แผนการสอนใหม่ ในเทอร์มินัลใหม่ ให้ทำดังนี้
👉เรียกใช้:
curl -X POST \
http://localhost:8080/ \
-H "Content-Type: application/json" \
-H "ce-id: event-id-01" \
-H "ce-source: planner-agent" \
-H "ce-specversion: 1.0" \
-H "ce-type: google.cloud.pubsub.topic.v1.messagePublished" \
-d '{
"message": {
"data": "eyJ0ZWFjaGluZ19wbGFuIjogIldlZWsgMTogMkQgU2hhcGVzIGFuZCBBbmdsZXMgLSBEYXkgMTogUmV2aWV3IG9mIGJhc2ljIDJEIHNoYXBlcyAoc3F1YXJlcywgcmVjdGFuZ2xlcywgdHJpYW5nbGVzLCBjaXJjbGVzKS4gRGF5IDI6IEV4cGxvcmluZyBkaWZmZXJlbnQgdHlwZXMgb2YgdHJpYW5nbGVzIChlcXVpbGF0ZXJhbCwgaXNvc2NlbGVzLCBzY2FsZW5lLCByaWdodC1hbmdsZWQpLiBEYXkgMzogRXhwbG9yaW5nIHF1YWRyaWxhdGVyYWxzIChzcXVhcmUsIHJlY3RhbmdsZSwgcGFyYWxsZWxvZ3JhbSwgcmhvbWJ1cywgdHJhcGV6aXVtKS4gRGF5IDQ6IEludHJvZHVjdGlvbiB0byBhbmdsZXM6IHJpZ2h0IGFuZ2xlcywgYWN1dGUgYW5nbGVzLCBhbmQgb2J0dXNlIGFuZ2xlcy4gRGF5IDU6IE1lYXN1cmluZyBhbmdsZXMgdXNpbmcgYSBwcm90cmFjdG9yLiBXZWVrIDI6IDNEIFNoYXBlcyBhbmQgU3ltbWV0cnkgLSBEYXkgNjogSW50cm9kdWN0aW9uIHRvIDNEIHNoYXBlczogY3ViZXMsIGN1Ym9pZHMsIHNwaGVyZXMsIGN5bGluZGVycywgY29uZXMsIGFuZCBweXJhbWlkcy4gRGF5IDc6IERlc2NyaWJpbmcgM0Qgc2hhcGVzIHVzaW5nIGZhY2VzLCBlZGdlcywgYW5kIHZlcnRpY2VzLiBEYXkgODogUmVsYXRpbmcgMkQgc2hhcGVzIHRvIDNEIHNoYXBlcy4gRGF5IDk6IElkZW50aWZ5aW5nIGxpbmVzIG9mIHN5bW1ldHJ5IGluIDJEIHNoYXBlcy4gRGF5IDEwOiBDb21wbGV0aW5nIHN5bW1ldHJpY2FsIGZpZ3VyZXMuIFdlZWsgMzogUG9zaXRpb24sIERpcmVjdGlvbiwgYW5kIFByb2JsZW0gU29sdmluZyAtIERheSAxMTogRGVzY3JpYmluZyBwb3NpdGlvbiB1c2luZyBjb29yZGluYXRlcyBpbiB0aGUgZmlyc3QgcXVhZHJhbnQuIERheSAxMjogUGxvdHRpbmcgY29vcmRpbmF0ZXMgdG8gZHJhdyBzaGFwZXMuIERheSAxMzogVW5kZXJzdGFuZGluZyB0cmFuc2xhdGlvbiAoc2xpZGluZyBhIHNoYXBlKS4gRGF5IDE0OiBVbmRlcnN0YW5kaW5nIHJlZmxlY3Rpb24gKGZsaXBwaW5nIGEgc2hhcGUpLiBEYXkgMTU6IFByb2JsZW0tc29sdmluZyBhY3Rpdml0aWVzIGludm9sdmluZyBwZXJpbWV0ZXIsIGFyZWEsIGFuZCBtaXNzaW5nIGFuZ2xlcy4ifQ=="
}
}'
แทนที่จะรอคำตอบไปเรื่อยๆ ให้เปลี่ยนไปใช้เทอร์มินัล Cloud Shell อื่น คุณสามารถดูความคืบหน้าและเอาต์พุตหรือข้อความแสดงข้อผิดพลาดที่ฟังก์ชันสร้างขึ้นได้ในเทอร์มินัลของโปรแกรมจำลอง 😁
กลับไปที่เทอร์มินัลที่ 2 คุณควรเห็นค่าที่แสดงเป็น OK
👉คุณจะยืนยันข้อมูลในที่เก็บข้อมูล โดยไปที่ Cloud Storage แล้วเลือกแท็บ "ที่เก็บข้อมูล" จากนั้นเลือก aidemy-recap-xxx
👉ในเทอร์มินัลที่เรียกใช้โปรแกรมจำลอง ให้พิมพ์ ctrl+c
เพื่อออก และปิดเทอร์มินัลที่ 2 และปิดเทอร์มินัลที่ 2 แล้วเรียกใช้ "ปิดใช้งาน" เพื่อออกจากสภาพแวดล้อมเสมือน
deactivate
การนำส่งไปยัง Google Cloud
👉หลังจากทดสอบในเครื่องแล้ว ก็ถึงเวลาทำให้ตัวแทนหลักสูตรใช้งานได้ใน Google Cloud เรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัล
cd ~/aidemy-bootstrap/courses
export COURSE_BUCKET_NAME=$(gcloud storage buckets list --format="value(name)" | grep aidemy-recap)
gcloud functions deploy courses-agent \
--region=us-central1 \
--gen2 \
--source=. \
--runtime=python312 \
--trigger-topic=plan \
--entry-point=process_teaching_plan \
--set-env-vars=GOOGLE_CLOUD_PROJECT=${PROJECT_ID},COURSE_BUCKET_NAME=$COURSE_BUCKET_NAME
ยืนยันการติดตั้งใช้งานโดยไปที่ Cloud Run ในคอนโซล Google Cloud คุณควรเห็นบริการใหม่ชื่อ courses-agent แสดงอยู่
หากต้องการตรวจสอบการกําหนดค่าทริกเกอร์ ให้คลิกบริการ courses-agent เพื่อดูรายละเอียด ไปที่แท็บ "ทริกเกอร์"
คุณควรเห็นทริกเกอร์ที่กำหนดค่าให้รอรับข้อความที่เผยแพร่ไปยังหัวข้อแผน
สุดท้าย เรามาดูการทํางานตั้งแต่ต้นจนจบกัน
👉ถัดไป เราต้องกำหนดค่าตัวแทนพอร์ทัลเพื่อให้ทราบตำแหน่งที่จะค้นหาไฟล์เสียงที่สร้างขึ้น ในเทอร์มินัล ให้เรียกใช้คำสั่งต่อไปนี้
export COURSE_BUCKET_NAME=$(gcloud storage buckets list --format="value(name)" | grep aidemy-recap)
export PROJECT_ID=$(gcloud config get project)
gcloud run services update aidemy-portal \
--region=us-central1 \
--set-env-vars=GOOGLE_CLOUD_PROJECT=${PROJECT_ID},COURSE_BUCKET_NAME=$COURSE_BUCKET_NAME
👉ลองสร้างแผนการสอนใหม่ในหน้าตัวแทนแผน การดำเนินการอาจใช้เวลา 2-3 นาที แต่ไม่ต้องกังวล เพราะเป็นบริการแบบเซิร์ฟเวอร์เลส รับ URL ของตัวแทนเครื่องมือวางแผน (หากไม่มี ให้เรียกใช้คำสั่งนี้ในเทอร์มินัล)
gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep planner
หลังจากสร้างแผนใหม่แล้ว ให้รอ 2-3 นาทีเพื่อให้ระบบสร้างเสียง ซึ่งอาจใช้เวลาอีก 2-3 นาทีเนื่องจากข้อจำกัดในการเรียกเก็บเงินของบัญชีห้องทดลองนี้
คุณสามารถตรวจสอบว่าฟังก์ชัน courses-agent
ได้รับแผนการสอนแล้วหรือยังโดยดูที่แท็บ "ทริกเกอร์" ของฟังก์ชัน รีเฟรชหน้าเป็นระยะๆ คุณควรจะเห็นว่ามีการเรียกใช้ฟังก์ชันแล้ว หากไม่ได้เรียกใช้ฟังก์ชันหลังจากผ่านไปนานกว่า 2 นาที ให้ลองสร้างแผนการสอนอีกครั้ง อย่างไรก็ตาม โปรดหลีกเลี่ยงการสร้างแผนซ้ำๆ ติดต่อกันอย่างรวดเร็ว เนื่องจากตัวแทนจะใช้งานและประมวลผลแผนแต่ละแผนตามลำดับ ซึ่งอาจทำให้เกิดงานค้าง
👉ไปที่พอร์ทัลแล้วคลิก "หลักสูตร" คุณควรเห็นการ์ด 3 ใบ โดยแต่ละใบจะแสดงสรุปเสียง วิธีค้นหา URL ของตัวแทนพอร์ทัล
gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep portal
คลิก "เล่น" ในหลักสูตรแต่ละหลักสูตรเพื่อให้แน่ใจว่าสรุปเสียงสอดคล้องกับแผนการสอนที่คุณเพิ่งสร้าง
ออกจากสภาพแวดล้อมเสมือนจริง
deactivate
13. ไม่บังคับ: การทำงานร่วมกันตามบทบาทด้วย Gemini และ DeepSeek
การมองปัญหาจากหลายมุมมองมีประโยชน์อย่างยิ่ง โดยเฉพาะเมื่อต้องสร้างงานที่น่าสนใจและมีประโยชน์ ตอนนี้เราจะสร้างระบบหลายตัวแทนที่ใช้ประโยชน์จากโมเดล 2 แบบที่มีบทบาทต่างกันเพื่อสร้างงาน โดยโมเดลหนึ่งส่งเสริมการทำงานร่วมกัน และอีกโมเดลหนึ่งส่งเสริมการศึกษาด้วยตนเอง เราจะใช้สถาปัตยกรรม "แบบยิงครั้งเดียว" ซึ่งเวิร์กโฟลว์จะเป็นไปตามเส้นทางที่กําหนดไว้
เครื่องมือสร้างงานของ Gemini
เราจะเริ่มต้นด้วยการตั้งค่าฟังก์ชัน Gemini เพื่อสร้างงานโดยเน้นการทำงานร่วมกัน แก้ไขไฟล์
gemini.py
ในโฟลเดอร์ assignment
👉วางโค้ดต่อไปนี้ที่ส่วนท้ายของไฟล์ gemini.py
def gen_assignment_gemini(state):
region=get_next_region()
client = genai.Client(vertexai=True, project=PROJECT_ID, location=region)
print(f"---------------gen_assignment_gemini")
response = client.models.generate_content(
model=MODEL_ID, contents=f"""
You are an instructor
Develop engaging and practical assignments for each week, ensuring they align with the teaching plan's objectives and progressively build upon each other.
For each week, provide the following:
* **Week [Number]:** A descriptive title for the assignment (e.g., "Data Exploration Project," "Model Building Exercise").
* **Learning Objectives Assessed:** List the specific learning objectives from the teaching plan that this assignment assesses.
* **Description:** A detailed description of the task, including any specific requirements or constraints. Provide examples or scenarios if applicable.
* **Deliverables:** Specify what students need to submit (e.g., code, report, presentation).
* **Estimated Time Commitment:** The approximate time students should dedicate to completing the assignment.
* **Assessment Criteria:** Briefly outline how the assignment will be graded (e.g., correctness, completeness, clarity, creativity).
The assignments should be a mix of individual and collaborative work where appropriate. Consider different learning styles and provide opportunities for students to apply their knowledge creatively.
Based on this teaching plan: {state["teaching_plan"]}
"""
)
print(f"---------------gen_assignment_gemini answer {response.text}")
state["model_one_assignment"] = response.text
return state
import unittest
class TestGenAssignmentGemini(unittest.TestCase):
def test_gen_assignment_gemini(self):
test_teaching_plan = "Week 1: 2D Shapes and Angles - Day 1: Review of basic 2D shapes (squares, rectangles, triangles, circles). Day 2: Exploring different types of triangles (equilateral, isosceles, scalene, right-angled). Day 3: Exploring quadrilaterals (square, rectangle, parallelogram, rhombus, trapezium). Day 4: Introduction to angles: right angles, acute angles, and obtuse angles. Day 5: Measuring angles using a protractor. Week 2: 3D Shapes and Symmetry - Day 6: Introduction to 3D shapes: cubes, cuboids, spheres, cylinders, cones, and pyramids. Day 7: Describing 3D shapes using faces, edges, and vertices. Day 8: Relating 2D shapes to 3D shapes. Day 9: Identifying lines of symmetry in 2D shapes. Day 10: Completing symmetrical figures. Week 3: Position, Direction, and Problem Solving - Day 11: Describing position using coordinates in the first quadrant. Day 12: Plotting coordinates to draw shapes. Day 13: Understanding translation (sliding a shape). Day 14: Understanding reflection (flipping a shape). Day 15: Problem-solving activities involving perimeter, area, and missing angles."
initial_state = {"teaching_plan": test_teaching_plan, "model_one_assignment": "", "model_two_assigmodel_one_assignmentnment": "", "final_assignment": ""}
updated_state = gen_assignment_gemini(initial_state)
self.assertIn("model_one_assignment", updated_state)
self.assertIsNotNone(updated_state["model_one_assignment"])
self.assertIsInstance(updated_state["model_one_assignment"], str)
self.assertGreater(len(updated_state["model_one_assignment"]), 0)
print(updated_state["model_one_assignment"])
if __name__ == '__main__':
unittest.main()
โดยใช้โมเดล Gemini เพื่อสร้างงาน
เราพร้อมทดสอบตัวแทน Gemini แล้ว
👉เรียกใช้คําสั่งต่อไปนี้ในเทอร์มินัลเพื่อตั้งค่าสภาพแวดล้อม
cd ~/aidemy-bootstrap/assignment
export PROJECT_ID=$(gcloud config get project)
python -m venv env
source env/bin/activate
pip install -r requirements.txt
👉คุณสามารถเรียกใช้เพื่อทดสอบได้โดยทำดังนี้
python gemini.py
คุณควรเห็นงานที่มีงานกลุ่มมากกว่าในเอาต์พุต การทดสอบการยืนยันในตอนท้ายจะแสดงผลลัพธ์ด้วย
Here are some engaging and practical assignments for each week, designed to build progressively upon the teaching plan's objectives:
**Week 1: Exploring the World of 2D Shapes**
* **Learning Objectives Assessed:**
* Identify and name basic 2D shapes (squares, rectangles, triangles, circles).
* .....
* **Description:**
* **Shape Scavenger Hunt:** Students will go on a scavenger hunt in their homes or neighborhoods, taking pictures of objects that represent different 2D shapes. They will then create a presentation or poster showcasing their findings, classifying each shape and labeling its properties (e.g., number of sides, angles, etc.).
* **Triangle Trivia:** Students will research and create a short quiz or presentation about different types of triangles, focusing on their properties and real-world examples.
* **Angle Exploration:** Students will use a protractor to measure various angles in their surroundings, such as corners of furniture, windows, or doors. They will record their measurements and create a chart categorizing the angles as right, acute, or obtuse.
....
**Week 2: Delving into the World of 3D Shapes and Symmetry**
* **Learning Objectives Assessed:**
* Identify and name basic 3D shapes.
* ....
* **Description:**
* **3D Shape Construction:** Students will work in groups to build 3D shapes using construction paper, cardboard, or other materials. They will then create a presentation showcasing their creations, describing the number of faces, edges, and vertices for each shape.
* **Symmetry Exploration:** Students will investigate the concept of symmetry by creating a visual representation of various symmetrical objects (e.g., butterflies, leaves, snowflakes) using drawing or digital tools. They will identify the lines of symmetry and explain their findings.
* **Symmetry Puzzles:** Students will be given a half-image of a symmetrical figure and will be asked to complete the other half, demonstrating their understanding of symmetry. This can be done through drawing, cut-out activities, or digital tools.
**Week 3: Navigating Position, Direction, and Problem Solving**
* **Learning Objectives Assessed:**
* Describe position using coordinates in the first quadrant.
* ....
* **Description:**
* **Coordinate Maze:** Students will create a maze using coordinates on a grid paper. They will then provide directions for navigating the maze using a combination of coordinate movements and translation/reflection instructions.
* **Shape Transformations:** Students will draw shapes on a grid paper and then apply transformations such as translation and reflection, recording the new coordinates of the transformed shapes.
* **Geometry Challenge:** Students will solve real-world problems involving perimeter, area, and angles. For example, they could be asked to calculate the perimeter of a room, the area of a garden, or the missing angle in a triangle.
....
หยุดด้วย ctl+c
และล้างโค้ดทดสอบ นําโค้ดต่อไปนี้ออกจาก gemini.py
import unittest
class TestGenAssignmentGemini(unittest.TestCase):
def test_gen_assignment_gemini(self):
test_teaching_plan = "Week 1: 2D Shapes and Angles - Day 1: Review of basic 2D shapes (squares, rectangles, triangles, circles). Day 2: Exploring different types of triangles (equilateral, isosceles, scalene, right-angled). Day 3: Exploring quadrilaterals (square, rectangle, parallelogram, rhombus, trapezium). Day 4: Introduction to angles: right angles, acute angles, and obtuse angles. Day 5: Measuring angles using a protractor. Week 2: 3D Shapes and Symmetry - Day 6: Introduction to 3D shapes: cubes, cuboids, spheres, cylinders, cones, and pyramids. Day 7: Describing 3D shapes using faces, edges, and vertices. Day 8: Relating 2D shapes to 3D shapes. Day 9: Identifying lines of symmetry in 2D shapes. Day 10: Completing symmetrical figures. Week 3: Position, Direction, and Problem Solving - Day 11: Describing position using coordinates in the first quadrant. Day 12: Plotting coordinates to draw shapes. Day 13: Understanding translation (sliding a shape). Day 14: Understanding reflection (flipping a shape). Day 15: Problem-solving activities involving perimeter, area, and missing angles."
initial_state = {"teaching_plan": test_teaching_plan, "model_one_assignment": "", "model_two_assigmodel_one_assignmentnment": "", "final_assignment": ""}
updated_state = gen_assignment_gemini(initial_state)
self.assertIn("model_one_assignment", updated_state)
self.assertIsNotNone(updated_state["model_one_assignment"])
self.assertIsInstance(updated_state["model_one_assignment"], str)
self.assertGreater(len(updated_state["model_one_assignment"]), 0)
print(updated_state["model_one_assignment"])
if __name__ == '__main__':
unittest.main()
กำหนดค่าเครื่องมือสร้างงาน DeepSeek
แม้ว่าแพลตฟอร์ม AI บนระบบคลาวด์จะสะดวก แต่ LLM ที่โฮสต์เองก็อาจมีความสำคัญต่อการปกป้องความเป็นส่วนตัวของข้อมูลและการรักษาสิทธิ์ในข้อมูล เราจะติดตั้งใช้งานโมเดล DeepSeek ที่เล็กที่สุด (พารามิเตอร์ 1.5 พันล้านรายการ) ในอินสแตนซ์ Cloud Compute Engine มีวิธีอื่นๆ เช่น โฮสติ้งในแพลตฟอร์ม Vertex AI ของ Google หรือโฮสติ้งในอินสแตนซ์ GKE แต่เนื่องจากนี่เป็นเพียงเวิร์กช็อปเกี่ยวกับตัวแทน AI และเราไม่อยากให้คุณรอนาน มาใช้วิธีที่ง่ายที่สุดกัน แต่หากสนใจและต้องการดูตัวเลือกอื่นๆ โปรดดูไฟล์ deepseek-vertexai.py
ในโฟลเดอร์งาน ซึ่งมีโค้ดตัวอย่างเกี่ยวกับวิธีโต้ตอบกับโมเดลที่ติดตั้งใช้งานใน VertexAI
👉เรียกใช้คําสั่งนี้ในเทอร์มินัลเพื่อสร้างแพลตฟอร์ม LLM แบบโฮสต์เอง Ollama
cd ~/aidemy-bootstrap/assignment
gcloud compute instances create ollama-instance \
--image-family=ubuntu-2204-lts \
--image-project=ubuntu-os-cloud \
--machine-type=e2-standard-4 \
--zone=us-central1-a \
--metadata-from-file startup-script=startup.sh \
--boot-disk-size=50GB \
--tags=ollama \
--scopes=https://www.googleapis.com/auth/cloud-platform
วิธียืนยันว่าอินสแตนซ์ Compute Engine ทำงานอยู่
ไปที่ Compute Engine > "อินสแตนซ์ VM" ใน Google Cloud Console คุณควรเห็น ollama-instance
แสดงอยู่พร้อมเครื่องหมายถูกสีเขียว ซึ่งบ่งบอกว่ากำลังทำงานอยู่ หากไม่เห็น ให้ตรวจสอบว่าโซนเป็น us-central1 หากไม่แสดง คุณอาจต้องค้นหา
👉เราจะติดตั้งโมเดล DeepSeek ที่เล็กที่สุดและทดสอบ โดยกลับไปที่เครื่องมือแก้ไข Cloud Shell ในเทอร์มินัลใหม่ ให้เรียกใช้คําสั่งต่อไปนี้เพื่อ SSH ไปยังอินสแตนซ์ GCE
gcloud compute ssh ollama-instance --zone=us-central1-a
เมื่อสร้างการเชื่อมต่อ SSH แล้ว ระบบอาจแสดงข้อความต่อไปนี้
"ต้องการดำเนินการต่อไหม (Y/n)"
เพียงพิมพ์ Y
(ไม่คำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่) แล้วกด Enter เพื่อดำเนินการต่อ
จากนั้นระบบอาจขอให้คุณสร้างรหัสผ่านสำหรับคีย์ SSH หากไม่ต้องการใช้รหัสผ่าน ให้กด Enter 2 ครั้งเพื่อยอมรับค่าเริ่มต้น (ไม่มีรหัสผ่าน)
👉ตอนนี้คุณอยู่ในเครื่องเสมือนแล้ว ให้ดึง DeepSeek R1 โมเดลที่เล็กที่สุดมาและทดสอบว่าใช้งานได้ไหม
ollama pull deepseek-r1:1.5b
ollama run deepseek-r1:1.5b "who are you?"
👉ออกจากอินสแตนซ์ GCE โดยป้อนข้อมูลต่อไปนี้ในเทอร์มินัล SSH
exit
ปิดเทอร์มินัลใหม่แล้วกลับไปที่เทอร์มินัลเดิม
👉และอย่าลืมตั้งค่านโยบายเครือข่ายเพื่อให้บริการอื่นๆ เข้าถึง LLM ได้ โปรดจำกัดการเข้าถึงอินสแตนซ์หากต้องการทําเช่นนี้สําหรับเวอร์ชันที่ใช้งานจริง ไม่ว่าจะใช้การเข้าสู่ระบบที่ปลอดภัยสําหรับบริการหรือจํากัดการเข้าถึง IP เรียกใช้
gcloud compute firewall-rules create allow-ollama-11434 \
--allow=tcp:11434 \
--target-tags=ollama \
--description="Allow access to Ollama on port 11434"
👉หากต้องการตรวจสอบว่านโยบายไฟร์วอลล์ทํางานอย่างถูกต้องหรือไม่ ให้ลองเรียกใช้คำสั่งต่อไปนี้
export OLLAMA_HOST=http://$(gcloud compute instances describe ollama-instance --zone=us-central1-a --format='value(networkInterfaces[0].accessConfigs[0].natIP)'):11434
curl -X POST "${OLLAMA_HOST}/api/generate" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Hello, what are you?",
"model": "deepseek-r1:1.5b",
"stream": false
}'
ถัดไป เราจะทํางานกับฟังก์ชัน Deepseek ในตัวแทนงานเพื่อสร้างงานโดยเน้นงานแต่ละชิ้น
👉แก้ไข deepseek.py
ในโฟลเดอร์ assignment
เพิ่มข้อมูลโค้ดต่อไปนี้ต่อท้าย
def gen_assignment_deepseek(state):
print(f"---------------gen_assignment_deepseek")
template = """
You are an instructor who favor student to focus on individual work.
Develop engaging and practical assignments for each week, ensuring they align with the teaching plan's objectives and progressively build upon each other.
For each week, provide the following:
* **Week [Number]:** A descriptive title for the assignment (e.g., "Data Exploration Project," "Model Building Exercise").
* **Learning Objectives Assessed:** List the specific learning objectives from the teaching plan that this assignment assesses.
* **Description:** A detailed description of the task, including any specific requirements or constraints. Provide examples or scenarios if applicable.
* **Deliverables:** Specify what students need to submit (e.g., code, report, presentation).
* **Estimated Time Commitment:** The approximate time students should dedicate to completing the assignment.
* **Assessment Criteria:** Briefly outline how the assignment will be graded (e.g., correctness, completeness, clarity, creativity).
The assignments should be a mix of individual and collaborative work where appropriate. Consider different learning styles and provide opportunities for students to apply their knowledge creatively.
Based on this teaching plan: {teaching_plan}
"""
prompt = ChatPromptTemplate.from_template(template)
model = OllamaLLM(model="deepseek-r1:1.5b",
base_url=OLLAMA_HOST)
chain = prompt | model
response = chain.invoke({"teaching_plan":state["teaching_plan"]})
state["model_two_assignment"] = response
return state
import unittest
class TestGenAssignmentDeepseek(unittest.TestCase):
def test_gen_assignment_deepseek(self):
test_teaching_plan = "Week 1: 2D Shapes and Angles - Day 1: Review of basic 2D shapes (squares, rectangles, triangles, circles). Day 2: Exploring different types of triangles (equilateral, isosceles, scalene, right-angled). Day 3: Exploring quadrilaterals (square, rectangle, parallelogram, rhombus, trapezium). Day 4: Introduction to angles: right angles, acute angles, and obtuse angles. Day 5: Measuring angles using a protractor. Week 2: 3D Shapes and Symmetry - Day 6: Introduction to 3D shapes: cubes, cuboids, spheres, cylinders, cones, and pyramids. Day 7: Describing 3D shapes using faces, edges, and vertices. Day 8: Relating 2D shapes to 3D shapes. Day 9: Identifying lines of symmetry in 2D shapes. Day 10: Completing symmetrical figures. Week 3: Position, Direction, and Problem Solving - Day 11: Describing position using coordinates in the first quadrant. Day 12: Plotting coordinates to draw shapes. Day 13: Understanding translation (sliding a shape). Day 14: Understanding reflection (flipping a shape). Day 15: Problem-solving activities involving perimeter, area, and missing angles."
initial_state = {"teaching_plan": test_teaching_plan, "model_one_assignment": "", "model_two_assignment": "", "final_assignment": ""}
updated_state = gen_assignment_deepseek(initial_state)
self.assertIn("model_two_assignment", updated_state)
self.assertIsNotNone(updated_state["model_two_assignment"])
self.assertIsInstance(updated_state["model_two_assignment"], str)
self.assertGreater(len(updated_state["model_two_assignment"]), 0)
print(updated_state["model_two_assignment"])
if __name__ == '__main__':
unittest.main()
👉มาทดสอบกันโดยเรียกใช้คำสั่งต่อไปนี้
cd ~/aidemy-bootstrap/assignment
source env/bin/activate
export PROJECT_ID=$(gcloud config get project)
export OLLAMA_HOST=http://$(gcloud compute instances describe ollama-instance --zone=us-central1-a --format='value(networkInterfaces[0].accessConfigs[0].natIP)'):11434
python deepseek.py
คุณควรเห็นงานที่มีงานแบบศึกษาด้วยตนเองมากกว่า
**Assignment Plan for Each Week**
---
### **Week 1: 2D Shapes and Angles**
- **Week Title:** "Exploring 2D Shapes"
Assign students to research and present on various 2D shapes. Include a project where they create models using straws and tape for triangles, draw quadrilaterals with specific measurements, and compare their properties.
### **Week 2: 3D Shapes and Symmetry**
Assign students to create models or nets for cubes and cuboids. They will also predict how folding these nets form the 3D shapes. Include a project where they identify symmetrical properties using mirrors or folding techniques.
### **Week 3: Position, Direction, and Problem Solving**
Assign students to use mirrors or folding techniques for reflections. Include activities where they measure angles, use a protractor, solve problems involving perimeter/area, and create symmetrical designs.
....
👉หยุด ctl+c
และล้างโค้ดทดสอบ นําโค้ดต่อไปนี้ออกจาก deepseek.py
import unittest
class TestGenAssignmentDeepseek(unittest.TestCase):
def test_gen_assignment_deepseek(self):
test_teaching_plan = "Week 1: 2D Shapes and Angles - Day 1: Review of basic 2D shapes (squares, rectangles, triangles, circles). Day 2: Exploring different types of triangles (equilateral, isosceles, scalene, right-angled). Day 3: Exploring quadrilaterals (square, rectangle, parallelogram, rhombus, trapezium). Day 4: Introduction to angles: right angles, acute angles, and obtuse angles. Day 5: Measuring angles using a protractor. Week 2: 3D Shapes and Symmetry - Day 6: Introduction to 3D shapes: cubes, cuboids, spheres, cylinders, cones, and pyramids. Day 7: Describing 3D shapes using faces, edges, and vertices. Day 8: Relating 2D shapes to 3D shapes. Day 9: Identifying lines of symmetry in 2D shapes. Day 10: Completing symmetrical figures. Week 3: Position, Direction, and Problem Solving - Day 11: Describing position using coordinates in the first quadrant. Day 12: Plotting coordinates to draw shapes. Day 13: Understanding translation (sliding a shape). Day 14: Understanding reflection (flipping a shape). Day 15: Problem-solving activities involving perimeter, area, and missing angles."
initial_state = {"teaching_plan": test_teaching_plan, "model_one_assignment": "", "model_two_assignment": "", "final_assignment": ""}
updated_state = gen_assignment_deepseek(initial_state)
self.assertIn("model_two_assignment", updated_state)
self.assertIsNotNone(updated_state["model_two_assignment"])
self.assertIsInstance(updated_state["model_two_assignment"], str)
self.assertGreater(len(updated_state["model_two_assignment"]), 0)
print(updated_state["model_two_assignment"])
if __name__ == '__main__':
unittest.main()
ตอนนี้เราจะใช้รูปแบบ Gemini เดียวกันเพื่อรวมงานทั้ง 2 รายการเข้าด้วยกันเป็นงานใหม่ แก้ไขไฟล์ gemini.py
ในโฟลเดอร์ assignment
👉วางโค้ดต่อไปนี้ที่ส่วนท้ายของไฟล์ gemini.py
def combine_assignments(state):
print(f"---------------combine_assignments ")
region=get_next_region()
client = genai.Client(vertexai=True, project=PROJECT_ID, location=region)
response = client.models.generate_content(
model=MODEL_ID, contents=f"""
Look at all the proposed assignment so far {state["model_one_assignment"]} and {state["model_two_assignment"]}, combine them and come up with a final assignment for student.
"""
)
state["final_assignment"] = response.text
return state
เราจะจัดระเบียบเวิร์กโฟลว์ที่กําหนดโดยใช้ LangGraph เพื่อรวมจุดแข็งของทั้ง 2 รูปแบบเข้าด้วยกัน เวิร์กโฟลว์นี้ประกอบด้วย 3 ขั้นตอน ได้แก่ ขั้นตอนแรก โมเดล Gemini จะสร้างงานโดยเน้นที่การทำงานร่วมกัน ขั้นตอนที่ 2 โมเดล DeepSeek จะสร้างงานโดยเน้นที่การทำงานเดี่ยว และขั้นตอนสุดท้าย Gemini จะสังเคราะห์งาน 2 รายการนี้ให้เป็นงานเดียวที่ครอบคลุม เนื่องจากเรากําหนดลําดับขั้นตอนไว้ล่วงหน้าโดยไม่มีการทําการตัดสินใจของ LLM การดำเนินการนี้จึงเป็นการประสานงานที่กําหนดโดยผู้ใช้ซึ่งใช้เส้นทางเดียว
👉วางโค้ดต่อไปนี้ที่ส่วนท้ายของmain.py
ไฟล์ในโฟลเดอร์ assignment
def create_assignment(teaching_plan: str):
print(f"create_assignment---->{teaching_plan}")
builder = StateGraph(State)
builder.add_node("gen_assignment_gemini", gen_assignment_gemini)
builder.add_node("gen_assignment_deepseek", gen_assignment_deepseek)
builder.add_node("combine_assignments", combine_assignments)
builder.add_edge(START, "gen_assignment_gemini")
builder.add_edge("gen_assignment_gemini", "gen_assignment_deepseek")
builder.add_edge("gen_assignment_deepseek", "combine_assignments")
builder.add_edge("combine_assignments", END)
graph = builder.compile()
state = graph.invoke({"teaching_plan": teaching_plan})
return state["final_assignment"]
import unittest
class TestCreatAssignment(unittest.TestCase):
def test_create_assignment(self):
test_teaching_plan = "Week 1: 2D Shapes and Angles - Day 1: Review of basic 2D shapes (squares, rectangles, triangles, circles). Day 2: Exploring different types of triangles (equilateral, isosceles, scalene, right-angled). Day 3: Exploring quadrilaterals (square, rectangle, parallelogram, rhombus, trapezium). Day 4: Introduction to angles: right angles, acute angles, and obtuse angles. Day 5: Measuring angles using a protractor. Week 2: 3D Shapes and Symmetry - Day 6: Introduction to 3D shapes: cubes, cuboids, spheres, cylinders, cones, and pyramids. Day 7: Describing 3D shapes using faces, edges, and vertices. Day 8: Relating 2D shapes to 3D shapes. Day 9: Identifying lines of symmetry in 2D shapes. Day 10: Completing symmetrical figures. Week 3: Position, Direction, and Problem Solving - Day 11: Describing position using coordinates in the first quadrant. Day 12: Plotting coordinates to draw shapes. Day 13: Understanding translation (sliding a shape). Day 14: Understanding reflection (flipping a shape). Day 15: Problem-solving activities involving perimeter, area, and missing angles."
initial_state = {"teaching_plan": test_teaching_plan, "model_one_assignment": "", "model_two_assignment": "", "final_assignment": ""}
updated_state = create_assignment(initial_state)
print(updated_state)
if __name__ == '__main__':
unittest.main()
👉หากต้องการทดสอบฟังก์ชัน create_assignment
เบื้องต้นและยืนยันว่าเวิร์กโฟลว์ที่รวม Gemini กับ DeepSeek ใช้งานได้ ให้เรียกใช้คําสั่งต่อไปนี้
cd ~/aidemy-bootstrap/assignment
source env/bin/activate
pip install -r requirements.txt
python main.py
คุณควรเห็นสิ่งที่รวมทั้ง 2 รูปแบบเข้าด้วยกันโดยมีมุมมองของแต่ละรูปแบบสำหรับการศึกษาของนักเรียนและงานกลุ่มของนักเรียน
**Tasks:**
1. **Clue Collection:** Gather all the clues left by the thieves. These clues will include:
* Descriptions of shapes and their properties (angles, sides, etc.)
* Coordinate grids with hidden messages
* Geometric puzzles requiring transformation (translation, reflection, rotation)
* Challenges involving area, perimeter, and angle calculations
2. **Clue Analysis:** Decipher each clue using your geometric knowledge. This will involve:
* Identifying the shape and its properties
* Plotting coordinates and interpreting patterns on the grid
* Solving geometric puzzles by applying transformations
* Calculating area, perimeter, and missing angles
3. **Case Report:** Create a comprehensive case report outlining your findings. This report should include:
* A detailed explanation of each clue and its solution
* Sketches and diagrams to support your explanations
* A step-by-step account of how you followed the clues to locate the artifact
* A final conclusion about the thieves and their motives
👉หยุด ctl+c
และล้างโค้ดทดสอบ นําโค้ดต่อไปนี้ออกจาก main.py
import unittest
class TestCreatAssignment(unittest.TestCase):
def test_create_assignment(self):
test_teaching_plan = "Week 1: 2D Shapes and Angles - Day 1: Review of basic 2D shapes (squares, rectangles, triangles, circles). Day 2: Exploring different types of triangles (equilateral, isosceles, scalene, right-angled). Day 3: Exploring quadrilaterals (square, rectangle, parallelogram, rhombus, trapezium). Day 4: Introduction to angles: right angles, acute angles, and obtuse angles. Day 5: Measuring angles using a protractor. Week 2: 3D Shapes and Symmetry - Day 6: Introduction to 3D shapes: cubes, cuboids, spheres, cylinders, cones, and pyramids. Day 7: Describing 3D shapes using faces, edges, and vertices. Day 8: Relating 2D shapes to 3D shapes. Day 9: Identifying lines of symmetry in 2D shapes. Day 10: Completing symmetrical figures. Week 3: Position, Direction, and Problem Solving - Day 11: Describing position using coordinates in the first quadrant. Day 12: Plotting coordinates to draw shapes. Day 13: Understanding translation (sliding a shape). Day 14: Understanding reflection (flipping a shape). Day 15: Problem-solving activities involving perimeter, area, and missing angles."
initial_state = {"teaching_plan": test_teaching_plan, "model_one_assignment": "", "model_two_assignment": "", "final_assignment": ""}
updated_state = create_assignment(initial_state)
print(updated_state)
if __name__ == '__main__':
unittest.main()
เราจะใช้ประโยชน์จากสถาปัตยกรรมที่ทำงานตามเหตุการณ์ที่มีอยู่เพื่อทำให้กระบวนการสร้างงานเป็นแบบอัตโนมัติและตอบสนองต่อแผนการเรียนการสอนใหม่ โค้ดต่อไปนี้จะกำหนดฟังก์ชัน Cloud Run (generate_assignment) ซึ่งจะทริกเกอร์เมื่อใดก็ตามที่มีการเผยแพร่แผนการสอนใหม่ไปยังหัวข้อ Pub/Sub "plan"
👉เพิ่มโค้ดต่อไปนี้ที่ส่วนท้ายของ main.py
@functions_framework.cloud_event
def generate_assignment(cloud_event):
print(f"CloudEvent received: {cloud_event.data}")
try:
if isinstance(cloud_event.data.get('message', {}).get('data'), str):
data = json.loads(base64.b64decode(cloud_event.data['message']['data']).decode('utf-8'))
teaching_plan = data.get('teaching_plan')
elif 'teaching_plan' in cloud_event.data:
teaching_plan = cloud_event.data["teaching_plan"]
else:
raise KeyError("teaching_plan not found")
assignment = create_assignment(teaching_plan)
print(f"Assignment---->{assignment}")
#Store the return assignment into bucket as a text file
storage_client = storage.Client()
bucket = storage_client.bucket(ASSIGNMENT_BUCKET)
file_name = f"assignment-{random.randint(1, 1000)}.txt"
blob = bucket.blob(file_name)
blob.upload_from_string(assignment)
return f"Assignment generated and stored in {ASSIGNMENT_BUCKET}/{file_name}", 200
except (json.JSONDecodeError, AttributeError, KeyError) as e:
print(f"Error decoding CloudEvent data: {e} - Data: {cloud_event.data}")
return "Error processing event", 500
except Exception as e:
print(f"Error generate assignment: {e}")
return "Error generate assignment", 500
การทดสอบในเครื่อง
ก่อนทำให้ใช้งานได้ใน Google Cloud คุณควรทดสอบฟังก์ชัน Cloud Run ในเครื่อง ซึ่งจะช่วยให้การทดสอบซ้ำเร็วขึ้นและแก้ไขข้อบกพร่องได้ง่ายขึ้น
ก่อนอื่น ให้สร้างที่เก็บข้อมูล Cloud Storage เพื่อจัดเก็บไฟล์งานที่สร้าง และมอบสิทธิ์เข้าถึงที่เก็บข้อมูลแก่บัญชีบริการ เรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัล
👉สำคัญ: ตรวจสอบว่าคุณได้กำหนดชื่อ ASSIGNMENT_BUCKET ที่ไม่ซ้ำกันซึ่งขึ้นต้นด้วย "aidemy-assignment-" ชื่อที่ไม่ซ้ำกันนี้สำคัญมากในการหลีกเลี่ยงความขัดแย้งของชื่อเมื่อสร้างที่เก็บข้อมูล Cloud Storage (แทนที่ <YOUR_NAME> ด้วยคำใดก็ได้แบบสุ่ม)
export ASSIGNMENT_BUCKET=aidemy-assignment-<YOUR_NAME> #Name must be unqiue
👉แล้วเรียกใช้
export PROJECT_ID=$(gcloud config get project)
export SERVICE_ACCOUNT_NAME=$(gcloud compute project-info describe --format="value(defaultServiceAccount)")
gsutil mb -p $PROJECT_ID -l us-central1 gs://$ASSIGNMENT_BUCKET
gcloud storage buckets add-iam-policy-binding gs://$ASSIGNMENT_BUCKET \
--member "serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role "roles/storage.objectViewer"
gcloud storage buckets add-iam-policy-binding gs://$ASSIGNMENT_BUCKET \
--member "serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role "roles/storage.objectCreator"
👉ตอนนี้ให้เริ่มโปรแกรมจำลองฟังก์ชัน Cloud Run โดยทำดังนี้
cd ~/aidemy-bootstrap/assignment
functions-framework --target generate_assignment --signature-type=cloudevent --source main.py
👉ขณะที่โปรแกรมจำลองทํางานในเทอร์มินัลหนึ่ง ให้เปิดเทอร์มินัลที่ 2 ใน Cloud Shell ในเทอร์มินัลที่ 2 นี้ ให้ส่ง CloudEvent ทดสอบไปยังโปรแกรมจำลองเพื่อจำลองการเผยแพร่แผนการเรียนการสอนใหม่
curl -X POST \
http://localhost:8080/ \
-H "Content-Type: application/json" \
-H "ce-id: event-id-01" \
-H "ce-source: planner-agent" \
-H "ce-specversion: 1.0" \
-H "ce-type: google.cloud.pubsub.topic.v1.messagePublished" \
-d '{
"message": {
"data": "eyJ0ZWFjaGluZ19wbGFuIjogIldlZWsgMTogMkQgU2hhcGVzIGFuZCBBbmdsZXMgLSBEYXkgMTogUmV2aWV3IG9mIGJhc2ljIDJEIHNoYXBlcyAoc3F1YXJlcywgcmVjdGFuZ2xlcywgdHJpYW5nbGVzLCBjaXJjbGVzKS4gRGF5IDI6IEV4cGxvcmluZyBkaWZmZXJlbnQgdHlwZXMgb2YgdHJpYW5nbGVzIChlcXVpbGF0ZXJhbCwgaXNvc2NlbGVzLCBzY2FsZW5lLCByaWdodC1hbmdsZWQpLiBEYXkgMzogRXhwbG9yaW5nIHF1YWRyaWxhdGVyYWxzIChzcXVhcmUsIHJlY3RhbmdsZSwgcGFyYWxsZWxvZ3JhbSwgcmhvbWJ1cywgdHJhcGV6aXVtKS4gRGF5IDQ6IEludHJvZHVjdGlvbiB0byBhbmdsZXM6IHJpZ2h0IGFuZ2xlcywgYWN1dGUgYW5nbGVzLCBhbmQgb2J0dXNlIGFuZ2xlcy4gRGF5IDU6IE1lYXN1cmluZyBhbmdsZXMgdXNpbmcgYSBwcm90cmFjdG9yLiBXZWVrIDI6IDNEIFNoYXBlcyBhbmQgU3ltbWV0cnkgLSBEYXkgNjogSW50cm9kdWN0aW9uIHRvIDNEIHNoYXBlczogY3ViZXMsIGN1Ym9pZHMsIHNwaGVyZXMsIGN5bGluZGVycywgY29uZXMsIGFuZCBweXJhbWlkcy4gRGF5IDc6IERlc2NyaWJpbmcgM0Qgc2hhcGVzIHVzaW5nIGZhY2VzLCBlZGdlcywgYW5kIHZlcnRpY2VzLiBEYXkgODogUmVsYXRpbmcgMkQgc2hhcGVzIHRvIDNEIHNoYXBlcy4gRGF5IDk6IElkZW50aWZ5aW5nIGxpbmVzIG9mIHN5bW1ldHJ5IGluIDJEIHNoYXBlcy4gRGF5IDEwOiBDb21wbGV0aW5nIHN5bW1ldHJpY2FsIGZpZ3VyZXMuIFdlZWsgMzogUG9zaXRpb24sIERpcmVjdGlvbiwgYW5kIFByb2JsZW0gU29sdmluZyAtIERheSAxMTogRGVzY3JpYmluZyBwb3NpdGlvbiB1c2luZyBjb29yZGluYXRlcyBpbiB0aGUgZmlyc3QgcXVhZHJhbnQuIERheSAxMjogUGxvdHRpbmcgY29vcmRpbmF0ZXMgdG8gZHJhdyBzaGFwZXMuIERheSAxMzogVW5kZXJzdGFuZGluZyB0cmFuc2xhdGlvbiAoc2xpZGluZyBhIHNoYXBlKS4gRGF5IDE0OiBVbmRlcnN0YW5kaW5nIHJlZmxlY3Rpb24gKGZsaXBwaW5nIGEgc2hhcGUpLiBEYXkgMTU6IFByb2JsZW0tc29sdmluZyBhY3Rpdml0aWVzIGludm9sdmluZyBwZXJpbWV0ZXIsIGFyZWEsIGFuZCBtaXNzaW5nIGFuZ2xlcy4ifQ=="
}
}'
แทนที่จะรอคำตอบไปเรื่อยๆ ให้เปลี่ยนไปใช้เทอร์มินัล Cloud Shell อื่น คุณสามารถดูความคืบหน้าและเอาต์พุตหรือข้อความแสดงข้อผิดพลาดที่ฟังก์ชันสร้างขึ้นได้ในเทอร์มินัลของโปรแกรมจำลอง 😁
ผลลัพธ์ที่ได้ควรเป็น "OK"
หากต้องการยืนยันว่าสร้างและจัดเก็บงานเรียบร้อยแล้ว ให้ไปที่คอนโซล Google Cloud แล้วไปที่พื้นที่เก็บข้อมูล > "Cloud Storage" เลือกที่เก็บข้อมูล aidemy-assignment
ที่คุณสร้างขึ้น คุณควรเห็นไฟล์ข้อความชื่อ assignment-{random number}.txt
ในที่เก็บข้อมูล คลิกไฟล์เพื่อดาวน์โหลดและยืนยันเนื้อหา ซึ่งจะยืนยันว่าไฟล์ใหม่มีการมอบหมายใหม่ที่สร้างขึ้น
👉ในเทอร์มินัลที่เรียกใช้โปรแกรมจำลอง ให้พิมพ์ ctrl+c
เพื่อออก และปิดเทอร์มินัลที่ 2 👉นอกจากนี้ ให้ออกจากสภาพแวดล้อมเสมือนในเทอร์มินัลที่เรียกใช้โปรแกรมจำลอง
deactivate
👉ถัดไป เราจะติดตั้งใช้งานตัวแทนการมอบหมายในระบบคลาวด์
cd ~/aidemy-bootstrap/assignment
export ASSIGNMENT_BUCKET=$(gcloud storage buckets list --format="value(name)" | grep aidemy-assignment)
export OLLAMA_HOST=http://$(gcloud compute instances describe ollama-instance --zone=us-central1-a --format='value(networkInterfaces[0].accessConfigs[0].natIP)'):11434
export PROJECT_ID=$(gcloud config get project)
gcloud functions deploy assignment-agent \
--gen2 \
--timeout=540 \
--memory=2Gi \
--cpu=1 \
--set-env-vars="ASSIGNMENT_BUCKET=${ASSIGNMENT_BUCKET}" \
--set-env-vars=GOOGLE_CLOUD_PROJECT=${GOOGLE_CLOUD_PROJECT} \
--set-env-vars=OLLAMA_HOST=${OLLAMA_HOST} \
--region=us-central1 \
--runtime=python312 \
--source=. \
--entry-point=generate_assignment \
--trigger-topic=plan
ยืนยันการติดตั้งใช้งานโดยไปที่ Google Cloud Console แล้วไปที่ Cloud Run คุณควรเห็นบริการใหม่ชื่อ courses-agent แสดงอยู่
เมื่อติดตั้งใช้งาน ทดสอบ และทำให้เวิร์กโฟลว์การสร้างงานใช้งานได้แล้ว เราจึงไปยังขั้นตอนถัดไปได้ ซึ่งก็คือทำให้งานเหล่านี้เข้าถึงได้ในพอร์ทัลของนักเรียน
14. ไม่บังคับ: การทำงานร่วมกันตามบทบาทด้วย Gemini และ DeepSeek - ต่อ
การสร้างเว็บไซต์แบบไดนามิก
เราจะใช้การสร้าง HTML แบบไดนามิกสำหรับหน้างานเพื่อปรับปรุงพอร์ทัลของนักเรียนและทำให้น่าดึงดูดยิ่งขึ้น โดยมีเป้าหมายเพื่ออัปเดตพอร์ทัลโดยอัตโนมัติด้วยการออกแบบที่สดใหม่และดึงดูดสายตาทุกครั้งที่มีการสร้างงานใหม่ ซึ่งใช้ประโยชน์จากความสามารถในการเขียนโค้ดของ LLM เพื่อสร้างประสบการณ์การใช้งานที่หลากหลายและน่าสนใจยิ่งขึ้น
👉ในเครื่องมือแก้ไข Cloud Shell ให้แก้ไขไฟล์ render.py
ในโฟลเดอร์ portal
โดยแทนที่
def render_assignment_page():
return ""
โดยมีข้อมูลโค้ดต่อไปนี้
def render_assignment_page(assignment: str):
try:
region=get_next_region()
llm = VertexAI(model_name="gemini-2.0-flash-001", location=region)
input_msg = HumanMessage(content=[f"Here the assignment {assignment}"])
prompt_template = ChatPromptTemplate.from_messages(
[
SystemMessage(
content=(
"""
As a frontend developer, create HTML to display a student assignment with a creative look and feel. Include the following navigation bar at the top:
```
<nav>
<a href="/">Home</a>
<a href="/quiz">Quizzes</a>
<a href="/courses">Courses</a>
<a href="/assignment">Assignments</a>
</nav>
```
Also include these links in the <head> section:
```
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500&display=swap" rel="stylesheet">
```
Do not apply inline styles to the navigation bar.
The HTML should display the full assignment content. In its CSS, be creative with the rainbow colors and aesthetic.
Make it creative and pretty
The assignment content should be well-structured and easy to read.
respond with JUST the html file
"""
)
),
input_msg,
]
)
prompt = prompt_template.format()
response = llm.invoke(prompt)
response = response.replace("```html", "")
response = response.replace("```", "")
with open("templates/assignment.html", "w") as f:
f.write(response)
print(f"response: {response}")
return response
except Exception as e:
print(f"Error sending message to chatbot: {e}") # Log this error too!
return f"Unable to process your request at this time. Due to the following reason: {str(e)}"
โดยจะใช้รูปแบบ Gemini เพื่อสร้าง HTML แบบไดนามิกสำหรับงาน โดยระบบจะรับเนื้อหาของงานเป็นอินพุต และใช้พรอมต์เพื่อสั่งให้ Gemini สร้างหน้า HTML ที่ดึงดูดสายตาด้วยสไตล์ที่สร้างสรรค์
ต่อไป เราจะสร้างปลายทางที่จะทริกเกอร์ทุกครั้งที่มีการเพิ่มเอกสารใหม่ลงในที่เก็บงาน
👉ภายในโฟลเดอร์พอร์ทัล ให้แก้ไขไฟล์ app.py
และเพิ่มโค้ดต่อไปนี้ภายใน ## Add your code here" comments
หลังฟังก์ชัน new_teaching_plan
## Add your code here
@app.route('/render_assignment', methods=['POST'])
def render_assignment():
try:
data = request.get_json()
file_name = data.get('name')
bucket_name = data.get('bucket')
if not file_name or not bucket_name:
return jsonify({'error': 'Missing file name or bucket name'}), 400
storage_client = storage.Client()
bucket = storage_client.bucket(bucket_name)
blob = bucket.blob(file_name)
content = blob.download_as_text()
print(f"File content: {content}")
render_assignment_page(content)
return jsonify({'message': 'Assignment rendered successfully'})
except Exception as e:
print(f"Error processing file: {e}")
return jsonify({'error': 'Error processing file'}), 500
## Add your code here
เมื่อทริกเกอร์ ระบบจะดึงข้อมูลชื่อไฟล์และชื่อที่เก็บข้อมูลจากข้อมูลคำขอ ดาวน์โหลดเนื้อหางานจาก Cloud Storage และเรียกใช้ฟังก์ชัน render_assignment_page
เพื่อสร้าง HTML
👉เราจะเรียกใช้แอปในเครื่อง
cd ~/aidemy-bootstrap/portal
source env/bin/activate
python app.py
👉จากเมนู "ตัวอย่างเว็บ" ที่ด้านบนของหน้าต่าง Cloud Shell ให้เลือก "แสดงตัวอย่างบนพอร์ต 8080" ซึ่งจะเปิดแอปพลิเคชันในแท็บเบราว์เซอร์ใหม่ ไปที่ลิงก์งานในแถบนำทาง คุณควรเห็นหน้าว่าง ณ จุดนี้ ซึ่งเป็นลักษณะการทำงานที่คาดไว้เนื่องจากเรายังไม่ได้สร้างบริดจ์การสื่อสารระหว่างตัวแทนการมอบหมายกับพอร์ทัลเพื่อแสดงเนื้อหาแบบไดนามิก
👉หากต้องการรวมการเปลี่ยนแปลงเหล่านี้และทำให้โค้ดที่อัปเดตแล้วใช้งานได้ ให้สร้างและพุชรูปภาพตัวแทนพอร์ทัลอีกครั้งโดยทำดังนี้
cd ~/aidemy-bootstrap/portal/
export PROJECT_ID=$(gcloud config get project)
docker build -t gcr.io/${PROJECT_ID}/aidemy-portal .
export PROJECT_ID=$(gcloud config get project)
docker tag gcr.io/${PROJECT_ID}/aidemy-portal us-central1-docker.pkg.dev/${PROJECT_ID}/agent-repository/aidemy-portal
docker push us-central1-docker.pkg.dev/${PROJECT_ID}/agent-repository/aidemy-portal
👉หลังจากพุชอิมเมจใหม่แล้ว ให้ทำให้บริการ Cloud Run ใช้งานได้อีกครั้ง เรียกใช้สคริปต์ต่อไปนี้เพื่อบังคับใช้การอัปเดต Cloud Run
export PROJECT_ID=$(gcloud config get project)
export COURSE_BUCKET_NAME=$(gcloud storage buckets list --format="value(name)" | grep aidemy-recap)
gcloud run services update aidemy-portal \
--region=us-central1 \
--set-env-vars=GOOGLE_CLOUD_PROJECT=${PROJECT_ID},COURSE_BUCKET_NAME=$COURSE_BUCKET_NAME
👉ตอนนี้เราจะติดตั้งใช้งานทริกเกอร์ Eventarc ที่คอยตรวจหาออบเจ็กต์ใหม่ที่สร้าง (เสร็จสมบูรณ์) ในที่เก็บข้อมูลการมอบหมาย ทริกเกอร์นี้จะเรียกใช้ปลายทาง /render_assignment ในบริการพอร์ทัลโดยอัตโนมัติเมื่อมีการสร้างไฟล์งานใหม่
export PROJECT_ID=$(gcloud config get project)
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$(gcloud storage service-agent --project $PROJECT_ID)" \
--role="roles/pubsub.publisher"
export SERVICE_ACCOUNT_NAME=$(gcloud compute project-info describe --format="value(defaultServiceAccount)")
gcloud eventarc triggers create portal-assignment-trigger \
--location=us-central1 \
--service-account=$SERVICE_ACCOUNT_NAME \
--destination-run-service=aidemy-portal \
--destination-run-region=us-central1 \
--destination-run-path="/render_assignment" \
--event-filters="bucket=$ASSIGNMENT_BUCKET" \
--event-filters="type=google.cloud.storage.object.v1.finalized"
หากต้องการยืนยันว่าสร้างทริกเกอร์สําเร็จ ให้ไปที่หน้าทริกเกอร์ Eventarc ใน Google Cloud Console คุณควรเห็น portal-assignment-trigger
แสดงในตาราง คลิกชื่อทริกเกอร์เพื่อดูรายละเอียด
ระบบอาจใช้เวลาถึง 2-3 นาทีเพื่อให้ทริกเกอร์ใหม่ทำงาน
หากต้องการดูการสร้างการมอบหมายแบบไดนามิกที่ทำงานอยู่ ให้เรียกใช้คําสั่งต่อไปนี้เพื่อค้นหา URL ของตัวแทนผู้วางแผน (หากไม่สะดวก)
gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep planner
ค้นหา URL ของตัวแทนพอร์ทัล
gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep portal
สร้างแผนการเรียนการสอนใหม่ในตัวแทนแผน
หลังจากรอสักครู่ (เพื่อให้ระบบสร้างเสียง สร้างงาน และแสดงผล HTML ให้เสร็จสมบูรณ์) ให้ไปที่พอร์ทัลของนักเรียน
👉คลิกลิงก์ "งาน" ในแถบนำทาง คุณควรเห็นงานที่สร้างขึ้นใหม่ซึ่งมี HTML ที่สร้างขึ้นแบบไดนามิก ทุกครั้งที่สร้างแผนการเรียนการสอน แผนดังกล่าวควรเป็นงานแบบไดนามิก
ขอแสดงความยินดีที่ผ่านระบบหลายตัวแทนของ Aidemy คุณได้เรียนรู้ประสบการณ์จริงและข้อมูลเชิงลึกที่เป็นประโยชน์เกี่ยวกับสิ่งต่อไปนี้
- ประโยชน์ของระบบหลายตัวแทน ซึ่งรวมถึงความเป็นโมดูล การขยายขนาด ความเชี่ยวชาญ และการบำรุงรักษาที่ง่ายขึ้น
- ความสำคัญของสถาปัตยกรรมที่ทำงานตามเหตุการณ์สำหรับการสร้างแอปพลิเคชันที่ตอบสนองและเชื่อมโยงแบบหลวม
- การใช้ LLM อย่างมีกลยุทธ์ การจับคู่โมเดลที่เหมาะสมกับงาน และผสานรวมกับเครื่องมือเพื่อให้เกิดผลลัพธ์ในชีวิตจริง
- แนวทางการพัฒนาแบบระบบคลาวด์เนทีฟที่ใช้บริการของ Google Cloud เพื่อสร้างโซลูชันที่ปรับขนาดได้และเชื่อถือได้
- ความสำคัญของการพิจารณาความเป็นส่วนตัวของข้อมูลและรูปแบบการโฮสต์ด้วยตนเองเป็นทางเลือกแทนโซลูชันของผู้ให้บริการ
ตอนนี้คุณมีรากฐานที่มั่นคงในการสร้างแอปพลิเคชันที่ซับซ้อนซึ่งทำงานด้วยระบบ AI ใน Google Cloud แล้ว
15. ภารกิจและขั้นตอนถัดไป
ยินดีด้วยที่สร้างระบบตัวแทนหลายรายของ Aidemy คุณได้วางรากฐานที่มั่นคงสำหรับการศึกษาที่ทำงานด้วยระบบ AI แล้ว มาดูความท้าทายและแนวทางปรับปรุงที่อาจเกิดขึ้นในอนาคตเพื่อขยายความสามารถและตอบสนองความต้องการในชีวิตจริงกัน
การเรียนรู้แบบอินเทอร์แอกทีฟด้วยช่วงถามและตอบแบบสด:
- ภารกิจ: คุณใช้ประโยชน์จาก Live API ของ Gemini 2 เพื่อสร้างฟีเจอร์ถามและตอบแบบเรียลไทม์สำหรับนักเรียนได้ไหม ลองนึกภาพชั้นเรียนเสมือนจริงที่นักเรียนสามารถถามคำถามและรับคำตอบจาก AI ได้ทันที
การส่งและการให้คะแนนงานอัตโนมัติ:
- โจทย์: ออกแบบและติดตั้งใช้งานระบบที่อนุญาตให้นักเรียนส่งงานทางดิจิทัลและให้ AI เป็นผู้ให้คะแนนโดยอัตโนมัติ พร้อมกลไกในการตรวจหาและป้องกันการลอกเลียนแบบ ปัญหานี้ถือเป็นโอกาสที่ดีในการสำรวจRetrieval Augmented Generation (RAG) เพื่อเพิ่มความแม่นยำและความน่าเชื่อถือของกระบวนการให้คะแนนและการตรวจหาการลอกเลียน
16. ล้างข้อมูล
เมื่อสร้างและสำรวจระบบหลายตัวแทนของ Aidemy แล้ว ก็ถึงเวลาล้างข้อมูลในสภาพแวดล้อม Google Cloud
- ลบบริการ Cloud Run
gcloud run services delete aidemy-planner --region=us-central1 --quiet
gcloud run services delete aidemy-portal --region=us-central1 --quiet
gcloud run services delete courses-agent --region=us-central1 --quiet
gcloud run services delete book-provider --region=us-central1 --quiet
gcloud run services delete assignment-agent --region=us-central1 --quiet
- ลบทริกเกอร์ Eventarc
gcloud eventarc triggers delete portal-assignment-trigger --location=us --quiet
gcloud eventarc triggers delete plan-topic-trigger --location=us-central1 --quiet
gcloud eventarc triggers delete portal-assignment-trigger --location=us-central1 --quiet
ASSIGNMENT_AGENT_TRIGGER=$(gcloud eventarc triggers list --project="$PROJECT_ID" --location=us-central1 --filter="name:assignment-agent" --format="value(name)")
COURSES_AGENT_TRIGGER=$(gcloud eventarc triggers list --project="$PROJECT_ID" --location=us-central1 --filter="name:courses-agent" --format="value(name)")
gcloud eventarc triggers delete $ASSIGNMENT_AGENT_TRIGGER --location=us-central1 --quiet
gcloud eventarc triggers delete $COURSES_AGENT_TRIGGER --location=us-central1 --quiet
- ลบหัวข้อ Pub/Sub
gcloud pubsub topics delete plan --project="$PROJECT_ID" --quiet
- ลบอินสแตนซ์ Cloud SQL
gcloud sql instances delete aidemy --quiet
- ลบที่เก็บ Artifact Registry
gcloud artifacts repositories delete agent-repository --location=us-central1 --quiet
- ลบข้อมูลลับใน Secret Manager
gcloud secrets delete db-user --quiet
gcloud secrets delete db-pass --quiet
gcloud secrets delete db-name --quiet
- ลบอินสแตนซ์ Compute Engine (หากสร้างขึ้นสําหรับ Deepseek)
gcloud compute instances delete ollama-instance --zone=us-central1-a --quiet
- ลบกฎไฟร์วอลล์สําหรับอินสแตนซ์ Deepseek
gcloud compute firewall-rules delete allow-ollama-11434 --quiet
- ลบที่เก็บข้อมูล Cloud Storage
export COURSE_BUCKET_NAME=$(gcloud storage buckets list --format="value(name)" | grep aidemy-recap)
export ASSIGNMENT_BUCKET=$(gcloud storage buckets list --format="value(name)" | grep aidemy-assignment)
gsutil rb gs://$COURSE_BUCKET_NAME
gsutil rb gs://$ASSIGNMENT_BUCKET