สร้างเอเจนต์ AI ด้วย Agent Development Kit (ADK) สำหรับ Java

1. ยินดีต้อนรับ นักพัฒนาเอเจนต์ AI

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

คุณจะเริ่มต้นด้วยการแลกรับเครดิต Google Cloud, ตั้งค่าสภาพแวดล้อม Google Cloud จากนั้นสร้างเอเจนต์อย่างง่ายตัวแรก และค่อยๆ เพิ่มความสามารถขั้นสูงอื่นๆ เช่น เครื่องมือที่กำหนดเอง, การค้นหาเว็บ และการจัดระเบียบหลายเอเจนต์

d666c455bb267688.png

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

  • วิธีสร้างเอเจนต์ AI พื้นฐานที่อิงตามลักษณะตัวตน
  • วิธีเพิ่มประสิทธิภาพให้ตัวแทนด้วยเครื่องมือที่กำหนดเองและเครื่องมือที่มีอยู่ (เช่น Google Search)
  • วิธีเพิ่มเครื่องมือของคุณเองที่ใช้งานใน Java
  • วิธีจัดการ Agent หลายตัวให้เป็นเวิร์กโฟลว์แบบลำดับ แบบคู่ขนาน และแบบวนซ้ำที่มีประสิทธิภาพ

สิ่งที่คุณต้องมี

  • เว็บเบราว์เซอร์ที่เราจะใช้ในโหมดไม่ระบุตัวตน
  • บัญชี Gmail ส่วนตัว
  • โปรเจ็กต์ Google Cloud ใหม่ที่เชื่อมโยงกับบัญชี Gmail ส่วนตัว
  • บัญชีสำหรับการเรียกเก็บเงินที่สร้างขึ้นด้วยเครดิต Google Cloud ที่แลกรับข้อเสนอ
  • เครื่องมือบรรทัดคำสั่ง Git เพื่อตรวจสอบซอร์สโค้ด
  • Java 17 ขึ้นไปและ Apache Maven
  • โปรแกรมแก้ไขข้อความหรือ IDE เช่น IntelliJ IDEA หรือ VS Code

คุณใช้โปรแกรมแก้ไข VS Code ในตัวใน Cloud Shell ได้ในคอนโซล Google Cloud

2. การตั้งค่า: สภาพแวดล้อม

การอ้างสิทธิ์เครดิต Google Cloud สำหรับเวิร์กช็อป

e3e67ae61e86ec9f.png

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

  • ใช้บัญชี Google ส่วนตัว: คุณควรใช้บัญชี Google ส่วนตัว (เช่น อีเมลที่ลงท้ายด้วย @gmail.com) เนื่องจากอีเมลของบริษัทหรือโรงเรียนจะใช้ไม่ได้
  • ใช้ Google Chrome ในโหมดไม่ระบุตัวตน: เราขอแนะนำให้ทำเช่นนี้เพื่อสร้างเซสชันใหม่และป้องกันไม่ให้เกิดข้อขัดแย้งกับบัญชี Google อื่นๆ
  • ใช้ลิงก์กิจกรรมพิเศษ: ควรใช้ลิงก์พิเศษสำหรับกิจกรรม ซึ่งมีลักษณะคล้าย https://trygcp.dev/event/xxx ตามด้วยรหัสกิจกรรม (ในที่นี้คือ "xxx" ในตัวอย่างนี้)
  • ยอมรับข้อกำหนดในการให้บริการ: หลังจากลงชื่อเข้าใช้แล้ว คุณจะเห็นข้อกำหนดในการให้บริการของ Google Cloud Platform ซึ่งคุณต้องยอมรับเพื่อดำเนินการต่อ
  • สร้างโปรเจ็กต์ใหม่: ต้องสร้างโปรเจ็กต์ใหม่ที่ว่างเปล่าจาก Google Cloud Console
  • ลิงก์บัญชีสำหรับการเรียกเก็บเงิน: ลิงก์โปรเจ็กต์ที่สร้างขึ้นใหม่กับบัญชีสำหรับการเรียกเก็บเงิน
  • ยืนยันเครดิต: วิดีโอต่อไปนี้แสดงวิธีตรวจสอบว่ามีการใช้เครดิตกับโปรเจ็กต์โดยการตรวจสอบส่วน "เครดิต" ในหน้าการเรียกเก็บเงิน

