콘텐츠로 이동

실습 12: agents-cli를 사용한 ADK 에이전트 수명 주기

소요 시간: 45분 | 모듈: 5 — agents-cli를 사용하여 ADK 에이전트 구축하기


목표

전체 개발 수명 주기에 따라 agents-cli를 사용하여 ADK 에이전트를 스캐폴딩, 빌드, 평가 및 반복합니다. 원시 회의 대본을 입력받아 구조화된 실행 항목을 생성하는 회의록 요약기(Meeting Notes Summarizer) 에이전트를 빌드하게 됩니다.


사전 요구 사항

  • agents-cli 설치됨 (uvx google-agents-cli setup)
  • uv 설치됨 (설치 가이드)
  • Google Cloud 프로젝트 또는 AI Studio API 키
  • Antigravity CLI (agy) 설치 및 정상 작동

파트 1: 에이전트 스캐폴드 (10분)

1단계: 프로젝트 생성

Antigravity CLI 세션을 열고 스캐폴드합니다:

agents-cli scaffold create meeting-notes \
  --agent adk \
  --prototype \
  --agent-guidance-filename GEMINI.md

--prototype을 사용하는 이유

프로토타입 플래그는 CI/CD 및 Terraform을 건너뜁니다. 먼저 에이전트가 작동하도록 하는 데 집중한 다음, 나중에 scaffold enhance를 사용하여 배포를 추가할 수 있습니다.

2단계: 종속성 설치

스캐폴드는 올바른 ADK 종속성이 포함된 pyproject.toml을 생성합니다. 프로젝트 디렉터리로 이동하여 설치합니다:

cd meeting-notes
uv sync

google-adk ≠ google-antigravity

모듈 3은 google-antigravity(agy 내에서 에이전트를 빌드하기 위한 Antigravity SDK)를 사용합니다. 모듈 5는 google-adk(Google Cloud에 배포되는 독립형 ADK 에이전트를 빌드하기 위한 에이전트 개발 키트)를 사용합니다. 이들은 서로 다른 API를 가진 다른 패키지입니다. agents-cli scaffold는 항상 google-adk를 자동으로 설정합니다.

3단계: 환경 설정

# If using AI Studio:
echo 'GOOGLE_API_KEY=your-key-here' >> .env

# If using Google Cloud:
echo 'GOOGLE_CLOUD_PROJECT=your-project-id' >> .env
echo 'GOOGLE_CLOUD_LOCATION=global' >> .env

위치 선택

모든 모델 제품군과의 호환성을 보장하기 위해 에이전트 플랫폼에서는 GOOGLE_CLOUD_LOCATIONglobal을 사용하는 것이 일반적으로 권장됩니다. 리전 엔드포인트(예: us-central1 또는 us-east5)를 사용해야 하는 경우, GCP 프로젝트의 해당 리전에서 사용 중인 모델을 사용할 수 있는지 확인하세요.


파트 2: 에이전트 구축 (15분)

1단계: 도구 정의

요약 포맷팅 도구를 추가하려면 app/tools.py를 편집하세요:

def format_summary(
    title: str,
    attendees: list[str],
    action_items: list[dict],
    key_decisions: list[str],
) -> str:
    """Format the meeting summary into a structured markdown report.

    Args:
        title: Meeting title or topic.
        attendees: List of attendee names.
        action_items: List of dicts with 'task', 'assignee', and 'deadline' keys.
        key_decisions: List of key decisions made during the meeting.

    Returns:
        A formatted markdown string with the complete meeting summary.
    """
    lines = [f"# {title}", ""]
    lines.append(f"**Attendees:** {', '.join(attendees)}")
    lines.append("")
    lines.append("## Action Items")
    for i, item in enumerate(action_items, 1):
        assignee = item.get("assignee", "Unassigned")
        deadline = item.get("deadline", "TBD")
        lines.append(f"{i}. **{item['task']}** — {assignee} (due: {deadline})")
    lines.append("")
    lines.append("## Key Decisions")
    for decision in key_decisions:
        lines.append(f"- {decision}")
    return "\n".join(lines)

왜 도구가 하나뿐인가요?

LLM은 이미 컨텍스트 윈도우에 트랜스크립트를 가지고 있습니다. 즉, 이미 읽을 수 있는 텍스트를 "추출"하기 위한 도구가 필요하지 않습니다. format_summary 도구는 LLM이 하지 말아야 할 부분인 결정론적 포맷팅을 처리합니다. 도구는 모델이 스스로 할 수 없는(또는 해서는 안 되는) 작업을 수행해야 합니다.

2단계: 에이전트 구성

app/agent.py를 편집하세요:

from google.adk import Agent
from app.tools import format_summary

