본문 바로가기

Gemini

API 호출 한 번으로 격리 Linux 에이전트가 뜬다 — Gemini Managed Agents 실전 코드

반응형

에이전트를 만들려면 샌드박스를 프로비저닝하고, 도구를 연결하고, 실행 루프를 유지해야 했습니다. 2026년 5월 19일부터는 아닙니다. Gemini API Managed Agents는 client.interactions.create() 한 줄로 격리 Linux 환경을 띄우고, Gemini 3.5 Flash 에이전트가 코드 실행·웹 검색·파일 관리를 자율적으로 처리합니다. 설치부터 커스텀 에이전트 등록, 스트리밍, 백그라운드 실행까지 실제 코드로 전부 정리했습니다.


이 포스트 한 줄 요약 → 에이전트 ID: antigravity-preview-05-2026 (Gemini 3.5 Flash 기반, 퍼블릭 프리뷰) → SDK: google-genai >= 2.0.0 필수 — 기존 google-generativeai deprecated → 샌드박스 기본 도구: Bash/Python/Node.js 실행, 파일 관리, Google Search, URL 패치 → 멀티턴: previous_interaction_id로 세션·파일 상태 유지 → 스트리밍: stream=True, 백그라운드 장기 태스크: background=True + 폴링 → AGENTS.md + SKILL.md로 오케스트레이션 코드 없이 에이전트 커스터마이즈 → ⚠️ Breaking change: 5월 26일부로 outputs → steps 배열 전환, 6월 8일 레거시 스키마 완전 제거 → 인터랙션 저장: 유료 55일, 무료 1일 (기본 store=True) → 컨텍스트 자동 압축: ~135K 토큰에서 자동 실행


0단계: 설치 및 환경 준비

# 기존 google-generativeai가 있다면 제거
pip uninstall google-generativeai -y

# 반드시 2.0.0 이상
pip install -U google-genai
# API 키 설정
export GEMINI_API_KEY="your-api-key-here"
from google import genai

client = genai.Client()
# 별도 설정 없이 GEMINI_API_KEY 환경변수 자동 인식

1단계: 첫 번째 호출 — 기본 에이전트 실행

from google import genai

client = genai.Client()

# 단일 호출 → 격리 Linux 샌드박스 프로비저닝 + 에이전트 루프 자동 실행
interaction = client.interactions.create(
    agent="antigravity-preview-05-2026",
    input="Hacker News 상위 10개 기사를 읽고 요약해서 PDF로 저장해줘.",
    environment={"type": "remote"},  # 새 샌드박스 생성
)

# steps 배열에서 최종 텍스트 출력 (5/26 이후 새 스키마)
print(interaction.steps[-1].content[0].text)

⚠️ 주의: 5월 26일부로 응답 스키마가 바뀌었습니다. 기존에 interaction.outputs를 쓰던 코드는 interaction.steps로 교체해야 합니다. 6월 8일 이후 레거시 스키마는 완전히 제거됩니다.

curl로 직접 호출

curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "Content-Type: application/json" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H "Api-Revision: 2026-05-20" \
  -d '{
    "agent": "antigravity-preview-05-2026",
    "input": "피보나치 수열 20개를 계산하고 fibonacci.txt에 저장해줘.",
    "environment": "remote"
  }'

2단계: 스트리밍 — 실시간 진행 상황 확인

긴 작업에서 완료까지 기다리지 않고 에이전트의 각 단계를 실시간으로 받을 수 있습니다.

stream = client.interactions.create(
    agent="antigravity-preview-05-2026",
    input="sales_data.csv를 분석하고 월별 매출 차트를 포함한 리포트를 만들어줘.",
    environment={"type": "remote"},
    stream=True,
)

