Tạo Đặc vụ AI bằng Agent Development Kit (ADK) cho Java

1. Chào mừng các nhà phát triển tác nhân AI!

Trong lớp học lập trình này, bạn sẽ tìm hiểu cách tạo các tác nhân AI bằng Java, bằng cách sử dụng Bộ công cụ phát triển tác nhân (ADK) cho Java. Chúng tôi sẽ vượt ra ngoài các lệnh gọi API Mô hình ngôn ngữ lớn (LLM) đơn giản để tạo ra các tác nhân AI tự trị có thể suy luận, lập kế hoạch, sử dụng các công cụ và phối hợp với nhau để giải quyết các vấn đề phức tạp.

Bạn sẽ bắt đầu bằng cách đổi tín dụng Google Cloud, thiết lập môi trường Google Cloud, sau đó xây dựng tác nhân đơn giản đầu tiên và dần dần thêm các chức năng nâng cao hơn như công cụ tuỳ chỉnh, tìm kiếm trên web và điều phối nhiều tác nhân.

d666c455bb267688.png

Kiến thức bạn sẽ học được

  • Cách tạo một tác nhân AI cơ bản dựa trên tính cách.
  • Cách trang bị cho nhân viên hỗ trợ các công cụ tuỳ chỉnh và công cụ tích hợp (như Google Tìm kiếm).
  • Cách thêm các công cụ của riêng bạn được triển khai bằng Java.
  • Cách điều phối nhiều tác nhân thành các quy trình công việc tuần tự, song song và lặp lại mạnh mẽ.

Bạn cần có

  • Một trình duyệt web mà chúng ta sẽ sử dụng ở Chế độ ẩn danh.
  • Tài khoản Gmail cá nhân.
  • Một dự án Google Cloud mới được liên kết với tài khoản Gmail cá nhân của bạn.
  • Tài khoản thanh toán được tạo bằng các khoản tín dụng đã sử dụng trên Google Cloud.
  • Công cụ dòng lệnh git để kiểm tra mã nguồn.
  • Java 17 trở lên và Apache Maven.
  • Một trình soạn thảo văn bản hoặc IDE, chẳng hạn như IntelliJ IDEA hoặc VS Code.

Bạn có thể sử dụng trình chỉnh sửa VS Code tích hợp trong Cloud Shell, trong Google Cloud Console.

2. Thiết lập: Môi trường của bạn

Yêu cầu tín dụng Google Cloud cho hội thảo

e3e67ae61e86ec9f.png