root_agent = Agent(
    name="meeting_notes",
    model="gemini-3.5-flash",
    instruction="""You are a meeting notes summarizer. Your job is to take raw
meeting transcripts and produce structured, actionable summaries.

Workflow:
1. Read the transcript carefully
2. Identify: attendees, action items (with assignees + deadlines), key decisions
3. Use `format_summary` to produce the final structured output

Rules:
- Every action item MUST have an assignee and a deadline
- If a deadline is not mentioned, mark it as "TBD"
- If an assignee is not clear, mark it as "Unassigned"
- Key decisions must be concrete, not vague summaries
- Never fabricate attendees or actions not in the transcript
""",
    tools=[format_summary],
)

3단계: 스모크 테스트

agents-cli run "Summarize this meeting: Alice and Bob discussed the Q3 launch. \
Alice will prepare the marketing deck by Friday. Bob will review the API docs by \
next Monday. They decided to use Cloud Run for deployment and skip the staging \
environment for the MVP."

확인:

  • [ ] 에이전트가 구조화된 데이터로 format_summary를 호출합니다.
  • [ ] 출력에 담당자와 기한이 포함된 실행 항목이 있습니다.
  • [ ] 주요 결정 사항이 나열되어 있습니다.

파트 3: 평가 케이스 작성 (10분)

1단계: 평가 데이터셋 생성

tests/eval/datasets/basic-dataset.json 편집:

{
  "eval_cases": [
    {
      "eval_case_id": "simple_meeting",
      "prompt": {
        "role": "user",
        "parts": [
          {
            "text": "Summarize this meeting transcript:\n\nMeeting: Sprint Planning\nDate: 2026-06-01\n\nAlice: Let's review the backlog. The auth migration is top priority.\nBob: I can take the auth migration. Should be done by end of week.\nCarol: I'll handle the API rate limiting. Need two weeks for that.\nAlice: Agreed. Let's also deprecate the v1 endpoints — Carol, can you add that to your scope?\nCarol: Sure, I'll bundle it with the rate limiting work.\nBob: One more thing — we decided to use Redis for session caching instead of Memcached.\nAlice: Confirmed. Meeting adjourned."
          }
        ]
      }
    },
    {
      "eval_case_id": "meeting_no_deadlines",
      "prompt": {
        "role": "user",
        "parts": [
          {
            "text": "Summarize this meeting:\n\nTeam standup. Dave mentioned he's blocked on the database schema review. Eve said she'll look at it when she gets a chance. Frank reported that the CI pipeline is green. No specific deadlines were discussed."
          }
        ]
      }
    },
    {
      "eval_case_id": "meeting_with_decisions",
      "prompt": {
        "role": "user",
        "parts": [
          {
            "text": "Meeting notes: Architecture Review\n\nParticipants: Grace, Heidi, Ivan\n\nGrace proposed moving from monolith to microservices. After discussion, the team decided to start with extracting the payment service first. Heidi will create the service boundary document by next Wednesday. Ivan will set up the new GKE cluster by Friday. They also decided to keep the monolith running in parallel for 3 months during migration. Grace will present the migration timeline to leadership next Monday."
          }
        ]
      }
    }
  ]
}

2단계: 메트릭 구성

tests/eval/eval_config.yaml 편집:

metrics_to_run:
  - multi_turn_task_success
  - multi_turn_tool_use_quality
  - final_response_quality
  - meeting_summary_quality

custom_metrics:
  - name: meeting_summary_quality
    # Optional: override the judge model for this custom metric.
    # Must be a fully-qualified resource path. Omit to use the service default autorater.
    judge_model: projects/<PROJECT_ID>/locations/<LOCATION>/publishers/google/models/gemini-3.1-flash-lite
    prompt_template: |
      Evaluate the agent's meeting summary on these criteria (1-5 each):

      1. **Completeness**: Are all action items from the transcript captured?
      2. **Attribution**: Does every action item have an assignee?
      3. **Deadlines**: Are deadlines captured or correctly marked as TBD?
      4. **Decisions**: Are key decisions listed accurately?
      5. **No hallucination**: Does the summary contain ONLY information from the transcript?

      Transcript/Prompt: {prompt}
      Agent response: {response}
      Full trace: {agent_data}

      Return JSON: {"score": <1-5 average>, "explanation": "<detailed reasoning>"}

에이전트 플랫폼 심사 모델 구성

  1. 기본 자동 평가기(autorater): 내장 메트릭(예: multi_turn_task_success, final_response_quality)은 GenAI Evaluation Service의 서버 측 자동 평가기를 사용합니다. 이러한 메트릭에 대해서는 심사 모델을 재정의할 수 없습니다. 사용자 지정 LLMMetric 항목의 경우 judge_model을 생략하면 서비스 기본값도 사용됩니다.
  2. 리소스 경로 형식: 사용자 지정 LLMMetric 항목은 선택적 judge_model 필드를 허용합니다. 이 필드는 반드시 정규화된 경로(fully-qualified path)여야 합니다: projects/<PROJECT_ID>/locations/<LOCATION>/publishers/google/models/<MODEL_NAME>. gemini-3.1-flash-lite와 같은 짧은 이름만 사용하면 400 INVALID_ARGUMENT 오류와 함께 실패합니다. 에이전트 플랫폼 심사 모델 구성 문서를 참조하세요.
  3. 모델 선택: 비용 효율적인 심사를 위해서는 gemini-3.1-flash-lite를 사용하고, 더 높은 품질의 루브릭 평가를 위해서는 gemini-3.1-pro-preview를 사용하세요. 더 이상 사용되지 않는 모델(gemini-1.5-flash, gemini-1.5-pro)은 사용하지 마세요.