for event in stream:
    if event.event_type == "step.start":
        print(f"\n▶ 단계 시작: {event.step.type}")

    elif event.event_type == "step.delta":
        if event.delta.type == "text":
            print(event.delta.text, end="", flush=True)
        elif event.delta.type == "thought_summary":
            # 에이전트 내부 추론 과정 (선택적 표시)
            print(f"\n[추론] {event.delta.content.text}")

    elif event.event_type == "interaction.completed":
        usage = event.interaction.usage
        print(f"\n\n✅ 완료 — 총 토큰: {usage.total_tokens:,}")

출력 예시:

▶ 단계 시작: code_execution
[추론] CSV 파일을 pandas로 읽어 월별 집계를 계산합니다.

▶ 단계 시작: file_management
리포트 파일을 저장합니다.

✅ 완료 — 총 토큰: 18,432

3단계: 멀티턴 세션 — 상태와 파일 이어받기

previous_interaction_id로 이전 인터랙션의 샌드박스 상태(파일, 변수, 실행 결과)를 그대로 유지합니다.

# 1턴: 데이터 로드 및 기본 분석
interaction_1 = client.interactions.create(
    agent="antigravity-preview-05-2026",
    input="q1_sales.csv를 불러와서 지역별 매출 합계를 계산해줘.",
    environment={"type": "remote"},
)
print("1턴 완료:", interaction_1.steps[-1].content[0].text)

# 2턴: 이전 환경 이어받기 (파일·변수 유지)
interaction_2 = client.interactions.create(
    agent="antigravity-preview-05-2026",
    input="방금 계산한 지역별 합계를 막대그래프로 시각화하고 PNG로 저장해줘.",
    environment={
        "type": "remote",
        "previous_interaction_id": interaction_1.id,  # 이전 환경 재사용
    },
)

# 3턴: 최종 리포트 생성
interaction_3 = client.interactions.create(
    agent="antigravity-preview-05-2026",
    input="차트와 수치를 합쳐서 PDF 리포트로 만들어줘. 파일명은 q1_report.pdf로.",
    environment={
        "type": "remote",
        "previous_interaction_id": interaction_2.id,
    },
)

4단계: 생성된 파일 다운로드

에이전트가 샌드박스 안에서 만든 파일을 로컬로 가져옵니다.

import os

interaction = client.interactions.create(
    agent="antigravity-preview-05-2026",
    input="소수 50개를 계산하고 분포 차트를 primes_report.pdf로 저장해줘.",
    environment={"type": "remote"},
)

# 샌드박스에서 생성된 파일 목록 확인
for file in interaction.files:
    print(f"파일: {file.name} ({file.size:,} bytes)")

# 특정 파일 다운로드
output_dir = "./agent_output"
os.makedirs(output_dir, exist_ok=True)

for file in interaction.files:
    if file.name.endswith(".pdf"):
        local_path = os.path.join(output_dir, file.name)
        with open(local_path, "wb") as f:
            f.write(file.content)
        print(f"✅ 저장됨: {local_path}")

5단계: AGENTS.md + SKILL.md로 커스터마이즈

오케스트레이션 코드 대신 마크다운 파일로 에이전트 행동을 정의합니다.

interaction = client.interactions.create(
    agent="antigravity-preview-05-2026",
    input="이번 달 KPI 리포트를 만들어줘.",
    system_instruction="너는 데이터 분석 전문 에이전트야. 항상 수치 근거를 포함해.",
    environment={
        "type": "remote",
        "sources": [
            # AGENTS.md: 프로젝트 전체 컨벤션
            {
                "type": "inline",
                "target": ".agents/AGENTS.md",
                "content": """
# 분석 에이전트 지침
- 모든 차트는 matplotlib 사용, 한글 폰트 적용
- 리포트에 항상 요약 테이블(markdown) 포함
- 숫자는 천 단위 콤마 적용 (예: 1,234,567)
- 결론은 bullet point 3개로 요약
- 출력 파일은 항상 /workspace/output/ 디렉토리에 저장
                """.strip(),
            },
            # SKILL.md: 특정 기능 정의
            {
                "type": "inline",
                "target": ".agents/skills/pdf-report/SKILL.md",
                "content": """
---
name: pdf-report
description: 데이터 분석 결과를 PDF 슬라이드로 변환합니다.
---
# PDF Report Skill

## 사용 조건
리포트 생성 요청 시 자동 호출됩니다.

## 실행 방법
1. matplotlib으로 차트 생성
2. pandas DataFrame을 HTML 테이블로 변환
3. reportlab으로 PDF 합성
4. /workspace/output/{파일명}.pdf로 저장
                """.strip(),
            },
            # GitHub에서 공유 스킬 라이브러리 마운트
            {
                "type": "repository",
                "source": "https://github.com/your-org/agent-skills",
                "target": ".agents/skills/shared",
            },
        ],
    },
)

