1. ברוכים הבאים, מפתחים של נציגי תמיכה מבוססי-AI!
ב-codelab הזה תלמדו איך לבנות סוכני AI ב-Java באמצעות ערכת פיתוח הסוכנים (ADK) ל-Java. נלמד איך ליצור סוכני AI אוטונומיים שיכולים להסיק מסקנות, לתכנן, להשתמש בכלים ולעבוד יחד כדי לפתור בעיות מורכבות, ולא רק איך לבצע קריאות פשוטות ל-API של מודלים גדולים של שפה (LLM).
תתחילו במימוש הקרדיטים ל-Google Cloud, בהגדרת סביבת Google Cloud, ואז תיצרו את הסוכן הפשוט הראשון שלכם ותוסיפו בהדרגה יכולות מתקדמות יותר כמו כלים בהתאמה אישית, חיפוש באינטרנט ותזמור של כמה סוכנים.

מה תלמדו
- איך יוצרים סוכן AI בסיסי שמבוסס על פרסונה.
- איך נותנים לסוכנים כלים מותאמים אישית וכלים מובנים (כמו חיפוש Google).
- איך מוסיפים כלים משלכם שהוטמעו ב-Java.
- איך לתזמר כמה סוכנים לתהליכי עבודה יעילים ברצף, במקביל ובלולאה.
הדרישות
- דפדפן אינטרנט שנשתמש בו במצב פרטי.
- חשבון 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 לסדנה

אם אתם משתתפים בסדנה בהנחיית מדריך, קיבלתם קישור לאתר שבו תוכלו לממש קרדיטים ל-Google Cloud לשימוש בסדנה.
- שימוש בחשבון Google אישי: חשוב להשתמש בחשבון Google אישי (למשל כתובת gmail.com), כי כתובות אימייל של חברות או בתי ספר לא יפעלו.
- שימוש ב-Google Chrome במצב פרטי: מומלץ להשתמש במצב הזה כדי ליצור סשן נקי ולמנוע התנגשויות עם חשבונות Google אחרים.
- שימוש בקישור לאירוע מיוחד: צריך להשתמש בקישור מיוחד לאירוע, שדומה לקישור https://trygcp.dev/event/xxx ואחריו קוד האירוע (בדוגמה הזו, xxx).
- מאשרים את התנאים וההגבלות: אחרי הכניסה לחשבון, מוצגים התנאים וההגבלות של Google Cloud Platform, שצריך לאשר כדי להמשיך.
- יצירת פרויקט חדש: צריך ליצור פרויקט חדש וריק מתוך מסוף Google Cloud.
- קישור חשבון לחיוב: קישור הפרויקט החדש לחשבון לחיוב.
- אישור הזיכוי: בסרטון הבא מוסבר איך בודקים שהזיכוי חל על הפרויקט. לשם כך, צריך לעיין בקטע 'זיכויים' בדף החיוב.
מומלץ לצפות בסרטון הזה כדי להבין איך לממש את הקרדיטים ולהשתמש בהם.
יצירה והגדרה של מפתח API
כדי לאמת את סוכני ה-AI של ADK באמצעות Gemini API בסדנת התכנות הזו, תשתמשו במפתח API שמשויך לפרויקט שלכם ב-Google Cloud.
- יצירת מפתח API:
- עוברים אל Google AI Studio ולוחצים על הקישור 'קבלת מפתח API' בתחתית החלונית הימנית.
- בוחרים באפשרות פרויקטים ואז לוחצים על הלחצן ייבוא פרויקטים.
- מחפשים את הפרויקט ב-Google Cloud שרוצים לייבא ובוחרים אותו, ואז לוחצים על הלחצן ייבוא.
- אחרי שמייבאים את הפרויקט, עוברים לדף API Keys בתפריט Dashboard ויוצרים מפתח API בפרויקט שזה עתה ייבאתם.
- רושמים את מפתח ה-API.
- מגדירים את משתנה הסביבה: לסוכן שלכם צריכה להיות גישה למפתח הזה. הדרך הסטנדרטית היא להגדיר משתנה סביבה בשם
GOOGLE_API_KEY.
- macOS / Linux: פותחים את הטרמינל ומריצים את הפקודה הבאה, ומחליפים את
"your-api-key"במפתח שהעתקתם. כדי להפוך את השינוי הזה לקבוע, מוסיפים את השורה הזו לקובץ ההפעלה של המעטפת (לדוגמה,~/.bash_profile,~/.zshrc).
export GOOGLE_API_KEY="your-api-key"
- Windows (שורת פקודה): פותחים שורת פקודה חדשה ומריצים:
setx GOOGLE_API_KEY "your-api-key"
- כדי שהשינוי ייכנס לתוקף, צריך להפעיל מחדש את שורת הפקודה.
- Windows (PowerShell): פותחים טרמינל ב-PowerShell ומריצים:
$env:GOOGLE_API_KEY="your-api-key"
- כדי שהשינוי הזה יהיה קבוע ב-PowerShell, צריך להוסיף אותו לסקריפט הפרופיל.
3. תחילת העבודה: הסוכן הראשון