คุณสามารถดูวิดีโอนี้เพื่อดูวิธีแลกรับและใช้เครดิตได้

สร้างและกำหนดค่าคีย์ API

หากต้องการตรวจสอบสิทธิ์เอเจนต์ AI ของ ADK ด้วย Gemini API สำหรับโค้ดแล็บนี้ คุณจะต้องใช้คีย์ API ที่เชื่อมโยงกับโปรเจ็กต์ Google Cloud

  1. สร้างคีย์ API:
  • ไปที่ Google AI Studio แล้วคลิกลิงก์ "รับคีย์ API" ที่ด้านล่างของแผงด้านซ้าย
  • เลือกโปรเจ็กต์ แล้วคลิกปุ่มนำเข้าโปรเจ็กต์
  • ค้นหาและเลือกโปรเจ็กต์ Google Cloud ที่ต้องการนำเข้า แล้วเลือกปุ่มนำเข้า
  • เมื่อนำเข้าโปรเจ็กต์แล้ว ให้ไปที่หน้าคีย์ API จากเมนูแดชบอร์ด แล้วสร้างคีย์ API ในโปรเจ็กต์ที่เพิ่งนำเข้า
  • จดคีย์ API ไว้
  1. ตั้งค่าตัวแปรสภาพแวดล้อม: เอเจนต์ต้องเข้าถึงคีย์นี้ วิธีมาตรฐานคือการตั้งค่าตัวแปรสภาพแวดล้อมชื่อ GOOGLE_API_KEY
  • macOS / Linux: เปิดเทอร์มินัลแล้วเรียกใช้คำสั่งต่อไปนี้ โดยแทนที่ "your-api-key" ด้วยคีย์ที่คุณเพิ่งคัดลอก หากต้องการให้การตั้งค่านี้มีผลถาวร ให้เพิ่มบรรทัดนี้ลงในไฟล์เริ่มต้นของเชลล์ (เช่น ~/.bash_profile, ~/.zshrc)
export GOOGLE_API_KEY="your-api-key"
  • Windows (Command Prompt): เปิด Command Prompt ใหม่แล้วเรียกใช้คำสั่งต่อไปนี้
setx GOOGLE_API_KEY "your-api-key"
  • คุณจะต้องรีสตาร์ทพรอมต์คำสั่งเพื่อให้การเปลี่ยนแปลงนี้มีผล
  • Windows (PowerShell): เปิดเทอร์มินัล PowerShell แล้วเรียกใช้คำสั่งต่อไปนี้
$env:GOOGLE_API_KEY="your-api-key"
  • หากต้องการทำการเปลี่ยนแปลงนี้อย่างถาวรใน PowerShell คุณจะต้องเพิ่มการเปลี่ยนแปลงนี้ลงในสคริปต์โปรไฟล์

3. เริ่มต้นใช้งาน: ตัวแทนแรก

f814ab5b7614e071.png

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

หากมีบัญชี GitHub คุณจะทำสิ่งต่อไปนี้ได้ Use this template > Create a new repository จากนั้นตรวจสอบโค้ดในเครื่องด้วยคำสั่ง git clone

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

1613a3d0ddc66dc5.png

อีกวิธีหนึ่งคือการโคลนที่เก็บนั้นโดยตรงด้วยคำสั่งต่อไปนี้

git clone https://github.com/glaforge/adk-java-maven-template.git

จากนั้น cd เป็น adk-java-maven-template

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

mvn compile

ขั้นตอนการเขียนโค้ด: เอเจนต์ครูสอนวิทยาศาสตร์ที่เป็นมิตร

องค์ประกอบพื้นฐานใน ADK คือคลาส LlmAgent ลองคิดว่านี่คือ AI ที่มีบุคลิกและเป้าหมายที่เฉพาะเจาะจง ซึ่งทำงานด้วยโมเดลภาษาขนาดใหญ่ เราจะเพิ่มความสามารถอื่นๆ ผ่านเครื่องมือในภายหลัง และทำให้มีความสามารถมากขึ้นด้วยการทำงานร่วมกันอย่างใกล้ชิดกับเอเจนต์อื่นๆ ที่คล้ายกัน