Đối với một hội thảo có người hướng dẫn, bạn sẽ nhận được một đường liên kết đến trang web nơi bạn có thể yêu cầu cấp tín dụng Google Cloud để sử dụng cho hội thảo.

  • Sử dụng Tài khoản Google cá nhân: Bạn cần sử dụng Tài khoản Google cá nhân (chẳng hạn như địa chỉ gmail.com) vì địa chỉ email của công ty hoặc trường học sẽ không hoạt động.
  • Sử dụng Google Chrome ở chế độ ẩn danh: Bạn nên làm việc này để tạo một phiên hoạt động mới và tránh xung đột với các Tài khoản Google khác.
  • Sử dụng đường liên kết đến sự kiện đặc biệt: Bạn nên sử dụng một đường liên kết đặc biệt đến sự kiện (có dạng như https://trygcp.dev/event/xxx kèm theo mã sự kiện (trong ví dụ này là "xxx")).
  • Chấp nhận điều khoản dịch vụ: Sau khi đăng nhập, bạn sẽ thấy điều khoản dịch vụ của Google Cloud Platform. Bạn cần chấp nhận điều khoản này để tiếp tục.
  • Tạo một dự án mới: Bạn phải tạo một dự án trống mới trong Google Cloud Console.
  • Liên kết tài khoản thanh toán: Liên kết dự án mới tạo với một tài khoản thanh toán.
  • Xác nhận khoản tín dụng: Video sau đây hướng dẫn cách xác nhận rằng khoản tín dụng đã được áp dụng cho dự án bằng cách kiểm tra phần "tín dụng" trên trang thanh toán.

Bạn có thể xem video này để tìm hiểu cách sử dụng và áp dụng các khoản tín dụng.

Tạo và định cấu hình khoá API

Để xác thực các tác nhân AI ADK bằng Gemini API trong lớp học lập trình này, bạn sẽ sử dụng một khoá API được liên kết với dự án Google Cloud của mình.

  1. Tạo khoá API:
  • Truy cập Google AI Studio rồi nhấp vào đường liên kết "Lấy khoá API" ở cuối bảng điều khiển bên trái.
  • Chọn Dự án rồi nhấp vào nút Nhập dự án.
  • Tìm và chọn dự án Google Cloud mà bạn muốn nhập, sau đó chọn nút Nhập.
  • Sau khi nhập dự án, hãy chuyển đến trang API Keys (Khoá API) trong trình đơn Dashboard (Trang tổng quan) rồi tạo khoá API trong dự án mà bạn vừa nhập.
  • Ghi lại khoá API.
  1. Đặt biến môi trường: Agent của bạn cần truy cập vào khoá này. Cách tiêu chuẩn là thiết lập một biến môi trường có tên là GOOGLE_API_KEY.
  • macOS / Linux: Mở cửa sổ dòng lệnh rồi chạy lệnh sau, thay thế "your-api-key" bằng khoá mà bạn vừa sao chép. Để thực hiện việc này vĩnh viễn, hãy thêm dòng này vào tệp khởi động của trình bao (ví dụ: ~/.bash_profile, ~/.zshrc).
export GOOGLE_API_KEY="your-api-key"
  • Windows (Command Prompt): Mở một cửa sổ dòng lệnh mới và chạy:
setx GOOGLE_API_KEY "your-api-key"
  • Bạn sẽ cần khởi động lại dấu nhắc lệnh để thay đổi này có hiệu lực.
  • Windows (PowerShell): Mở một cửa sổ dòng lệnh PowerShell rồi chạy:
$env:GOOGLE_API_KEY="your-api-key"
  • Để thay đổi vĩnh viễn trong PowerShell, bạn cần thêm thay đổi đó vào tập lệnh hồ sơ của mình.

3. Bắt đầu: Tác nhân đầu tiên của bạn

f814ab5b7614e071.png

Cách tốt nhất để bắt đầu một dự án mới là sử dụng mẫu ADK cho Java trên GitHub. Nó cung cấp cấu trúc dự án và tất cả các phần phụ thuộc cần thiết.

Nếu có tài khoản Github, bạn có thể làm như sau: Use this template > Create a new repository, sau đó kiểm tra mã cục bộ bằng lệnh git clone.

Đây là ảnh chụp màn hình cho thấy trình đơn trên cùng bên phải để sử dụng mẫu.

1613a3d0ddc66dc5.png

Cách khác là chỉ cần sao chép trực tiếp kho lưu trữ đó bằng cách:

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

Sau đó, cd vào adk-java-maven-template.

Để kiểm tra xem bạn đã sẵn sàng bắt đầu viết mã cho tác nhân AI đầu tiên bằng Java hay chưa, hãy đảm bảo bạn có thể biên dịch mã trong dự án này bằng cách:

mvn compile

Bước lập trình: Một tác nhân giáo viên khoa học thân thiện

Thành phần cơ bản trong ADK là lớp LlmAgent. Hãy coi đây là một AI có tính cách và mục tiêu cụ thể, được hỗ trợ bởi Mô hình ngôn ngữ lớn. Sau này, chúng tôi sẽ bổ sung thêm nhiều chức năng thông qua các công cụ và tăng cường sức mạnh cho công cụ này bằng cách hợp tác chặt chẽ với các tác nhân tương tự khác.

Hãy tạo một lớp Java mới trong gói com.example.agent và gọi lớp đó là ScienceTeacher.

Đây là "Hello, World!" của quá trình tạo tác nhân. Chúng ta sẽ xác định một tác nhân đơn giản có tính cách của một giáo viên khoa học.

// 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()
        );
    }
}