הדרך הכי טובה להתחיל פרויקט חדש היא באמצעות תבנית ADK for Java GitHub. הוא מספק את מבנה הפרויקט ואת כל יחסי התלות הנדרשים.
אם יש לכם חשבון ב-GitHub, אתם יכולים לבצע את הפעולות הבאות: Use this template > Create a new repository, ואז להוציא את הקוד באופן מקומי באמצעות הפקודה git clone.
צילום מסך שבו מוצג התפריט בפינה השמאלית העליונה לשימוש בתבנית.

גישה אחרת היא פשוט לשכפל את המאגר ישירות באמצעות הפקודה:
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 מוגדר באמצעות ה-method LlmAgent.builder(). הפרמטרים name(), description() ו-model() הם חובה, וכדי להגדיר לסוכן אישיות ספציפית והתנהגות מתאימה, תמיד צריך לספק הנחיות מפורטות באמצעות השיטה instruction().
במקרה הזה בחרנו להשתמש במודל Gemini 2.5 Flash, אבל אתם יכולים לנסות גם את Gemini 2.5 Pro למשימות מורכבות יותר.
הנציג הזה עטוף בשיטה AdkWebServer.start(). זהו ממשק הצ'אט שנקרא ממשק המשתמש של ADK Dev. הוא מאפשר לכם לשוחח עם הסוכן באמצעות ממשק צ'אט רגיל. בנוסף, הוא יכול לעזור לכם להבין מה קורה מאחורי הקלעים, כמו כל האירועים שמתרחשים במערכת, הבקשות והתשובות שנשלחות ל-LLM.
כדי לקמפל ולהריץ את הסוכן הזה באופן מקומי, מריצים את הפקודה הבאה:
mvn compile exec:java -Dexec.mainClass=com.example.agent.ScienceTeacher
אחר כך עוברים לדפדפן בכתובת http://localhost:8080. ממשק המשתמש אמור להיראות כמו בצילום המסך שלמטה. אפשר לשאול את הסוכן שאלות שקשורות למדע.

4. מתן כלים לסוכנים

למה נציגים צריכים כלים? מודלים גדולים של שפה הם עוצמתיים, אבל הידע שלהם קפוא בזמן והם לא יכולים ליצור אינטראקציה עם העולם החיצוני. הכלים הם הגשר. הם מאפשרים לסוכן לגשת למידע בזמן אמת (כמו מחירי מניות או חדשות), לשאול שאילתות בממשקי 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 הבסיסי כדי להבין מתי ואיך הוא צריך להפעיל שיטה מסוימת.
חשוב לא פחות לתת למודל שפה גדול הוראות ברורות לגבי אופן השימוש בכלי ומתי להשתמש בו. יכול להיות שהמודל יצליח להבין את זה בעצמו, אבל אם תספקו הסברים ברורים בשיטה instruction(), הסיכוי שהפונקציה תיקרא בצורה מתאימה יהיה גבוה יותר.
השיטה הזו צריכה להחזיר Map. בדרך כלל, הרעיון הוא להחזיר מפה עם מפתח שמייצג את התוצאה, כמו stock_price, ולשייך אליה את ערך מחיר המניה. בסופו של דבר, אפשר להוסיף צמד מפתח / ערך נוסף של הצלחה או true כדי לציין שהפעולה הצליחה. במקרה של שגיאה, צריך להחזיר מפה עם מפתח שנקרא, למשל, 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 בחיפוש מידע עדכני