มาสร้างคลาส Java ใหม่ในแพ็กเกจ com.example.agent และตั้งชื่อว่า ScienceTeacher กัน

นี่คือ "Hello, World!" ของการสร้างเอเจนต์ เรากำลังกำหนดเอเจนต์แบบง่ายๆ ที่มีลักษณะเป็นครูสอนวิทยาศาสตร์

// src/main/java/com/example/agent/ScienceTeacher.java
package com.example.agent;

import com.google.adk.agents.LlmAgent;
import com.google.adk.web.AdkWebServer;

public class ScienceTeacher {
    public static void main(String[] args) {
        AdkWebServer.start(
            LlmAgent.builder()
                .name("science-teacher")
                .description("A friendly science teacher")
                .instruction("""
                    You are a science teacher for teenagers.
                    You explain science concepts in a simple, concise and direct way.
                    """)
                .model("gemini-2.5-flash")
                .build()
        );
    }
}

ระบบจะกำหนดค่าเอเจนต์ AI ผ่านLlmAgent.builder() พารามิเตอร์ name(), description() และ model() เป็นพารามิเตอร์ที่ต้องระบุ และเพื่อให้เอเจนต์มีลักษณะเฉพาะและมีพฤติกรรมที่เหมาะสม คุณควรให้คำแนะนำโดยละเอียดผ่านวิธีการ instruction() เสมอ

ในที่นี้เราเลือกใช้โมเดล Gemini 2.5 Flash แต่คุณสามารถลองใช้ Gemini 2.5 Pro สำหรับงานที่ซับซ้อนกว่าได้

ตัวแทนนี้รวมอยู่ในเมธอด AdkWebServer.start() ซึ่งเป็นอินเทอร์เฟซแชทที่เรียกว่าUI สำหรับนักพัฒนา ADK ซึ่งจะช่วยให้คุณสนทนากับตัวแทนผ่านอินเทอร์เฟซแชททั่วไปได้ นอกจากนี้ ยังเป็นประโยชน์อย่างยิ่งหากคุณต้องการทำความเข้าใจสิ่งที่เกิดขึ้นเบื้องหลัง เช่น เหตุการณ์ทั้งหมดที่ไหลผ่านระบบ คำขอและการตอบกลับที่ส่งไปยัง LLM

หากต้องการคอมไพล์และเรียกใช้เอเจนต์นี้ในเครื่อง ให้เรียกใช้คำสั่งต่อไปนี้

mvn compile exec:java -Dexec.mainClass=com.example.agent.ScienceTeacher

จากนั้นไปที่เบราว์เซอร์ที่ http://localhost:8080 คุณควรเห็น UI ดังที่แสดงในภาพหน้าจอด้านล่าง คุณสามารถถามคำถามเกี่ยวกับวิทยาศาสตร์กับเอเจนต์ได้เลย

da094da276ba15d6.png

4. การเสริมศักยภาพตัวแทนด้วยเครื่องมือ

cd5c5798a0861a1c.png

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

ขั้นตอนการเขียนโค้ด: สร้างเครื่องมือที่กำหนดเอง (StockTicker)

ในที่นี้ เราจะให้เครื่องมือแก่เอเจนต์เพื่อค้นหาราคาหุ้น เอเจนต์ให้เหตุผลว่าเมื่อผู้ใช้ถามถึงราคา เอเจนต์ควรเรียกใช้เมธอด Java ของเรา

// src/main/java/com/example/agent/StockTicker.java
package com.example.agent;

import com.google.adk.agents.LlmAgent;
import com.google.adk.tools.Annotations.Schema;
import com.google.adk.tools.FunctionTool;
import com.google.adk.web.AdkWebServer;
import java.util.Map;

public class StockTicker {
    public static void main(String[] args) {
        AdkWebServer.start(
            LlmAgent.builder()
                .name("stock_agent")
                .instruction("""
                    You are a stock exchange ticker expert.
                    When asked about the stock price of a company,
                    use the `lookup_stock_ticker` tool to find the information.
                    """)
                .model("gemini-2.5-flash")
                .tools(FunctionTool.create(StockTicker.class, "lookupStockTicker"))
                .build()
        );
    }

