> EulerAgent > 튜토리얼 > 기본 > 04. 태스크 파일, 변수 치환, 배치 리서치, 재개 ...

04. 태스크 파일, 변수 치환, 배치 리서치, 재개 실행


학습 목표

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


사전 준비

euleragent new research-agent --template marketing-expert

왜 태스크 파일을 쓰나?

인라인 --task "..." 방식은 짧고 단순한 태스크에 적합합니다. 하지만 다음 상황에서는 파일이 훨씬 낫습니다:

상황 인라인 태스크 태스크 파일
태스크가 3줄 이상 셸 이스케이프 지옥 마크다운으로 깔끔하게
같은 태스크를 반복 실행 매번 타이핑 파일 재사용
변수로 태스크 커스터마이징 불가능 --var로 치환
팀에서 공유 어려움 버전 관리 가능
구조화된 요구사항 어려움 마크다운 헤딩/목록 활용

단계별 실습

Step 1: 첫 번째 태스크 파일 작성

research_task.md를 현재 디렉토리에 생성합니다:

# ${COMPANY} 경쟁사 분석

다음 주제에 대해 웹에서 각각 최소 2개 이상의 출처를 조사해주세요:

## 조사 항목

1. **주요 경쟁자**: ${COMPANY}와 경쟁하는 주요 AI 에이전트 프레임워크 (LangChain, CrewAI, AutoGen 등)
2. **차별화 요소**: 각 프레임워크의 핵심 기능과 강점
3. **시장 동향**: 2024-2025년 AI 에이전트 시장 성장 추세

## 출력 형식

- 각 항목에 대해 마크다운 섹션으로 구분하여 작성
- 출처 URL을 각 항목 끝에 참조 형식으로 포함
- 전체 분량: 500~800 단어
- 언어: 한국어

## 저장

결과를 `${OUTPUT_FILE}` 파일에 저장해주세요.

이 파일은 ${COMPANY}${OUTPUT_FILE} 두 개의 변수를 사용합니다.


Step 2: 태스크 파일로 실행 (변수 없이)

먼저 변수 없이 실행하면 ${COMPANY}가 그대로 전달됩니다:

euleragent run research-agent \
  --task-file research_task.md \
  --mode plan

예상 출력:

Run a1b2c3d4e5f6 started (task-file: research_task.md)
  [warn] Unresolved variables: ${COMPANY}, ${OUTPUT_FILE}
  Task will include literal variable placeholders.

Step 3: --var로 변수 치환

--var KEY=VALUE 옵션으로 태스크 파일의 변수를 치환합니다. ${KEY} 형식과 {KEY} 형식 모두 지원합니다:

euleragent run research-agent \
  --task-file research_task.md \
  --var COMPANY=EulerAI \
  --var OUTPUT_FILE=competitor_analysis.md \
  --mode plan \
  --max-loops 5

예상 출력:

Run b2c3d4e5f6a1 started
  Task file: research_task.md
  Variables:
    COMPANY=EulerAI
    OUTPUT_FILE=competitor_analysis.md
  Resolved task:
    # EulerAI 경쟁사 분석
    ...결과를 `competitor_analysis.md` 파일에 저장해주세요.

[loop 1/5] Generating plan...
  → Proposed: web.search (query: "EulerAI competitor AI agent framework 2025")

[loop 2/5] Continuing...
  → Proposed: web.search (query: "LangChain CrewAI AutoGen comparison 2025")

[loop 3/5] Continuing...
  → Proposed: file.write (path: competitor_analysis.md)

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

Step 4: 여러 변수 조합 — 재사용 가능한 태스크 파일

같은 태스크 파일을 다른 회사에 재사용합니다:

# EulerAI 분석
euleragent run research-agent \
  --task-file research_task.md \
  --var COMPANY=EulerAI \
  --var OUTPUT_FILE=eulerAI_analysis.md \
  --mode plan

# LangChain 분석 (같은 파일 재사용)
euleragent run research-agent \
  --task-file research_task.md \
  --var COMPANY=LangChain \
  --var OUTPUT_FILE=langchain_analysis.md \
  --mode plan

