使用 Gemini API 建構受管理技術摘要代理程式

1. 總覽

AI 和科技領域的發展速度非常快,每天都有新模型、論文和產品推出。如果每天早上都能取得當日新聞摘要、精簡的總結,並產生 PDF,就能解決這個問題。但過去要建構這類摘要代理程式,就得挑選框架、在 Python 中定義工具、編寫自動化調度管理迴圈、封裝容器,然後部署至 Cloud Run。在代理程式發出任何網頁要求之前,所有這些作業都已完成。

Gemini API 中的受管理代理改變了這個等式。您會編寫兩個 Markdown 設定檔和一個預先建構的算繪器指令碼,發出一個 API 呼叫,然後啟動實際的 Ubuntu 沙箱、瀏覽網頁、撰寫摘要並產生 PDF。沒有容器。無需部署。完全不需要自動化調度管理程式碼。

在本程式碼研究室中,您將從空白函式開始,逐步建構出可運作的每日摘要代理程式。

建構目標

  • 在實際的 Linux 沙箱中建立及執行第一個受管理代理
  • 提供詳細指令來自訂代理程式
  • 下載代理程式的 PDF 輸出內容
  • 繼續對話,進一步修正摘要,不必重新擷取網頁內容
  • 儲存代理程式設定,並在日後執行時依 ID 叫用

軟硬體需求

  • Python 3.10 以上版本
  • 已啟用計費功能的 Gemini API 金鑰:aistudio.google.com/api-keys
  • 約$1 美元的 API 抵免額 (每次完整執行費用為 $0.30 美元至 $1.30 美元)

2. 什麼是 Gemini API 中的受管理代理?

三種層級的 AI 系統

開始編寫程式碼前,請先瞭解 Managed Agents 相對其他兩種替代方案的適用情況:

等級

簡介

誰負責管理基礎架構?

標準 LLM

你輸入提示,它會以文字回覆。不需動手、不需記憶、不需網路。

不適用:無法自行執行任何動作

自行代管的代理程式

您需要將 ADK/LangChain/AutoGen + Docker + 工具 + 記憶體連接起來。

您:所有項目 (或 Agent Engine 等代管平台)

代管代理程式

你為其設定目標,Google 會提供安全沙箱。代理會編寫程式碼、執行程式碼、讀取錯誤、搜尋網路,並自主修正錯誤。

Google:所有內容

本程式碼研究室將介紹第三列。您提供工作和設定檔,其餘作業則由 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

也就是在代理程式執行一次之前。您仍擁有沙箱隔離功能 (因此代理程式不會損壞伺服器)、套件安裝、工具呼叫之間的狀態管理,以及將事件傳送至用戶端的串流基礎架構。

Managed Agents 的替代方案

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 的必要條件

Managed Agents 為您處理的事項

容器映像檔 + 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.mdSKILL.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. 設定

點選下方按鈕,在 Google Cloud Shell 中開啟這個程式碼研究室。所有依附元件都已預先安裝。

在 Cloud Shell 中開啟

選項 B:本機設定

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() 有一個 TODO 現在要填寫,下一個步驟還有三個。系統已在上方預先填入兩個輔助程式:

  • load_source(path):從相對於指令碼的 .agents/ 讀取檔案。您會在下一個練習中使用這項資訊,將編輯觀點、PDF 教戰手冊和轉譯器掛接到沙箱。
  • run_stream(stream):處理事件串流並傳回 (environment_id, interaction_id)。您不需要自行編寫事件迴圈。

應加入的資訊