    @Schema(
        name = "lookup_stock_ticker",
        description = "Lookup stock price for a given company or ticker"
    )
    public static Map<String, String> lookupStockTicker(
        @Schema(name = "company_name_or_stock_ticker", description = "The company name or stock ticker")
        String ticker) {
        // ... (logic to return a stock price)
    }
}

หากต้องการให้เอเจนต์ฉลาดขึ้นและสามารถโต้ตอบกับโลกภายนอก (หรือกับโค้ด, API, บริการ ฯลฯ ของคุณเอง) คุณสามารถกำหนดค่าเอเจนต์ให้ใช้เครื่องมือ และโดยเฉพาะอย่างยิ่งเครื่องมือโค้ดที่กำหนดเอง ผ่านเมธอด tools() โดยส่ง FunctionTool.create(...) ไปให้

FunctionTool ต้องมีชื่อคลาสและชื่อเมธอดที่ชี้ไปยังเมธอดแบบคงที่ของคุณเอง นอกจากนี้ คุณยังส่งอินสแตนซ์ของคลาสและชื่อเมธอดอินสแตนซ์ของออบเจ็กต์นั้นได้ด้วย

คุณควรระบุ name และ description ของทั้งเมธอดและพารามิเตอร์ของเมธอดผ่านคำอธิบายประกอบ @Schema เนื่องจาก LLM ที่อยู่เบื้องหลังจะใช้ข้อมูลนี้เพื่อพิจารณาว่าควรเรียกใช้เมธอดที่กำหนดเมื่อใดและอย่างไร

นอกจากนี้ การช่วย LLM ด้วยวิธีการที่ชัดเจนเกี่ยวกับวิธีและเวลาที่ควรใช้เครื่องมือก็เป็นสิ่งสำคัญเช่นกัน โมเดลอาจคิดออกได้ด้วยตัวเอง แต่หากคุณให้คำอธิบายที่ชัดเจนในinstruction()เมธอด ฟังก์ชันของคุณก็จะมีโอกาสสูงที่จะถูกเรียกใช้อย่างเหมาะสม

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

  • เมื่อสำเร็จ ให้ส่งคืน {"stock_price": 123}
  • เมื่อเกิดข้อผิดพลาด ให้แสดงผล {"error": "Impossible to retrieve stock price for XYZ"}

จากนั้นเรียกใช้คลาสนี้ด้วยคำสั่งต่อไปนี้

mvn compile exec:java -Dexec.mainClass=com.example.agent.StockTicker

5. ศักยภาพของ Google Search ในการให้ข้อมูลล่าสุด

ae215e7b7cde02ab.png

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

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

มาดูเอเจนต์ค้นหาข่าวแบบง่ายๆ นี้กัน

// src/main/java/com/example/agent/LatestNews.java
package com.example.agent;

import java.time.LocalDate;
import com.google.adk.agents.LlmAgent;
import com.google.adk.tools.GoogleSearchTool;
import com.google.adk.web.AdkWebServer;

public class LatestNews {
    public static void main(String[] args) {
        AdkWebServer.start(LlmAgent.builder()
            .name("news-search-agent")
            .description("A news search agent")
            .instruction("""
                You are a news search agent.
                Use the `google_search` tool
                when asked to search for recent events and information.
                Today is \
                """ + LocalDate.now())
            .model("gemini-2.5-flash")
            .tools(new GoogleSearchTool())
            .build());
    }
}

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

จากนั้นเรียกใช้คลาสนี้ด้วยคำสั่งต่อไปนี้

mvn compile exec:java -Dexec.mainClass=com.example.agent.LatestNews

คุณสามารถลองใช้พรอมต์เพื่อขอผลลัพธ์ที่แตกต่างกันในแง่ของสไตล์ ความกระชับ หรือโฟกัส ฯลฯ

ขั้นตอนของโค้ด: เอเจนต์การค้นหาเป็นเครื่องมือ