Bạn có thể định cấu hình tác nhân AI thông qua phương thức LlmAgent.builder(). Các tham số name(), description()model() là bắt buộc. Để mang lại tính cách cụ thể và hành vi phù hợp cho trợ lý ảo, bạn nên luôn đưa ra hướng dẫn chi tiết thông qua phương thức instruction().

Ở đây, chúng tôi chọn sử dụng mô hình Gemini 2.5 Flash, nhưng bạn cũng có thể dùng thử Gemini 2.5 Pro cho các nhiệm vụ phức tạp hơn.

Tác nhân này được bao bọc trong phương thức AdkWebServer.start(). Đây là giao diện trò chuyện ADK Dev UI. Tính năng này cho phép bạn trò chuyện với trợ lý ảo thông qua một giao diện trò chuyện thông thường. Hơn nữa, việc này sẽ rất hữu ích nếu bạn muốn tìm hiểu những gì đang diễn ra bên trong, chẳng hạn như tất cả các sự kiện đang diễn ra trong hệ thống, các yêu cầu và phản hồi được gửi đến LLM.

Để biên dịch và chạy tác nhân này cục bộ, hãy chạy lệnh sau:

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

Sau đó, hãy chuyển đến trình duyệt tại http://localhost:8080. Bạn sẽ thấy giao diện người dùng như trong ảnh chụp màn hình bên dưới. Hãy đặt câu hỏi liên quan đến khoa học cho trợ lý ảo.

da094da276ba15d6.png

4. Trao quyền cho nhân viên hỗ trợ bằng các công cụ

cd5c5798a0861a1c.png

Tại sao nhân viên cần có công cụ? Mặc dù có sức mạnh, nhưng kiến thức của các LLM chỉ giới hạn trong một khoảng thời gian và chúng không thể tương tác với thế giới bên ngoài. Công cụ là cầu nối. Chúng cho phép một tác nhân truy cập vào thông tin theo thời gian thực (chẳng hạn như giá cổ phiếu hoặc tin tức), truy vấn các API riêng tư hoặc thực hiện mọi hành động mà bạn có thể lập trình bằng Java.

Bước mã: Tạo một công cụ tuỳ chỉnh (StockTicker)

Ở đây, chúng ta cung cấp cho trợ lý một công cụ để tra cứu giá cổ phiếu. Tác nhân suy luận rằng khi người dùng yêu cầu giá, tác nhân sẽ gọi phương thức Java của chúng tôi.

// 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)
    }
}

Để giúp các tác nhân thông minh hơn và có khả năng tương tác với thế giới (hoặc với mã, API, dịch vụ, v.v. của riêng bạn), bạn có thể định cấu hình tác nhân để sử dụng các công cụ, đặc biệt là các công cụ mã tuỳ chỉnh, thông qua phương thức tools(), truyền cho phương thức này một FunctionTool.create(...).

FunctionTool cần một lớp và tên phương thức trỏ đến phương thức tĩnh của riêng bạn – bạn cũng có thể truyền một phiên bản của lớp và tên của phương thức phiên bản của đối tượng đó.

Bạn cần chỉ định namedescription của cả phương thức và các tham số của phương thức đó thông qua chú thích @Schema, vì LLM cơ bản sẽ dùng thông tin này để xác định thời điểm và cách gọi một phương thức nhất định.

Điều quan trọng không kém là bạn nên đưa ra hướng dẫn rõ ràng cho LLM về cách thức và thời điểm sử dụng công cụ này. Mô hình có thể tự tìm ra, nhưng nếu bạn đưa ra lời giải thích rõ ràng trong phương thức instruction(), thì hàm của bạn sẽ có nhiều khả năng được gọi một cách thích hợp hơn.

