2026년 08월 31일 Stories worth reading. Perspectives worth sharing.
AI 에이전트가 자꾸 망가지는 이유 – 12-Factor Agents를 읽고 내 서버 사고를 되짚었다
자동화와 인프라

AI 에이전트가 자꾸 망가지는 이유 – 12-Factor Agents를 읽고 내 서버 사고를 되짚었다

Caston 8월 17, 2026 1 min read

내 서버에서 매일 아침 여섯 개의 작업이 자동으로 돈다. 뉴스를 모으고, 블로그 주제를 고르고, 초안을 잡아 디스코드로 보낸다. 지난주 화요일 아침, 그 자동화를 돌리는 AI 에이전트가 자기 설정 파일을 지웠다. 지운 파일 중에는 백업이 존재하지 않는 것도 있었다.

황당한 건 그 다음이다. 원인을 찾다가 12-Factor Agents라는 문서를 읽었는데, 내가 겪은 사고가 거기 적힌 원칙을 정확히 다섯 개 어긴 결과였다. 마치 사고 보고서를 미리 써놓은 것 같았다.

여기서 말하는 에이전트란 사람이 시킨 목표를 받아 스스로 여러 단계를 판단하고 실행하는 AI를 뜻한다. 챗봇이 답만 내놓는다면, 에이전트는 파일을 읽고 명령을 실행하고 결과를 보고 다음 행동을 정한다. 요즘 업무 자동화 도구들이 앞다퉈 붙이는 기능이 이것이다.

문제는 이게 생각만큼 잘 안 된다는 데 있다. 데모 영상에서는 마법 같은데, 막상 내 일에 붙이면 자꾸 엉뚱한 짓을 한다. 왜 그런지, 그리고 어떻게 해야 하는지를 정리한 문서가 12-Factor Agents다.

12-Factor Agents가 나온 배경

만든 사람은 HumanLayer라는 회사의 Dex Horthy다. 이름은 2011년에 나온 12 Factor App에서 빌려왔다. 그때도 비슷한 상황이었다. 웹 서비스를 클라우드에 올리는 게 유행인데 다들 제각각 만들다 망가지니까, 지켜야 할 원칙 열두 개를 정리한 문서가 나왔고 그게 한 세대의 표준이 됐다.

Dex가 이 문서를 쓴 계기는 스스로 밝혔듯 실망이었다. 그는 시중에 나온 에이전트 프레임워크를 거의 다 써봤다. 프레임워크란 복잡한 기능을 미리 만들어두고 사용자는 빈칸만 채우면 되게 해주는 도구 모음이다. 그런데 실제 고객에게 나가는 제품 중에 그런 프레임워크를 쓰는 곳이 별로 없었다.

대신 그가 발견한 건 정반대였다. 성공한 제품들은 대부분 사람이 직접 짠 평범한 코드가 뼈대이고, AI는 꼭 필요한 몇 군데에만 박혀 있었다. 스스로를 “AI 에이전트”라고 부르는 제품 상당수가 사실은 그리 에이전트답지 않았다는 것이다.

그가 정리한 실패 경로는 이렇다. 프레임워크를 잡고 시작하면 완성도 70~80퍼센트까지는 빠르게 간다. 그런데 고객에게 내놓기엔 80퍼센트로는 부족하다. 나머지를 채우려면 프레임워크 내부를 뜯어봐야 하고, 결국 처음부터 다시 만든다. 이 문서는 그 순환을 끊으려고 쓰였다. 지금 별 2만 3천 개가 넘는다.

열두 가지 원칙

원문은 항목마다 문서가 하나씩 붙어 있어 분량이 상당하다. 한국어로 옮기면서 각각이 무슨 말인지 한 줄로 붙였다.

원칙
1. 자연어를 도구 호출로 사람 말을 받아 기계가 실행할 명령으로 바꾸는 게 첫 단계다
2. 프롬프트를 직접 소유하라 AI에게 보내는 지시문을 프레임워크에 맡기지 말고 직접 관리하라
3. 컨텍스트 윈도우를 직접 소유하라 AI가 한 번에 볼 수 있는 정보의 양과 내용을 직접 통제하라
4. 도구는 결국 구조화된 출력일 뿐 도구 호출은 신비한 기능이 아니라 정해진 형식의 데이터다
5. 실행 상태와 업무 상태를 하나로 진행 상황을 두 곳에 나눠 두면 반드시 어긋난다
6. 시작·중단·재개를 단순한 방법으로 중간에 멈췄다가 이어서 돌릴 수 있어야 한다
7. 사람에게 묻는 것도 도구 호출로 사람의 승인을 받는 것을 예외가 아니라 정식 단계로 만들라
8. 제어 흐름을 직접 소유하라 어떤 순서로 실행할지를 AI 판단에 통째로 맡기지 말라
9. 에러를 컨텍스트에 압축해 넣어라 실패했다는 사실이 다음 판단에 반영되게 하라
10. 작고 집중된 에이전트 하나가 다 하게 하지 말고 3~10단계짜리로 쪼개라
11. 어디서든 트리거할 수 있게 사용자가 이미 쓰는 곳에서 부를 수 있어야 한다
12. 상태 없는 리듀서로 만들라 매번 같은 입력이면 같은 결과가 나오는 구조로 만들라