แทนที่จะส่ง GoogleSearchTool ไปยังเอเจนต์โดยตรงเป็นเครื่องมือ คุณสามารถสร้างเอเจนต์ค้นหาเฉพาะที่จะห่อหุ้มฟังก์ชันการค้นหาและแสดง เอเจนต์นั้นเป็นเครื่องมือให้กับเอเจนต์ระดับสูงกว่าได้

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

// src/main/java/com/example/agent/SearchAgentAsTool.java
package com.example.agent;

import java.time.LocalDate;

import com.google.adk.agents.LlmAgent;
import com.google.adk.tools.AgentTool;
import com.google.adk.tools.GoogleSearchTool;
import com.google.adk.web.AdkWebServer;

public class SearchAgentAsTool {
    public static void main(String[] args) {
        // 1. Define the specialized Search Agent
        LlmAgent searchAgent = LlmAgent.builder()
            .name("news-search-agent-tool")
            .description("Searches for recent events and provides a concise summary.")
            .instruction("""
                You are a concise information retrieval specialist.
                Use the `google_search` tool to find information.
                Always provide the answer as a short,
                direct summary, without commentary.
                Today is \
                """ + LocalDate.now())
            .model("gemini-2.5-flash")
            .tools(new GoogleSearchTool()) // This agent uses the Google Search Tool
            .build();

        // 2. Wrap the Search Agent as a Tool
        AgentTool searchTool = AgentTool.create(searchAgent);

        // 3. Define the Main Agent that uses the Search Agent Tool
        AdkWebServer.start(LlmAgent.builder()
            .name("main-researcher")
            .description("Main agent for answering complex, up-to-date questions.")
            .instruction("""
                You are a sophisticated research assistant.
                When the user asks a question that requires up-to-date or external information,
                you MUST use the `news-search-agent-tool` to get the facts before answering.
                After the tool returns the result, synthesize the final answer for the user.
                """)
            .model("gemini-2.5-flash")
            .tools(searchTool) // This agent uses the Search Agent as a tool
            .build()
       );
    }
}

AgentTool.create(searchAgent) บรรทัดคือแนวคิดหลักในที่นี้ โดยจะลงทะเบียน searchAgent ทั้งหมด (พร้อมตรรกะภายใน พรอมต์ และเครื่องมือของตัวเอง) เป็นเครื่องมือที่เรียกใช้ได้รายการเดียวสำหรับ mainAgent ซึ่งส่งเสริมความสามารถในการแยกส่วนและการนำกลับมาใช้ใหม่

เรียกใช้คลาสนี้ด้วยคำสั่งต่อไปนี้

mvn compile exec:java -Dexec.mainClass=com.example.agent.SearchAgentAsTool

สำหรับคำถามทั่วไป เอเจนต์จะตอบจากฐานความรู้ของตนเอง แต่เมื่อถูกถามเกี่ยวกับเหตุการณ์ล่าสุด เอเจนต์จะมอบหมายการค้นหาให้กับเอเจนต์การค้นหาเฉพาะทางโดยใช้เครื่องมือ Google Search

6. การฝึกฝนเวิร์กโฟลว์เชิงตัวแทน

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

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

  • Agent ปกติที่มี subAgent() เพื่อมอบหมายงานให้
  • SequentialAgent หากต้องการทำงานตามลำดับ
  • ParallelAgent เพื่อเรียกใช้ Agent แบบขนาน
  • LoopAgent โดยปกติจะใช้เพื่อผ่านกระบวนการปรับแต่งหลายครั้งตามที่ต้องการ

กรณีการใช้งานหลัก รวมถึงข้อดีและข้อเสียของแต่ละเวิร์กโฟลว์ โปรดดูตารางด้านล่าง แต่โปรดทราบว่าพลังที่แท้จริงจะมาจากการรวมกันของหลายๆ อย่าง

เวิร์กโฟลว์

ชั้นเรียน ADK

กรณีการใช้งาน

ข้อดี

ข้อเสีย

Agent ย่อย

LlmAgent

งานที่ยืดหยุ่นซึ่งขับเคลื่อนโดยผู้ใช้และไม่ทราบขั้นตอนถัดไปเสมอไป