6단계: 에이전트 등록 — ID로 재사용

매번 인라인으로 정의하는 대신 에이전트를 한 번 등록해두고 ID로 호출합니다. 프로덕션 환경에서 일관된 동작을 보장하는 핵심 패턴입니다.

# 에이전트 등록 (한 번만)
agent = client.agents.create(
    id="kpi-analyst-v1",                          # 고유 ID
    base_agent="antigravity-preview-05-2026",
    system_instruction=(
        "KPI 분석 전문 에이전트. "
        "항상 차트와 요약 테이블을 포함하고 PDF로 저장한다."
    ),
    base_environment={
        "type": "remote",
        "sources": [
            {
                "type": "inline",
                "target": ".agents/AGENTS.md",
                "content": "항상 matplotlib 사용. 한글 지원 폰트 적용 필수.",
            },
            {
                "type": "repository",
                "source": "https://github.com/your-org/agent-skills",
                "target": ".agents/skills",
            },
        ],
    },
)
print(f"등록된 에이전트 ID: {agent.id}")

# 이후 ID 하나로 호출
interaction = client.interactions.create(
    agent="kpi-analyst-v1",   # 등록된 에이전트 ID
    input="3월 매출 데이터 분석해줘.",
)

7단계: 백그라운드 모드 — 장기 태스크 처리

Deep Research처럼 수 분이 걸리는 작업에는 background=True로 비동기 실행 후 폴링합니다.

import time

# 백그라운드로 시작
initial = client.interactions.create(
    agent="deep-research-preview-04-2026",
    input="2026년 AI 에이전트 시장 동향을 분석하고 20페이지 분량의 리포트를 작성해줘.",
    background=True,
)

print(f"태스크 시작됨 (ID: {initial.id})")

# 완료까지 폴링
while True:
    interaction = client.interactions.get(initial.id)

    if interaction.status == "completed":
        print("✅ 완료")
        print(interaction.steps[-1].content[0].text)
        break
    elif interaction.status in ("failed", "cancelled"):
        print(f"❌ 실패: {interaction.status}")
        break
    else:
        print(f"⏳ 진행 중... (상태: {interaction.status})")
        time.sleep(10)   # 10초마다 확인

실무 패턴 — 자주 쓰는 시나리오 3가지

① CSV → 분석 리포트 파이프라인

import base64

# 로컬 파일을 에이전트 샌드박스에 업로드
with open("sales_data.csv", "rb") as f:
    csv_content = base64.b64encode(f.read()).decode()

interaction = client.interactions.create(
    agent="kpi-analyst-v1",
    input="업로드된 sales_data.csv를 분석하고 q1_report.pdf를 만들어줘.",
    environment={
        "type": "remote",
        "sources": [
            {
                "type": "inline",
                "target": "workspace/sales_data.csv",
                "content": csv_content,
                "encoding": "base64",
            }
        ],
    },
)

# 결과 PDF 다운로드
for file in interaction.files:
    if file.name == "q1_report.pdf":
        with open("q1_report.pdf", "wb") as f:
            f.write(file.content)

② 웹 스크래핑 + 정형화 파이프라인