3단계: 평가 실행

# Generate traces (runs agent on each eval case)
agents-cli eval generate

# Grade the traces
agents-cli eval grade

출력을 검토합니다. 임계값 미만인 메트릭 점수가 있다면 파트 4로 진행하세요.


파트 4: 평가-수정 루프 (10분)

여기서 실제 작업이 이루어집니다. 실패한 각 지표에 대해 다음을 수행합니다:

1단계: 결과 확인

# Open the HTML report (easiest to read)
open artifacts/grade_results/results_*.html

# Or check the JSON programmatically
cat artifacts/grade_results/results_*.json | python -m json.tool | head -50

2단계: 진단 및 수정

일반적인 수정 사항:

증상 해결 방법
에이전트가 format_summary를 건너뜀 지침 강화: "출력을 생성하려면 format_summary를 반드시 호출해야 합니다"
에이전트가 format_summary에 잘못된 키를 전달함 지침에 다음을 명시: "action_items는 'task', 'assignee', 'deadline' 키를 포함하는 딕셔너리의 목록이어야 합니다"
담당자 누락 지침에 추가: "모든 실행 항목에는 담당자가 있어야 합니다. 불분명한 경우 'Unassigned'를 사용하세요"
환각(Hallucinated) 실행 항목 추가: "대화록에 명시적으로 언급되지 않은 실행 항목은 절대 추가하지 마세요"
낮은 tool_use_quality 도구 독스트링(docstrings) 개선 — 매개변수에 대해 더 구체적으로 작성

3단계: 재평가 및 비교

# Save the previous results
cp artifacts/grade_results/results_*.json artifacts/grade_results/baseline.json

# Re-run
agents-cli eval generate
agents-cli eval grade

# Compare
agents-cli eval compare \
  artifacts/grade_results/baseline.json \
  artifacts/grade_results/results_*.json

모든 지표를 통과할 때까지 반복합니다.


도전 과제

배포 추가

# Add Cloud Run deployment
agents-cli scaffold enhance . --deployment-target cloud_run

# Deploy
agents-cli deploy

CI/CD 추가

agents-cli scaffold enhance . --cicd-runner github_actions

더 많은 평가 케이스 합성

# Auto-generate multi-turn eval scenarios
agents-cli eval dataset synthesize \
  -n 5 \
  --instruction "User provides meeting transcripts of varying complexity" \
  --max-turns 3

agy가 전체 흐름을 주도하도록 하기

agy 세션을 열고 다음과 같이 말합니다:

> Use agents-cli to improve my meeting-notes agent.
  The eval scores for meeting_summary_quality are low.
  Analyze the failures and fix them.

agy가 평가 스킬을 로드하고, eval analyze를 실행하여 실패 클러스터를 식별한 후, 반복적으로 에이전트를 수정하는 과정을 지켜보세요.


완료 기준

  • [ ] agents-cli scaffold create를 사용하여 프로젝트 스캐폴딩 완료
  • [ ] app/tools.pyformat_summary 도구 정의 완료
  • [ ] 에이전트 지침에 명확한 워크플로우 및 규칙 포함 완료
  • [ ] agents-cli run을 사용한 스모크 테스트 통과
  • [ ] basic-dataset.json에 3개의 평가 케이스 작성 완료
  • [ ] 사용자 지정 meeting_summary_quality 지표 정의 완료
  • [ ] agents-cli eval generate + eval grade 성공적으로 실행 완료
  • [ ] eval compare로 개선을 확인하며 최소 한 번의 평가-수정(eval-fix) 반복 완료

핵심 요약

  1. agents-cli scaffold create는 전체 프로젝트 구조를 부트스트랩합니다 — 수동으로 설정하지 마세요.
  2. agents-cli eval은 선택 사항이 아닙니다 — 이는 데모와 프로덕션 에이전트의 차이를 만듭니다.
  3. pytest ≠ eval — pytest는 코드의 정확성을 테스트하고, eval은 에이전트의 동작을 테스트합니다.
  4. eval-fix 루프는 반복적입니다 — 5~10회 이상의 반복을 예상하세요. 이는 정상적인 과정입니다.
  5. agents-cli 스킬은 코딩 에이전트(agy)를 자동으로 ADK 개발 전문가로 만들어 줍니다.