에이전트 제어부는 샌드박스 밖에 두어야 한다
AI 에이전트를 구동하는 핵심 루프인 '하니스(harness)'를 샌드박스 내부가 아닌 외부(백엔드)에 배치해야 보안성과 안정성을 확보할 수 있다는 주장입니다. 특히 다수의 사용자가 동시에 에이전트를 사용하는 환경에서는 자격 증명(Credential) 유출 방지, 리소스 효율화, 장애 복구 등의 이점이 있어 외부 배치가 필수적입니다. 이 글은 실제 프로덕션 환경에서 하니스를 외부에 두기 위해 해결해야 했던 기술적 과제와 그 이유를 설명합니다.
에이전트 하니스(harness)는 LLM을 구동하는 루프(loop)입니다. 이 루프는 프롬프트를 보내고 응답을 받은 뒤, 모델이 요청한 도구 호출(툴 콜)을 실행하고 그 결과를 다시 피드백하며, 모델이 작업이 완료되었다고 할 때까지 이 과정을 반복합니다. 모든 프로덕션 에이전트에는 이러한 하니스가 존재합니다. 중요한 것은 이 하니스가 '어디서' 실행되느냐입니다. 정답은 두 가지로 나뉩니다. 두 방식은 보안 속성, 장애 발생 모드(Failure mode), 그리고 에이전트가 수행할 수 있는 작업의 범위에서 서로 다른 함의를 가집다. 또한 단일 사용자용 에이전트(노트북을 사용하는 한 명의 엔지니어)를 구축하는지, 아니면 다중 사용자용 에이전트(같은 조직의 수십 명의 엔지니어가 동일한 에이전트를 공유)를 구축하는지에 따라 트레이드오프가 다르게 보입니다. 저희는 다중 사용자 환경에 해당하며, 이는 단일 사용자 환경을 구축하는 개발자들은 겪지 못하는 문제들을 드러냅니다.
두 가지 아키텍처
샌드박스 내부의 하니스 루프가 작업 중인 코드와 동일한 컨테이너 내에 존재합니다. LLM 호출은 컨테이너 내부에서 외부로 나가며, 도구 호출(bash, read, write)은 로컬에서 실행됩니다. 하니스가 추적하는 스킬(Skills), 메모리 등은 모두 컨테이너의 파일 시스템에 파일 형태로 저장됩니다. 이는 노트북에서 Claude를 실행할 때, 또는 원격 컨테이너에서 Claude Code를 돌릴 때 작동하는 방식입니다. 단일 사용자 에이전트를 구축 중이라면 Claude Code SDK를 사용해 그대로 작동하는 것을 출시(Ship)할 수 있습니다.
샌드박스 외부의 하니스 루프는 자체 백엔드에서 실행됩니다. 도구를 실행해야 할 때 API를 통해 샌드박스를 호출합니다. 샌드박스는 도구를 실행하고 결과를 반환하며, 루프 자체는 절대 샌드박스 내부로 들어가지 않습니다.
트레이드오프
샌드박스 내부에서 하니스를 실행하는 방식에는 몇 가지 장점이 있습니다. 실행 모델이 단순합니다. 즉, 하나의 컨테이너, 하나의 프로세스 트리, 하나의 파일 시스템, 하나의 수명 주기(Lifetime)를 가집니다. 기존에 잘 만들어진 오프 셸프(Off-the-shelf) 하니스를 있는 그대로 재사용할 수 있습니다. 스킬과 메모리 역시 로컬 파일 시스템을 기반으로 작동하도록 작성되어 있으므로 수정 없이 그대로 사용할 수 있습니다.
반면 샌드박스 외부에서 하니스를 실행하면 내부 모델에서는 얻을 수 없는 이점들이 있습니다. 먼저 인증 정보(Credentials)를 샌드박스 밖에 안전하게 보관할 수 있습니다. 루프에는 LLM API 키, 사용자 토큰, 데이터베이스 접근 권한이 유지되며, 샌드박스에는 에이전트가 작업을 수행하는 데 필요한 환경만 존재합니다. 샌드박스 내부에는 에이전트가 빠져나가려 해야 할 대상(권한, 토큰 등)이 없으므로, 권한 모델을 강제하거나 자격 증명 유출을 막기 위한 조치를 할 필요가 없습니다.
또한 에이전트가 샌드박스를 사용하지 않을 때 이를 일시 정지(Suspend)할 수 있습니다. 에이전트가 하는 많은 작업(생각하기, API 호출, 요약, CI 대기 등)은 사실 샌드박스가 전혀 필요하지 않습니다. 일부 세션은 샌드박스를 아예 터치하지 않기도 합니다. 하니스가 외부에 있으면 에이전트가 명령을 실행해야 할 때만 샌드박스를 프로비저닝(할당)하고, 유휴 상태가 되면 즉시 일시 정지할 수 있습니다. 하니스가 샌드박스 내부에 있으면 루프가 실행되는 공간 자체를 일시 정지할 수 없으므로 이러한 최적화가 불가능합니다.
샌드박스를 소모성 리소스(Cattle)처럼 다룰 수 있게 됩니다. 세션 도중 하나의 샌드박스가 죽더라도 루프는 새로운 샌드박스를 프로비저닝하고 계속해서 작업을 진행할 수 있습니다. 반면 하니스가 내부에서 실행될 경우 샌드박스가 곧 세션을 의미하므로, 샌드박스를 잃으면 세션도 잃게 됩니다.
결과적으로 다중 사용자 환경 지원이 단순한 '공유 데이터베이스' 문제로 변환됩니다. 같은 조직의 여러 엔지니어가 동일한 에이전트를 사용하며 스킬과 메모리를 공유하고, 때로는 동일한 장애 인시던트를 병렬로 조사하기도 합니다. 하니스가 샌드박스 외부에 있다면 이는 단순히 공유 데이터베이스를 사용하는 문제가 됩니다. 하지만 내부에 있다면 나중에 다룰 분산 파일 시스템 문제로 번지게 됩니다.
물론 루프를 외부로 옮기면 기존의 로컬용 오프 셸프 하니스들은 더 이상 작동하지 않습니다. 이들은 모두 로컬 파일 시스템이 있다고 가정하고 설계되었기 때문입니다. 에이전트 세션은 몇 시간 동안 실행될 수 있고 배포(Deploy) 과정에서도 살아남아야 하므로, 내구성 있는 실행(Durable execution)을 직접 구현해야 하는 과제가 생깁니다. 하니스와 샌드박스가 다른 머신에 존재하게 되므로, 더 이상 가리킬 수 있는 단일 "파일 시스템"이라는 개념은 사라집니다.
저희는 외부 모델을 선택했습니다. 이 글의 나머지 부분에서는 이 방식이 작동하게 만들기 위해 저희가 해결해야 했던 세 가지 과제에 대해 다룹니다.
내구성 있는 실행 (Durable execution) 에이전트 루프는 오래 실행되는(Long-running) 함수입니다. 최소 몇 분, 저희의 경우 몇 시간씩 실행됩니다. 이 과정은 롤링 배포(Rolling deploys), 스케일링 이벤트(Scale events), 인스턴스 장애 속에서도 살아남아야 합니다. API 서버의 메모리에 루프를 올려두는 방식은 새 버전을 배포하는 즉시 데이터가 날아가 버리는 치명적인 단점이 있습니다. 저희는 이미 CI 수집(Ingest) 과정에서...