호라이즌앱스 로고
← 기술 노트

혼자서 AI 함대를 운영한다는 것, 처음부터 만드는 대신 조립하기로 했습니다

임균영조회 —

처음엔 이걸 만들어야 할 시스템이라고 생각했습니다. 여러 대의 기계를 묶어 AI에게 일을 시키는 지휘 계층입니다.

큐가 있고, 워커가 있고, 상태를 주고받는 데몬이 있어야 할 것 같았습니다. 그렇게 며칠 설계를 붙들고 있다가, 문득 이상하다는 생각이 들었습니다.

제가 매일 쓰던 코딩 에이전트는 이미 기억(세션이 끝나도 남는 메모리)을 갖고 있었습니다. 재사용 절차(반복 작업을 접어 둔 스킬)도 있었습니다.

자동 트리거(특정 상황에 스스로 발동하는 훅), 예약 실행(정해진 시각에 도는 스케줄)도 있었습니다. 하위 일꾼(잘게 쪼갠 서브에이전트)과 외부 도구 연결까지 전부 손에 있었습니다.

없던 건 그것들을 하나의 루프로 엮는 얇은 지휘선 하나뿐이었습니다.

그래서 문제를 다시 정의했습니다. 부품은 다 있으니 남은 일은 조립이었습니다.

그 순간부터 코드는 극적으로 줄었고, 시스템은 오히려 훨씬 튼튼해졌습니다.

조립을 고른 이유

혼자 운영하는 시스템에서 가장 무서운 건 부품 수입니다. 데몬(상주하며 계속 도는 백그라운드 프로세스) 하나를 세우면 그 데몬이 죽었을 때를 감시할 무언가가 필요합니다.

그걸 감시할 또 무언가도 필요해집니다. 감시자의 감시자로 이어지는 사슬이 1인 운영자를 조용히 갉아먹습니다.

조립으로 방향을 틀자 이 사슬이 통째로 사라졌습니다. 오케스트레이터와 워커는 HTTP로 대화하지 않습니다. 상주 데몬도, 소켓도, 인증 토큰도 없습니다.

둘은 파일로만 주고받습니다. 태스크를 파일로 던지고, 결과를 파일로 회수합니다.

투박해 보이지만, 실제로 돌려 보니 이 파일 기반 단순 통합이 가장 견고했습니다. 프로세스가 죽어도 파일은 남습니다. 재부팅해도 상태는 디스크에 있습니다.

2편 마크다운이 곧 기억이다의 연장선입니다. 기억을 파일에 두었더니, 지휘 통신마저 파일이 가장 안전한 매체였습니다.

파일은 살아 있을 필요가 없으니 감시할 필요도 없습니다. 혼자 굴리는 시스템에서는 그 점이 가장 컸습니다.

강점대로 나눈 역할

함대라고 거창하게 불렀지만, 실체는 홈서버 몇 대입니다. 제가 공을 들인 건 각 기계에 강점대로 역할을 준 일입니다.

기계강점맡긴 역할
데스크톱화면·손이 붙어 있음콘솔·지식 허브·모든 결과의 최종 종착지
작은 리눅스 보드24시간 조용히 켜져 있음오케스트레이터 + 1차 워커풀 + 라이브 봇 호스트
힘센 저장서버힘은 세지만 다른 일도 함조건부(부하 낮을 때만) 빌드 워커 겸 배포 타겟

이 세 대를 원격 백본으로 묶어, 같은 방 안에 있는 것처럼 다룹니다.

IP를 외우거나 포트를 하드코딩하는 배선을 걷어 냈습니다. 그러자 어느 기계에 태스크를 보낼지는 코드에서 빠지고 제 판단으로 넘어왔습니다.

라우팅 규칙은 하나로 수렴했습니다. 정본(원본 소스)이 어디 있느냐가 모든 걸 정합니다.

정본이 어느 기계에 있으면 워커도 거기서 코드를 쓰고, 배포 경로도 거기서 뻗습니다.

정본에서 워커가 작성하고, 배포 타겟으로 나갑니다. 이 한 줄이 "이 일을 어디서 시키지?"라는 질문을 매번 없애 줬습니다.

쓰기만 하는 워커

여기서부터가 이 시스템에서 가장 중요한 규칙입니다. 1편에서 예고한 게이트의 실체이기도 합니다.

워커는 코드를 작성만 합니다. 그게 전부입니다.

커밋, 푸시, 재시작, 데이터베이스 쓰기, 실제 배포, 무중단 전환은 워커가 하지 않습니다. 전부 사람이나 오케스트레이터의 게이트를 한 번 거칩니다.

특히 남의 돈이나 데이터가 걸린 프로덕션에서 사람 없는 완전 자동은 금지입니다. 예외 없이.

태스크도 결과도 파일로 오갑니다. 워커가 격리 사본에서 쓴 결과는 게이트 앞에서 멈추고, 사람 확인을 거친 뒤에야 배포 타겟에 반영됩니다.

이유는 단순합니다. AI 워커는 지치지 않고, 그래서 틀려도 지치지 않고 틀립니다.

초안을 쓰는 일과 그 초안을 세상에 반영하는 일 사이에는 되돌릴 수 있느냐 없느냐의 절벽이 있습니다.

작성한 코드는 언제든 버릴 수 있습니다. 배포는 되돌리는 데 대가가 듭니다. 그 절벽 위에 사람 손을 얹는 게 게이트입니다.

