יצירת סוכן מנוהל לסיכום חדשות טכנולוגיות באמצעות Gemini API

1. סקירה כללית

תחום ה-AI והטכנולוגיה מתפתח בקצב מהיר יותר ממה שאפשר לעקוב אחריו. מדי יום מתווספים מודלים, מאמרים ומוצרים חדשים. סוכן סיכום שמביא את הכותרות של היום, כותב סיכומים תמציתיים ומייצר קובץ PDF בכל בוקר יכול לפתור את הבעיה הזו, אבל בעבר כדי לבנות אותו היה צריך לבחור מסגרת, להגדיר כלים ב-Python, לכתוב לולאת תזמור, לארוז קונטיינר ולפרוס אותו ב-Cloud Run. כל זה קורה לפני שהסוכן מבצע בקשה אחת לאינטרנט.

סוכנים מנוהלים ב-Gemini API משנים את התמונה. כותבים שני קובצי הגדרות של Markdown וסקריפט מוכן מראש לעיבוד, מבצעים קריאה אחת ל-API, וארגז חול אמיתי של Ubuntu מופעל, גולש באינטרנט, כותב את הסיכומים ויוצר קובץ PDF. אין מאגרים. אין פריסה. אין קוד תזמור.

ב-Codelab הזה תפתחו סוכן כזה בדיוק: מפונקציה ריקה ועד לתקציר יומי פעיל, שלב אחר שלב.

מה תפַתחו

  • יצירה והפעלה של סוכן מנוהל ראשון בארגז חול אמיתי של Linux
  • התאמה אישית של הסוכן באמצעות הוראות מפורטות
  • הורדת פלט ה-PDF של הסוכן
  • כדי לשפר את התקציר בלי לאחזר מחדש את התוכן מהאינטרנט, אפשר להמשיך את השיחה
  • שמירת הגדרות הסוכן והפעלתן באמצעות מזהה בהרצות עתידיות

הדרישות

  • ‫Python 3.10 ואילך
  • מפתח Gemini API שמופעל בו חיוב: aistudio.google.com/api-keys
  • קרדיט של כ-4 ש"ח לשימוש ב-API (כל הפעלה מלאה עולה 1.20-5.20 ש"ח)

2. מה זה ניהול סוכנים ב-Gemini API?

שלוש רמות של מערכות AI

לפני שמתחילים לכתוב קוד, כדאי להבין איפה סוכנים מנוהלים משתלבים ביחס לשתי החלופות:

רמה

מה זה

מי מנהל את התשתית?

Standard LLM

אתם נותנים הנחיה, והוא עונה בטקסט. אין ידיים, אין זיכרון, אין אינטרנט.

לא רלוונטי: הוא לא יכול לעשות שום דבר בעצמו

Self-Hosted Agent

אתם מחברים ADK/LangChain/AutoGen + Docker + כלים + זיכרון.

אתם: הכל (או פלטפורמה מנוהלת כמו Agent Engine)

סוכן מנוהל

מגדירים לו יעד. ‫Google מספקת ארגז חול מאובטח. הסוכן כותב קוד, מריץ אותו, קורא שגיאות, מחפש באינטרנט ומתקן באגים באופן אוטונומי.

‫Google: כל השירותים

ה-Codelab הזה עוסק בשורה השלישית. אתם מספקים משימה וקובצי הגדרה. Google תטפל בכל השאר.

מה אפשר לפתח באמצעות ADK + Cloud Run

כדי לבנות סוכן חדשות שמסכם את החדשות, גולש באינטרנט, מריץ Python ויוצר קובץ PDF, תצטרכו את כל אלה עם ADK + Cloud Run:

# agent.py: define tools and wire up the agent
from google.adk.agents import LlmAgent
from google.adk.tools import google_search, built_in_code_execution