Phương thức này sẽ trả về một Map. Thông thường, ý tưởng là trả về một bản đồ có khoá đại diện cho kết quả, chẳng hạn như stock_price và liên kết giá trị của giá cổ phiếu với khoá đó. Cuối cùng, bạn có thể thêm một cặp khoá/giá trị thành công/true để báo hiệu thành công của thao tác. Trong trường hợp xảy ra lỗi, bạn nên trả về một bản đồ có khoá, chẳng hạn như error và liên kết thông báo lỗi trong giá trị được liên kết. Điều này giúp LLM hiểu được liệu lệnh gọi có thành công hay không thành công vì lý do nào đó.

  • Khi thành công, hãy trả về: {"stock_price": 123}
  • Khi có lỗi, hãy trả về: {"error": "Impossible to retrieve stock price for XYZ"}

Sau đó, hãy chạy lớp này bằng lệnh sau:

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

5. Sức mạnh của Google Tìm kiếm trong việc cung cấp thông tin mới nhất

ae215e7b7cde02ab.png

ADK cho Java đi kèm với một số công cụ mạnh mẽ, trong đó có GoogleSearchTool. Với công cụ này, tác nhân của bạn có thể yêu cầu sử dụng Google Tìm kiếm để tìm thông tin liên quan nhằm đạt được mục tiêu.

Thật vậy, kiến thức của một LLM được cố định theo thời gian: LLM được huấn luyện cho đến một ngày nhất định ("ngày cắt") bằng dữ liệu cũng mới nhất có thể tại thời điểm thông tin được thu thập. Điều này có nghĩa là LLM có thể không biết về các sự kiện gần đây hoặc kiến thức của LLM có thể hạn chế và hời hợt. Do đó, sự trợ giúp của một công cụ tìm kiếm có thể làm mới bộ nhớ hoặc dạy cho LLM thêm về chủ đề đó.

Hãy xem xét tác nhân tìm kiếm tin tức đơn giản này:

// 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());
    }
}

Lưu ý cách chúng ta truyền một phiên bản của công cụ tìm kiếm bằng: tools(new GoogleSearchTool()). Nhờ đó, trợ lý ảo của chúng tôi có thể nắm bắt thông tin mới nhất trên web. Ngoài ra, câu lệnh còn chỉ định ngày trong ngày, vì điều này có thể giúp LLM hiểu được khi nào câu hỏi là về thông tin trong quá khứ và cần tra cứu thông tin gần đây hơn.

Sau đó, hãy chạy lớp này bằng lệnh sau:

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

Bạn có thể thoải mái điều chỉnh câu lệnh để yêu cầu kết quả khác nhau về phong cách, tính súc tích hoặc tiêu điểm, v.v.

Bước mã: Tác nhân tìm kiếm dưới dạng một công cụ

Thay vì truyền GoogleSearchTool trực tiếp đến một tác nhân dưới dạng một công cụ, bạn có thể tạo một tác nhân tìm kiếm chuyên dụng bao bọc chức năng tìm kiếm và hiển thị tác nhân đó dưới dạng một công cụ cho tác nhân cấp cao hơn.

Đây là một khái niệm nâng cao cho phép bạn uỷ quyền các hành vi phức tạp (chẳng hạn như tìm kiếm tóm tắt kết quả) cho một tác nhân phụ chuyên biệt. Phương pháp này thường hữu ích cho các quy trình phức tạp hơn, vì bạn không thể dùng các công cụ tích hợp với các công cụ tuỳ chỉnh dựa trên mã.

// 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()
       );
    }
}

Dòng AgentTool.create(searchAgent) là khái niệm chính ở đây. Thao tác này sẽ đăng ký toàn bộ searchAgent (với logic, lời nhắc và công cụ nội bộ riêng) dưới dạng một công cụ có thể gọi duy nhất cho mainAgent. Điều này giúp tăng tính mô-đun và khả năng tái sử dụng.

Chạy lớp này bằng lệnh sau:

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