오케스트레이터 자신도 얇아야 합니다. 1편에서 말한 위임의 역설을 여기서 회수합니다. 지휘층이 얇을수록 오래 갑니다.

언젠가 오케스트레이터가 워커의 결과가 마음에 안 든다고 스스로 코드를 고치기 시작한 적이 있습니다. 그 순간부터 하네스가 자기 발을 씹기 시작했습니다.

상위 모델과 하위 모델을 나눠 쓰는 패턴은 확실히 효과가 있었습니다. 설계·판단은 힘센 모델이 한 번, 반복 실행은 가벼운 모델이 여러 번 맡습니다.

다만 여러 세션을 무작정 병렬로 켜는 건 대체로 손해였습니다. 격리 없이 나란히 돌리면 서로의 작업 트리를 밟습니다.

병렬은 자원과 격리를 먼저 설계했을 때만 이득입니다. 그래서 모든 워커는 스냅샷 격리(각자 별도 사본에서만 손대게 만드는 방식)를 전제로만 돕니다.

물어뜯긴 자리들

여기 적는 건 전부 실제로 당한 것들입니다. 조립이 쉬웠던 만큼, 조립된 시스템이 물어뜯을 때는 예상 밖의 방향에서 옵니다.

split-brain, 은퇴한 옛 사본의 부팅

split-brain은 한 몸이 둘로 쪼개지는 사고입니다. 봇 호스트를 새 기계로 옮긴 뒤, 옛 기계를 실수로 한 번 켠 적이 있습니다.

그러자 같은 봇이 두 곳에서 동시에 살아나 모든 메시지에 두 번씩 응답했습니다.

죽었다고 믿은 인스턴스가 살아 있으면, 시스템은 조용히 둘로 쪼개집니다. 은퇴시킨 기계는 전원을 끄는 데서 멈추지 말고 부팅 금지로 못 박으세요.

태스크 스펙의 '커밋까지'

한번은 태스크 지시에 "작업하고 커밋해 줘"라고 무심코 적었습니다. 워커가 시키는 대로 스스로 커밋을 했습니다.

워커가 이미 커밋으로 치웠으니 작업 트리에는 변경이 없었습니다. 하네스는 그걸 보고 브랜치를 빈 작업으로 간주해 지워 버렸습니다.

몇 시간짜리 결과가 dangling 커밋(어디에도 연결 안 된 채 떠도는 커밋)으로 사라질 뻔했습니다.

복구는 됐습니다. 그 뒤로 커밋은 하네스만 합니다. 스펙에 '커밋까지'를 넣는 순간 이 경계가 무너집니다.

격리 없는 라이브 트리

라이브 트리 옆에서 격리 없이 작업한 대가도 치렀습니다. 돌아가는 봇의 라이브 소스 바로 옆에서, 스냅샷 없이 여러 워커를 붙였다가 라이브 트리가 오염됐습니다.

병렬 워커가 서로의 추적되지 않은 파일을 지우면서 라이브가 크래시 루프에 빠졌습니다. 워커는 언제나 격리된 사본 안에서만 손을 대야 합니다.

grep 한 줄의 서버 정지

가장 얼얼했던 건 탐색 한 줄이었습니다. grep -r / 한 줄로 작은 서버 한 대가 통째로 멈춘 적이 있습니다.

커널 가상 파일까지 훑느라 I/O가 포화됐고, 원격 접속이 먹통이 됐습니다. 결국 재부팅밖에 답이 없었습니다.

탐색에는 항상 구체 경로와 깊이 제한, 타임아웃을 물려서 워커에게 상속시키세요. 워커에게 준 탐색권은 서버를 세울 수 있는 권한이기도 합니다.

설정 백업의 평문 시크릿

편의로 남겨 둔 설정 백업 파일이 평문 시크릿을 흘린 적도 있습니다.

조립은 부품을 빠르게 붙이는 만큼, 붙인 자리마다 무엇이 새는지 따로 감사해야 합니다.

시리즈의 층

이 시리즈는 한 채의 집을 짓는 이야기였습니다. 편마다 층 하나씩을 올렸습니다.

층편하는 일
원칙1편위임·역할 분리·정보 흐름·자원 배분, 나 대신 일할 구조의 뼈대
기억2편파일에 적힌 지식, 세션이 끝나도 잊지 않게
절차3편두 번 하면 스킬로, 반복을 접어 재사용 가능하게
오케스트레이션4편위 셋을 하나의 루프로 지휘, 얇은 지휘선과 게이트

비슷한 걸 세우려는 분께 드리고 싶은 말은 순서입니다. 먼저 이미 가진 부품부터 세어 보세요. 없는 건 대개 그것들을 엮는 루프 하나뿐입니다.

그다음 워커가 할 수 있는 일을 쓰기로 묶으세요. 커밋은 하네스에, 배포처럼 되돌리기 어려운 일은 사람 확인에 맡깁니다.

마지막으로 오케스트레이터가 직접 코드를 고치기 시작하면 멈추세요. 지휘층은 얇을수록 오래 갑니다.

혼자서 함대를 운영한다고 제가 만능이 되지는 않았습니다. 제가 자리를 비워도 각 기계가 제 강점대로 일하고, 위험한 문턱마다 저를 기다려 주는 구조가 생겼을 뿐입니다.

1편의 하네스 엔지니어링이 발상이었다면, 이 4편은 그 발상이 실제로 돌아가는 모습입니다.

절차를 어떻게 접었는지 궁금하다면 두 번 하면 스킬로 만든다로 돌아가 보셔도 좋습니다.

이어서 읽기