6. AI Agent가 서버를 고친다 — 자동 조치와 Runbook
LLM이 실제로 시스템 명령을 실행하는 구조. 3단계 접근법(Read-Only → Human-in-the-Loop → 자율), ReAct 패턴, 안전장치 설계와 Runbook 자동화를 다룹니다.
여기까지는 LLM이 "분석"만 했다. 로그를 읽고, 원인을 추론하고, 보고서를 쓰는 것까지. 하지만 실제 조치 — 디스크 정리, 서비스 재시작, 설정 변경 — 는 여전히 사람이 SSH로 접속해서 직접 해야 한다.
이 편에서는 LLM이 시스템 명령을 실행하는 AI Agent를 설계한다. Level 1(보조) → Level 2(반자율)로 넘어가는 전환점이다.
안전하지 않으면 자동화하지 않는 것이 핵심이다.
3단계 접근 — 제안에서 실행까지
한 번에 자율 실행으로 가면 사고가 난다. 단계를 밟아야 한다.
- 1단계 - Read-Only : LLM이 상황을 분석하고 명령어를 생성하지만, 실행은 전적으로 사람이 한다. LLM이 "
find /var/log -name '*.gz' -mtime +30 -delete를 실행하면 2.3GB를 확보할 수 있다"고 제안하면, 사람이 복사해서 직접 실행한다. 가장 안전하고, 바로 도입할 수 있다. - 2단계 - Human-in-the-Loop : LLM이 실행 계획을 세우고, 사람에게 승인을 요청한다. "30일 이상 된 로그 파일 847개(6.2GB)를 삭제합니다. 승인하시겠습니까?" 사람이 승인하면 자동 실행된다. 사람은 판단만 하면 된다.
- 3단계 - 자율 실행 : 위험도가 낮은 작업은 자동으로 실행한다. 로그 정리, 상태 확인 같은 건 승인 없이 바로. 서비스 재시작 같은 건 여전히 승인 필요. 데이터 삭제 같은 건 절대 자동화하지 않는다.
대부분의 팀에서 현실적인 목표는 2단계다. 1단계로 시작해서, 충분한 신뢰가 쌓이면 2단계로 넘어간다. 3단계는 1~2단계를 6개월 이상 운영한 후에 고려해도 늦지 않다.
ReAct 패턴 — 생각하고 행동하기
AI Agent의 기본 패턴은 ReAct(Reasoning + Acting)다. LLM이 생각(Thought) → 행동(Action) → 관찰(Observation)을 반복하면서 문제를 해결한다.
Thought: 웹 서버 응답이 느리다. 먼저 프로세스 상태를 확인하자.
Action: check_process("nginx")
Observation: nginx PID 3847, CPU 2%, MEM 150MB. 정상.
Thought: nginx는 정상이다. upstream API 서버를 확인하자.
Action: check_process("api-service")
Observation: api-service PID 5210, CPU 95%, MEM 3.8GB.
Thought: API 서버가 CPU 95%를 쓰고 있다. 로그를 확인하자.
Action: get_logs("api-service", lines=20)
Observation: [ERROR] OutOfMemoryError... BatchProcessor...
Thought: OOM이 원인이다. 서비스를 재시작해야 한다.
위험도: Medium이므로 승인이 필요하다.
Action: request_approval("api-service 재시작")LLM이 한 번에 답을 내는 게 아니라, 단계적으로 조사하면서 상황을 좁혀나간다. 사람이 장애를 조사하는 과정과 비슷하다.
중요한 건 Agent가 쓸 수 있는 도구를 화이트리스트로 제한하는 거다. disk_usage, check_process, get_logs 같은 허용된 도구만 실행할 수 있다. 허용 목록에 없는 명령은 실행 자체가 불가능하다.
안전장치 설계
Agent가 시스템 명령을 실행하는 순간, 안전장치가 핵심이 된다.
위험도 4단계.
| 레벨 | 예시 | 정책 |
|---|---|---|
| Low | 디스크 조회, 프로세스 확인, 로그 읽기 | 자동 실행 |
| Medium | 서비스 재시작, 로그 삭제, 캐시 클리어 | 사람 승인 후 실행 |
| High | 설정 변경, 스케일 조정, 방화벽 수정 | 반드시 승인 + 백업 |
| Critical | 데이터 삭제, DB 조작, 서버 종료 | 자동화 금지 |
- 차단 패턴 :
rm -rf /,mkfs,dd if=,DROP DATABASE같은 명령은 어떤 상황에서도 실행되지 않도록 하드코딩으로 차단한다. - 빈도 제한 : 같은 서비스를 시간당 3번 이상 재시작하면 뭔가 잘못된 거다. 빈도 제한을 걸어서 무한 루프를 방지한다.
- Dry-run 모드 : 실제 실행 전에 "이 명령을 실행할 것이다"만 출력하고 멈추는 모드. 처음 도입할 때 한 달 정도 Dry-run으로 돌리면서 Agent의 판단이 맞는지 확인하는 게 좋다. Dry-run의 출력은 이런 식이다.
[DRY-RUN] 장애 시나리오: 디스크 사용률 88%
Step 1: disk_usage("/") → 실행
결과: /dev/sda1 50G 42G 5.8G 88%
Step 2: find_large_files("/var/log") → 실행
결과: /var/log/nginx/access.log.gz 2.1G
/var/log/app/debug.log.gz 1.8G
...
Step 3: delete_old_logs("/var/log", days=30) → [DRY-RUN 중단]
⚠️ 위험도 Medium — 실제 환경에서는 승인 필요
삭제 대상: 847개 파일, 6.2GB
예상 결과: 디스크 사용률 88% → 72%
Step 4: (삭제 후) disk_usage("/") → [DRY-RUN 중단]
예상: 72%
[요약] Agent는 올바른 판단을 했는가? → 사람이 검토이 로그를 한 달치 모으면, "Agent가 몇 번 맞았고 몇 번 틀렸는가"를 정량적으로 알 수 있다. 이 데이터가 Phase 2(실제 실행)로 넘어갈 수 있는지 판단하는 근거가 된다.
실행 환경 보안
LLM이 서버에 명령을 실행하는 구조에서, 보안팀이 가장 먼저 물어보는 것들이 있다.
- "Agent가 어떤 권한으로 실행되나?"
=> Agent 전용 서비스 계정을 만든다. 이 계정에는 필요한 명령만 sudo로 허용한다. root 권한을 주면 안 된다. - "실행 환경이 격리되어 있나?"
=> Agent는 전용 컨테이너나 VM에서 실행하고, 프로덕션 서버에는 SSH 키 기반으로 접근한다. Agent 컨테이너가 뚫려도 프로덕션 서버 전체가 뚫리지 않도록 격리한다. - "누가 뭘 했는지 추적할 수 있나?"
-> 감사 로그를 남긴다. 누가(어떤 Agent), 언제, 어떤 명령을, 왜(분석 근거) 실행했는지 기록한다. 이 로그가 없으면 문제가 생겼을 때 원인을 추적할 수 없다.
Runbook 자동화
여기서 Runbook 이야기로 넘어간다.
SRE 팀에는 Runbook이 있다. "502 에러 나면 이렇게 해라", "디스크 차면 이렇게 정리해라"가 Confluence에 써있다. 문제는 이게 자연어 텍스트라는 거다. 자동화하려면 별도 스크립트를 짜야 하고, Runbook이 바뀔 때마다 스크립트도 바꿔야 한다.
LLM은 자연어를 이해한다. 한국어 Runbook을 읽고, 실행 가능한 구조로 변환할 수 있다.
한국어 Runbook이 이렇게 생겼다고 하자.
## 웹 서버 502 에러 대응
1. nginx 프로세스 확인: ps aux | grep nginx
- 죽었으면 systemctl restart nginx
2. upstream 헬스체크: curl http://localhost:8080/health
- 200 아니면 API 서버 문제
3. API 로그 확인: tail -50 /var/log/api/error.log
- OOM이면 systemctl restart api-service
4. 안 되면 시니어에게 에스컬레이션LLM에게 "이걸 YAML Action Chain으로 변환해줘"라고 요청하면, 각 스텝을 구조화된 형태(조건 → 명령 → 예상 결과 → 실패 시 분기)로 바꿔준다. 변환된 YAML을 실행 엔진이 읽고 단계별로 실행한다.
변환 결과는 이런 모양이다.
runbook:
name: "웹 서버 502 에러 대응"
steps:
- id: step1
name: "nginx 프로세스 확인"
action: check_process
params: { name: "nginx" }
on_fail:
action: restart_service
params: { name: "nginx" }
risk: medium
next: step2
- id: step2
name: "upstream 헬스체크"
action: http_check
params: { url: "http://localhost:8080/health", expect: 200 }
on_fail: { next: step3 }
on_success: { action: done, summary: "nginx·upstream 모두 정상" }
- id: step3
name: "API 로그 확인"
action: get_logs
params: { service: "api-service", lines: 50 }
analyze:
prompt: "OOM, OutOfMemory, killed 패턴이 있는가?"
on_match:
action: restart_service
params: { name: "api-service" }
risk: medium
on_no_match:
action: escalate
params: { to: "oncall-senior" }한국어 자연어가 구조화된 YAML로 변환됐다. 각 스텝에 조건 분기, 위험도 레벨, 에스컬레이션이 포함되어 있다. 실행 엔진은 이 YAML을 읽으면서 step1부터 순서대로 실행하고, 조건에 따라 분기한다.
이 구조의 장점은 Runbook이 바뀌어도 LLM이 새 텍스트를 읽으면 된다는 거다. 스크립트를 다시 짤 필요가 없다.
알림이 오면 RAG로 관련 Runbook을 검색하고, LLM이 가장 적합한 Runbook을 선택하고, 실행 엔진이 단계별로 실행한다. 이 전체 흐름이 자동화된다.
Google의 완화 플레이북 패턴
Google SRE가 2026년에 공개한 Gemini CLI 사례에서, 이 구조를 실제로 쓰고 있다.
장애 발생 시 Gemini CLI가 "동적으로 생성하는 완화 플레이북"을 실행한다. 이 플레이북에는 세 가지가 반드시 포함된다. 실행할 명령. 변경이 문제를 해결하고 있는지 검증하는 방법. 문제가 해결되지 않으면 롤백하는 지침.
핵심은 "실행 → 검증 → 롤백"이 하나의 세트라는 점이다. 명령만 실행하고 끝이 아니라, 실행 후 검증하고, 검증 실패 시 원상복구하는 것까지 포함된다. 이게 Human-in-the-Loop의 프로덕션 수준 구현이다.
경로 A에서 이걸 구현하려면, Claude의 Tool Use(Function Calling)를 활용한다. 도구 정의를 넘기면 Claude가 적절한 도구를 선택해서 호출한다. 구현이 상대적으로 간단하다.
경로 B에서는 로컬 모델의 Function Calling 지원 수준에 따라 구현 복잡도가 달라진다. Qwen3와 Llama 3.1은 Function Calling을 지원하지만, Claude만큼 안정적이지는 않다. 출력 형식을 강하게 규정하는 프롬프트가 필요하다.
다음 편에서는 이 Agent를 여러 개로 나눠서 협업시키는 구조를 다룬다. 감시 Agent, 분석 Agent, 실행 Agent, 보고 Agent가 각자의 역할을 하고, 오케스트레이터가 전체를 조율한다. 장애 해결 후 포스트모템 자동 작성과 지식 축적까지.
이 글이 어떠셨나요?
관련 포스트
5. 왜 죽었는가 — RCA 자동화와 환각 방지
LLM 기반 근본 원인 분석(RCA)의 핵심 - 프롬프트 5단계 진화와 환각 방지 전략. Meta의 접근법과 실전 RCA 파이프라인을 설계합니다.
2026. 05. 24. PM 10:00DevOps4. LLM이 장애를 감지한다 — 알림 피로 끝내기
임계값 알림의 한계를 넘어서는 LLM 기반 이상 탐지. 프롬프트 설계, 알림 상관관계 분석, 실시간 감시 구조와 기존 모니터링과의 통합 방법을 다룹니다.
2026. 05. 17. PM 10:00DevOps3. LLM에게 먹일 데이터 준비 — 전처리와 RAG
운영 데이터 품질이 분석 결과를 결정한다. 로그 전처리 5단계, 컨텍스트 전략, RAG 시스템 구축 방법과 알림이 LLM에 도달하는 전체 파이프라인을 설계합니다.
2026. 05. 10. PM 10:00뉴스레터 구독
새 글이 올라오면 이메일로 알려드려요.