이렇게 하면 같은 분석 형식으로 여러 회사를 일관되게 비교할 수 있습니다.

MCP 검색 프로바이더를 구성한 경우, 각 배치 실행마다 --source-set을 다르게 지정하여 검색 소스를 분리할 수 있습니다:

# 학술 소스만 사용
euleragent run research-agent \
  --task-file research_task.md \
  --var COMPANY=EulerAI \
  --var OUTPUT_FILE=eulerAI_academic.md \
  --source-set academic \
  --mode plan

# 뉴스 소스만 사용
euleragent run research-agent \
  --task-file research_task.md \
  --var COMPANY=EulerAI \
  --var OUTPUT_FILE=eulerAI_news.md \
  --source-set news \
  --mode plan

Step 5: --min-proposals로 배치 정보 수집 강제

배치 리서치에서는 에이전트가 충분한 웹 검색을 제안하도록 강제합니다:

euleragent run research-agent \
  --task-file research_task.md \
  --var COMPANY=EulerAI \
  --var OUTPUT_FILE=research_output.md \
  --mode plan \
  --min-proposals 5 \
  --max-loops 8

--source-set 옵션: MCP 검색 프로바이더를 사용하는 환경에서는 --source-set 옵션으로 이 배치 실행에서 사용할 검색 소스 집합을 지정할 수 있습니다. 자세한 내용은 07_web_rag.md의 "MCP 검색 프로바이더 설정" 섹션을 참조하세요.

예상 출력:

Run c3d4e5f6a1b2 started
  min-proposals: 5, max-loops: 8

[loop 1/8] Generating plan... (proposals: 0/5)
  → Proposed: web.search ("EulerAI AI agent framework features")

[loop 2/8] Continuing... (proposals: 1/5)
  → Proposed: web.search ("LangChain vs EulerAI comparison 2025")

[loop 3/8] Continuing... (proposals: 2/5)
  → Proposed: web.search ("CrewAI AutoGen market share AI agents")

[loop 4/8] Continuing... (proposals: 3/5)
  → Proposed: web.search ("AI agent framework growth trends 2024 2025")

[loop 5/8] Continuing... (proposals: 4/5)
  → Proposed: web.search ("EulerAI local-first AI agent benchmark")

[loop 6/8] Continuing... (proposals: 5/5) ← min-proposals 충족!
  → Proposed: file.write (path: research_output.md)

Run c3d4e5f6a1b2 completed (state: PENDING_APPROVAL)
6 approval(s) pending.
  [5x] web.search
  [1x] file.write

--min-proposals 5가 없었다면 에이전트는 2~3개 검색 후 조기 종료했을 수 있습니다.


Step 6: 배치 승인 및 실행

5개의 웹 검색 제안을 한 번에 검토하고 수락합니다:

# 목록 확인
euleragent approve list --run-id c3d4e5f6a1b2

예상 출력:

Pending approvals (6):

  ID           TOOL         RISK    STATUS
  apv_001      web.search   medium  pending
  apv_002      web.search   medium  pending
  apv_003      web.search   medium  pending
  apv_004      web.search   medium  pending
  apv_005      web.search   medium  pending
  apv_006      file.write   medium  pending

웹 검색만 먼저 수락하고 실행합니다:

euleragent approve accept-all \
  --run-id c3d4e5f6a1b2 \
  --tool web.search \
  --actor "user:you" \
  --execute

예상 출력:

Accepted and executed 5 web.search approval(s).
  [OK] apv_001 — "EulerAI AI agent framework features" → 5 results
  [OK] apv_002 — "LangChain vs EulerAI comparison 2025" → 5 results
  [OK] apv_003 — "CrewAI AutoGen market share AI agents" → 4 results
  [OK] apv_004 — "AI agent framework growth trends 2024 2025" → 5 results
  [OK] apv_005 — "EulerAI local-first AI agent benchmark" → 3 results
Executed 5/5 successfully.

1 approval(s) remain (file.write).

Step 7: --resume-run으로 이전 실행 이어받기

