Gemini API로 관리형 기술 요약 에이전트 빌드

1. 개요

AI 및 기술 환경은 그 누구도 따라갈 수 없을 정도로 빠르게 변화하고 있습니다. 매일 새로운 모델, 논문, 제품이 출시됩니다. 오늘의 헤드라인을 가져오고, 간결한 요약을 작성하고, 매일 아침 PDF를 생성하는 요약 에이전트가 있다면 이 문제를 해결할 수 있지만, 이전에는 프레임워크를 선택하고, Python에서 도구를 정의하고, 오케스트레이션 루프를 작성하고, 컨테이너를 패키징하고, Cloud Run에 배포해야 했습니다. 에이전트가 단일 웹 요청을 하기 전의 모든 작업입니다.

Gemini API의 관리형 에이전트는 이 공식을 바꿉니다. 마크다운 구성 파일 2개와 사전 빌드된 렌더러 스크립트를 작성하고 API 호출을 한 번 하면 실제 Ubuntu 샌드박스가 부팅되고, 웹을 탐색하고, 요약을 작성하고, PDF를 생성합니다. 컨테이너가 없습니다. 배포가 없습니다. 조정 코드가 없습니다.

이 Codelab에서는 빈 함수에서 작동하는 일일 요약까지 한 번에 하나의 개념을 사용하여 정확히 그 에이전트를 빌드합니다.

빌드 대상

  • 실제 Linux 샌드박스에서 첫 번째 관리형 에이전트 만들기 및 실행
  • 자세한 요청 사항으로 에이전트 맞춤설정
  • 에이전트의 PDF 출력을 다운로드합니다.
  • 웹을 다시 가져오지 않고 대화를 이어가 요약을 다듬습니다.
  • 에이전트 구성을 저장하고 향후 실행에서 ID로 호출

필요한 항목

  • Python 3.10 이상
  • 결제가 사용 설정된 Gemini API 키: aistudio.google.com/api-keys
  • API 크레딧 약$1 (각 전체 실행 비용은 $0.30~$1.30)

2. Gemini API의 관리형 에이전트란 무엇인가요?

AI 시스템의 세 가지 수준

코드를 살펴보기 전에 관리 에이전트가 두 가지 대안과 비교해 어떤 위치에 있는지 살펴보세요.

수준

어떤 기능인가요?

인프라를 관리하는 주체

표준 LLM

프롬프트를 입력하면 텍스트로 대답합니다. 손도, 메모리도, 인터넷도 없습니다.

해당 사항 없음: 스스로 할 수 있는 작업이 없음

자체 호스팅 에이전트

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 / 16GB 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. 설정

아래 버튼을 클릭하여 Google Cloud Shell에서 이 Codelab을 엽니다. 모든 종속 항목이 사전 설치되어 있습니다.

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가 하나 있고 다음 단계에 필요한 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: Gemini 3.5 Flash로 구동되는 범용 관리형 에이전트인 Antigravity 에이전트 (antigravity-preview-05-2026)를 선택합니다. 기본적으로 사용 설정된 세 가지 내장 도구(code_execution(Bash, Python, Node.js 실행), google_search, url_context(웹페이지 가져오기 및 읽기))가 제공됩니다. environment 매개변수를 전달하면 파일 시스템 도구 (read_file, write_file, list_files)가 자동으로 사용 설정됩니다. 한 번의 호출로 Python 3.12, Node.js 22, git, pip, curl이 사전 설치된 완전 관리형 Ubuntu 환경이 프로비저닝됩니다. 빌드할 컨테이너가 없고 실행할 배포가 없습니다.
  • input: 이 실행의 태스크입니다. 에이전트가 Hacker News를 탐색하고 결과에 대해 추론합니다.
  • environment="remote": 이 상호작용을 위해 새로운 클라우드 샌드박스를 프로비저닝합니다.
  • stream=True: 차단하는 대신 이벤트의 반복 가능 객체를 반환합니다. 이 옵션이 없으면 호출이 30~90초 동안 대기하고 모든 출력을 interaction.output_text로 한 번에 반환합니다. 스트리밍을 사용하면 에이전트 이유를 확인하고 실시간으로 조치를 취할 수 있습니다. 스트리밍은 여기에서 고급 기능이 아닙니다. 90초 동안의 블랙박스는 에이전트가 작동 중인지 아니면 멈췄는지에 관한 신호를 제공하지 않으므로 스트리밍이 올바른 기본값입니다.