חבילת ה-ADK ל-Java כוללת כמה כלים מתקדמים, ביניהם GoogleSearchTool. בעזרת הכלי הזה, הסוכן יכול לבקש להשתמש בחיפוש Google כדי למצוא מידע רלוונטי להשגת המטרה שלו.
הידע של מודל 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 ישירות לסוכן ככלי, אפשר ליצור סוכן חיפוש ייעודי שמכיל את פונקציית החיפוש ולחשוף את הסוכן הזה ככלי לסוכן ברמה גבוהה יותר.
זהו מושג מתקדם שמאפשר להעביר התנהגויות מורכבות (כמו חיפוש וסיכום התוצאות) לסוכן משנה ייעודי. הגישה הזו שימושית בדרך כלל לתהליכי עבודה מורכבים יותר, כי אי אפשר להשתמש בכלים מובנים עם כלים מותאמים אישית שמבוססים על קוד.
// 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.
6. איך משתמשים בתהליכי עבודה מבוססי-סוכנים
לבעיות מורכבות, לא מספיק נציג תמיכה אחד. כשנותנים למודלים מסוג LLM מטרה שמורכבת ממשימות משנה רבות מדי, עם הנחיה ענקית שמסבירה יותר מדי פרטים, או עם גישה למספר עצום של פונקציות, הם מתקשים, והביצועים והדיוק שלהם יורדים.
הפתרון הוא לפצל את הבעיה ולפתור אותה באמצעות תיאום בין כמה סוכנים מומחים. למזלנו, ערכת ה-ADK כוללת סוכנים מובנים שונים:
- סוכן רגיל עם
subAgent()להאצלת משימות, -
SequentialAgent, כדי לבצע משימות ברצף, -
ParallelAgent, כדי להריץ סוכנים במקביל, -
LoopAgent, בדרך כלל כדי לעבור תהליך שיפור כמה פעמים שצריך.
בטבלה הבאה מפורטים תרחישים לדוגמה, וגם היתרונות והחסרונות של כל תהליך עבודה. אבל חשוב לדעת שהכוח האמיתי יגיע מהשילוב של כמה מהם.
תהליך עבודה | ADK Class | תרחיש לדוגמה | יתרונות | חסרונות |
סוכני משנה |
| משימות גמישות שמבוססות על משתמשים, שבהן לא תמיד ידוע מה השלב הבא. | גמישות גבוהה, ממשק שיחה, מתאים מאוד לבוטים שפונים למשתמשים. | פחות צפוי, מסתמך על נימוקי LLM לשליטה בזרימה. |
לפי הסדר |
| תהליכים קבועים עם כמה שלבים שבהם הסדר חשוב מאוד. | צפוי, אמין, קל לניפוי באגים, מבטיח סדר. | לא גמיש, יכול להיות איטי יותר אם אפשר להריץ את המשימות במקביל. |
מקביל |
| איסוף נתונים ממספר מקורות או הפעלת משימות עצמאיות. | יעיל מאוד, ומקצר באופן משמעותי את זמן האחזור של משימות שמוגבלות על ידי קלט/פלט. | כל המשימות מופעלות, ללא קיצור דרך. פחות מתאים למשימות עם יחסי תלות. |
Loop |
| שיפור איטרטיבי, תיקון עצמי או תהליכים שחוזרים על עצמם עד שמתקיים תנאי מסוים. | הוא עוזר לפתור בעיות מורכבות ומאפשר לנציגים לשפר את העבודה שלהם. | עלול להוביל ללולאות אינסופיות אם לא מעצבים אותו בקפידה (תמיד צריך להשתמש ב-maxIterations!). |
7. תהליכי עבודה מבוססי-סוכנים – העברה של משימות לסוכני משנה