Đối với những câu hỏi thông thường, trợ lý sẽ trả lời dựa trên cơ sở kiến thức của riêng mình, nhưng khi được hỏi về các sự kiện gần đây, trợ lý sẽ uỷ quyền tìm kiếm cho trợ lý tìm kiếm chuyên biệt bằng cách sử dụng công cụ Google Tìm kiếm.

6. Nắm vững quy trình làm việc hỗ trợ

Đối với các vấn đề phức tạp, một nhân viên hỗ trợ là không đủ. Khi được giao một mục tiêu bao gồm quá nhiều nhiệm vụ phụ, với một câu lệnh giải thích quá chi tiết hoặc có quyền truy cập vào một số lượng lớn các hàm, LLM sẽ gặp khó khăn và hiệu suất cũng như độ chính xác của chúng sẽ giảm sút.

Điều quan trọng là phải chia để trị bằng cách điều phối nhiều đặc vụ chuyên biệt. Rất may, ADK đi kèm với nhiều tác nhân chuyên biệt tích hợp sẵn:

  • Tác nhân thông thường có subAgent() để uỷ quyền các việc cần làm,
  • SequentialAgent, để thực hiện các việc cần làm theo trình tự,
  • ParallelAgent để thực thi các tác nhân song song,
  • LoopAgent, thường là để trải qua quy trình tinh chỉnh nhiều lần nếu cần.

Vui lòng xem bảng dưới đây để biết các trường hợp sử dụng chính cũng như ưu và nhược điểm của từng quy trình. Tuy nhiên, bạn cần biết rằng sức mạnh thực sự sẽ đến từ việc kết hợp nhiều yếu tố trong số đó!

Quy trình làm việc

Lớp ADK

Trường hợp sử dụng

Ưu điểm

Nhược điểm

Đại lý phụ

LlmAgent

Các tác vụ linh hoạt do người dùng thực hiện, trong đó bước tiếp theo không phải lúc nào cũng được biết.

Tính linh hoạt cao, mang tính trò chuyện, phù hợp với các bot tương tác với người dùng.

Ít dự đoán được, dựa vào khả năng suy luận của LLM để kiểm soát luồng.

Tuần tự

SequentialAgent

Quy trình cố định, nhiều bước mà thứ tự là yếu tố quan trọng.

Có thể dự đoán, đáng tin cậy, dễ gỡ lỗi, đảm bảo thứ tự.

Không linh hoạt, có thể chậm hơn nếu các tác vụ có thể được thực hiện song song.

Song song

ParallelAgent

Thu thập dữ liệu từ nhiều nguồn hoặc chạy các tác vụ độc lập.

Có hiệu suất cao, giảm đáng kể độ trễ cho các tác vụ liên kết I/O.

Tất cả các tác vụ đều chạy; không có tác vụ nào bị bỏ qua. Ít phù hợp với những công việc có phần phụ thuộc.

Lặp

LoopAgent

Tinh chỉnh lặp đi lặp lại, tự sửa lỗi hoặc các quy trình lặp lại cho đến khi đạt được một điều kiện.

Mạnh mẽ trong việc giải quyết các vấn đề phức tạp, cho phép nhân viên cải thiện công việc của chính họ.

Có thể dẫn đến vòng lặp vô hạn nếu không được thiết kế cẩn thận (luôn sử dụng maxIterations!).

7. Quy trình công việc dạng tác nhân AI – Uỷ quyền bằng tác nhân phụ

3b3074b840f57c1c.png

Nhân viên giám sát có thể uỷ quyền một số việc cụ thể cho nhân viên cấp dưới. Ví dụ: hãy tưởng tượng một tác nhân cho trang web thương mại điện tử sẽ uỷ quyền các câu hỏi liên quan đến đơn đặt hàng cho một tác nhân ("đơn đặt hàng của tôi có trạng thái như thế nào?") và các câu hỏi về dịch vụ hậu mãi cho một tác nhân khác ("Tôi không biết cách bật!"). Đây là trường hợp sử dụng mà chúng ta sẽ thảo luận.