TODO 1:pass 替換為 (暫時忽略 TODO 3 和 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() 會從環境中讀取 GEMINI_API_KEY。其他所有項目都會透過這個用戶端傳送。

interactions.create() 是核心呼叫。這項功能需要四個參數才能運作:

  • agent=BASE_AGENT:選取 Antigravity 代理程式 (antigravity-preview-05-2026),這是由 Gemini 3.5 Flash 支援的通用型受管理代理程式。這項功能預設啟用三種內建工具:code_execution (執行 Bash、Python、Node.js)、google_searchurl_context (擷取及讀取網頁)。傳遞 environment 參數時,系統會自動啟用檔案系統工具 (read_filewrite_filelist_files)。只要呼叫一次,即可佈建全面代管的 Ubuntu 環境,並預先安裝 Python 3.12、Node.js 22、git、pip 和 curl。無需建構容器,也不必執行部署作業。
  • input:本次執行的工作。代理會瀏覽 Hacker News,並推論結果。
  • environment="remote":為這項互動佈建新的雲端沙箱。
  • stream=True:傳回事件的可疊代項目,而非封鎖。如果沒有,呼叫會等待 30 到 90 秒,然後以 interaction.output_text 形式一次傳回所有輸出內容。使用串流功能時,您可以即時查看代理的推理和行動。串流並非進階功能,而是正確的預設值,因為 90 秒的黑畫面無法提供服務專員是否正常運作或卡住的信號。

您剛才佈建的內容:每次 interactions.create() 呼叫都會啟動專屬沙箱:

元件

規格

作業系統

隔離的 Ubuntu Linux 環境

預先安裝的執行階段

Python 3.12、Node.js 22、Bash

運算

4 個 CPU 核心,16 GB RAM

情境脈絡管理

在約 135,000 個權杖時觸發自動壓縮

網路

透過 Egress Proxy 存取外部網站

代理程式可以使用 pipnpm 安裝任何套件、讀取及寫入檔案,以及發出外送網頁要求。我們絕不會接觸您的電腦和憑證。

environment_id 是剛執行的沙箱控制代碼。interaction.completed後,沙箱不會關閉,最多可存留 7 天。environment_id 是返回該頁面的方式。將其傳遞至第二次 interactions.create() 呼叫,代理程式就會在相同檔案系統中繼續執行,並使用相同檔案和已安裝的套件,就像從未離開一樣。下一個步驟會使用這個 ID 下載 PDF,不必重新執行代理程式,再下一個步驟則會使用這個 ID 繼續對話。

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

即使有 environment="remote",API 仍會傳回實際的 environment_id。沙箱已執行。缺少設定:沒有語音、技能或 PDF 產生器。代理程式只會以文字形式列印故事,然後停止運作。下一個步驟會新增這些項目。

每行輸出內容都會對應至 run_stream() 的事件:

step.type

簡介

run_stream() 張沖印相片

"url_context_call"

代理程式擷取網址

[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 頂端匯入)。

這會在執行期間將兩個 ID 寫入 .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路徑

變數

安全帶如何與安全座椅搭配使用

.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

現在執行作業只需 1 到 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。環境快照會透過 Gemini Files API 以 tar 封存檔的形式提供。

視需要安裝 requests

uv pip install requests

填寫內容

開啟 download_pdf.py。其中有兩個 TODO。

TODO 1:填寫 requests.get() 呼叫:

    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()

網址會指向沙箱快照。params={"alt": "media"} 會傳回原始位元組,而非中繼資料。現有的 GEMINI_API_KEY 也會驗證 Files API。

TODO 2:從 tar 封存檔找出並擷取 PDF:

            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。其中有三個 TODO。

TODO 1 和 2:interactions.create() 中填寫兩個多輪對話參數:

    environment=environment_id,
    previous_interaction_id=interaction_id,

environment=environment_id 會繼續使用相同的沙箱,並保留檔案和套件。previous_interaction_id=interaction_id 會提供代理程式對話記錄。第一次通話後,其他設定不會變更。

TODO 3:在事件迴圈後,將新的 interaction_id 持續傳回 .env

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

每次呼叫 interactions.create() 都會產生新的 interaction_id。寫回表示下次執行時,會將這項修正內容當做 previous_interaction_id 傳遞,正確地串連回合。沙箱 ID 不會變更,因此不需要更新 ENVIRONMENT_ID

讓多輪對話運作的兩個參數

ID

保留內容

比喻

environment=environment_id

檔案、已安裝的套件、系統狀態:Linux 檔案系統中的所有內容

在會議之間使用同一張辦公桌

previous_interaction_id=interaction_id

對話記錄:代理在先前回合中說過和做過的事

回顧上次會議的討論內容

您可以單獨傳遞任一 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.mdSKILL.mdgenerate_pdf.py 內嵌。這樣做沒問題,但每次執行時,呼叫程式碼都會攜帶完整檔案內容。agents.create() 會將設定烘焙到 Google 端的已儲存具名代理程式中。下一個呼叫只會傳遞代理程式 ID:

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

填寫內容

開啟 save_agent.py。其中包含一個 TODO (TODO 1)。

請注意,常數是直接從 run_digest.py 匯入 (不會重複):

from run_digest import BASE_AGENT, AGENTS_MD, SKILL_MD, GENERATE_PDF_PY

TODO 1:填寫 agents.create() 呼叫:

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。它會透過 ID 呼叫已儲存的代理程式,且沒有來源:

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

您應該會看到與內嵌執行相同的即時串流,但呼叫不攜帶任何來源檔案。執行完畢後,.env 中的 ENVIRONMENT_IDINTERACTION_ID 會更新,因此您可以照常繼續使用 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

自訂代理

掛接設定檔;在同一次執行中將 ID 保留在 .env

environment.sourcesset_key

下載 PDF

下載 PDF,不必重新執行代理程式

Gemini Files API :download in download_pdf.py

延續對話

繼續對話,不必重新擷取網頁內容

environment=environment_idprevious_interaction_id=interaction_id

保留代理程式設定

保存代理設定;依 ID 叫用,無須來源

agents.create()agents.list()

鍵模式

  1. 一次呼叫,一個沙箱interactions.create() 會處理所有基礎架構 (無需部署容器,也無須在本機安裝套件)
  2. 漸進式串流stream=True將 90 秒的黑方塊轉換為工具呼叫和文字區塊的現行動態饋給
  3. 內嵌來源:將 AGENTS.mdSKILL.md 和預先建構的指令碼掛接到沙箱,不必上傳或部署
  4. 自動探索 Harness:系統會自動挑選 .agents/ 中的檔案 (無須設定 SDK)
  5. 二維狀態environment_id 追蹤檔案和套件;previous_interaction_id 追蹤對話脈絡;兩者皆可獨立傳遞
  6. 下載快照:環境是完整的檔案系統 tar,可透過 Gemini Files API 存取
  7. 具名代理agents.create() 會永久烘焙設定;日後呼叫時只會傳遞代理 ID 和 environment="remote",不會傳遞來源

ADK + Cloud Run 與代管型代理:差異一覽

功能

ADK + Cloud Run

Gemini API 中的受管理代理

佈建沙箱

docker build + gcloud run deploy

interactions.create()

定義工具

向代理程式註冊的 Python 函式

內建:網頁瀏覽、執行程式碼、檔案系統

安裝套件

Dockerfile 中的 pip install

代理程式在沙箱中執行 pip install

串流事件

自訂 SSE 基礎架構

stream=True

繼續執行工作階段

工作階段資料庫 + 注入脈絡

environment_id + previous_interaction_id

設定檔

在代理程式中硬式編碼,或在啟動時插入

透過「environment.sources」掛接

要管理的基礎架構

容器、Cloud Run、IAM、密鑰

後續步驟