LLM이 뱉은 코드가 서버를 터뜨리지 않게 격리하는 방법
19 mai 2026
0
컴퓨터/소프트웨어Related Video
8:08Vercel이 프로그래밍 언어를 만들었습니다
Better Stack
Comments (0)
Log in to leave a comment
No posts yet
8:08Better Stack
Log in to leave a comment
No posts yet
LLM이 짠 코드를 프로덕션 환경에서 그대로 돌리는 일은 시한폭탄을 안고 사는 것과 같습니다. 무한 루프를 돌며 CPU를 100% 점유하거나, 데이터베이스의 마스터 테이블을 통째로 날려버릴 수도 있으니까요. 프롬프트를 아무리 다듬어도 이 불확실성은 사라지지 않습니다. 결국 해결책은 코드 생성 인프라 자체를 메인 서버와 완전히 격리하고, 에러를 스스로 교정하게 만드는 시스템을 구축하는 것뿐입니다.
메인 API 서버와 에이전트의 코드 컴파일 환경은 물리적으로 분리해야 안전합니다. 에이전트가 로컬 파일 시스템이나 사내 데이터베이스 네트워크망에 직접 접근하는 경로를 원천 차단하는 게 핵심입니다. AWS Firecracker 기반의 가상화 microVM 런타임인 Vercel Sandbox를 활용하면 활성 연산 시점에만 초 단위로 인스턴스를 구동할 수 있어 보안과 비용을 동시에 잡을 수 있습니다.
기존 Node.js Express 아키텍처를 그대로 유지하면서 플러그인 형태로 컴파일러 구동 환경을 내장하는 구조입니다. 메인 애플리케이션 서비스와 에이전트 컴파일러용 컨테이너를 가상화 네트워크 브리지로 격리하기 위해 docker-compose.yml을 다음과 같이 설정합니다. security_opt와 read_only 옵션을 통해 호스트 권한 무단 취득을 막습니다.
version: '3.8'
services:
legacy-api-server:
build: .
ports:
- "3000:3000"
networks:
- agent-bridge
xero-compiler:
image: xero-runtime:latest
security_opt:
- "no-new-privileges:true"
read_only: true
networks:
- agent-bridge
networks:
agent-bridge:
driver: bridge
메인 서버가 에이전트 코드 컴파일 요구 사항을 비동기식으로 처리하는 내부 통신 로직은 @vercel/sandbox SDK를 활용해 구현합니다. 원시 코드를 가상 microVM 내에서 실행하는 단계는 다음과 같습니다.
import { Sandbox } from '@vercel/sandbox';
async function executeAgentCode(agentCode: string) {
// 1. 런타임 바인딩 및 10초 제한 설정
const sandboxInstance = await Sandbox.create({
runtime: 'node24',
resources: { vcpus: 1 },
timeout: 10000
});
try {
// 2. 가상 환경에 에이전트 코드 임베딩
await sandboxInstance.writeFiles({
'runtime_agent.js': agentCode
});
// 3. 가상 셸 격리 상태에서 런타임 구동 및 출력 획득
const result = await sandboxInstance.runCommand({
cmd: 'node',
args: ['runtime_agent.js'],
sudo: false
});
return result;
} finally {
// 4. 리소스 누수 방지를 위한 즉시 종료
await sandboxInstance.stop({ blocking: true });
}
}
이 방식으로 프로세스 간 통신(IPC) 채널을 프로덕션에 적용하면 LLM 호출 오류로 메인 서버가 다운되는 현상이 사라집니다. 매주 에이전트 유지보수에 쏟아붓던 개발자의 시간 중 최소 5시간 이상을 확보할 수 있습니다.
동적으로 실행되는 에이전트가 외부 망에 무분별하게 HTTP 요청을 보내거나 파일 시스템을 변경하는 행위는 정적 파싱 메커니즘과 프리커밋 검증 훅으로 통제해야 합니다. StaticIOAnalyzer 규칙 엔진 클래스를 만들어 require('child_process'), fs.writeFileSync, eval() 같은 위험한 시스템 라이브러리 패턴을 정규식으로 잡아내고, 외부 데이터 접근 시 일반 axios 대신 명시적으로 import { secureFetch } from 'xero:io' 규격만 사용하도록 강제하는 구문 레벨 검증 로직을 static-analyzer 서비스에 내장합니다.
에이전트가 프로덕션 회계 정보나 고객 데이터베이스에 전체 관리자 토큰으로 접근하지 못하도록 컴파일 타임에 권한 매핑 테이블을 구축하는 과정은 다음과 같습니다.
accounting.contacts, 임시 송장 초안 생성은 accounting.transactions 스코프로 제한하는 OAuth API 매핑 정책을 정의합니다.Status = 'DRAFT' 형태의 세션만 허용하도록 규칙을 바인딩합니다.fetchScopedTemporaryToken()으로 취득합니다.Sandbox.create() 호출 시 env 설정 객체 내부에 XERO_SECURE_TOKEN 변수로 해당 제한 권한 토큰을 동적으로 주입하여 에이전트의 절대 권한 취득을 막습니다.만약 정적 분석을 우회하여 동적 실행 단계에서 무한 루프를 시도하면 Vercel Sandbox의 시스템 인터럽트 모니터가 이를 감지합니다. sandboxInstance.activeCpuUsageMs가 8000ms를 초과하여 비정상 폭주할 때 sandboxInstance.updateNetworkPolicy({ mode: "deny-all" })을 실행해 패킷을 차단하고 즉시 microVM을 중지시키는 동적 예외 처리 로직을 구현하면 데이터베이스 쓰기 오염 사고를 방지할 수 있습니다.
원시 구문 에러 로그를 통째로 프롬프트에 다시 밀어 넣는 방식은 토큰 낭비가 심하고 모델이 길을 잃기 쉽습니다. 컴파일러 출력의 추상 구문 트리(AST)와 구문 에러 메시지를 JSON 데이터로 구조화하여 LLM의 툴 콜링 영역으로 전달하는 자가 치유(Self-Healing) 루틴이 필요합니다.
정규식 패턴을 활용해 SyntaxError, ReferenceError 등의 발생 위치를 추적하고, 에러가 발생한 소스 파일 명칭, 정확한 라인 번호, 컬럼 위치 및 문제가 된 노드 명칭을 JSON 객체인 StructuredASTError 규격으로 정제하는 ErrorTransformer 모듈을 구성합니다.
배포 및 디버깅 가시성을 확보하기 위해 GitHub Actions와 연동되는 실시간 에러 모니터링 대시보드 워크플로우를 형성하는 방법은 다음과 같습니다.
repository_dispatch 이벤트를 발생시키고 에러 데이터(error_details)와 원본 코드(broken_code)를 클라이언트 페이로드에 담아 GitHub API로 전송합니다..github/workflows/agent-monitoring.yml 설정 파일을 생성하고 on: repository_dispatch 환경에서 구동되도록 명세한 뒤 actions/checkout@v4 및 actions/setup-node@v4를 통해 우분투 러너에 Node.js 24 환경을 수립합니다.- name: Run Auto Fix Generator
run: |
node ./scripts/auto-fix-generator.js \
--error-json '${{ toJson(github.event.client_payload.error_details) }}' \
--original-code '${{ github.event.client_payload.broken_code }}'
만약 에이전트에게 오류 피드백 데이터를 주입해 수정을 시도했음에도 불구하고 연속적으로 3회 이상 컴파일이 실패하면 AutonomousRecoveryPipeline 클래스 내부의 서킷 브레이커가 작동합니다. failedAttempts >= 3 임계치에 도달하는 즉시 개발자 슬랙 알림 채널로 에러 상세 내역 패킷을 전송하고, sandboxInstance에 대해 Vercel Sandbox의 Native Snapshot API를 호출하여 직전의 안전 스냅샷 버전으로 런타임 환경을 즉시 복원(Revert)시킵니다. 이 피드백 루프 시스템을 배포 인프라와 결합하면 수동 디버깅 비용을 40% 이상 줄일 수 있습니다.
원시 텍스트 로그 피드백 형태를 그대로 주입했을 때와 본 아키텍처의 정형 AST 데이터를 연동했을 때의 토큰 소비 추이는 명확한 차이를 보입니다.
| 비교 평가 영역 (Metrics) | 일반 프롬프트 직접 정정 아키텍처 | Xero AST 구조화 JSON 툴체인 | 비용 절감 효율 및 근거 |
|---|---|---|---|
| 평균 인풋 토큰 수량 | 약 6,500 ~ 8,000 Tokens | 약 1,200 ~ 1,800 Tokens | 75% 이상 절감: 불필요한 전체 코드 재입력 없이 실패한 해당 노드의 정보만 함축해서 피딩 |
| 평균 아웃풋 토큰 수량 | 약 3,000 ~ 4,000 Tokens | 약 400 ~ 600 Tokens | 85% 이상 절감: 에이전트 코드 전체 재작성 대신 부분 델타 패치 코드만 생성 유도 |
| 디버깅 피드백 루프 성공율 | 1회 교정 성공율: 42.1% | 1회 교정 성공율: 89.4% | 정밀 위치와 에러 타입에 대한 문법 힌트로 인해 수렴 연산 속도가 비약적으로 향상 |
Vercel Sandbox 인프라 비용 요금 체계는 실제 에이전트 연산 코드가 수행되는 초 단위 연산 시간인 Active CPU Time만을 측정하여 과금하며, 기본 과금 체계식은 다음과 같이 유도됩니다.
일 1만 회 작동 기준으로 자원 사양을 설정할 때, 1 vCPU와 2 GB RAM을 할당하는 'Light CPU-Profile'은 예상 월간 총 비용이 약 $42.10 내외로 청구되며 최대 1,100개의 세션을 동시에 실행할 수 있어 실시간 소형 회계 데이터 파싱이나 단순 CRUD 에이전트 시스템에 적합합니다. 반면 4 vCPUs와 8 GB RAM을 할당하는 'Heavy Compute-Profile'은 월간 약 $168.40의 비용으로 최대 2,000개 동시 세션 트래픽 임계 한계점을 처리할 수 있어 대용량 파일 가공 시스템에 맞춘 구성입니다.
실제 API 호출 비용이 청구되기 전에 에이전트의 오작동 제어 성능을 검증할 수 있도록 로컬 가상 컴파일러 모의 테스트베드 환경을 세팅하는 절차는 다음과 같습니다.
npm install -g sandbox를 실행해 글로벌 샌드박스 CLI를 배포하고 vercel link로 백엔드를 임시 연결한 뒤 vercel env pull을 수행하여 로컬 디렉토리에 12시간 임시 만료 자격 인증을 담은 .env.local 덤프를 생성합니다.npm install -g @stoplight/prism-cli 명령어만으로 Prism 라이브러리를 가동하고 prism mock ./openapi-specs/xero-api.yaml --port 4010을 실행하여 로컬에 가상 데이터베이스 엔드포인트를 수립합니다.npm install) 과정을 생략할 수 있도록 최초 가상 머신에 환경이 조성되는 순간 sandbox.snapshot()을 실행해 환경을 완전히 동결합니다.이후 생성되는 가상 샌드박스는 이 스냅샷 ID를 로드하여 스타트업 오버헤드를 150ms 미만으로 제어하게 되며, 불필요한 리소스 과금을 전면 차단하는 세이프가드 효과를 제공합니다. Xero 구조화 툴체인과 격리된 가상화 샌드박스의 결합은 복잡한 프롬프트 조율 없이도 AI 에이전트의 기동 안정을 보장하는 명확한 기술적 해법입니다.