agent = LlmAgent(
    name="digest-agent",
    model=MODEL,
    instruction=AGENTS_MD,          # your editorial voice and rules
    tools=[google_search, built_in_code_execution],
)
# app.py: serve the agent over HTTP
from google.adk.runners import FastApiRunner
runner = FastApiRunner(agent=agent)
app = runner.app
# pdf_tool.py: custom tool, install reportlab, render PDF
# scraper.py: custom tool, fetch each news source
# streaming.py: wire agent events to your SSE endpoint
# Dockerfile: package everything
FROM python:3.12
COPY . /app
RUN pip install google-adk reportlab requests
CMD ["uvicorn", "app:app", "--host", "0.0.0.0"]
# Deploy to Cloud Run
gcloud run deploy digest-agent \
  --image gcr.io/your-project/digest-agent \
  --set-secrets GEMINI_API_KEY=gemini-key:latest \
  --memory 2Gi

הפעולה הזו מתבצעת לפני שהסוכן מופעל בפעם הראשונה. אתם עדיין הבעלים של בידוד ארגז החול (כך שהסוכן לא יכול לגרום נזק לשרת), התקנת החבילה, ניהול המצב בין קריאות הכלים והתשתית של הסטרימינג כדי להעביר אירועים ללקוח.

מה מחליף את התכונה 'סוכנים מנוהלים'

from google import genai
client = genai.Client()

stream = client.interactions.create(
    agent="antigravity-preview-05-2026",
    input="",
    stream=True,
    environment={
        "type": "remote",
        "sources": [          # your config files, mounted at startup
            {
                "type": "inline",
                "target": ".agents/AGENTS.md",
                "content": AGENTS_MD,
            },
            {
                "type": "inline",
                "target": ".agents/skills/digest-pdf/SKILL.md",
                "content": SKILL_MD,
            },
            {
                "type": "inline",
                "target": ".agents/skills/digest-pdf/scripts/generate_pdf.py",
                "content": GENERATE_PDF_PY,
            },
        ],
    },
)

מה נדרש ל-ADK + Cloud Run

מה הסוכנים המנוהלים עושים בשבילכם

קובץ אימג' של קונטיינר + Dockerfile + CI/CD

ארגז חול מנוהל באופן מלא של Ubuntu‏ (Python 3.12, ‏ Node 22, ‏ 4 CPU / 16 GB RAM)

פריסה והתאמה לעומס ב-Cloud Run

מוקצים לכל אינטראקציה, התוקף שלהם פג אוטומטית אחרי 7 ימים ללא פעילות

בידוד של ארגז חול

מבודד לכל אינטראקציה

כלי PDF בהתאמה אישית + pip install

הסוכן מתקין חבילות בתוך ארגז החול

תשתית סטרימינג של SSE

stream=True מחזירה איטרציה של אירוע

הגדרות של כלים ב-Python

כלים מובנים: גלישה באינטרנט, הרצת קוד, מערכת קבצים

ניהול מצב בין קריאות לכלי

מוטמע בלולאת החשיבה הרציונלית של הסוכן

אתם כותבים קובצי הגדרה (AGENTS.md, ‏ SKILL.md, סקריפט מוכן מראש) ושולחים קריאה אחת ל-API. Google תטפל בכל השאר.

איך פועל ארגז החול

interactions.create() call
        
        
Google provisions Ubuntu sandbox (Python 3.12, Node 22, 4 CPU / 16 GB RAM)
        
        
Agent reasoning loop:
  plan  fetch URLs  run Python  write files  reason  repeat
        
        
Events stream back in real time: tool calls, text chunks, completion
        
        
interaction.completed  environment_id + interaction_id

ארגז החול נשמר למשך 7 ימים ללא פעילות. אפשר להמשיך את השיחה עם environment_id כדי לשפר את הפלט, להריץ משימות המשך או לשמור את הסוכן בשם.

3. הגדרה

כדי לפתוח את ה-codelab הזה ב-Google Cloud Shell, לוחצים על הלחצן שלמטה. כל יחסי התלות מותקנים מראש.