סוכן מפקח יכול להאציל משימות מסוימות לסוכנים משניים. לדוגמה, נניח שיש סוכן באתר מסחר אלקטרוני שמקבל שאלות שקשורות להזמנות ומעביר אותן לסוכן אחר ("מה הסטטוס של ההזמנה שלי?") ושאלות שקשורות לשירות אחרי המכירה ומעביר אותן לסוכן אחר ("אני לא יודע איך להפעיל את זה!"). זהו תרחיש השימוש שנדון בו.
// 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 orderAgent = 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 afterSaleAgent = 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 to 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(afterSaleAgent, orderAgent)
.build()
);
}
}
השורה החשובה כאן היא השורה שבה מתבצעת הקריאה ל-method subAgents(), והיא מעבירה את שני הסוכנים המשניים שהתפקיד הספציפי שלהם יטופל בנפרד על ידי כל אחד מהם.
מריצים את הדוגמה שלמעלה באמצעות הפקודה הבאה:
mvn compile exec:java -Dexec.mainClass=com.example.agent.SupportAgent
הקונספט של העברת משימות לסוכנים משניים משקף ניהול אנושי יעיל, שבו מנהל טוב (הסוכן המפקח) מסתמך על עובדים מומחים (הסוכנים המשניים) כדי לטפל במשימות ספציפיות שבהן יש להם מומחיות רבה יותר. המנהל לא צריך לדעת את כל הפרטים הקטנים של כל תהליך. במקום זאת, הוא מעביר בצורה חכמה בקשת לקוח (למשל, שאילתה לגבי הזמנה או בעיה טכנית) אל 'חבר הצוות' המתאים ביותר, וכך מבטיח תגובה איכותית ויעילה יותר מזו שאיש מקצוע כללי יכול לספק לבדו. בנוסף, סוכני המשנה האלה יכולים להתרכז באופן מלא במשימות הספציפיות שלהם בלי להבין את התהליך המורכב הכולל.
8. תהליכי עבודה מבוססי-סוכנים – פס הייצור

כשסדר הפעולות חשוב, משתמשים ב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. תהליכי עבודה מבוססי-סוכן – עבודה במקביל

כשמשימות הן בלתי תלויות, ParallelAgent יכול לספק שיפור משמעותי ביעילות על ידי הפעלתן בו-זמנית. בדוגמה הבאה, נשלב אפילו SequentialAgent עם ParallelAgent: המשימות המקבילות יפעלו קודם, ואז סוכן סופי יסכם את התוצאה של המשימות המקבילות.
בואו ניצור בלש חברה שתפקידו יהיה לחפש מידע על:
- הפרופיל של החברה (מנכ"ל, משרדים ראשיים, מוטו וכו')
- החדשות האחרונות על החברה.
- פרטים על המצב הפיננסי של החברה.
// 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. תהליכי עבודה אג'נטיים – שיפור איטרטיבי

למשימות שדורשות מחזור של 'יצירה → בדיקה → שיפור', משתמשים ב-LoopAgent. המערכת משפרת את הביצועים באופן איטרטיבי עד להשגת היעד. בדומה ל-SequentialAgent, המערכת LoopAgent תתקשר לסוכנים המשניים ברצף, אבל היא תחזור להתחלה. ה-LLM שבו הסוכן משתמש באופן פנימי יחליט אם לבקש את השיחה לכלי מיוחד, exit_loop הכלי המובנה, כדי להפסיק את הביצוע של הלולאה.
בדוגמה הבאה של שיפור קוד, באמצעות LoopAgent, שיפור הקוד מתבצע באופן אוטומטי: יצירה, בדיקה ותיקון. התהליך הזה דומה להתפתחות האנושית. כלי ליצירת קוד יוצר קודם את הקוד המבוקש, ושומר אותו במצב הסוכן תחת המפתח 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. מעולה!
יצרתם מגוון סוכני AI וערכתם ניתוחים שלהם, מסוכנים פשוטים לניהול שיחות ועד למערכות מורכבות מרובות סוכנים. למדתם את המושגים המרכזיים של ADK ל-Java: הגדרת סוכנים עם הוראות, מתן כלים לסוכנים וארגון הסוכנים לתהליכי עבודה יעילים.
מה השלב הבא?
- אפשר לעיין במאגר הרשמי של ADK ל-Java ב-GitHub.
- מידע נוסף על המסגרת מופיע במאמרי העזרה.
- בסדרת הפוסטים הזו בבלוג אפשר לקרוא על תהליכי עבודה שונים שמבוססים על סוכנים, וגם על הכלים השונים שזמינים.
- כדאי לעיין במידע נוסף על הכלים המובנים האחרים ועל קריאות חוזרות מתקדמות.
- טיפול בהקשר, במצב ובארטיפקטים, כדי ליצור אינטראקציות עשירות יותר ורב-אופניות.
- הטמעה והפעלה של תוספים שמתחברים למחזור החיים של הסוכנים.
- נסו ליצור סוכן משלכם שיפתור בעיה בעולם האמיתי.