> EulerAgent > 튜토리얼 > 기본 > 02. Plan 모드 vs Execute 모드 — 언제...

02. Plan 모드 vs Execute 모드 — 언제 무엇을 쓸까


학습 목표

이 튜토리얼을 마치면 다음을 할 수 있습니다:


사전 준비

euleragent new code-agent --template code-assistant

Plan 모드와 Execute 모드란?

euleragent의 실행 모드는 사람의 개입 시점에 따라 두 가지로 나뉩니다.

Plan 모드 (기본값)

Plan 모드에서는 에이전트가 어떤 행동을 취할지 제안하고 실제 실행 전에 멈춥니다.

[사용자] ──태스크──▶ [LLM] ──제안──▶ [승인 큐]
                                         ↓
                                    [사람이 검토]
                                         ↓
                                    [승인 후 실행]

이 방식은: - 위험한 작업(파일 쓰기, 웹 검색, 셸 실행)을 실행 전에 검토할 수 있습니다 - 에이전트의 의도를 파악하고 파라미터를 수정할 수 있습니다 - 실수를 미연에 방지할 수 있습니다

Execute 모드

Execute 모드에서는 require_approval 목록에 없는 도구는 즉시 실행하고, 목록에 있는 도구는 승인을 큐에 넣습니다.

[사용자] ──태스크──▶ [LLM] ──제안──▶ [즉시 실행] (require_approval 아닌 경우)
                              └──제안──▶ [승인 큐]  (require_approval 경우)

이 방식은: - 신뢰할 수 있는 저위험 태스크를 빠르게 처리할 수 있습니다 - 읽기 전용 작업이나 이미 검증된 파이프라인에 적합합니다


단계별 실습

Step 1: 같은 태스크를 두 모드로 실행

Plan 모드로 실행

euleragent run code-agent \
  --task "fibonacci.py 파일을 만들고 피보나치 수열을 반환하는 Python 함수를 작성해줘" \
  --mode plan

예상 출력:

Run c3d4e5f6a1b2 started (agent: code-agent, mode: plan)

[loop 1/5] Generating plan...
  → Proposed: file.write (risk: medium)
      path: fibonacci.py
      content: "def fibonacci(n): ..."

Run c3d4e5f6a1b2 completed (state: PENDING_APPROVAL)
Artifacts:
  .euleragent/runs/c3d4e5f6a1b2/artifacts/plan.md

1 approval(s) pending.
  Use: euleragent approve list --run-id c3d4e5f6a1b2

에이전트가 file.write제안했지만 아직 파일은 생성되지 않았습니다. fibonacci.py는 존재하지 않습니다:

ls fibonacci.py   # No such file or directory

Execute 모드로 실행

이번에는 --mode execute로 실행합니다. 단, file.writepolicy.pyHIGH_RISK_TOOLS 집합에 속하므로 여전히 승인이 필요합니다. HIGH_RISK_TOOLS에 속하지 않는 file.read 같은 도구는 즉시 실행됩니다.

euleragent run code-agent \
  --task "fibonacci.py 파일을 만들고 피보나치 수열을 반환하는 Python 함수를 작성해줘" \
  --mode execute

예상 출력:

Run d4e5f6a1b2c3 started (agent: code-agent, mode: execute)

[loop 1/5] Generating plan...
  → Proposed: file.write (risk: medium) — queued for approval

Run d4e5f6a1b2c3 completed (state: PENDING_APPROVAL)

1 approval(s) pending.

왜 execute 모드도 승인이 필요한가요? file.writepolicy.pyHIGH_RISK_TOOLS 집합에 속하기 때문입니다. resolve_tool_permission()은 도구가 allowlist에 있고 HIGH_RISK_TOOLS에도 속하면 "require_approval"을 반환합니다. Execute 모드는 "승인이 필요 없는 저위험 도구만 즉시 실행"하는 것이지, 모든 도구를 자동 실행하는 것이 아닙니다.

두 모드의 핵심 차이

항목 Plan 모드 Execute 모드
도구 제안 제안 후 중단 즉시 실행 (가능한 경우)
require_approval 도구 승인 큐에 추가 후 중단 승인 큐에 추가 후 계속 진행
아티팩트 plan.md (제안 내용) result.md (실행 결과)
실행 속도 항상 승인 대기 저위험 도구는 즉시 처리
권장 사용 위험한 작업, 초기 개발 신뢰된 파이프라인, 읽기 전용

