Optimization convention-adk-agent
Google ADK 에이전트 구현 패턴. root_agent export, PromptLoader, ToolContext state schema 설계 우선, initial_state 구조.
install
source · Clone the upstream repo
git clone https://github.com/sunLeee/optimization
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/sunLeee/optimization "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.claude/skills/reference/adk/agent" ~/.claude/skills/sunleee-optimization-convention-adk-agent && rm -rf "$T"
manifest:
.claude/skills/reference/adk/agent/SKILL.mdsource content
convention-adk-agent
Google ADK 기반 에이전트 구현 시 준수해야 할 패턴. CLAUDE.md § Agent 구현과 AW-011(데이터 구조 우선 설계)을 따른다.
1. 에이전트 디렉토리 구조
agents/{agent_name}/ ├── src/ │ └── {agent_name}/ │ ├── __init__.py # root_agent export 필수 │ ├── agent.py # 에이전트 정의 │ ├── tools.py # tool function 모음 │ └── prompts/ # Jinja2 템플릿 │ └── system.yaml ├── tests/ │ ├── __init__.py │ ├── test_agent.py │ └── test_tools.py ├── pyproject.toml └── CLAUDE.md # 에이전트별 규칙
2. root_agent export (필수)
__init__.py에서 반드시 root_agent를 export한다.
# agents/{agent_name}/src/{agent_name}/__init__.py from {agent_name}.agent import root_agent __all__ = ["root_agent"]
3. State Schema 설계 우선 (AW-011 Rule 5)
코드 작성 전
initial_state와 tool_context.state key 목록을 먼저 확정한다.
# STEP 1 (구현 전): state schema 문서화 # app: prefix = 파일 경로 및 설정값 # agent: prefix = 에이전트 내부 상태 INITIAL_STATE_SCHEMA = { "app:demand_file": "str — 수요 데이터 CSV 경로", "app:output_dir": "str — 출력 디렉토리", "agent:processed": "bool — 전처리 완료 여부", "agent:zone_count": "int — 처리된 zone 수", } # STEP 2: agent __init__에서 파일 존재 확인 class DemandAgent: def __init__(self, demand_file: str, output_dir: str) -> None: demand_path = Path(demand_file) if not demand_path.exists(): raise FileNotFoundError(f"수요 데이터 없음: {demand_path}") self.initial_state = { "app:demand_file": str(demand_path), "app:output_dir": str(output_dir), }
4. Prompt 외부화 (Jinja2 + PromptLoader)
prompt를 코드에 하드코딩하지 않는다.
# agents/{agent_name}/src/{agent_name}/agent.py from utils.prompt_loader import PromptLoader loader = PromptLoader(Path(__file__).parent / "prompts") root_agent = LlmAgent( name="demand_analyst", model="gemini-2.0-flash", instruction=loader.load("system.yaml", zone_count="{zone_count}"), )
# prompts/system.yaml system: | 당신은 모빌리티 수요 분석 전문가입니다. 분석 대상 zone 수: {{ zone_count }} 입력 변수: - zone_count: 처리할 H3 zone 수
5. Tool Function 패턴 (CLAUDE.md § File Path Pattern)
# tools.py from google.adk.tools import ToolContext import pandas as pd from typing import Any def load_demand_data(tool_context: ToolContext) -> dict[str, Any]: """수요 데이터를 로드하고 기본 통계를 반환한다. Logics: tool_context.state["app:demand_file"]에서 경로를 읽어 CSV를 로드하고 zone별 집계 결과를 반환한다. Args: tool_context: ADK tool context. state에서 파일 경로를 읽음. Returns: zone별 수요 집계 결과 dict. """ file_path = tool_context.state["app:demand_file"] df = pd.read_csv(file_path) # vectorized 연산 (iterrows 금지 — AW-011 Rule 3/4) result = df.groupby("zone_id")["demand"].sum().to_dict() tool_context.state["agent:processed"] = True tool_context.state["agent:zone_count"] = len(result) return {"zone_demands": result, "total_zones": len(result)}
6. 에이전트 등록 (pyproject.toml)
[tool.uv.sources] utils = { workspace = true } {agent_name} = { workspace = true } [project] name = "{agent_name}" dependencies = [ "google-adk>=0.1.0", "pandas>=2.0.0", "utils", ]
7. 체크리스트
구현 전:
-
key 목록 확정 (state schema 문서화)initial_state -
prefix 파일 경로 key 식별app: - tool function signature 확정 (ToolContext만 인자)
구현 중:
-
export 확인root_agent - 파일 존재 확인은
에서만__init__ - tool function 내
금지os.path.exists - prompt는 YAML 파일로 분리
검증:
-
실행/check-data-pipeline -
실행/convention-python -
통과uv run pytest -m unit
관련 규칙
- CLAUDE.md § Agent 구현 (Google ADK)
- CLAUDE.md § File Path & Data Access Pattern
- team-operations.md § AW-011
- check-data-pipeline
- claude-code-rule-convention.md § Practice 8, 27