프로덕션 에이전트가 갑자기 이상하게 동작할 때, 대부분의 팀은 두 가지 선택지 앞에 선다. 코드를 고쳐 다시 배포하거나, 아니면 그냥 전체를 꺼버리거나. 둘 다 느리고, 둘 다 위험하다. 이 글은 세 번째 길 — 런타임 토글로 재배포 없이 에이전트 기능을 실시간 전환하는 방법 — 을 Mac Mini 클러스터 직접 운영 경험 기반으로 정리한다.
1. 왜 지금 이걸 봐야 하나
Claude Code 에이전트는 LLM 응답 시간, 툴 실행 결과, 외부 API 상태에 따라 예측 못한 행동을 한다. 프로덕션에서 이상 징후가 포착됐을 때, 재배포 사이클은 보통 4~10분이 걸린다. 그 사이에 에이전트는 계속 돌아간다.
티켓팅 사이트 서버 관리자가 트래픽 폭주 순간 '특정 좌석 잠금' 토글을 누르는 장면을 생각해보자. 코드 수정이 아니다. 설정값 하나가 시스템 행동을 바꾼다. Claude Code 에이전트도 정확히 이 구조로 운영할 수 있다.
Mac4 클러스터에서 Draw Things 동시 호출이 몰릴 때 특정 기능만 순간 off 해야 했던 상황이 실제로 여러 번 있었다. 재배포 없이, 프로세스 재시작 없이 말이다. 그때마다 런타임 토글이 조용히 역할을 해줬다.
2. 핵심 아이디어
결론부터: 툴을 '선택하지 않게' 만드는 게 아니라, 애초에 '존재하지 않게' 만들어야 한다.
LLM에게 "이 툴은 지금 쓰지 마"라고 프롬프트로 지시하는 방식은 불안정하다. LLM이 판단을 잘못 내릴 수 있고, 프롬프트가 길어질수록 지시가 묻힌다. 반면 툴 자체를 에이전트 등록 목록에서 빼버리면 LLM 입장에서 그 기능은 처음부터 없는 것이다.
아래 표는 두 접근 방식의 차이를 보여준다.
| 항목 | 프롬프트 지시 방식 | 런타임 토글 방식 |
|---|---|---|
| 동작 보장 | 불안정 (LLM 판단 의존) | 완전 보장 (등록 자체 미포함) |
| 전환 속도 | 재배포 필요 | 파일 수정 즉시 반영 |
| 추가 지연 | 프롬프트 길이 증가 | 0ms |
| 이력 추적 | 어려움 | 로그로 자동화 가능 |
이 구조의 핵심은 외부 JSON 파일 하나다. 에이전트 초기화 시 이 파일을 읽어 툴 배열을 동적으로 조립한다. 파일을 수정하면 다음 에이전트 호출부터 즉시 반영된다.
3. 바로 따라하는 방법
토글 파일 작성
프로젝트 루트에 features.json을 만든다. 키는 기능 이름, 값은 true/false다.
{
"web_search": true,
"code_execution": false,
"file_write": true,
"long_context_mode": false,
"last_modified": "2026-05-21T09:00:00Z"
}
이 파일이 에이전트 행동의 유일한 제어판이 된다.
에이전트 초기화 코드에 토글 주입
import json
from pathlib import Path
def load_active_tools(feature_path='features.json'):
flags = json.loads(Path(feature_path).read_text())
all_tools = {
'web_search': web_search_tool,
'code_execution': code_exec_tool,
'file_write': file_write_tool,
'long_context_mode': long_ctx_tool,
}
# 켜진 기능만 반환 — 꺼진 기능은 리스트에 포함되지 않음
return [tool for key, tool in all_tools.items() if flags.get(key, False)]
active_tools = load_active_tools()
agent = ClaudeAgent(tools=active_tools)
load_active_tools()는 에이전트 초기화마다 호출된다. features.json이 바뀌면 다음 호출부터 새 목록이 적용된다.
전환 후 검증
# 현재 등록된 툴 목록 출력
active = load_active_tools()
print("현재 활성 툴:", [t.name for t in active])
기대 출력 예시 (code_execution: false 상태):
현재 활성 툴: ['web_search', 'file_write']
code_exec_tool이 목록에 없으면 정상이다.
4. 운영할 때 조심할 점
변경 이력 추적 — 반드시 붙여야 한다
토글을 아무렇게나 바꾸면 나중에 "언제 껐지?"를 아무도 모른다. 변경할 때마다 타임스탬프를 함께 기록하는 래퍼 스크립트를 쓴다.
# features.json 수정 후 타임스탬프 갱신
jq --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
'.last_modified = $ts' features.json > features.tmp \
&& mv features.tmp features.json
# 현재 활성 기능 확인
cat features.json | jq '{last_modified, active: [to_entries[] | select(.value==true) | .key]}'
기대 출력:
{
"last_modified": "2026-05-21T09:32:11Z",
"active": ["web_search", "file_write"]
}
n8n 자동화와 연결
Mac Mini n8n 2.8.4 워크플로우에서 이 스크립트를 훅으로 연결하면, Slack 알림까지 자동으로 붙는다. 토글 하나 바꿀 때마다 누가 언제 어떤 기능을 껐는지 팀 전체가 실시간으로 확인할 수 있다.
주의사항 정리
- 파일 권한:
features.json이 여러 프로세스에서 동시에 쓰이면 경쟁 상태가 생긴다.mv로 원자적 교체를 쓰는 게 안전하다 (위 스크립트에서 이미 적용). - 기본값 처리:
flags.get(key, False)로 키가 없는 경우 항상 꺼진 상태로 처리한다. 새 기능 추가 시 JSON에 명시적으로 넣기 전까지는 비활성이다. - Docker 환경: 컨테이너 내부에서 파일을 수정해도 반영되지만, 볼륨 마운트로 외부에서 제어하는 구조가 더 깔끔하다.
docker run -v ./features.json:/app/features.json ...형태로 마운트하면 호스트에서 직접 편집할 수 있다. - 롤백 시나리오: 토글 전환 후 에이전트 동작이 더 이상해지면,
features.json을 이전 버전으로 교체하면 된다. git으로 관리하면git checkout features.json한 줄로 되돌아간다.
마무리
툴 등록 자체를 동적으로 제어하면 LLM이 쓸 수 없는 기능은 처음부터 존재하지 않아, 오동작 가능성을 원천에서 막는다. Mac Mini 클러스터 4대를 직접 운영하면서 체감한 가장 조용한 안전망이다.
다음 글에서는 이 토글 구조에 원격 API 제어를 붙여, 배포 없이 웹 대시보드에서 에이전트 기능을 켜고 끄는 방법을 다룬다.
🐦 X에서 더 빠르게: @baegseungh7061
📚 이 시리즈 더 보기: Code 실전
💌 새 글 알림: X 팔로우 또는 블로그 RSS 구독
'Code 실전' 카테고리의 다른 글
| Claude Code Sub-agent 병렬 실행으로 빌드 시간 61% 줄이는 법 (0) | 2026.05.25 |
|---|---|
| 에이전트 인스턴스가 늘어날수록 상태가 갈라지는 문제, Redis 브로드캐스트로 구조적으로 막는 법 (0) | 2026.05.22 |
| Claude Code Hooks로 배포 안전망 만들기: staging·prod 환경 분기 자동 차단 (1) | 2026.05.19 |
| MCP 요청 위변조를 HMAC 서명으로 원천 차단하는 법 (0) | 2026.05.15 |
| Claude Code 훅을 이벤트 버스로 바꾸면 응답이 26배 빨라진다 (0) | 2026.05.13 |