Step 2: 에이전틱 루프와 --max-loops

에이전틱 루프는 LLM이 태스크를 완료할 때까지 반복적으로 도구를 사용하는 과정입니다:

루프 시작
  ↓
LLM이 다음 행동 결정 (도구 호출 or 텍스트 응답)
  ↓
도구 호출이 있으면 → 승인 큐 추가 or 즉시 실행
  ↓
결과를 컨텍스트에 추가
  ↓
태스크 완료? → 아니면 루프 반복

기본 최대 루프 수는 5회입니다. 복잡한 태스크나 단순한 태스크에 맞게 조정할 수 있습니다:

# 단순 태스크: 루프 1회로 제한
euleragent run code-agent \
  --task "hello_world.py 파일에 Hello, World! 출력 코드를 작성해줘" \
  --mode plan \
  --max-loops 1
# 복잡한 태스크: 루프 10회 허용
euleragent run code-agent \
  --task "프로젝트 전체 코드를 분석하고 개선점을 찾아 리포트를 작성해줘" \
  --mode plan \
  --max-loops 10

--max-loops를 사용해야 하는 경우:


Step 3: --min-proposals로 배치 수집 강제

--min-proposals N은 에이전트가 최소 N개의 도구 호출을 제안하기 전에는 종료하지 않도록 강제합니다. 배치 정보 수집이 필요할 때 유용합니다.

euleragent run code-agent \
  --task "프로젝트의 Python 파일들을 읽고 각 파일의 주요 기능을 요약해줘" \
  --mode plan \
  --min-proposals 3 \
  --max-loops 5

예상 출력:

Run e5f6a1b2c3d4 started (agent: code-agent, mode: plan)

[loop 1/5] Generating plan...
  → Proposed: file.read (path: main.py)

[loop 2/5] Continuing... (proposals so far: 1, min required: 3)
  → Proposed: file.read (path: utils.py)

[loop 3/5] Continuing... (proposals so far: 2, min required: 3)
  → Proposed: file.read (path: config.py)

[loop 4/5] Continuing... (proposals so far: 3, min required: 3)
  → Min proposals reached. Generating summary...

Run e5f6a1b2c3d4 completed (state: PENDING_APPROVAL)
3 approval(s) pending.

팁: --min-proposals--mode plan과 함께 쓸 때 가장 효과적입니다. 에이전트가 충분한 정보를 수집하도록 강제한 후, 사람이 모든 제안을 한 번에 검토하고 승인할 수 있습니다.


Step 4: --artifact-name으로 출력 파일명 지정

기본적으로 아티팩트 파일명은 모드에 따라 plan.md 또는 result.md입니다. --artifact-name으로 커스터마이징할 수 있습니다:

euleragent run code-agent \
  --task "fibonacci.py 파일을 만들고 피보나치 함수를 구현해줘" \
  --mode execute \
  --artifact-name fibonacci_report.md

예상 출력:

Run f6a1b2c3d4e5 completed (state: RUN_FINALIZED)
Artifacts:
  .euleragent/runs/f6a1b2c3d4e5/artifacts/fibonacci_report.md

--artifact-name은 다음 상황에서 유용합니다: - 여러 실행의 결과를 의미 있는 이름으로 구분할 때 - 자동화 파이프라인에서 예측 가능한 파일명이 필요할 때 - CI/CD 시스템에서 아티팩트를 수집할 때


Step 4-1: --source-set으로 검색 소스 그룹 지정

--source-setweb.search 도구가 사용할 검색 소스 그룹을 지정합니다. workspace.yamlmcp.sources에 정의된 소스들을 그룹으로 묶어 태스크별로 다른 검색 전략을 적용할 수 있습니다:

euleragent run code-agent \
  --task "최신 Python 패키지 동향을 조사해줘" \
  --mode plan \
  --source-set research

--source-set을 지정하면 내부적으로 SearchRouter가 해당 그룹의 후보 소스(예: tavily, brave, local_kb) 중 최적의 소스를 선택하여 web.search 호출을 라우팅합니다. 소스를 지정하지 않으면 기본 소스 그룹이 사용됩니다.

