LLM에게 bash 터미널 권한을 부여하는 것이 두려운 이유
요약
자율형 AI 에이전트에게 bash 터미널 권한을 부여할 때 발생하는 위험성과 이를 해결하기 위한 '즉각적인 체크포인팅' 개념을 제안합니다. 단순한 샌드박스를 넘어, 에이전트의 실수 시 파일 시스템을 즉시 롤백할 수 있는 Git 트리 방식의 워크플로우가 필요함을 강조합니다.
핵심 포인트
- 에이전트의 환각으로 인한 파일 시스템 파괴 위험성
- 샌드박스는 폭발 반경은 줄이지만 내부 상태 복구는 불가능함
- 도구 호출 전 자동 체크포인트를 생성하는 안전 장치 필요
- Git 트리 구조와 유사한 상태 복구(Rollback) 메커니즘 제안
최근에 저는 로컬 디렉토리에서 자율형 AI 에이전트 (autonomous AI agent)를 테스트하고 있었습니다. 저는 에이전트에게 다단계 코딩 작업과 스스로 테스트를 실행할 수 있는 터미널 도구 (terminal tool)를 부여했습니다.
처음 세 단계까지는 모든 것이 괜찮아 보였습니다. 저는 속으로 _'생각보다 훨씬 쉽네'_라고 생각했습니다. 하지만 제 생각이 틀렸습니다. 에이전트가 오류를 만났고, 이상한 해결책을 환각 (hallucinate) 했으며, 이를 수정하려 시도하다가 제 워크스페이스 파일 시스템 (workspace filesystem)을 날려버리는 명령어를 실행했습니다. 아무런 경고 없이 모든 것이 손상되었습니다.
만약 여러분이 지금 LLM을 활용해 무언가를 구축하고 있다면, 에이전트에게 가공되지 않은 셸 접근 권한 (raw shell access)을 주는 것이 마치 첫 출근한 여름 인턴에게 운영 환경 (prod) 자격 증명을 주는 것처럼 느껴진다는 것을 이미 알고 계실 것입니다. 하지만 진짜 문제는 단순히 에이전트가 무언가를 망가뜨린다는 점이 아닙니다. 문제는 그들이 망가뜨렸을 때, 우리가 '실행 취소 (undo)'를 할 수 있는 표준화된 방법이 없다는 것입니다.
누락된 기본 요소 (The Missing Primitive)
현재 이 문제에 대한 표준적인 답변은 다음과 같을 것입니다: "그냥 샌드박스 (sandbox)를 사용하면 되잖아요?"
하지만 임시 Docker 컨테이너나 microVM을 실행하는 것은 문제의 절반, 즉 폭발 반경 (blast radius) 문제만 해결할 뿐입니다. 이는 에이전트가 여러분의 기계를 파괴하는 것은 막아주지만, 작업 자체의 내부 상태 (internal state)를 보호하는 데에는 아무런 도움이 되지 않습니다.
예를 들어 10단계의 에이전트 워크플로 (workflow)를 가정해 봅시다. 에이전트가 1단계부터 5단계까지 완벽하게 수행했지만, 6단계에서 워크스페이스를 완전히 망가뜨렸다면 전체 실행은 망가진 것입니다. 샌드박스 프로세스 내에 즉각적인 상태 복구 (state recovery) 기능이 내장되어 있지 않기 때문에, 여러분이 할 수 있는 유일한 실제 선택지는 전체 루프를 처음부터 다시 시작하는 것뿐입니다.
표준 소프트웨어 개발에서는 상태를 저장하기 위해 git checkout이나 VM 스냅샷 (snapshots)을 사용합니다. 하지만 터미널 명령어를 실행하는 자율 에이전트의 경우, 우리는 기본적인 안전 기본 요소 (safety primitive)인 '즉각적인 체크포인팅 (instant checkpointing)'이 완전히 결여되어 있습니다.
깨달음의 순간 (The Lightbulb Moment)
저는 우리가 더 무거운 샌드박스가 필요한 것이 아니라, 단지 시간을 되돌릴 수 있는 방법이 필요하다는 것을 깨달았습니다.
현재 에이전트가 실행되는 방식을 살펴보면, 매우 취약한 선형 구조입니다:
[Step 1: OK] -> [Step 2: OK] -> [Step 3: rm -rf /] -> 💥 TOTAL CRASH (Start Over)
대신, 저는 워크플로우(workflow)가 Git 트리와 더 유사해야 한다고 생각합니다. 에이전트가 어떠한 도구 호출(tool call)이나 bash 명령을 실행하기 전에, 시스템은 자동으로 조용한 체크포인트(checkpoint)를 생성해야 합니다. 명령이 성공하면 체크포인트가 병합(merge)됩니다. 만약 에이전트가 환각(hallucination)을 일으켜 실수를 한다면, 명령이 실행되기 직전의 정확한 시점으로 전체 파일 시스템(filesystem)을 즉시 롤백(roll back)할 수 있습니다.
[Step 1: OK]
↓
[Step 2: OK] -> (체크포인트 생성됨)
...
하지만 이를 실용적으로 만들기 위해서는 속도가 느려서는 안 됩니다. 모든 도구 호출 사이에 VM 스냅샷(snapshot)을 찍기 위해 5초씩 기다리고 싶은 사람은 아무도 없기 때문입니다. 이는 가볍고 거의 즉각적인 파일 시스템 트릭(filesystem trick)이어야 했습니다.
작동 원리
체크포인팅을 거의 즉각적으로 만들기 위해, 저는 무거운 VM 스냅샷을 피하고 OverlayFS를 사용하여 리눅스 커널(Linux kernel) 레벨로 바로 들어갔습니다.
OverlayFS를 사용하면 읽기 전용 베이스 레이어(read-only base layer)와 빈 쓰기 가능 레이어(writable layer)라는 두 개의 디렉터리를 하나의 병합된 뷰(merged view)로 결합할 수 있습니다. AI 에이전트가 명령을 실행할 때, 에이전트는 실제 프로젝트 파일을 편집하고 있다고 생각하지만, 운영체제(OS)는 실제로 해당 변경 사항을 격리된 스크래치 공간(scratch space)에 기록합니다.
.rewind/
├── base/ <-- 사용자의 원본, 수정되지 않은 작업 공간 파일 (읽기 전용)
├── scratch/ <-- 에이전트의 변경 사항이 실제로 저장되는 곳 (쓰기 전용)
...
이러한 쓰기 시 복사(copy-on-write) 메커니즘 덕분에, 체크포인트를 생성하는 작업은 20ms 미만으로 수행됩니다.
에이전트가 명령을 성공적으로 실행하면, scratch 레이어를 메인 작업 공간으로 동기화(sync)하여 변경 사항을 커밋(commit)하기만 하면 됩니다. 하지만 에이전트가 파괴적인 행동을 한다면, 단순히 해당 디렉터리를 언마운트(unmount)하고 빈 디렉터리를 새로 띄우면 됩니다.
간결함을 위해 이 사이클을 처리하는 로직을 TypeScript로 작성하면 다음과 같습니다.
// 런타임 루프의 추상화
async function runAgentStep(agent, command) {
// 파일 시스템 체크포인트
...
rewind-sdk로 패키징하기
새로운 에이전트 스크립트를 테스트하고 싶을 때마다 매번 커스텀 쉘 스크립트(shell scripts)와 OverlayFS 마운트 명령어를 수동으로 조합하는 것에 지쳤습니다. 그래서 이 모든 기저의 Linux 파일 시스템 로직을 rewind-sdk라는 가볍고 오픈 소스인 인프라 계층(infra layer)으로 패키징했습니다.
여기서 목표는 체크포인트(checkpoint)와 롤백(rollback)을 프레임워크에 완전히 무관하게(framework-agnostic) 만드는 것이었습니다. 현재는 LangGraph, 로우 스크립트(raw scripts), 그리고 표준 도구 호출(standard tool calls)만을 지원하지만, 이상적으로는 구축된 시스템이 다른 에이전트 프레임워크로 확장될 수 있도록 설계되었습니다. 하지만 핵심 기능(killer feature)은 원자적 상태 관리(atomic state management)입니다. 체크포인트를 설정하거나 롤백할 때, SDK는 파일 시스템 상태와 대화 기록(conversation history)을 단 한 번의 호출로 함께 동기화합니다.
보호된 런타임 세션(runtime session)을 초기화하고 Python에서 사용하는 방법은 다음과 같이 간단합니다:
from rewind_sdk import session, Verifier
# 보호된 워크스페이스 환경 초기화
...
이것은 빙산의 일각일 뿐입니다. @session.tool 데코레이터(decorator)를 사용하면 도구 함수(tool functions)를 롤백 가능한 액션(actions)으로 전환할 수 있습니다. 또한 추가적인 검증(verification) 기능을 통해 외부의 전용 테스트 스위트(testing suite)를 rewind-sdk에 연결하여 실패 관리(failure management)에 대해 더 많은 제어권을 가질 수 있습니다.
이 방식을 통해 워크스페이스 상태에 대해 완전하고 결정론적인(deterministic) 제어권을 얻을 수 있습니다. 만약 에이전트가 파괴적인 명령어를 환각(hallucinate)한다면, 컨테이너는 손상된 레이어(layer)를 폐기하고, LLM 제공업체가 스키마(schema)를 거부하지 않도록 히스토리에서 매달려 있는(dangling) 메시지들을 삭제한 뒤, 에이전트가 깨끗한 상태에서 다시 시도할 수 있도록 합니다.
앞으로의 방향은?
실제로 '무언가를 수행하는' 자율 에이전트(autonomous agents)를 구축하는 것은 매우 흥미로운 일입니다. 하지만 단순한 채팅 인터페이스를 넘어 나아가려면 더 나은 런타임 가드레일(runtime guardrails)이 필요합니다.
저는 현재 이것을 초기 프로토타입(prototype)으로 취급하고 있으며, 모든 과정을 공개적으로(in public) 구축하고 있습니다. 전체 소스 코드를 확인하고 싶거나, 데모 스크립트를 실행해 보거나, 심지어 여러분의 에이전트 워크플로(workflows)에 통합해 보고 싶다면, 모든 것이 완전히 오픈 소스로 공개되어 있습니다:
Github Repo Link
PyPI
시작하려면:
pip install rewind-sdk
(참고: 컨테이너 기반 격리 (containerized isolation)를 위해 로컬에서 Docker가 실행 중이어야 합니다)
여러분은 현재 자신의 워크플로 (workflows)에서 에이전트 안전성 (agent safety)과 런타임 오류 (runtime errors)를 어떻게 처리하고 계신가요? 댓글로 알려주세요. 다른 분들은 이 문제를 어떻게 해결하고 있는지 정말 궁금합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기