Dual-Mode 실행
왜 모드를 분리하는가?
섹션 제목: “왜 모드를 분리하는가?”에이전트가 계획을 세우면서 동시에 파일을 수정하거나 명령을 실행하면 위험합니다. 탐색 중에 의도치 않은 부작용이 발생하고, 불완전한 계획이 즉시 실행될 수 있습니다.
Dual-Mode 실행은 에이전트의 상태를 명시적으로 두 가지로 구분합니다:
- Plan Mode: 읽기 전용. 정보를 수집하고 계획을 수립합니다.
- Normal Mode (Execute Mode): 전체 접근. 실제 변경을 수행합니다.
모드별 도구 접근
섹션 제목: “모드별 도구 접근”| 도구 | Plan Mode | Normal Mode |
|---|---|---|
read_file | 허용 | 허용 |
search_code | 허용 | 허용 |
list_directory | 허용 | 허용 |
write_file | 차단 | 허용 |
run_command | 차단 | 허용 |
delete_file | 차단 | 허용 |
call_api | 차단 | 허용 |
스키마 수준 강제
섹션 제목: “스키마 수준 강제”도구 목록을 줄여 정상적인 선택 범위를 제한하고, 실행기에서도 현재 모드와 권한을 검사합니다. 스키마에서 이름을 숨기는 것만으로 실행 권한이 강제되지는 않습니다.
from enum import Enumfrom typing import Callable
class AgentMode(Enum): PLAN = "plan" EXECUTE = "execute"
# 도구에 모드 메타데이터 부착TOOL_REGISTRY = { "read_file": {"fn": read_file, "modes": [AgentMode.PLAN, AgentMode.EXECUTE]}, "search_code": {"fn": search_code, "modes": [AgentMode.PLAN, AgentMode.EXECUTE]}, "list_directory": {"fn": list_directory, "modes": [AgentMode.PLAN, AgentMode.EXECUTE]}, "write_file": {"fn": write_file, "modes": [AgentMode.EXECUTE]}, "run_command": {"fn": run_command, "modes": [AgentMode.EXECUTE]}, "delete_file": {"fn": delete_file, "modes": [AgentMode.EXECUTE]},}
def get_available_tools(mode: AgentMode) -> list[dict]: """현재 모드에서 사용 가능한 도구만 LLM에 노출""" return [ {"name": name, "fn": tool["fn"]} for name, tool in TOOL_REGISTRY.items() if mode in tool["modes"] ]
def run_agent(goal: str): # Plan Mode: 읽기 전용 도구만 제공 plan_tools = get_available_tools(AgentMode.PLAN) plan = llm.complete(f"계획 수립: {goal}", tools=plan_tools)
# Execute Mode: 전체 도구 제공 exec_tools = get_available_tools(AgentMode.EXECUTE) result = llm.complete(f"실행: {plan}", tools=exec_tools)
return resultOpenDev의 6단계 실행 구조
섹션 제목: “OpenDev의 6단계 실행 구조”OpenDev 논문은 에이전트의 각 반복(iteration)이 다음 6단계로 구성됨을 제안합니다:
반복(iteration) N:
1. Pre-check & Compaction └── 컨텍스트 길이 확인, 오래된 히스토리 압축
2. Optional Thinking Phase └── 복잡한 태스크의 경우 extended thinking 활성화
3. Optional Self-Critique └── 이전 단계 출력 검토, Reflection 트리거 여부 결정
4. Action (LLM Call) └── 실제 LLM 호출, 도구 선택 및 파라미터 결정
5. Tool Execution with Approval └── 도구 실행, 필요시 인간 승인 요청
6. Post-processing & Termination Decision └── 결과 처리, 목표 달성 여부 판단단계별 상세
섹션 제목: “단계별 상세”1단계: Pre-check & Compaction
def pre_check(context: Context) -> Context: if context.token_count > COMPACTION_THRESHOLD: # 오래된 히스토리를 요약으로 교체 summary = llm.summarize(context.old_messages) return context.replace_old_with_summary(summary) return context5단계: Tool Execution with Approval
모든 도구 실행에 승인 레이어를 추가할 수 있습니다. 특히 파괴적 작업(파일 삭제, 배포 등)은 인간 승인이 권장됩니다.
APPROVAL_REQUIRED = {"delete_file", "deploy", "send_email"}
def execute_tool(tool_name: str, params: dict) -> str: if tool_name in APPROVAL_REQUIRED: approved = request_human_approval(tool_name, params) if not approved: return f"사용자가 {tool_name} 실행을 거부했습니다"
return TOOL_REGISTRY[tool_name]["fn"](**params)6단계: Termination Decision
def should_terminate(state: AgentState) -> bool: return ( state.goal_achieved or state.step_count >= MAX_STEPS or state.consecutive_failures >= MAX_FAILURES or state.explicitly_stopped )Plan Mode의 실제 적용
섹션 제목: “Plan Mode의 실제 적용”Claude Code, Cursor 등 실제 코딩 에이전트 도구들은 이미 이 패턴을 채택하고 있습니다.
계획 모드의 명칭과 활성화 방법은 제품마다 다릅니다. 현재 제품 문서에서 모드별 도구·파일·네트워크 권한을 확인하고, UI의 “계획” 표시만으로 읽기 전용이라고 판단하지 않습니다. 읽기 도구도 민감 파일 접근이나 외부 조회 비용을 발생시킬 수 있습니다.
Dual-Mode 실행은 계획과 실행을 명확히 분리하여 안전성과 예측 가능성을 높입니다. 스키마 필터링과 런타임 권한 검사를 함께 사용해야 합니다. OpenDev의 6단계 구조는 각 반복을 체계화하여 에이전트 루프의 신뢰성을 높입니다. 다음 챕터에서는 여러 에이전트를 조율하는 Multi-Agent 오케스트레이션을 다룹니다.