참고: web.search는 내부적으로 SearchRouter를 통해 라우팅됩니다. 사용자가 직접 호출하는 인터페이스는 동일하지만, 뒤에서는 mcp.sources에 정의된 후보 소스들이 평가되어 최적의 소스가 선택됩니다. 소스 활성화에는 HITL 승인이 필요할 수 있습니다 — 자세한 내용은 03_hitl_approval.md를 참조하세요.


Step 4-2: --llm-plan / --llm-final으로 스코프별 LLM 프로필 지정

태스크의 계획 단계최종 결과물 생성 단계에서 서로 다른 LLM을 사용할 수 있습니다:

# 계획은 로컬 LLM으로, 최종 결과물은 외부 LLM으로
euleragent run code-agent \
  --task "Python 유틸리티 설계 및 작성" \
  --mode execute \
  --llm-plan ollama_local \
  --llm-final openai_main

workspace.yamlis_external: true로 표시된 프로필은 HITL 승인이 필요합니다:

llm_profiles:
  ollama_local:
    provider: ollama
    base_url: http://localhost:11434
    model: qwen3:32b
    is_external: false     # 로컬 → 승인 불필요

  openai_main:
    provider: openai
    api_key: ${OPENAI_API_KEY}
    model: gpt-4o-mini
    base_url: https://api.openai.com/v1
    is_external: true      # 외부 → 승인 필요

default_llm_profile: ollama_local

폴백 동작: 외부 프로필이 아직 승인되지 않았다면 로컬 기본 제공자로 폴백하며, 런은 중단되지 않습니다. kind: llm_profile_enable 승인 레코드가 생성되며, 승인 후 다음 런부터 외부 프로필이 적용됩니다. 폴백→승인→재실행 전체 사이클의 상세 실습은 09_scoped_llm_profile.md를 참조하세요.

# 승인 대기 목록 확인
euleragent approve list --tool llm.external_call

# 개별 승인
euleragent approve accept <approval-id> --actor "user:you"

# 일괄 승인
euleragent approve accept-all --actor "user:you" --tool llm.external_call

Step 5: 전체 시나리오 — 코드 어시스턴트 실전 활용

실제 업무와 유사한 시나리오로 두 모드를 모두 경험합니다.

시나리오: Python 유틸리티 스크립트 작성

Step 5-1: Plan 모드로 초안 검토

euleragent run code-agent \
  --task "data_processor.py 파일을 만들어줘. CSV 파일을 읽어서 각 행의 합계를 계산하고 결과를 output.csv에 저장하는 Python 스크립트야. pandas 사용하고 타입 힌트 포함해줘." \
  --mode plan \
  --max-loops 2

예상 출력:

Run a1b2c3d4e5f6 started (agent: code-agent, mode: plan)

[loop 1/2] Generating plan...
  → Proposed: file.write (risk: medium)
      path: data_processor.py
      content: [python code with pandas...]

Run a1b2c3d4e5f6 completed (state: PENDING_APPROVAL)

1 approval(s) pending.

제안된 코드를 먼저 확인합니다:

euleragent approve show apv_p1q2r3
{
  "id": "apv_p1q2r3",
  "tool_name": "file.write",
  "params": {
    "path": "data_processor.py",
    "content": "import pandas as pd\nfrom pathlib import Path\nfrom typing import Optional\n\ndef process_csv(input_path: str, output_path: str = 'output.csv') -> None:\n    ..."
  },
  "risk_level": "medium",
  "status": "pending"
}

코드가 마음에 들면 승인하고 실행합니다:

euleragent approve accept apv_p1q2r3 --actor "user:you" --execute

Step 5-2: Execute 모드로 후속 작업

파일이 생성된 후, 간단한 테스트 파일 생성은 execute 모드로 빠르게 처리합니다:

euleragent run code-agent \
  --task "test_data.csv 샘플 파일을 만들어줘. 이름, 점수1, 점수2 컬럼에 5개 행을 포함해줘." \
  --mode execute \
  --artifact-name test_setup_report.md

test_data.csv 생성도 file.write이므로 승인이 필요하지만, execute 모드는 루프를 멈추지 않고 다음 도구 호출로 계속 진행하므로 더 빠르게 완료됩니다.


언제 어떤 모드를 써야 하나?