פתיחה ב-Cloud Shell

אפשרות ב': הגדרה מקומית

git clone https://github.com/Saoussen-CH/tech-digest-managed-agent.git
cd tech-digest-managed-agent

אם צריך, מתקינים את uv:

curl -LsSf https://astral.sh/uv/install.sh | sh

הגדרת מפתח API

cp .env.example .env
cloudshell edit .env

מגדירים את המפתח:

GEMINI_API_KEY=your-key-here

התקנת יחסי תלות

uv sync

4. ביצוע השיחה הראשונה לסוכן

פתיחת קובץ ההתחלה

cloudshell edit run_digest.py

ל-run_digest() יש משימה אחת למילוי עכשיו ועוד שלוש לשלב הבא. שני העוזרים כבר מולאו מראש מעל:

  • load_source(path): קורא קובץ מ-.agents/ ביחס לסקריפט. תשתמשו בו בתרגיל הבא כדי לטעון את הקו המנחה, את מדריך ה-PDF ואת מנוע הרינדור לארגז החול.
  • run_stream(stream): מעבד את זרם האירועים ומחזיר (environment_id, interaction_id). אתם לא צריכים לכתוב את לולאת האירועים בעצמכם.

אילו נתונים צריך לציין

TODO 1: מחליפים את pass ב- (בינתיים מתעלמים מ-TODO 3 ו-TODO 4 – הם מיועדים לשלב הבא):

    from google import genai
    client = genai.Client()

    stream = client.interactions.create(
        agent=BASE_AGENT,
        input="Fetch the Hacker News front page and list the top 5 stories.",
        stream=True,
        environment="remote",
    )

    environment_id, interaction_id = run_stream(stream)
    print(f"\nDone. environment_id={environment_id}")

מה עושה כל חלק

genai.Client() reads GEMINI_API_KEY מהסביבה. כל השאר עובר דרך הלקוח הזה.

interactions.create() היא השיחה הראשית. ארבעה פרמטרים מאפשרים את הפעולה:

  • agent=BASE_AGENT: בחירה בסוכן Antigravity‏ (antigravity-preview-05-2026), סוכן מנוהל למטרות כלליות שמבוסס על Gemini 3.5 Flash. הוא כולל שלושה כלים מובנים שמופעלים כברירת מחדל: code_execution (הפעלה של Bash,‏ Python,‏ Node.js),‏ google_search ו-url_context (אחזור וקריאה של דפי אינטרנט). הכלים של מערכת הקבצים (read_file, ‏ write_file, ‏ list_files) מופעלים אוטומטית כשמעבירים את הפרמטר environment. קריאה אחת מספקת סביבת Ubuntu מנוהלת באופן מלא עם Python 3.12,‏ Node.js 22,‏ git,‏ pip ו-curl שהותקנו מראש. אין קונטיינר לבנייה, אין פריסה להפעלה.
  • input: המשימה של ההרצה הזו. הסוכן מעיין ב-Hacker News ומסיק מסקנות לגבי התוצאות.
  • environment="remote": הקצאת ארגז חול חדש ב-Cloud לאינטראקציה הזו.
  • stream=True: מחזירה איטרטור של אירועים במקום לחסום. בלי זה, השיחה תמתין 30-90 שניות ותחזיר את כל הפלט בבת אחת כ-interaction.output_text. בסטרימינג אפשר לראות את הסיבה שהנציג ציין ולפעול בהתאם בזמן אמת. הסטרימינג הוא לא תכונה מתקדמת כאן: הוא ברירת המחדל הנכונה, כי אם יש תיבה שחורה למשך 90 שניות, אי אפשר לדעת אם הנציג עובד או תקוע.

מה שהקציתם עכשיו: כל שיחה ל-interactions.create() מפעילה ארגז חול ייעודי:

רכיב