// 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()
        );
    }
}

Dòng khoá ở đây là nơi phương thức subAgents() được gọi, truyền vào 2 tác nhân phụ có vai trò cụ thể sẽ được xử lý riêng biệt với nhau.

Chạy ví dụ trên bằng lệnh sau:

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

Khái niệm uỷ quyền nhiệm vụ cho các trợ lý phụ này phản ánh việc quản lý hiệu quả của con người, trong đó một nhà quản lý giỏi (trợ lý giám sát) dựa vào các nhân viên chuyên trách (trợ lý phụ) để xử lý các nhiệm vụ cụ thể mà họ có chuyên môn cao hơn. Người giám sát không cần biết chi tiết của từng quy trình; thay vào đó, hệ thống sẽ định tuyến một cách thông minh yêu cầu của khách hàng (chẳng hạn như yêu cầu về đơn đặt hàng hoặc vấn đề kỹ thuật) đến "thành viên nhóm" có trình độ chuyên môn cao nhất, đảm bảo phản hồi chất lượng cao và hiệu quả hơn so với một chuyên viên tổng quát có thể cung cấp một mình. Hơn nữa, các nhân viên phụ này có thể hoàn toàn tập trung vào nhiệm vụ riêng của mình mà không cần hiểu toàn bộ quy trình tổng thể phức tạp.

8. Quy trình làm việc dựa trên trợ lý AI – Dây chuyền lắp ráp

108f8601cd36b559.png

Khi thứ tự của các phép toán quan trọng, hãy sử dụng SequentialAgent. Giống như một dây chuyền lắp ráp, nó thực thi các tác nhân phụ theo một thứ tự cố định, trong đó mỗi bước có thể phụ thuộc vào bước trước đó.

Hãy tưởng tượng một nhà thơ người Anh hợp tác với một người dịch tiếng Anh sang tiếng Pháp để sáng tác thơ bằng tiếng Anh trước, sau đó dịch sang tiếng Pháp:

// 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());
    }
}

Chạy ví dụ để nhận một bài thơ bằng tiếng Anh, sau đó dịch sang tiếng Pháp bằng lệnh sau:

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

Việc phân tách có hệ thống các tác vụ phức tạp thành các tác vụ phụ nhỏ hơn, có thứ tự đảm bảo một quy trình xác định và đáng tin cậy hơn, giúp tăng đáng kể khả năng đạt được kết quả thành công so với việc chỉ dựa vào một tác nhân có mục đích chung.

Việc phân tách hiệu quả một nhiệm vụ thành một chuỗi các nhiệm vụ phụ (khi có thể và khi cần thiết) là điều quan trọng để đạt được kết quả xác định và thành công hơn, vì điều này cho phép tiến trình có cấu trúc và quản lý sự phụ thuộc giữa các bước.

9. Quy trình làm việc dựa trên tác nhân – Làm việc song song

4ba95f71e0189ae7.png

Khi các tác vụ độc lập, ParallelAgent sẽ giúp tăng hiệu suất đáng kể bằng cách chạy các tác vụ đó cùng lúc. Trong ví dụ sau, chúng ta thậm chí sẽ kết hợp SequentialAgent với ParallelAgent: các tác vụ song song sẽ chạy trước, sau đó một tác nhân cuối cùng sẽ tóm tắt kết quả của các tác vụ song song.

Hãy tạo một thám tử công ty có nhiệm vụ tìm kiếm thông tin về:

  • Hồ sơ công ty (Giám đốc điều hành, trụ sở chính, phương châm, v.v.)
  • Tin tức mới nhất về công ty.
  • Thông tin chi tiết về tình hình tài chính của công ty.
// 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());
    }
}

Như thường lệ, bạn có thể chạy tác nhân bằng lệnh sau:

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

Tác nhân này minh hoạ sự kết hợp mạnh mẽ giữa các quy trình làm việc, trong đó cả tác nhân song song và tác nhân tuần tự đều được sử dụng hiệu quả, nhờ khả năng song song hoá việc nghiên cứu và tổng hợp thông tin.

