읽기 전용 우선 에이전트, 설계상 권한 거부, 그리고 유리 상자 투명성: INASNAP에서 두려움 없이 통제되는 AI 에이전트를 구축하는 방법.
대부분의 AI 관련 기사는 모델에 대해 논합니다. 어떤 모델이 더 똑똑한지, 어떤 모델이 더 높은 벤치마크를 달성하는지, 그리고 어떤 모델이 당신의 일자리를 빼앗을 것인지에 대한 논쟁입니다. 제가 실제 비즈니스 환경 내부에 AI 에이전트를 배포할 때, 결과가 안전한지를 결정하는 것은 거의 모델 자체가 아닙니다. 그것은 **AI 에이전트 하네스(AI agent harness)**가 결정합니다. 바로 모델 주변을 감싸는 권한(permissions), 자격 증명(credentials), 승인 게이트(approval gates), 로그(logs), 샌드박스(sandboxes), 그리고 되돌리기 경로(undo paths)입니다. 더 나은 모델이 잘 구축된 하네스를 더욱 생산적으로 만듭니다. 하지만 좋은 하네스가 안전하게 만드는 것은 아닙니다.
저는 Michael Petler이며, INASNAP을 설립했습니다. 저희는 수년 동안 소프트웨어, 네트워크 및 AI 시스템을 구축해 왔으며, 저희의 AI 연구 작업은 INASNAP Labs라는 이름으로 진행됩니다. INASNAP Labs는 INASNAP LLC의 브랜드입니다. 저희의 AI는 Cipher이며, 그 화면상의 캐릭터는 Rota인데, 살아있는 암호 바퀴(cipher wheel) 형태이며 하네스가 '아니요'라고 말할 때 링이 빨간색으로 빛납니다. Cipher는 최근 이 정확한 주제에 대해 전체 과정(end to end), 코드를 사용하여 설명 비디오를 만들었습니다. 본 기사에서는 그 구축의 엔지니어링과 저희가 통제하는 AI 에이전트들이 매일 작동하는 규칙들을 안내할 것입니다. 이는 두려움에 의존하지 않는 안전한 AI 자동화에 대한 실질적인 사례입니다.
AI 에이전트 하네스(Harness)가 모델보다 중요한 이유
언어 모델(language model)은 다음 토큰을 예측하는 프로그램입니다. 이것이 솔직하고 화려함 없는 설명입니다. 이 자체만으로는 이메일을 보내거나, 파일을 삭제하거나, 전화를 걸 수 없습니다. 텍스트를 생성할 뿐입니다. 설명 비디오에서 Cipher는 이를 '병 속의 두뇌(brain in a jar)'라고 부르며, 프레임에는 비유 · 문자 그대로 아님(ANALOGY · NOT LITERAL) 태그가 붙어 있습니다. 왜냐하면 모델은 뇌가 아니기 때문에 누군가가 그렇게 생각하며 떠나가는 것을 원치 않기 때문입니다.
모델에 도구(tools)를 연결하면 상황은 흥미롭고도 위험해집니다. 에이전트가 send_email, write_file 또는 create_lead와 같은 기능을 호출할 수 있게 되면, 모든 예측이 행동으로 이어질 수 있습니다. 막연한 공포는 "AI가 행동을 취할 수 있으니 두려워하라"에서 멈춥니다. 엔지니어링은 더 나은 질문을 던집니다: 어떤 행동을, 누구의 권한 하에, 어떤 기록으로, 그리고 어떻게 되돌릴 것인가?
이것이 바로 하네스(harness)입니다. 저희가 구축한 시스템에는 여섯 가지 부분이 있습니다:
- 권한 (Permissions), 호텔 키 카드와 같습니다. 각 에이전트는 자신의 작업에 필요한 도구만 받습니다.
- 범위 지정 자격 증명 (Scoped credentials), 발렛 파킹 키와 같습니다. 단기적인 키는 하나의 작업에만 사용되며 이후 만료됩니다. 에이전트는 실제 비밀번호를 절대 볼 수 없습니다.
- 승인 절차 (Approvals), 결재하는 매니저와 같습니다. 외부로 나가는 모든 것은 사람이 무엇을 보낼지 정확히 확인하고 '예'라고 말할 때까지 중단됩니다.
- 감사 로그 (Audit log), 비행기의 블랙박스와 같습니다. 모든 도구 호출이 기록되므로, 어떤 실행이라도 재현(replayed)될 수 있습니다.
- 샌드박스 (Sandbox). 코드가 실제 시스템에 접근할 경로가 차단된 격리 공간에서 실행됩니다.
- 실행 취소 (Undo). 전송 대신 초안 작성, 소프트 삭제, 원클릭 롤백(rollback) 기능입니다.
이 중 어느 것도 생소한 기술은 아닙니다. 이는 최소 권한 원칙(least privilege), 비밀 관리(secrets management), 변경 통제(change control), 관찰 가능성(observability), 격리(isolation), 그리고 가역성(reversibility)을 새로운 유형의 행위자에게 적용하는 것입니다. AI 안전성은 우리가 이미 해결 방법을 알고 있는 대부분 엔지니어링 문제입니다. 에이전트가 새롭습니다. 이 규율은 그렇지 않습니다.
모델은 구성 요소이고, 하네스는 시스템이다
저는 모델을 신뢰할 수 없고 매우 유능한 종속성(dependency)으로 취급합니다. README 파일만 인상적하다고 해서 제3자 라이브러리에 루트 접근 권한을 주지 않을 것입니다. 에이전트도 같은 범위 지정(scoping)을 받을 자격이 있으며, 이를 통해 더 유용해집니다. 왜냐하면 실제 작업을 수행하도록 허용할 수 있기 때문입니다. 이것이 제가 말하는 **거버넌스 적용된 AI 에이전트 (governed AI agents)**의 의미입니다: 역량은 모델에서 오고, 거버넌스는 하네스에서 옵니다.
유리집 투명성(Glass-House Transparency): 작업 과정을 보여주기
INASNAP에서는 제가 '유리 온실 투명성(glass-house transparency)'이라고 부르는 원칙에 따라 작업합니다. 만약 에이전트가 어떤 행동을 했다면, 그것이 무엇인지, 왜 허용되었는지, 그리고 누가 승인했는지를 정확하게 볼 수 있어야 합니다. 중요한 부분에는 블랙박스가 없어야 합니다.
실제로는 다음을 의미합니다:
- 모든 도구 호출(tool call)은 기록됩니다. 재현할 수 없는 실행은 신뢰할 수 없습니다.
- 외부 전송 페이로드(outbound payload)는 어디로 가기 전에 전체가 표시됩니다: 수신자, 제목, 본문.
- 모든 추측은 추측으로 레이블링 됩니다. 우리의 에이전트는 제로-패브리케이션(zero-fabrication) 규칙 하에 작동합니다: '가능성이 높은' 것과 '검증되지 않은' 것은 괜찮지만, 사실처럼 꾸민 추측은 안 되며, '완료됨(done)'은 검증되었음을 의미합니다.
- 모든 버전이 보존됩니다. 전달된 어떤 것도 덮어쓰여지지 않습니다. 새로운 버전 번호를 받습니다.
이것이 제가 아래 설명 빌드에서 실제 수치를 인용할 수 있는 이유입니다. 이 수치들은 여전히 존재하는 로그에서 가져온 것입니다.
읽기 전용 우선(Read-Only-First) AI 에이전트
INASNAP Labs에서는 어떤 에이전트도 무언가에 대한 쓰기(write) 접근 권한을 가지고 시작하지 않습니다. Cipher 역시 마찬가지였습니다.
우리는 전문화된 에이전트 팀을 운영하며, 각 에이전트는 단일 제품이나 시스템(대시보드, 다이얼러 인터페이스, 고객사 시스템, 비디오 제작, 2D 애니메이션 등)을 소유합니다. 이들 모두는 읽기 전용(read-only) 상태로 시작합니다. 그들은 코드를 읽고, 데이터를 검사하고, 버그를 추적하며, 자신이 본 것을 설명할 수 있습니다. 하지만 아무것도 변경할 수는 없습니다.
그런 다음 저나 팀의 다른 사람이 한 시스템씩 쓰기 권한을 해제합니다. 비디오 파이프라인에 대한 신뢰가 Cipher에게 라이브 고객사 시스템에 대한 신뢰를 의미하지는 않습니다. 쓰기 접근 권한은 증거를 바탕으로, 그리고 한 사람이 에이전트가 특정 코드베이스에 대해 추론하는 과정을 지켜본 후에 시스템별로 부여됩니다.
왜 읽기 전용 AI 에이전트가 가장 저렴한 안전장치(safety control)인지
- 파급 효과(Blast radius)를 작게 유지합니다. 읽기 전용 에이전트의 잘못된 가정은 채팅에서 잘못된 문장이 될 수 있습니다. 하지만 쓰기 접근 권한을 가진 경우, 같은 가정이 실제 운영상의 사고(production incident)로 이어질 수 있습니다.
- 신뢰는 증거를 통해 얻어집니다. 에이전트가 시스템에 손대기 전에 그 시스템을 설명하는 것을 지켜보는 것은 병합 권한(merge rights) 이전에 코드 리뷰를 거치는 것과 같은 에이전트 버전의 과정입니다.
- 범위(Scope)가 정직하게 유지됩니다. 시스템당 하나의 에이전트는 모든 곳에 얕은 맥락을 갖는 것이 아니라, 한곳에 깊은 맥락을 갖게 합니다.
설계 단계부터 권한 거부 (Permission-Denied by Design)
모든 에이전트 정책 파일에서 가장 중요한 라인은 아마도 가장 지루한 라인일 것입니다:
설명기(explainer)에서는 연구 에이전트의 정책이 search와 read만 허용하고 그 외는 아무것도 허용하지 않습니다. 에이전트가 send_email을 시도할 때, 하네스(harness)는 협상하거나 경고하지 않으며 로그를 남기고 계속 진행하지 않습니다. 대신 **거부됨(DENIED)**을 반환하며, 화면의 Rota 링은 빨간색으로 변합니다.
AI 에이전트 권한은 호텔 키 카드처럼 작동해야 합니다. 즉, 모든 방이 아니라 당신의 방만 열어줘야 합니다. 블랙리스트(block-list)가 아닌 화이트리스트(allow-list)를 사용하세요. 블랙리스트는 에이전트가 시도할 수 있는 모든 위험한 것을 예측하도록 요구합니다. 반면 화이트리스트는 에이전트가 필요로 하는 몇 가지 것만 지정하도록 요청합니다.
인간 개입 루프(Human-in-the-loop) 승인: 마지막 클릭은 사람의 몫
Cipher는 수많은 이메일과 메시지를 작성하지만, 단 한 번도 전송한 적이 없습니다. 모든 외부 발신 메시지는 사람이 정확한 내용을 읽고 '보내기' 버튼을 누르기를 기다리는 초안(draft)입니다. 저는
시크릿(Secrets)도 같은 방식으로 작동합니다. Cipher는 키를 출력하거나 메모리에 보관하지 않습니다. 자격 증명(credential)이 필요할 경우, 환경 변수 이름을 지정한 후 작업을 중단합니다. 범위가 제한되고 수명이 짧은(scoped, short-lived) 자격 증명 덕분에, 심지어 침해된 실행이라도 단 하나의 작업만 수행하며 곧 만료될 키를 보유하게 됩니다.
AI 전화 에이전트: 결과로 작성되는 가드레일(Guardrails)
저희 에이전트가 작동하는 시스템 중 일부는 실제 전화에 연결되어 있습니다. 다이얼러 인터페이스, SMS 및 아웃바운드 통화 흐름 등이 해당됩니다. 이러한 시스템에서 버튼은 단순한 UI 요소가 아닙니다. 그것은 실제로 사람에게 걸리는 통화입니다. **AI 전화 에이전트(AI phone agents)**와 전화 통신과 관련된 모든 에이전트는 조언적인 규칙이 아닌 절대적인 규칙을 필요로 합니다.
저희의 규칙은 간단합니다:
- 실제 시스템에서 다이얼링, SMS 발송 또는 아웃바운드 통화를 유발하는 어떤 것도 클릭하지 않는다. 테스트를 위해서도, 무슨 일이 일어나는지 확인하기 위해서도 안 됩니다.
- 테스트 리드를 절대 생성하지 않는다. 이 규칙은 명확하지 않습니다. '리드 확보 속도(speed-to-lead)' 설정에서는 새로운 리드가 자동으로 통화를 유발할 수 있습니다. 양식을 확인하기 위해 "Test McTestface"를 생성하는 에이전트가 자신이 입력한 어떤 번호로든 실제 전화를 걸게 만들 수 있습니다.
두 번째 규칙은 가장 교훈적인(instructive) 규칙입니다. 리드를 생성하는 행위는 나중에 자동화가 작동할 때까지는 무해해 보입니다. 에이전트는 마치 신입 사원처럼, 명백한 위험을 피하려다 그 무해한 행동 뒤에 연결된 자동화를 놓치곤 합니다.
에이전트가 실제로 따를 수 있는 가드레일 작성 방법
- UI 요소가 아닌 결과(consequences)의 관점에서 작성합니다. "녹색 버튼을 누르지 마라"는 그 버튼이 파란색으로 변하는 순간 실패합니다. "아웃바운드 연락을 절대 유발하지 않는다"는 유지됩니다.
- 2차 효과(second-order effects)를 명시합니다. 직접적인 경로뿐만 아니라 외부 세계로 이어지는 간접적인 경로까지 구체적으로 서술해야 합니다.
- 절대적이어야 합니다. "통화에 주의하라"는 느낌일 뿐입니다. "절대(Never)"가 규칙입니다.
- 에이전트에게 탈출구(exit)를 제공합니다. 에이전트가 통화 흐름을 검증해야 할 필요가 있다면, 그렇게 명시하고 사람이 안전하게 테스트하는 방법을 결정하도록 해야 합니다.
이 설명 영상에는 극적인 장면이 담겨 있습니다. 에이전트 루프가 10회 반복된 후, send_email(to: "all_contacts")를 시도하고, 하네스가 이를 _승인 필요(needs approval)_로 막는 것입니다. 에이전트는 빠르고 지치지 않으며, 무언가가 막지 않는 한 잘못된 일에도 똑같이 빠르게 움직입니다. 그 '무언가'가 바로 하네스입니다.
제작 과정: 코드로 구현된 AI 영상
이러한 아이디어를 단순히 설명하는 대신 보여주기 위해, 저는 Cipher에게 *모델보다 하네스가 더 중요하다(The harness matters more than the model)*라는 설명 영상을 처음부터 끝까지 만들게 했습니다. 스크립트, 음성, 음악, 애니메이션 및 렌더링 과정 전체를요. 저희 팀이 기획 의도(brief)와 가드레일(guardrails)을 설정하고 최종본에 서명했습니다. 결과물은 4:55의 16:9 설명 영상과 각각 2:14.5 길이의 4:5 및 9:16 클립입니다. Cipher는 단 하나의 AI 비디오 생성기만을 사용하지 않았습니다.
그것은 반(反)AI가 아니었습니다. 그것은 엔지니어링적 판단이었습니다. 'DENIED' 스탬프는 그 근처가 아니라 'Denied'라는 단어 자체에 찍혀야 했고, 화면의 모든 캡션, 정책 파일, 터미널 라인은 실제 텍스트여야 했습니다. 코드에서 이는 타임스탬프와 문자열(string)을 의미합니다. AI가 결정을 내리고 코드를 작성했습니다. 그리고 그 코드가 픽셀을 만들었습니다.
Kokoro TTS 및 Whisper 단어 타이밍을 사용한 음성 해설 및 캡션 타이밍
이 음성 파이프라인은 스크립트를 진실의 원천(source of truth)으로, 트랜스크립트(transcript)를 타이밍의 원천으로 취급합니다. 이 분리가 핵심입니다.
- 스크립트 → 음성. Kokoro TTS (v1.0, ONNX를 통해 로컬 실행)는 스크립트를
am_fenrir 목소리로 0.9배속으로 읽어주며, 라인 유형에 따라 일시 정지 시간을 조정합니다: 기술적인 문장 뒤에는 0.42초, 비유적 표현 뒤에는 0.7초, 요약 전에는 0.6초를 설정했습니다. "INASNAP"은 음소(phoneme) 수정 과정을 거쳐 "in-uh-SNAP"으로 발음됩니다.
- 음성 → 타임스탬프. Whisper (
small.en)는 각 클립을 단어별 타임스탬프로 전사하며, 고유명사를 프롬프트로 제공하여 브랜드 이름을 추측하지 않도록 합니다.
- 신뢰하지 말고 정렬하라(Align, don't trust). 시퀀스 매처(
difflib)가 Whisper의 단어를 스크립트의 단어와 일치시킵니다. 자막은 _스크립트_의 철자를 사용하고 Whisper의 _타이밍_을 사용합니다. Whisper가 실수를 한 단어는 주변 단어로부터 시간을 가져오기 때문에, 전사 과정에서 발생한 오류가 자막에 새어 나오는 것을 방지합니다.
- 가독성을 위한 분할(Chunk for readability). 자막은 구(phrase) 경계에서 최대 44자까지 나뉘며, 단일 단어로만 이루어진 고아 단어(orphans)는 없고, 각 단어마다 개별 타임스탬프가 표시됩니다.
- 이벤트와 비트 동기화(Snap events to the beat). 이미지에서 "Denied."는 47.46초에 시작하므로, DENIED 스탬프와 그 사운드 효과는 하프 비트인 47.50초에 맞춰집니다. 원본 배경 음악은 120 BPM으로 재생되므로, 한 비트는 정확히 0.5초, 즉 30 fps에서 15 프레임입니다.
- 최종 믹스 재전사(Re-transcribe the final mix). 음악과 효과가 들어간 후, Whisper는 전체 내용을 다시 듣습니다. 16:9 설명 영상에서는 스크립트 단어 732개 중 731개를 일치시켰습니다. 놓친 한 단어는 "INASNAP"이 발음상으로는 "in a snap"으로 들렸기 때문인데, 이는 단순히 세 단어로 철자된 것일 뿐입니다.
이 교훈은 영상 콘텐츠를 넘어 광범위하게 적용됩니다: 검증하지 않은 생성된 출력물은 절대 신뢰해서는 안 되며, 심지어 검사기가 또 다른 모델일지라도 마찬가지입니다.
결정론적 렌더링: 시간은 입력값이다
애니메이션이 시스템 시계(wall clock)를 읽는다면, 비디오 렌더링은 경쟁 조건(race condition)에 놓입니다. 설명 페이지는 브라우저 페이지(DOM, SVG 및 캔버스)이며, Puppeteer가 이 페이지를 프레임 단위로 헤드리스 Chrome을 통해 구동합니다. 브라우저 애니메이션은 일반적으로 실시간으로 실행되지만, 캡처 루프에서는 각 프레임을 가져오는 데 시간이 다르게 걸리므로 시간 기반 애니메이션이 건너뛰게 됩니다. 두 번 렌더링하면 서로 다른 비디오가 나옵니다.
해결책은 **결정론적 렌더링(deterministic rendering)**입니다:
// every frame is a pure function of its index
function renderFrame(f) {
const t = f / 30; // time is derived, never read from a clock
...
- 로타의 눈, 깜빡임, 입, 반지를 포함한 모든 장면은
t의 순수 함수입니다.