מפרט

מערכת הפעלה

סביבת Ubuntu Linux מבודדת

סביבות זמן ריצה שהותקנו מראש

Python 3.12, ‏ Node.js 22, ‏ Bash

Compute

מעבד עם 4 ליבות, RAM בנפח 16GB

ניהול ההקשרים

הדחיסה האוטומטית מופעלת בערך ב-135,000 טוקנים

רשתות

גישה לאינטרנט יוצאת באמצעות Egress Proxy

הסוכן יכול להתקין כל חבילה באמצעות pip או npm, לקרוא ולכתוב קבצים ולשלוח בקשות אינטרנט יוצאות. אנחנו אף פעם לא ניגשים למחשב ולפרטי הכניסה שלכם.

environment_id הוא כינוי לארגז החול שהופעל. אחרי interaction.completed, ארגז החול לא נסגר: הוא נשאר פעיל למשך עד 7 ימים. כדי לחזור אליו, לוחצים על environment_id. העברת השיחה לנציג שני ב-interactions.create(), והנציג ממשיך את הטיפול באותה מערכת קבצים, עם אותם קבצים וחבילות מותקנות, כאילו השיחה מעולם לא הועברה. בשלב הבא, הוא משמש להורדת ה-PDF בלי להריץ מחדש את הסוכן, ובשלב שאחריו הוא משמש להמשך השיחה.

interaction_id הוא שם של תור בשיחה שהסתיים. מעבירים אותו כ-previous_interaction_id בשיחה הבאה, ולנציג יש זיכרון מלא של מה שנאמר ומה שנעשה בתור הזה.

אימות

uv run python run_digest.py

הפלט בשידור חי אמור להופיע בזמן שהסוכן פועל:

[agent started]
  [tool] run_code
Here are the top 5 stories currently on the Hacker News front page, retrieved via the official Hacker News API:

1. **Qwen 3.6 27B is the sweet spot for local development** — 471 points
2. **.self: A new top-level domain designed to support self-hosting** — 116 points
...
Done. environment_id=e3de58774073f75a6ef42924c6ce2e88

ה-API מחזיר ערך אמיתי של environment_id גם אם מציינים environment="remote". ארגז החול הופעל. מה שחסר הוא הגדרה: אין קול, אין מיומנות, אין מחולל PDF. הסוכן פשוט הדפיס את הסיפורים כטקסט והפסיק. בשלב הבא מוסיפים אותם.

כל שורה בפלט ממופה לאירוע מ-run_stream():

step.type

מה זה

מה מדפיסים ב-run_stream()

"url_context_call"

סוכן מאחזר כתובת URL