상황 권장 모드 이유
처음 보는 태스크, 결과가 불확실 Plan 에이전트 의도를 먼저 확인
프로덕션 파일 수정 Plan 실수 시 복구 어려움
외부 서비스 호출 (웹, 이메일) Plan 의도치 않은 외부 전송 방지
읽기 전용 분석 Execute 즉각 처리 가능
이미 검증된 파이프라인 Execute 속도 우선
초기 개발/프로토타이핑 Plan 에이전트 동작 학습
배치 정보 수집 Plan + --min-proposals 충분한 데이터 수집 보장
CI/CD 자동화 Execute + 사전 허용 목록 관리 자동화 요구

하이브리드 접근법

실제 운영에서는 두 모드를 조합하는 것이 가장 안전합니다:

  1. 리서치 단계: --mode plan --min-proposals 5 — 충분한 정보 수집 제안을 생성
  2. 검토 단계: euleragent approve listeuleragent approve show — 각 제안 검토
  3. 실행 단계: euleragent approve accept-all --actor "user:you" --execute — 승인 후 일괄 실행
  4. 결과 확인: euleragent logs <run-id> — 실행 내역 감사

예상 출력 요약

# Plan 모드 — 파일 쓰기 제안 있는 경우
Run a1b2c3... completed (state: PENDING_APPROVAL)
1 approval(s) pending.

# Execute 모드 — 즉시 실행 가능한 도구 있는 경우
Run b2c3d4... completed (state: RUN_FINALIZED)
  [executed] file.read — OK
  [queued]   file.write — pending approval

# max-loops 초과 시
Run c3d4e5... completed (state: RUN_FINALIZED)
  [warn] Max loops (3) reached. Task may be incomplete.

# min-proposals 충족 시
Run d4e5f6... completed (state: PENDING_APPROVAL)
  [info] min-proposals (3) satisfied after loop 3.
3 approval(s) pending.

자주 묻는 질문 / 흔한 오류

Q: execute 모드인데 왜 여전히 승인을 요청하나요?

file.write, web.search, shell.execpolicy.pyHIGH_RISK_TOOLS 집합에 속하는 도구는 execute 모드에서도 반드시 승인이 필요합니다. Execute 모드는 고위험이 아닌 도구(예: file.read, git.diff)를 즉시 실행하는 것입니다. 승인 판단은 resolve_tool_permission()의 반환값 기준입니다: "allow" → 즉시 실행, "require_approval" → 승인 필요, "deny" → 차단.


Q: --max-loops를 초과하면 어떻게 되나요?

에이전트가 태스크를 완료하지 못한 상태로 종료됩니다. 아티팩트는 생성되지만 불완전할 수 있습니다. 경고 메시지가 출력됩니다. 더 많은 루프가 필요하면 --max-loops를 늘리세요.

# 루프 부족 시 증상 확인
euleragent logs <run-id>
# [warn] Max loops (5) reached. Task may be incomplete.

Q: --min-proposals를 설정했는데 에이전트가 도구를 충분히 제안하지 않으면 어떻게 되나요?

--max-loops에 도달하면 에이전트가 종료됩니다. 이 경우 --max-loops를 늘리거나 태스크 설명을 더 구체적으로 작성하세요. 예를 들어 "5개의 파일을 각각 읽어서 분석해줘"처럼 도구 호출 횟수를 명시하면 효과적입니다.


Q: plan.md와 result.md의 차이는 무엇인가요?


Q: --mode를 지정하지 않으면 기본값이 무엇인가요?

기본값은 plan입니다. euleragent는 안전 우선 원칙에 따라 기본적으로 실행 전 사람의 검토를 요구합니다.


자주 하는 실수 (순서 어긋남)

증상 원인 복구
Error: No task provided. --resume-run만 지정, --task 누락 자동으로 이전 run의 task 로드됨
Info: --max-loops auto-raised from 2 to 7 --min-proposals--max-loops보다 큼 정상 — 자동 조정 안내
Plan 결과가 placeholder 텍스트 FakeProvider 사용 중 workspace.yamldefault_llm_profile을 실제 LLM으로 변경

다음 단계: 03_hitl_approval.md — HITL 승인 워크플로우를 심층적으로 학습합니다.

← 이전 목록으로 다음 →