방금 프로비저닝한 항목: 모든 interactions.create() 호출은 전용 샌드박스를 부팅합니다.

구성요소

사양

운영체제

격리된 Ubuntu Linux 환경

사전 설치된 런타임

Python 3.12, Node.js 22, Bash

컴퓨팅

CPU 코어 4개, RAM 16GB

컨텍스트 관리

자동 압축은 토큰이 약 135,000개일 때 트리거됩니다.

네트워킹

이그레스 프록시를 통한 아웃바운드 웹 액세스

에이전트는 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="remote"이 있어도 실제 environment_id를 반환합니다. 샌드박스가 실행되었습니다. 누락된 것은 구성입니다. 음성, 스킬, 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/...)

delta.type == "text" 조건을 충족하는 step.delta

상담사가 텍스트를 작성하고 있음

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

URL은 샌드박스 스냅샷을 나타냅니다. 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"는 안전하지 않은 tar 추출에 관한 Python 3.13 지원 중단 경고를 표시하지 않습니다.

확인

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를 엽니다. 할 일이 3개 있습니다.

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.md, SKILL.md, generate_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"로 대체되고 인라인 소스가 3개인 전체 environment 블록이 environment="remote"로 대체됩니다. 구성 파일은 이미 Google 측에 포함되어 있습니다.

확인: 저장된 에이전트 호출

uv run python invoke_agent.py

인라인 실행과 동일한 라이브 스트림이 표시되지만 호출에는 소스 파일이 포함되지 않습니다. 실행 후 .envENVIRONMENT_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. 요약

관리 에이전트를 처음부터 한 번에 하나의 개념으로 빌드했습니다. 각 연습에서 배운 내용은 다음과 같습니다.

연습

개념

주요 API

첫 번째 통화하기

실제 Linux 샌드박스를 프로비저닝하고 이벤트를 실시간으로 스트리밍합니다.

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

상담사 맞춤설정

구성 파일 마운트, 동일한 실행에서 ID를 .env에 유지

environment.sources, set_key

PDF 다운로드

에이전트를 다시 실행하지 않고 PDF 다운로드

download_pdf.py의 Gemini Files API :download

대화 계속하기

웹을 다시 가져오지 않고 대화 계속하기

environment=environment_id, previous_interaction_id=interaction_id

에이전트 구성 유지

에이전트 구성을 유지합니다. ID로 호출하며 소스가 필요하지 않습니다.

agents.create(), agents.list()

주요 패턴

  1. 하나의 호출, 하나의 샌드박스: interactions.create()에서 모든 인프라를 처리합니다 (배포할 컨테이너 없음, 로컬에 설치할 패키지 없음).
  2. 프로그레시브 스트리밍: stream=True는 90초의 블랙박스를 도구 호출 및 텍스트 청크의 실시간 피드로 전환합니다.
  3. 인라인 소스: 업로드 또는 배포 단계 없이 AGENTS.md, SKILL.md, 사전 빌드된 스크립트를 샌드박스에 마운트
  4. 하네스 자동 검색: .agents/에 배치된 파일이 자동으로 선택됩니다 (SDK 구성 필요 없음).
  5. 2차원 상태: environment_id는 파일과 패키지를 추적하고 previous_interaction_id는 대화 컨텍스트를 추적하며 둘 다 독립적으로 전달할 수 있습니다.
  6. 스냅샷 다운로드: 환경은 Gemini Files API를 통해 액세스할 수 있는 전체 파일 시스템 tar입니다.
  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, 보안 비밀

없음

다음 단계