interaction = client.interactions.create(
    agent="antigravity-preview-05-2026",
    input="""
    다음 3개 URL에서 가격 정보를 수집하고 비교표를 JSON으로 저장해줘:
    - https://example.com/product/a
    - https://example.com/product/b
    - https://example.com/product/c
    """,
    environment={"type": "remote"},
)

# 에이전트가 실제로 URL을 패치하고 파싱한 결과 반환
print(interaction.steps[-1].content[0].text)

③ 코드 실행 결과 검증

interaction = client.interactions.create(
    agent="antigravity-preview-05-2026",
    input="""
    다음 Python 함수를 테스트해줘:
    
    def fibonacci(n):
        if n <= 1: return n
        return fibonacci(n-1) + fibonacci(n-2)
    
    1) 정확성 테스트 (n=0~10 전체 케이스)
    2) 성능 측정 (n=30, 35 실행 시간)
    3) 개선된 메모이제이션 버전 작성 후 성능 비교
    """,
    environment={"type": "remote"},
)

주의해야 할 세 가지

① 6월 8일 레거시 스키마 완전 제거

# ❌ 레거시 (6월 8일 이후 에러 발생)
result = interaction.outputs[0].text

# ✅ 새 스키마 (지금 바로 전환)
result = interaction.steps[-1].content[0].text

② store=False는 세션 재개 불가

인터랙션 저장을 끄면 previous_interaction_id 사용이 불가능합니다. 멀티턴 세션이 필요하다면 반드시 store=True(기본값) 상태를 유지해야 합니다.

# store=False 사용 시: 비용 절감 가능하지만 세션 재개 불가
interaction = client.interactions.create(
    agent="antigravity-preview-05-2026",
    input="단순 일회성 태스크",
    environment={"type": "remote"},
    store=False,  # 저장 안 함 → previous_interaction_id 사용 불가
)

③ 컨텍스트 자동 압축 인지

롱 세션에서 약 135K 토큰에 도달하면 자동으로 컨텍스트 압축이 실행됩니다. 이 과정에서 초반 세션의 세밀한 내용이 요약될 수 있습니다. 장기 프로젝트라면 중요한 중간 결과물을 파일로 명시적으로 저장하도록 에이전트에 지시하는 것이 안전합니다.


✅ 결론

항목 평가

시작 난이도 ✅ API 호출 5줄로 에이전트 실행 가능
인프라 관리 ✅ 샌드박스·루프 전부 플랫폼 처리
멀티턴 상태 관리 ✅ previous_interaction_id로 간단히
커스터마이즈 방식 ✅ 마크다운 파일로 선언적 정의
스트리밍·백그라운드 ✅ 두 모드 모두 지원
Breaking change 위험 ⚠️ 6월 8일 스키마 전환 대응 필수
현재 성숙도 ⚠️ 퍼블릭 프리뷰, 프로덕션 안정성 검증 필요

Gemini API Managed Agents는 "에이전트를 만들기 위한 인프라"를 학습하는 시간을 줄이고, "에이전트가 실제로 무엇을 해야 하는가"에 집중할 수 있게 해주는 방향입니다. AGENTS.md 컨벤션이 Grok Build, Antigravity, Claude Code 전반에서 수렴되고 있다는 점도 주목할 만합니다 — 에이전트 행동을 코드가 아닌 마크다운으로 정의하는 방식이 표준이 되고 있습니다.


관련 포스트

https://cell-devlog.tistory.com/256

 

에이전트 코드 다 짤 필요 없습니다 — Managed Agents vs 직접 오케스트레이션 실전 비교

에이전트를 만들려면 LangGraph 그래프를 설계하고, 샌드박스를 프로비저닝하고, 에이전트 루프를 유지하고, 상태를 관리해야 한다 — 2026년 5월 18일까지는 맞는 말이었습니다. 5월 19일 Google I/O에

cell-devlog.tistory.com

 

반응형