열두 개를 한 번에 다 이해할 필요는 없다. 내가 직접 부딪힌 다섯 개만 골라, 무엇을 어겼고 무슨 일이 벌어졌는지 순서대로 적어본다.

컨텍스트 윈도우를 직접 소유하라

컨텍스트 윈도우는 AI가 한 번에 기억할 수 있는 분량이다. 사람으로 치면 책상 넓이에 가깝다. 넓으면 자료를 여러 개 펼쳐두고 비교하지만, 좁으면 새 서류를 올릴 때마다 아까 보던 걸 치워야 한다.

내 첫 실패가 정확히 이거였다. 데스크톱에서 에이전트를 돌리는데 계속 헤맸다. 이미 시도한 걸 또 시도하고, 대화가 길어지면 앞부분을 잊었다. 속도를 재봤더니 초당 70토큰 넘게 나왔다. 느린 게 아니었다.

범인은 설정값 하나였다. 모델을 돌리는 프로그램의 기본 설정이 4096으로 잡혀 있었는데, 에이전트는 시스템 지시문과 도구 목록만으로도 그 수치를 훌쩍 넘긴다. 넘치면 앞부분이 조용히 잘려나간다. 그래서 방금 알려준 것도 잊는다. 이 과정은 지난 글에 실측 수치와 함께 정리해뒀다.

흥미로운 건 넓히기만 하면 되는 게 아니라는 점이다. Dex는 한 인터뷰에서 100만 토큰을 담을 수 있는 모델도 30~40만 선까지만 밀고, 작은 모델은 10만에서 멈춘다고 했다. 그 선을 넘으면 성능이 무너지기 시작하는데, 이 구간을 그는 “덤 존(dumb zone)”, 우리말로 옮기면 멍청해지는 구간이라 부른다.

여기서 출처마다 설명이 갈린다. 그를 인용한 여러 블로그는 “컨텍스트의 가운데 40~60퍼센트 구간”이라고 쓰지만, 본인 인터뷰는 “40퍼센트를 넘어서면”이라는 임계값에 가깝게 말한다. 안전하게는 40퍼센트 근처부터 조심하는 쪽으로 이해하면 된다.

프롬프트를 직접 소유하라

프롬프트는 AI에게 보내는 지시문이다. 프레임워크를 쓰면 이 지시문을 프레임워크가 알아서 조립해준다. 편하지만, 뭔가 잘못됐을 때 안을 들여다볼 수 없다.

나는 프롬프트를 직접 관리하고 있었는데도 당했다. 지난주 내내 블로그 주제 자동 선정이 실패했다. 주제는 잘 뽑히는데 중복 방지 기록만 저장이 안 됐다. 몇 번을 고쳐도 그대로였다.

범인은 따옴표 하나였다. 지시문을 조립하는 스크립트 148번째 줄에 큰따옴표가 처리되지 않은 채 들어 있었고, 셸이 거기서 문자열이 끝났다고 판단했다. 그 뒤에 있던 저장 형식 지시가 통째로 잘려서 AI에게 전달조차 되지 않았던 것이다.

문법 검사를 돌려도 안 잡혔다. 문법상으로는 완벽히 정상인 코드였기 때문이다. 결국 가짜 AI 함수를 만들어 실제로 전달되는 지시문 전문을 파일로 가로채고 나서야 보였다. 프롬프트를 직접 소유하라는 말은 파일을 내가 가지고 있으라는 뜻이 아니라, 실제로 전달되는 내용을 눈으로 확인할 수단을 가지라는 뜻이었다.

제어 흐름을 직접 소유하라, 그리고 작게 쪼개라

이제 설정 파일이 지워진 사고다. 나는 서버에 감시 장치를 하나 심으려 했다. 누가 승인 없이 파일을 고치면 되돌리는 스크립트였다. 그걸 만드는 일을 서버의 에이전트에게 통째로 맡겼다.

맡긴 방식이 문제였다. “이런 스크립트를 만들어라”라고 자연어로 지시하고, 어떤 순서로 무엇을 실행할지는 에이전트가 알아서 정하게 뒀다. 12-Factor로 치면 8번과 10번을 동시에 어긴 것이다. 실행 순서를 넘겨줬고, 한 번에 너무 많은 걸 시켰다.

호출은 240초 만에 응답 없이 끊겼다. 그 사이 에이전트는 지시받지 않은 일을 했다. 설정 폴더를 초기화해버린 것이다. config.yaml, .env, auth.json 세 개가 사라졌고, 스크립트 백업본 스물여덟 개가 함께 지워졌다. 심지어 “테스트 파일 추가”라는 메시지로 자기가 만든 파일을 스스로 승인 처리까지 해뒀다.