10. Quy trình làm việc dựa trên trợ lý AI – Tinh chỉnh lặp đi lặp lại

ea37b0ab05aa5b28.png

Đối với những tác vụ yêu cầu chu trình "tạo → xem xét → tinh chỉnh", hãy sử dụng LoopAgent. Tính năng này tự động cải thiện lặp đi lặp lại cho đến khi đạt được mục tiêu. Tương tự như SequentialAgent, LoopAgent sẽ gọi các tác nhân phụ theo tuần tự, nhưng sẽ quay lại từ đầu. LLM được tác nhân sử dụng nội bộ sẽ quyết định có yêu cầu gọi đến một công cụ đặc biệt (công cụ exit_loop tích hợp) hay không để dừng quá trình thực thi vòng lặp.

Ví dụ về trình tinh chỉnh mã bên dưới, sử dụng LoopAgent, tự động hoá việc tinh chỉnh mã: tạo, xem xét, sửa. Điều này mô phỏng quá trình phát triển của con người. Trước tiên, trình tạo mã sẽ tạo mã được yêu cầu, lưu mã đó vào trạng thái của tác nhân theo khoá generated_code. Sau đó, người đánh giá mã sẽ xem xét mã đã tạo và đưa ra ý kiến phản hồi (trong khoá feedback) hoặc gọi một công cụ vòng lặp thoát để kết thúc sớm quá trình lặp.

Hãy xem mã này:

// 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());
    }
}

Chạy tác nhân này bằng lệnh sau:

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

Vòng lặp phản hồi/tinh chỉnh, được triển khai bằng cách sử dụng LoopAgent, là yếu tố không thể thiếu để giải quyết các vấn đề đòi hỏi phải cải thiện và tự điều chỉnh lặp đi lặp lại, mô phỏng chặt chẽ các quy trình nhận thức của con người. Mẫu thiết kế này đặc biệt hữu ích cho những tác vụ mà đầu ra ban đầu hiếm khi hoàn hảo, chẳng hạn như tạo mã, viết nội dung sáng tạo, lặp lại thiết kế hoặc phân tích dữ liệu phức tạp. Bằng cách chuyển đầu ra qua một tác nhân đánh giá chuyên biệt cung cấp ý kiến phản hồi có cấu trúc, tác nhân tạo sinh có thể liên tục tinh chỉnh công việc của mình cho đến khi đáp ứng được tiêu chí hoàn thành được xác định trước, dẫn đến kết quả cuối cùng có chất lượng cao hơn và đáng tin cậy hơn so với phương pháp một lần.

11. Xin chúc mừng!

337a2e319008d004.png

Bạn đã xây dựng và khám phá thành công nhiều tác nhân AI, từ những tác nhân đàm thoại đơn giản đến các hệ thống phức tạp gồm nhiều tác nhân. Bạn đã tìm hiểu các khái niệm cốt lõi của ADK cho Java: xác định các tác nhân bằng hướng dẫn, trang bị cho chúng các công cụ và điều phối chúng thành các quy trình công việc hiệu quả.

Tiếp theo là gì?

  • Khám phá kho lưu trữ GitHub chính thức của ADK cho Java.
  • Tìm hiểu thêm về khung này trong tài liệu của khung.
  • Hãy đọc về các quy trình làm việc dựa trên tác nhân trong chuỗi blog này và về các công cụ có sẵn.
  • Tìm hiểu sâu hơn về các công cụ tích hợp khác và lệnh gọi lại nâng cao.
  • Xử lý ngữ cảnh, trạng thái và cấu phần phần mềm để có các hoạt động tương tác phong phú và đa phương thức.
  • Triển khai và áp dụng các trình bổ trợ cắm vào vòng đời của các tác nhân.
  • Hãy thử tạo một tác nhân của riêng bạn để giải quyết một vấn đề thực tế!