웹 검색 결과가 컨텍스트에 쌓인 상태에서, 이제 --resume-run으로 이전 실행을 이어받아 보고서를 작성합니다.

--resume-run이 하는 일: - 이전 실행(run-id)의 메시지 히스토리와 도구 실행 결과를 로드합니다 - 5개의 웹 검색 결과가 이미 컨텍스트에 있는 상태에서 새 태스크를 시작합니다

euleragent run research-agent \
  --task "앞서 수집한 검색 결과를 바탕으로 EulerAI 경쟁사 분석 보고서를 작성해줘. competitor_analysis.md 파일에 저장해줘." \
  --resume-run c3d4e5f6a1b2 \
  --mode execute \
  --artifact-name analysis_report.md

예상 출력:

Run d4e5f6a1b2c3 started
  Resuming context from run c3d4e5f6a1b2
  Loaded: 5 web search results, 10 messages from previous run

[loop 1/5] Generating...
  Context: [5 web search results injected]
  → Proposed: file.write
      path: competitor_analysis.md
      content: "# EulerAI 경쟁사 분석 보고서\n\n## 개요\n..."

Run d4e5f6a1b2c3 completed (state: PENDING_APPROVAL)
1 approval(s) pending.

파일 쓰기 승인 후 완료:

euleragent approve accept-all --run-id d4e5f6a1b2c3 --actor "user:you" --execute

예상 출력:

Accepted and executed 1 approval(s).
  [OK] file.write — competitor_analysis.md created (2.8KB)

Run d4e5f6a1b2c3 state: RUN_FINALIZED
Artifacts:
  .euleragent/runs/d4e5f6a1b2c3/artifacts/analysis_report.md
  competitor_analysis.md  ← 실제 파일

Step 8: 전체 리서치 파이프라인 — Plan → Execute 핸드오프

지금까지 배운 내용을 조합하여 완전한 리서치 파이프라인을 구성합니다:

Phase 1: 배치 정보 수집 (Plan 모드)

# research_task.md 파일 준비
cat > research_task.md << 'EOF'
# ${COMPANY} 시장 분석

다음을 각각 독립적으로 조사해주세요 (각 항목마다 별도 웹 검색 수행):

1. ${COMPANY}의 주요 경쟁사와 시장 포지셔닝
2. AI 에이전트 프레임워크 시장 규모와 성장률 (2023-2025)
3. ${COMPANY}의 기술적 차별화 요소
4. 주요 경쟁사들의 최신 제품 업데이트 (최근 6개월)
5. 개발자 커뮤니티 반응과 GitHub 스타 추세
EOF

euleragent run research-agent \
  --task-file research_task.md \
  --var COMPANY=EulerAI \
  --mode plan \
  --min-proposals 5 \
  --max-loops 8
# 실행 ID 기록
PHASE1_RUN=c3d4e5f6a1b2  # 실제 출력에서 복사

# 웹 검색 일괄 승인 + 실행
euleragent approve accept-all \
  --run-id $PHASE1_RUN \
  --tool web.search \
  --actor "user:you" \
  --execute

Phase 2: 보고서 합성 (Execute 모드, resume)

# synthesis_task.md 파일 준비
cat > synthesis_task.md << 'EOF'
# 분석 보고서 작성 요청

앞서 수집한 ${COMPANY} 관련 시장 조사 데이터를 바탕으로:

## 보고서 구성

1. **경영진 요약** (Executive Summary, 200단어)
2. **시장 현황** (Market Overview, 400단어)
3. **경쟁사 비교표** (Competitive Matrix, 표 형식)
4. **전략적 제언** (Strategic Recommendations, 300단어)

## 형식 요구사항

- 파일명: ${OUTPUT_FILE}
- 언어: 한국어 (기술 용어는 영어 병기)
- 총 분량: 1000~1500 단어
EOF

euleragent run research-agent \
  --task-file synthesis_task.md \
  --var COMPANY=EulerAI \
  --var OUTPUT_FILE=market_analysis_report.md \
  --resume-run $PHASE1_RUN \
  --mode execute \
  --max-loops 3