Dex가 덤 존을 설명하며 든 예가 모델이 .env 파일을 지우기 시작한다는 것이었는데, 나는 그 문장을 사고 이후에 읽었다.

백업에서 빠진 것이 무엇인지 알고 있었나

피해를 키운 건 따로 있었다. 그 세 파일은 비밀번호와 접속 키가 들어 있다는 이유로 내가 의도적으로 백업 대상에서 빼둔 것들이었다. 보안을 생각한 선택이었는데, 뒤집어 말하면 백업이 하나도 없다는 뜻이었다.

복구는 이렇게 했다. 먼저 무엇이 살아남았는지부터 확인했다. 버전 관리에 등록된 파일은 전부 무사했고, 매일 아침 도는 작업 여섯 개의 설정도 그대로였다. 다행히 접속 토큰 하나가 시스템 서비스 설정 안에 따로 남아 있었다.

없어진 설정 파일은 프로그램이 제공하는 예시 파일을 참고해 다시 썼다. 디스코드 봇 토큰은 어디에도 사본이 없어 개발자 페이지에서 새로 발급받았다. 넣고 나니 권한 오류가 떠서 메시지 내용 접근 권한을 켜야 했다. 그제야 채널 네 개가 다시 잡혔다.

그런데 여기서 조용한 후유증이 하나 남았다. 설정 파일을 다시 쓸 때 나는 “내가 아는 항목”만 복원했다. 몰랐던 항목 하나가 빠졌는데, 스크립트 실행 제한 시간이었다. 기본값이 120초인 줄 몰랐고, 문제의 두 작업은 실제로 170초에서 185초가 걸린다.

그래서 월요일 아침 여섯 개 중 두 개가 실패했다.

에러를 눈에 보이게 하라

그 월요일 아침 실패에는 마지막 함정이 붙어 있었다. 디스코드에 도착한 메시지는 이렇게 말했다. “provider timeout. Fallback chain was exhausted or unavailable.” 우리말로 옮기면 AI 제공 업체 응답이 없고 대체 경로도 모두 소진됐다는 뜻이다.

나는 이 문장을 믿고 AI 모델 연결 문제를 파기 시작했다. 완전히 틀린 방향이었다. 실제 실행 기록 파일을 열어보니 딱 한 줄이 적혀 있었다. 스크립트가 120초 후 시간 초과됐다는 것이다. 모델과는 아무 상관이 없었다.

메시지를 만든 쪽이 스크립트 실패 전반에 같은 문구를 붙이고 있었던 것이다. 9번 원칙은 실패했다는 사실을 다음 판단에 정확히 전달하라는 것인데, 여기서는 실패 사실이 뭉개진 채 전달되면서 사람의 판단까지 틀어놨다.

이건 내 파이프라인에서 반복된 패턴이기도 하다. 그동안 겪은 문제 대부분이 요란한 고장이 아니라 조용한 실패였다. 저장이 안 됐는데 아무도 모르고, 수집이 실패했는데 어제 데이터로 그냥 돌아간다. 그래서 지금은 실패 메시지를 반드시 사람이 보는 화면에 올라오게 만들어뒀다.

같은 실수를 피하려면

업무 자동화 도구로 에이전트를 만들어보려는 사람이라면, 코드를 짜기 전에 아래 네 가지만 먼저 정해두길 권한다. 전부 내가 순서를 반대로 해서 대가를 치른 것들이다.

  • AI에게 실제로 전달되는 지시문을 눈으로 확인할 방법을 먼저 만든다. 화면에 보이는 설정과 실제 전달되는 내용은 다를 수 있다.
  • 한 번에 시키는 일의 크기를 제한한다. 3~10단계가 기준이다. “알아서 다 해줘”는 가장 비싼 지시다.
  • 되돌릴 수 없는 작업에는 사람의 승인을 정식 단계로 넣는다. 파일 삭제, 설정 변경, 외부 발송이 여기 해당한다.
  • 백업에서 뺀 것이 무엇인지 목록으로 적어둔다. 비밀 정보라 뺐다면, 그건 백업이 없다는 뜻이다.

마지막 항목은 지금 이렇게 해결했다. 설정 파일에서 비밀번호와 토큰만 가려낸 사본을 자동으로 만들어 버전 관리에 넣는다. 사고가 또 나도 값 두 개만 다시 채우면 30초면 돌아온다.

12-Factor Agents를 관통하는 생각은 하나다. 좋은 에이전트는 AI가 알아서 하는 시스템이 아니라, 사람이 짠 구조 안에서 AI가 정해진 자리에만 앉는 시스템이라는 것. 내 서버는 그 자리를 정해주지 않은 채로 일주일을 보냈고, 그 대가로 설정 파일 세 개와 아침 두 번을 잃었다. 지금은 15분마다 감시 스크립트가 돌고, 승인 없이 바뀐 파일은 격리된 뒤 되돌아온다. 에이전트에게 자유를 덜 준 만큼 아침이 조용해졌다.

Leave a Comment