[tool] url_context (https://...)

"code_execution_call"

סוכן שמריץ קוד בארגז החול

[tool] run_code

"google_search_call"

סוכן שמבצע חיפוש באינטרנט

[tool] google_search

"function_call"

כלים לקבצים ועוד

[tool] read_file (/workspace/...)

step.delta כשdelta.type == "text"

הנציג כותב טקסט

השידור מוזרם ישירות ל-stdout

5. התאמה אישית של הסוכן

לא היו לנציג הוראות: לא קול, לא מיומנות ולא מחולל PDF. בשלב הזה טוענים את קובצי ההגדרות מ-.agents/ ומעלים אותם לארגז החול.

מה צריך לשנות

תבצע ארבעה שינויים ב-run_digest.py:

TODO 2: מתחת ל-load_source(), מוסיפים את שלושת הקבועים ברמת המודול (הם נמצאים מחוץ ל-run_digest(), בחלק העליון של הקובץ):

AGENTS_MD       = load_source(".agents/AGENTS.md")
SKILL_MD        = load_source(".agents/skills/digest-pdf/SKILL.md")
GENERATE_PDF_PY = load_source(".agents/skills/digest-pdf/scripts/generate_pdf.py")

פותחים כל קובץ כדי לראות מה נטען: AGENTS.md מגדיר את הכללים של הקו המנחה ושל תהליך העבודה, SKILL.md הוא מדריך PDF מפורט, generate_pdf.py הוא כלי רינדור מוכן מראש שהסוכן יפעיל.

עכשיו מבצעים עוד שני שינויים בתוך run_digest():

TODO 3: מחליפים את environment מ-"remote" במילון המקורות, ומגדירים את input ל-"":

        environment={
            "type": "remote",
            "sources": [
                {
                    "type": "inline",
                    "target": ".agents/AGENTS.md",
                    "content": AGENTS_MD,
                },
                {
                    "type": "inline",
                    "target": ".agents/skills/digest-pdf/SKILL.md",
                    "content": SKILL_MD,
                },
                {
                    "type": "inline",
                    "target": ".agents/skills/digest-pdf/scripts/generate_pdf.py",
                    "content": GENERATE_PDF_PY,
                },
            ],
        },

TODO 4: מוסיפים את השורות האלה מיד אחרי print(f"\nDone. environment_id={environment_id}"):

    set_key(".env", "ENVIRONMENT_ID", environment_id)
    set_key(".env", "INTERACTION_ID", interaction_id)

(הקובץ set_key כבר יובא לחלק העליון של run_digest.py).

במהלך ההרצה הזו, שני המזהים נכתבים אל .env, כך שבשלב הבא אפשר להוריד את קובץ ה-PDF בלי להריץ מחדש את הסוכן.

מה עושה כל מקור

כל מקור הוא קובץ שנטען למערכת הקבצים של ארגז החול בהפעלה לפני שהסוכן מופעל. הנתיבים target תואמים למקומות שבהם רתמת Antigravity מצפה למצוא אותם:

.agents/
├── AGENTS.md                               auto-loaded as global instructions
└── skills/
    └── digest-pdf/
        ├── SKILL.md                        auto-discovered and registered as a skill
        └── scripts/
            └── generate_pdf.py             pre-built renderer the agent can run

target path

משתנה

מה קורה עם הנתונים האלה

.agents/AGENTS.md

AGENTS_MD

נטען אוטומטית כהוראות קבועות: קו מנחה, תהליך עבודה, כללי ביצוע

.agents/skills/digest-pdf/SKILL.md

SKILL_MD

התגלה ונרשם אוטומטית כמיומנות עם שם; הסוכן מפעיל אותו לפי שם

.agents/skills/digest-pdf/scripts/generate_pdf.py

GENERATE_PDF_PY

כלי מובנה לרינדור PDF; הנציג כותב summaries.json ואז מפעיל את הסקריפט הזה

אימות

uv run python run_digest.py

ההרצה נמשכת עכשיו דקה עד 3 דקות. אפשר לראות את הסוכן קורא קובצי תצורה, כותב סיכומים ושומר את קובץ ה-PDF:

[agent started]
  [tool] read_file (/.agents/skills/digest-pdf/SKILL.md)
  [tool] list_files (/.agents/skills/digest-pdf/scripts)
  [tool] read_file (/.agents/skills/digest-pdf/scripts/generate_pdf.py)
  [tool] run_code
  [tool] write_file (/workspace/summaries.json)
  [tool] run_code
  [tool] delete_file (/tmp/test_scrape.py)
I have successfully generated today's tech news digest and saved the formatted document to /workspace/digest.pdf.
Done. environment_id=4129ffd75574e308748e9425d7ec828f

environment_id הוא עכשיו ערך אמיתי: ארגז החול פעל עם קובצי ההגדרות שלכם והסוכן יצר את digest.pdf. בשלב הבא מורידים אותו.

6. הורד את ה-PDF

הנציג כתב digest.pdf אל /workspace/digest.pdf בארגז החול. תמונת המצב של הסביבה זמינה כארכיון tar דרך Gemini Files API.

אם צריך, מתקינים את requests:

uv pip install requests

מה צריך למלא

פתיחת download_pdf.py. יש בו שתי משימות לביצוע.

TODO 1: למלא את requests.get() call:

    r = requests.get(
        f"https://generativelanguage.googleapis.com/v1beta/files/environment-{environment_id}:download",
        params={"alt": "media"},
        headers={"x-goog-api-key": api_key},
        allow_redirects=True,
    )
    r.raise_for_status()

כתובת ה-URL מפנה לתמונת המצב של ארגז החול. ‫params={"alt": "media"} מחזירה בייטים גולמיים במקום מטא-נתונים. הקובץ הקיים GEMINI_API_KEY מאמת גם את Files API.

TODO 2: find and extract the PDF from the tar archive:

            member = next(m for m in tar.getmembers() if m.name.endswith("workspace/digest.pdf"))
            tar.extract(member, path=tmp, filter="data")

התחילית של הנתיב ב-tar משתנה בין הרצות, לכן כדאי לחפש לפי הסיומת במקום להגדיר את הנתיב המדויק בקידוד. ‫filter="data" מדכא את אזהרת ההוצאה משימוש של Python 3.13 לגבי חילוץ tar לא בטוח.

אימות

uv run python download_pdf.py
Saved digest.pdf (48,231 bytes)

פותחים את digest.pdf באותה ספרייה. הוא מכיל את התקציר המעוצב שהסוכן יצר מדפי אינטרנט פעילים.

7. המשך השיחה

כבר יש לך digest.pdf. אם רק רציתם את הקובץ, סיימתם. בשלב הזה לא מבקשים מהסוכן לאחזר את האינטרנט מחדש, אלא לשנות את התקציר.

ארגז החול עדיין פעיל. הסוכן עדיין מחזיק ב-/workspace/digest.pdf וזוכר כל סיפור שהוא סיכם. קריאה שנייה ל-interactions.create() שולחת הודעת המשך לאותו ארגז חול. כאן מבקשים ממנו להוסיף הערה עם הכותרת 'למה זה חשוב' מתחת לכל סיפור, והוא מעדכן את קובץ ה-PDF במקום, בלי לאחזר מחדש ובלי לסכם מחדש.

מה צריך למלא

פתיחת refine_digest.py. יש בו שלוש משימות לביצוע.

TODOs 1 and 2: ממלאים את שני הפרמטרים הרב-שלביים בתוך interactions.create():

    environment=environment_id,
    previous_interaction_id=interaction_id,

environment=environment_id ממשיך את אותו ארגז חול עם הקבצים והחבילות שלו. ‫previous_interaction_id=interaction_id מעביר לסוכן את היסטוריית השיחות. שום דבר אחר לא משתנה מהשיחה הראשונה.

TODO 3: persist the new interaction_id back to .env after the event loop:

set_key(".env", "INTERACTION_ID", interaction_id)

כל שיחה ב-interactions.create() יוצרת interaction_id חדש. הכתיבה חזרה של השאילתה המשופרת פירושה שההרצה הבאה תעבור את השיפור הזה כ-previous_interaction_id, ותשרשר את התורות בצורה נכונה. המזהה של ארגז החול לא משתנה אף פעם, ולכן אין צורך לעדכן את ENVIRONMENT_ID.

שני הפרמטרים שמאפשרים עבודה רב-שלבית

מזהה

מה נשמר

אנלוגיה

environment=environment_id

קבצים, חבילות מותקנות, מצב המערכת: כל מה שנמצא במערכת הקבצים של Linux

שמירת אותו שולחן במשרד בין פגישות

previous_interaction_id=interaction_id

היסטוריית השיחה: מה הסוכן אמר ועשה בתורות הקודמים

לזכור על מה דיברו בפגישה האחרונה

אפשר להעביר כל מזהה בנפרד:

  • environment_id בלבד: שימוש חוזר בקבצים ובחבילות, אבל התחלת שיחה חדשה. האפשרות הזו שימושית למשימה חדשה באותו מרחב עבודה.
  • previous_interaction_id בלבד: המשך ההקשר של השיחה, אבל בארגז חול חדש (הקבצים נעלמו).
  • שניהם: המשכיות מלאה, שזה מה שמשמש בשלב הזה.

ללא environment_id: ארגז חול ריק, ללא PDF. ללא previous_interaction_id: אין הקשר, הסוכן לא יכול לשפר קטע ספציפי.

אימות

uv run python refine_digest.py

העדכון צריך להיות מהיר, הסוכן לא מאחזר מחדש שום דבר. אחרי שההעברה מסתיימת:

Refinement done.
Saved digest_v2.pdf (52,418 bytes)

פותחים את digest_v2.pdf ומשווים אותו ל-digest.pdf. לכל סיפור נוספה עכשיו השורה 'למה זה חשוב'.

8. שמירה של הגדרת סוכן מנוהלת

כל השיחות עד עכשיו עברו בתוך השורה AGENTS.md, SKILL.md ו-generate_pdf.py. זה עובד, אבל קוד ההפעלה מעביר את התוכן המלא של הקובץ בכל הפעלה. ‫agents.create() משלב את ההגדרה בסוכן בעל שם שנשמר בצד של Google. הקריאה הבאה לפונקציה מעבירה רק את מזהה הסוכן:

Inline calls:   send sources on every call
Named agent:    bake once → invoke by ID, no sources

מה צריך למלא

פתיחת save_agent.py. יש בו משימה אחת לביצוע (משימה לביצוע 1).

שימו לב שהקבועים מיובאים ישירות מ-run_digest.py (ללא כפילות):

from run_digest import BASE_AGENT, AGENTS_MD, SKILL_MD, GENERATE_PDF_PY

TODO 1: למלא את agents.create() call:

agent = client.agents.create(
    id="my-digest",
    base_agent=BASE_AGENT,
    description="Daily tech digest with editorial voice and PDF generation.",
    base_environment={
        "type": "remote",
        "sources": [
            {
                "type": "inline",
                "target": ".agents/AGENTS.md",
                "content": AGENTS_MD,
            },
            {
                "type": "inline",
                "target": ".agents/skills/digest-pdf/SKILL.md",
                "content": SKILL_MD,
            },
            {
                "type": "inline",
                "target": ".agents/skills/digest-pdf/scripts/generate_pdf.py",
                "content": GENERATE_PDF_PY,
            },
        ],
    },
)

base_environment (לא environment) הוא ההבדל העיקרי מהקריאה המוטבעת בשלב הקודם: המקורות מאוחסנים בצד של Google ומצורפים באופן אוטומטי לכל הפעלה עתידית. להפעיל אותו פעם אחת, ולא בכל הפעלה של התקציר.

אימות: שמירת הסוכן

uv run python save_agent.py
Saved: my-digest
my-digest: Daily tech digest with editorial voice and PDF generation.

הפעלת הסוכן השמור

פתיחת invoke_agent.py. הוא קורא לסוכן השמור לפי מזהה ללא מקורות:

stream = client.interactions.create(
    agent="my-digest",
    input="",
    stream=True,
    environment="remote",
)

השוואה לשיחה בתוך השורה: agent=BASE_AGENT מוחלף ב-"my-digest", ובלוק environment המלא עם שלושה מקורות בתוך השורה מוחלף ב-environment="remote". ההגדרה כבר מוטמעת בצד של Google.

אימות: הפעלת הסוכן שנשמר

uv run python invoke_agent.py

השידור החי שיוצג יהיה זהה לשידור החי שמוצג בתוך הדף, אבל הקריאה לא תכלול קבצי מקור. אחרי ההרצה, הערכים של ENVIRONMENT_ID ושל INTERACTION_ID ב-.env מתעדכנים, כך שאפשר להמשיך להשתמש ב-refine_digest.py כמו קודם.

[agent started]
  [tool] read_file
  [tool] write_file
  [tool] run_code
I have successfully created today's tech news digest.
Done. environment_id=9a1c3e02-...

9. הסרת המשאבים

התוקף של ארגז החול יפוג אוטומטית אחרי 7 ימים של חוסר פעילות. אין שרתים להפסיק. אין מאגרים למחיקה.

אם שמרתם הגדרות של סוכן, מחקו אותן:

uv run python delete_agent.py

10. סיכום

בניתם סוכן מנוהל מאפס, מושג אחד בכל פעם. הנה מה שלומדים בכל תרגיל:

פעילות גופנית

קונספט

Key API

ביצוע השיחה הראשונה

הקצאת ארגז חול אמיתי של Linux ושידור חי של האירועים שלו

interactions.create(agent, input, environment, stream=True), event.event_type

התאמה אישית של הסוכן

טעינת קובצי הגדרות; שמירת מזהים ב-.env באותה הרצה

environment.sources, set_key

הורד את ה-PDF

הורדת קובץ ה-PDF בלי להפעיל מחדש את הסוכן

‫Gemini Files API :download ב-download_pdf.py

המשך השיחה

המשך השיחה בלי לאחזר מחדש את האינטרנט

environment=environment_id, previous_interaction_id=interaction_id

שמירת הגדרות הסוכן

שמירת הגדרות הסוכן; הפעלה לפי מזהה, ללא צורך במקורות

agents.create(), agents.list()

דפוסים מרכזיים

  1. קריאה אחת, ארגז חול אחד: interactions.create() מטפל בכל התשתית (אין קונטיינרים לפריסה, אין חבילות להתקנה מקומית)
  2. סטרימינג מתקדם: stream=True הופך תיבה שחורה של 90 שניות לפיד פעיל של קריאות לכלים וקטעי טקסט
  3. מקורות מוטמעים: טעינת AGENTS.md,‏ SKILL.md וסקריפטים מוכנים מראש אל ארגז החול בלי לבצע העלאה או פריסה
  4. שימוש בזיהוי אוטומטי: המערכת מזהה באופן אוטומטי קבצים שמוצבים בתיקייה .agents/ (אין צורך בהגדרת SDK)
  5. מצב דו-ממדי: environment_id עוקב אחרי קבצים וחבילות; previous_interaction_id עוקב אחרי הקשר השיחה; אפשר להעביר כל אחד מהם בנפרד
  6. הורדת תמונת מצב: הסביבה היא קובץ tar של מערכת קבצים מלאה, שאפשר לגשת אליו באמצעות Gemini Files API
  7. סוכנים עם שם: agents.create() מגדיר את ההגדרה באופן קבוע; בשיחות עתידיות מועברים רק מזהה הסוכן ו-environment="remote", ללא מקורות

‫ADK + Cloud Run לעומת סוכנים מנוהלים: סקירה קצרה של ההבדלים

יכולת

ADK + Cloud Run

ניהול סוכנים ב-Gemini API

הקצאת ארגז חול

docker build + gcloud run deploy

interactions.create()

הגדרת כלים

פונקציות Python שרשומות בסוכן

מובנה: גלישה באינטרנט, הרצת קוד, מערכת קבצים

התקנת חבילות

pip install ב-Dockerfile

הסוכן פועל pip install בתוך ארגז חול

אירועים בשידור חי

תשתית SSE בהתאמה אישית

stream=True

המשך הסשן

מסד נתונים של סשנים + החדרת הקשר

environment_id + previous_interaction_id

קובצי הגדרה

מוטמעים בנציג או מוזרקים בזמן ההפעלה

התקנה באמצעות environment.sources

תשתית לניהול

קונטיינר, Cloud Run, ‏ IAM, סודות

ללא

השלבים הבאים