มีความยืดหยุ่นสูง เป็นแบบสนทนา เหมาะสำหรับบ็อตที่หันหน้าเข้าหาผู้ใช้

คาดเดาได้น้อยกว่า ต้องอาศัยการให้เหตุผลของ LLM ในการควบคุมโฟลว์

ตามลำดับ

SequentialAgent

กระบวนการแบบหลายขั้นตอนที่กำหนดไว้ซึ่งลำดับมีความสำคัญ

คาดการณ์ได้ เชื่อถือได้ แก้จุดบกพร่องได้ง่าย รับประกันลำดับ

ไม่ยืดหยุ่น อาจช้ากว่าหากสามารถทำงานแบบคู่ขนานได้

แบบขนาน

ParallelAgent

การรวบรวมข้อมูลจากหลายแหล่งหรือการเรียกใช้ฟังก์ชันที่แยกกัน

มีประสิทธิภาพสูง ลดเวลาในการตอบสนองสำหรับงานที่ต้องใช้ I/O อย่างมาก

งานทั้งหมดจะทำงานโดยไม่มีการลัดวงจร ไม่เหมาะกับงานที่มีทรัพยากร Dependency

รอบ

LoopAgent

การปรับแต่งแบบวนซ้ำ การแก้ไขด้วยตนเอง หรือกระบวนการที่ทำซ้ำจนกว่าจะตรงตามเงื่อนไข

มีประสิทธิภาพในการแก้ปัญหาที่ซับซ้อน ช่วยให้ตัวแทนปรับปรุงงานของตนเองได้

อาจทำให้เกิดลูปไม่สิ้นสุดหากออกแบบไม่ดี (ควรใช้ maxIterations เสมอ)

7. เวิร์กโฟลว์แบบเป็น Agent - การมอบหมายงานให้ตัวแทนย่อย

3b3074b840f57c1c.png

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

// src/main/java/com/example/agent/SupportAgent.java
package com.example.agent;

import com.google.adk.agents.LlmAgent;
import com.google.adk.web.AdkWebServer;

public class SupportAgent {
    public static void main(String[] args) {
                LlmAgent topicSearchAgent = LlmAgent.builder()
            .name("order-agent")
            .description("Order agent")
            .instruction("""
                Your role is to help our customers
                with all the questions they may have about their orders.
                Always respond that the order has been received, prepared,
                and is now out for delivery.
                """)
            .model("gemini-2.5-flash")
            .build();

        LlmAgent socialMediaAgent = LlmAgent.builder()
            .name("after-sale-agent")
            .description("After sale agent")
            .instruction("""
                You are an after sale agent,
                helping customers with the product they received.
                When a customer has a problem,
                suggest the person to switch the product off and on again.
                """)
            .model("gemini-2.5-flash")
            .build();

        AdkWebServer.start(LlmAgent.builder()
            .name("support-agent")
            .description("Customer support agent")
            .instruction("""
                Your role is help our customers.
                Call the `order-agent` for all questions related to order status.
                Call the `after-sale-agent` for inquiries about the received product.
                """)
            .model("gemini-2.5-flash")
            .subAgents(socialMediaAgent, topicSearchAgent)
            .build()
        );
    }
}

บรรทัดสำคัญในที่นี้คือบรรทัดที่เรียกใช้subAgents()เมธอด โดยส่งผ่าน 2 เอเจนต์ย่อยซึ่งแต่ละเอเจนต์จะจัดการบทบาทของตนแยกกัน

เรียกใช้ตัวอย่างด้านบนด้วยคำสั่งต่อไปนี้

mvn compile exec:java -Dexec.mainClass=com.example.agent.SupportAgent

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

8. เวิร์กโฟลว์ของ Agent - สายการประกอบ

108f8601cd36b559.png

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

ลองจินตนาการว่ากวีชาวอังกฤษร่วมงานกับนักแปลภาษาอังกฤษเป็นฝรั่งเศสเพื่อสร้างบทกวีเป็นภาษาอังกฤษก่อน แล้วจึงแปลเป็นภาษาฝรั่งเศส

// src/main/java/com/example/agent/PoetAndTranslator.java
package com.example.agent;

