12시 정각에 무슨 일이 있었나
내 개인 사이트에는 글을 사람 없이 만들어 올리는 파이프라인이 하나 돌고 있었다. 매일 정오에 예약작업이 깨어나 주제를 고르고, 모델에게 원고를 시키고, 검사를 통과한 것만 서버로 올린다. 누적 100편 가까이가 그렇게 나갔다.
그날도 정확히 12시 정각에 돌았다. 작업 스케줄러가 남긴 결과 코드는 0. 2분 뒤 글 한 편이 라이브에 올라갔고 사이트맵과 글 목록에도 반영됐다. 겉으로 보면 흠잡을 데 없는 실행이다.
30분쯤 지나 다른 일로 사이트를 훑다가 그 글의 광고 자리 하나가 존재하지 않는 번호를 물고 있는 것을 봤다. 하단 광고가 통째로 죽어 있었다는 뜻이다. 본문에는 그림이 한 장도 없었고, 읽는시간 표기도 빠져 있었다.
중요한 건 그 다음이다. 이 셋 중 무엇도 게이트에 걸리지 않았다. 검사를 통과했고, 종료 코드는 0이었고, 업로더는 조용히 성공을 보고했다. 발견한 것은 사람이었고, 그것도 우연이었다.
게이트는 파이프라인의 어디에 있나
이런 파이프라인을 나는 «하네스»라고 부른다. 모델은 사서 쓰고, 그 바깥의 나머지를 직접 만드는 일이다. 기동, 권한, 지시, 판정, 기록, 그리고 멈추는 장치. 게이트는 그 부품 중 하나다.
구조를 이렇게 잡은 이유는 하나다. 위험한 동작은 코드가 맡고, 판단만 모델에게 넘기기 위해서다. 파일을 지우고 서버에 올리는 일은 스크립트가 하고, 모델은 읽고 쓰고 판단만 한다. 게이트는 그 경계에 서서 «이건 밖으로 내보내도 되는가»를 코드로 답한다.
그래서 게이트는 프롬프트가 아니라 코드여야 한다. «AI 흔적이 없게 써라»라고 지시하는 것과, 결과물에서 그 문구를 정규식으로 찾아 불합격시키는 것은 전혀 다른 장치다. 앞엣것은 부탁이고 뒤엣것은 검사다.
게이트가 보는 것과 안 보는 것
사건 뒤에 게이트 코드를 열어 검사 항목을 세어 봤다. 세 가지였다.
그리고 이번에 어긋난 세 가지는 모두 오른쪽에 있었다. 여기서 내가 착각하고 있던 것이 드러난다. 나는 «게이트를 통과했다»를 «기준을 지켰다»로 읽고 있었다. 실제로 게이트가 말한 것은 «내가 넣어 둔 세 가지 검사에서는 문제가 없다»였다.
이건 게이트가 고장 난 게 아니다. 설계대로 동작했다. 문제는 검사 목록이 «위험한 것의 목록»이 아니라 «내가 그때 떠올린 것의 목록»이었다는 데 있다. 이 구분은 며칠 전에도 한 번 겪었다. 서버로 올라가면 안 되는 파일을 막는 차단 목록에 확장자 하나가 빠져 있어서, 작업 메모 파일 열두 개가 웹 루트로 나갈 뻔했다. 그때도 차단 목록은 정확히 적힌 대로 동작했다.
통과와 불합격을 숫자로 말하게 한다
게이트가 판단한 결과는 사람이 로그를 열지 않아도 다음 동작이 갈리도록 종료 코드로 내보낸다. 지금 쓰는 갈래는 이렇다.
처음에는 0과 1만 썼다. 성공이면 0, 실패면 1. 그런데 그렇게 하면 «쓸 주제가 없어서 안 썼다»와 «오류가 나서 못 썼다»가 같은 값이 된다. 앞엣것은 정상이고 뒤엣것은 사고인데 구별할 방법이 없다.
특히 «주제 고갈»을 따로 뺀 것이 도움이 됐다. 쓸 소재가 떨어졌을 때 모델은 그럴듯한 주제를 지어낼 수 있다. 그게 가장 나쁜 결과다. 그래서 소재가 비면 지어내지 말고 고유한 코드로 멈추게 만들었다. 멈춘 것은 실패가 아니라 정상 동작이다.
# 종료 코드로 다음 동작을 가른다 node generator.js case $? in 0) echo "발행 완료" ;; 2) echo "게이트 불합격 - 초안만 남았다" ;; 3) echo "쓸 주제가 없다 - 소재를 채워야 한다" ;; 4) echo "분량 하한 미달" ;; 20) echo "검사 2회 실패 - 스스로 중단했다" ;; esac
한 줄이 만든 구멍
광고 슬롯이 어긋난 원인을 따라가 보니 생성기 템플릿의 상수 한 줄이었다. 상단과 중간 슬롯은 맞는데 하단만 실제로 존재하지 않는 번호가 박혀 있었다.
사이트 전체를 훑어 보니 242편 중 어긋난 것은 이 한 편뿐이었다. 나머지는 멀쩡했다. 그래서 처음엔 «한 편만 고치면 되겠다»고 생각했는데, 그게 이 사건에서 두 번째로 위험한 판단이었다.
이건 한 편의 사고가 아니라 템플릿의 결함이다. 예약작업이 살아 있는 한 다음 날 정오에 같은 결함을 가진 글이 또 나온다. 사고를 «발생한 사례»로 세면 대응이 그 사례에서 끝나고, «생산 설비»로 세면 대응이 설비로 간다. 고친 건 결국 그 한 줄이었다.
결과 코드 0은 «성공»이 아니다
게이트 이야기를 하다 보면 반드시 걸리는 문제가 하나 더 있다. 검사를 붙이기 전에, «실행이 제대로 됐는가»부터 알 수 있어야 한다.
처음 무인 루프를 만들었을 때 첫 회차가 이랬다. 실행이 끝났고, 결과 코드는 0이고, 오류 표시도 없었다. 그런데 파일이 하나도 바뀌지 않았다. 모델은 그저 «하겠습니다»에 가까운 말만 하고 턴을 끝냈다.
종료 코드가 알려주는 것은 «프로그램이 죽지 않았다»는 사실뿐이다. «할 일을 했다»는 뜻이 아니다. 그래서 지금은 모델에게 첫 줄에 판정문을 내도록 시키고, 스크립트가 그 줄을 읽어 성공과 불합격을 가른다. 판정문이 없으면 «판정 없음»으로 센다.
누적 13회 기록 중 이 «판정 없음»은 첫 회 하나다. 성공률을 12/13으로 적을 수도 있었지만 그러지 않았다. 계측을 붙이기 전의 실행은 성공이라고 말할 근거가 없다. 자동화 기록에서 가장 쓸모 있는 항목은 대개 이런 항목이다.
게이트를 붙일 값어치가 있나
검사를 붙이고 계측을 붙이는 일은 공짜가 아니다. 그럼 얼마나 드는가. 지금까지 실제로 나간 값을 그대로 옮기면 이렇다.
같은 «자동화»라도 값이 60배 가까이 갈린다. 여기서 나온 판단이 하나 있다. 대시보드를 다시 그리는 작업은 원래 모델을 띄워 명령 한 줄을 시키는 방식이었는데, 그건 모델이 필요한 일이 아니었다. 그래서 영구히 껐다. 표기를 정정하는 루프는 아예 모델 없이 도는데 결과는 같고 값은 0원이다.
언제 되돌리는가
사건 당일에 나는 이 파이프라인을 껐다. 결함을 고치면 계속 돌릴 수도 있었지만 그러지 않았다. 판단의 근거는 하나였다.
자동화의 성공은 «돌아가느냐»가 아니라 «기준을 지키느냐»로 본다. 이 기준으로 보면 이 파이프라인은 100편 가까이 «돌아갔지만», 사이트가 요구하는 기준 세 가지를 처음부터 한 번도 검사하지 않고 있었다. 그건 잘 도는 자동화가 아니라 검사받지 않은 채 오래 돈 자동화다.
끄는 것 자체는 명령 한 줄이다. 어려운 쪽은 다시 켜는 조건을 적어 두는 일이다. 이걸 안 적으면 몇 주 뒤에 «그때 왜 껐더라»가 되고, 결국 고치지 않은 채로 다시 켜게 된다. 그래서 조건을 파일에 적어 두고, 그중 이미 끝낸 항목까지 함께 남겼다.
마지막 항목이 이 글의 결론이기도 하다. 앞의 세 가지를 다 고쳐도 그 검사를 게이트에 넣지 않으면 같은 일이 다시 일어난다. 결함을 고치는 것과 그 결함을 잡는 검사를 만드는 것은 별개의 작업이고, 대개 두 번째가 빠진다.
자주 묻는 질문
Q1. 무인 발행 게이트는 결국 무엇을 검사하는 장치인가요?
사람이 손으로 확인하던 기준을 코드로 옮긴 검사입니다. 이 파이프라인의 게이트는 AI 흔적 문구, 도입부 페르소나, 본문 글자수 하한 세 가지를 봅니다. 통과한 것만 업로드로 넘어가고, 불합격이면 초안만 남기고 멈춥니다.
Q2. 게이트를 통과했는데도 기준 미달인 결과물이 나올 수 있나요?
나옵니다. 게이트는 넣어 둔 검사만 하기 때문입니다. 이번 사건에서 광고 슬롯 번호, 본문 이미지 장수, 읽는시간 표기는 검사 항목에 없었고, 그래서 셋 다 잘못된 채로 통과했습니다. 검사에 없는 항목은 불합격이 아니라 «판정 대상이 아님»입니다.
Q3. 종료 코드는 몇 개로 나누는 것이 좋나요?
최소한 «통과», «검사 불합격», «할 일이 없음», «스스로 중단» 네 갈래는 나누는 편이 좋습니다. 0과 1만 쓰면 멈춘 것과 틀린 것이 같은 값이 되어, 자동화가 조용히 아무 일도 안 하는 상태를 알아챌 수 없습니다.
Q4. 결과 코드가 0이면 성공으로 봐도 되나요?
안 됩니다. 첫 무인 실행에서 결과 코드는 0이고 오류 표시도 없었는데 실제로는 파일이 하나도 바뀌지 않았습니다. 그때부터 모델이 첫 줄에 내는 판정문을 따로 읽어 성공 여부를 가르고 있고, 판정문이 없으면 «판정 없음»으로 세어 성공률에 넣지 않습니다.
Q5. 무인 자동화 비용은 실제로 얼마나 드나요?
같은 성격의 일도 모델 선택에 따라 크게 갈립니다. 표기 정정처럼 모델이 필요 없는 작업은 0원, 경량 모델로 대시보드를 갱신하는 작업은 회당 5센트 남짓, 상위 모델로 글을 쓰고 발행하는 작업은 회당 3달러 가까이 들었습니다. 누적 13회에 6.52달러, 회당 평균 0.50달러였습니다.
Q6. 자동화를 언제 멈춰야 한다고 판단하나요?
결과물이 기준을 지키지 못했을 때입니다. «돌아가느냐»가 아니라 «기준을 지키느냐»로 성공을 판정하면 멈출 시점이 분명해집니다. 다만 끄기 전에 다시 켜는 조건을 함께 적어 두어야 합니다. 그러지 않으면 왜 껐는지 잊은 채로 고치지 않고 다시 켜게 됩니다.