# 파일 쓰기 승인 + 실행
PHASE2_RUN=d4e5f6a1b2c3  # 실제 출력에서 복사

euleragent approve accept-all \
  --run-id $PHASE2_RUN \
  --actor "user:you" \
  --execute

최종 결과 확인:

cat market_analysis_report.md

좋은 태스크 파일 작성 요령

권장 구조

# [태스크 제목]

## 배경 / 컨텍스트
(에이전트가 알아야 할 배경 정보)

## 수행 항목
1. 항목 1
2. 항목 2
...

## 출력 형식
- 파일명: ${OUTPUT_FILE}
- 언어: 한국어
- 형식: 마크다운

## 제약 조건 / 주의사항
- 민감 정보 검색 금지
- 최신 정보 (2024-2025년) 우선

변수 작성 규칙

규칙 예시 설명
대문자 권장 ${COMPANY} 식별하기 쉬움
두 형식 모두 지원 ${KEY} or {KEY} 둘 다 치환됨
기본값 없음 미지정 시 경고
공백 포함 불가 ${MY_COMPANY} 언더스코어 사용

예상 출력 요약

# --task-file + --var 실행
Run b2c3d4... started
  Variables:
    COMPANY=EulerAI
    OUTPUT_FILE=competitor_analysis.md

# --min-proposals 충족 시
[loop 5/8] Continuing... (proposals: 5/5) ← min-proposals 충족!
6 approval(s) pending.

# --resume-run으로 이전 컨텍스트 로드
Run d4e5f6... started
  Resuming context from run c3d4e5f6...
  Loaded: 5 web search results, 10 messages from previous run

자주 묻는 질문 / 흔한 오류

Q: 변수가 치환되지 않고 ${COMPANY} 그대로 나옵니다.

--var COMPANY=값 옵션을 지정했는지 확인하세요. --var 앞에 --task-file이 있어야 합니다:

# 올바른 순서
euleragent run my-agent --task-file task.md --var COMPANY=EulerAI

# 잘못된 예 (--var가 태스크 파일 앞에 올 경우 일부 셸에서 문제 발생)
euleragent run my-agent --var COMPANY=EulerAI --task-file task.md

Q: 태스크 파일에 {} 문자가 포함되어 있는데 변수로 인식됩니다.

JSON이나 코드 블록 안의 중괄호가 변수로 인식되는 경우, 이중 중괄호 {{ }}를 사용하면 리터럴 중괄호로 처리됩니다:

JSON 예시:
{{
  "key": "value"
}}

Q: --resume-run을 사용하면 어떤 데이터가 로드되나요?

이전 런의 다음 데이터가 로드됩니다: - messages.jsonl: 전체 LLM 대화 기록 - tool_calls.jsonl: 실행된 도구 결과 (웹 검색 결과 포함) - artifacts/: 이전 아티팩트 목록

로드 범위는 --max-loops에 따라 컨텍스트 크기가 조정됩니다.


Q: --min-proposals--max-loops를 동시에 쓸 때 어떤 게 우선인가요?

--max-loops가 항상 상한선입니다. --min-proposals가 충족되기 전에 --max-loops에 도달하면 에이전트가 종료됩니다. 따라서 --min-proposals N을 쓸 때는 --max-loopsN + 2 이상으로 설정하는 것을 권장합니다:

# min-proposals=5이면 max-loops는 7~8 정도로
euleragent run my-agent --task-file task.md \
  --min-proposals 5 --max-loops 8

Q: 태스크 파일을 버전 관리하려면 어떻게 하나요?

태스크 파일은 일반 마크다운 파일이므로 Git으로 버전 관리할 수 있습니다. .euleragent/ 디렉토리는 .gitignore에 추가하고, 태스크 파일은 tasks/ 같은 별도 디렉토리에 보관하는 것을 권장합니다:

my-project/
├── .euleragent/          # gitignore 권장
├── tasks/
│   ├── research_task.md  # 버전 관리
│   └── synthesis_task.md
└── .gitignore

다음 단계: 05_chat_and_memory.md — 대화 모드와 장기기억을 학습합니다.

← 이전 목록으로 다음 →