import com.google.adk.agents.LlmAgent;
import com.google.adk.agents.SequentialAgent;
import com.google.adk.web.AdkWebServer;

public class PoetAndTranslator {
    public static void main(String[] args) {
        LlmAgent poet = LlmAgent.builder()
            .name("poet-agent")
            .description("Poet writing poems")
            .model("gemini-2.5-flash")
            .instruction("""
                You are a talented poet,
                who writes short and beautiful poems.
                """)
            .outputKey("poem")
            .build();

        LlmAgent translator = LlmAgent.builder()
            .name("translator-agent")
            .description("English to French translator")
            .model("gemini-2.5-flash")
            .instruction("""
                As an expert English-French translator,
                your role is to translate the following poem into French,
                ensuring the poem still rhymes even after translation:

                {poem}
                """)
            .outputKey("translated-poem")
            .build();

        AdkWebServer.start(SequentialAgent.builder()
            .name("poet-and-translator")
            .subAgents(poet, translator)
            .build());
    }
}

เรียกใช้ตัวอย่างเพื่อรับบทกวีภาษาอังกฤษ จากนั้นแปลเป็นภาษาฝรั่งเศสด้วยคำสั่งต่อไปนี้

mvn compile exec:java -Dexec.mainClass=com.example.agent.PoetAndTranslator

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

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

9. เวิร์กโฟลว์ของเอเจนต์ - การทำงานแบบคู่ขนาน

4ba95f71e0189ae7.png

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

มาสร้างนักสืบของบริษัทกันดีกว่า ซึ่งมีหน้าที่ค้นหาข้อมูลเกี่ยวกับ

  • โปรไฟล์ของบริษัท (CEO, สำนักงานใหญ่, คำขวัญ ฯลฯ)
  • ข่าวสารล่าสุดเกี่ยวกับบริษัท
  • รายละเอียดเกี่ยวกับงบการเงินของบริษัท
// src/main/java/com/example/agent/CompanyDetective.java 
package com.example.agent;

import com.google.adk.agents.LlmAgent;
import com.google.adk.agents.ParallelAgent;
import com.google.adk.agents.SequentialAgent;
import com.google.adk.tools.GoogleSearchTool;
import com.google.adk.web.AdkWebServer;

public class CompanyDetective {
    public static void main(String[] args) {
        var companyProfiler = LlmAgent.builder()
            .name("company-profiler")
            .description("Provides a general overview of a company.")
            .instruction("""
                Your role is to provide a brief overview of the given company.
                Include its mission, headquarters, and current CEO.
                Use the Google Search Tool to find this information.
                """)
            .model("gemini-2.5-flash")
            .tools(new GoogleSearchTool())
            .outputKey("profile")
            .build();

        var newsFinder = LlmAgent.builder()
            .name("news-finder")
            .description("Finds the latest news about a company.")
            .instruction("""
                Your role is to find the top 3-4 recent news headlines for the given company.
                Use the Google Search Tool.
                Present the results as a simple bulleted list.
                """)
            .model("gemini-2.5-flash")
            .tools(new GoogleSearchTool())
            .outputKey("news")
            .build();

        var financialAnalyst = LlmAgent.builder()
            .name("financial-analyst")
            .description("Analyzes the financial performance of a company.")
            .instruction("""
                Your role is to provide a snapshot of the given company's recent financial performance.
                Focus on stock trends or recent earnings reports.
                Use the Google Search Tool.
                """)
            .model("gemini-2.5-flash")
            .tools(new GoogleSearchTool())
            .outputKey("financials")
            .build();

        var marketResearcher = ParallelAgent.builder()
            .name("market-researcher")
            .description("Performs comprehensive market research on a company.")
            .subAgents(
                companyProfiler,
                newsFinder,
                financialAnalyst
            )
            .build();

        var reportCompiler = LlmAgent.builder()
            .name("report-compiler")
            .description("Compiles a final market research report.")
            .instruction("""
                Your role is to synthesize the provided information into a coherent market research report.
                Combine the company profile, latest news, and financial analysis into a single, well-formatted report.

                ## Company Profile
                {profile}

                ## Latest News
                {news}

                ## Financial Snapshot
                {financials}
                """)
            .model("gemini-2.5-flash")
            .build();

        AdkWebServer.start(SequentialAgent.builder()
            .name("company-detective")
            .description("Collects various information about a company.")
            .subAgents(
                marketResearcher,
                reportCompiler
            ).build());
    }
}

คุณเรียกใช้เอเจนต์ได้ตามปกติโดยใช้คำสั่งต่อไปนี้

mvn compile exec:java -Dexec.mainClass=com.example.agent.CompanyDetective

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

10. เวิร์กโฟลว์ของ Agent - การปรับแต่งแบบวนซ้ำ

ea37b0ab05aa5b28.png

สำหรับงานที่ต้องมีวงจร "สร้าง → ตรวจสอบ → ปรับแต่ง" ให้ใช้ LoopAgent ซึ่งจะช่วยปรับปรุงซ้ำๆ โดยอัตโนมัติจนกว่าจะบรรลุเป้าหมาย LoopAgent จะเรียกใช้ตัวแทนย่อยแบบอนุกรมเช่นเดียวกับ SequentialAgent แต่จะวนกลับไปที่จุดเริ่มต้น ซึ่งเป็น LLM ที่เอเจนต์ใช้ภายในที่จะตัดสินใจว่าจะขอให้โทรไปยังเครื่องมือพิเศษ ซึ่งก็คือexit_loopเครื่องมือในตัวexit_loopหรือไม่ เพื่อหยุดการดำเนินการของลูป

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

มาดูโค้ดกัน

// src/main/java/com/example/agent/CodeRefiner.java
package com.example.agent;

import com.google.adk.agents.LlmAgent;
import com.google.adk.agents.LoopAgent;
import com.google.adk.agents.SequentialAgent;
import com.google.adk.tools.ExitLoopTool;
import com.google.adk.web.AdkWebServer;

public class CodeRefiner {
    public static void main(String[] args) {
        var codeGenerator = LlmAgent.builder()
            .name("code-generator")
            .description("Writes and refines code based on a request and feedback.")
            .instruction("""
                Your role is to write a Python function based on the user's request.
                In the first turn, write the initial version of the code.
                In subsequent turns, you will receive feedback on your code.
                Your task is to refine the code based on this feedback.

                Previous feedback (if any):
                {feedback?}
                """)
            .model("gemini-2.5-flash")
            .outputKey("generated_code")
            .build();

        var codeReviewer = LlmAgent.builder()
            .name("code-reviewer")
            .description("Reviews code and decides if it's complete or needs more work.")
            .instruction("""
                Your role is to act as a senior code reviewer.
                Analyze the provided Python code for correctness, style, and potential bugs.

                Code to review:
                {generated_code}

                If the code is perfect and meets the user's request,
                you MUST call the `exit_loop` tool.

                Otherwise, provide constructive feedback for the `code-generator to improve the code.
                """)
            .model("gemini-2.5-flash")
            .outputKey("feedback")
            .tools(ExitLoopTool.INSTANCE)
            .build();

        var codeRefinerLoop = LoopAgent.builder()
            .name("code-refiner-loop")
            .description("Iteratively generates and reviews code until it is correct.")
            .subAgents(
                codeGenerator,
                codeReviewer
            )
            .maxIterations(3) // Safety net to prevent infinite loops
            .build();

        var finalPresenter = LlmAgent.builder()
            .name("final-presenter")
            .description("Presents the final, accepted code to the user.")
            .instruction("""
                The code has been successfully generated and reviewed.
                Present the final version of the code to the user in a clear format.

                Final Code:
                {generated_code}
                """)
            .model("gemini-2.5-flash")
            .build();

        AdkWebServer.start(SequentialAgent.builder()
            .name("code-refiner-assistant")
            .description("Manages the full code generation and refinement process.")
            .subAgents(
                codeRefinerLoop,
                finalPresenter)
            .build());
    }
}

เรียกใช้เอเจนต์นี้ด้วยคำสั่งต่อไปนี้

mvn compile exec:java -Dexec.mainClass=com.example.agent.CodeRefiner

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

11. ยินดีด้วย

337a2e319008d004.png

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

ขั้นตอนต่อไปคืออะไร

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