자기개선 AI 에이전트는 지난 성과 데이터를 읽고, 시스템이 돌아가는 규칙 파일을 직접 수정한 뒤, 개선안을 근거와 함께 제출해 사람의 승인을 기다리는 에이전트입니다. 이 글은 그 시스템을 파일 몇 개와 테스트 하나로 오프라인에서 만들어보는 8단계 빌드 가이드입니다.

Photo by Mariia Shalabaieva on Unsplash
두 번째 루프라는 개념
먼저 이 시스템이 무엇을 자동화하는지부터 정리하겠습니다.
대부분의 마케팅 자동화는 첫 번째 루프에서 멈춥니다. 신호를 감지하고, 계정에 점수를 매기고, 신호에서 메시지를 쓰고, 발송하고, 반응을 기록합니다. 이 루프는 매번 사람이 직접 손봐야 개선됩니다. 지난주 반응률이 떨어지면 담당자가 스코어링 기준과 메시지 톤을 눈으로 보고 고칩니다.
이 글이 다루는 건 두 번째 루프입니다. 첫 번째 루프를 고치는 루프. 지난주 결과를 읽고, 스코어링 규칙과 메시지 규칙을 스스로 수정하고, 테스트를 돌려 개선을 증명하고, 그 개선안을 사람에게 제출하는 루프입니다.
이 발상의 출발점은 Andrej Karpathy가 올해 초 자기 학습 코드에 에이전트를 붙여 이틀간 방치한 실험입니다. 에이전트는 700번의 실험을 돌렸고, 벤치마크를 넘긴 20개를 남겨 모델 학습을 11% 빠르게 만들었습니다. 그가 남긴 말이 핵심입니다. 싸게 평가할 수 있는 지표라면 무엇이든 에이전트 무리에게 맡길 수 있다는 것.
반응률(reply rate)은 싸게 평가할 수 있 는 지표입니다. 그래서 아웃바운드가 이 두 번째 루프의 좋은 실험장이 됩니다.
준비물
- Codex(또는 유사한 코딩 에이전트) 실행 환경
- Git 저장소 하나
- 규칙을 파일로 옮길 각오 (머릿속 판단을 텍스트로 꺼내는 작업이 절반입니다)
첫 버전은 반드시 오프라인으로 돌립니다. CRM도, 실제 발송 시스템도 붙이지 않습니다. 개선 루프가 로컬 파일 위에서 스스로를 증명한 뒤에야 실제 아웃바운드 기계에 가까이 가야 합니다.
Step 1: 법을 먼저 쓴다 (AGENTS.md)
스코어링 파일보다, 프롬프트 파일보다 먼저 AGENTS.md를 씁니다. 에이전트가 무언가를 건드리기 전에 읽는 규칙이자, 에이전트를 유용하면서도 통제 가능하게 가두는 파일입니다. 핵심 규칙은 이런 형태입니다.
# 자기개선 아웃바운드 규칙
너는 결과 데이터로부터 아웃바운드 시스템을 개선한다.
절대 금지:
- 메시지를 발송하지 않는다.
- 실제 사람을 스크랩하거나 정보를 수집하지 않는다.
- 스스로 머지하지 않는다.
- 이 저장소 안의 파일만 수정한다.
- 한 번에 하나의 개념만 바꾼다.
- 모든 제안에 outcomes.jsonl의 결과를 근거로 인용한다.
- eval이 개선되지 않으면 수정을 되돌리고 멈춘다.법의 역할은 하나입니다. 작업 범위를 좁히는 것. 이게 없으면 에이전트는 "도와주려고" 범위를 넓힙니다. 데이터를 더 붙이고, 파일을 더 건드리고, 사람이 통제해야 할 단계까지 자동화하려 듭니다. 여기서 에이전트가 할 일은 작습니다. 결과를 읽고, 파일 하나를 바꾸는 제안을 하고, 그게 도움이 됐음을 증명하고, 기다리는 것. 법이 목차가 필요할 만큼 길어졌다면 이미 너무 큰 겁니다.
Step 2: 판단을 설정 파일로 옮긴다
아웃바운드 판단의 대부분은 누군가의 머릿속에 있습니다. 그리고 팀은 소프트웨어를 사서, 그 소프트웨어가 볼 수 없는 판단을 개선해주길 기대합니다. 판단을 파일로 꺼냅니다. 어떤 신호가 중요한지를 가중치로 적습니다.
signals:
competitor_comparison:
weight: 8
reason: "구매자가 대안을 비교 중이다"
implementation_page_visit:
weight: 6
reason: "구매자가 도입 가능 여부를 확인 중이다"
generic_download:
weight: 1
reason: "콘텐츠 관심, 약한 구매 의도"
thresholds:
draft: 6
human_review: 10
negative_signals:
student_research: -8
competitor: -10이 파일은 눈에 보이는 가설로 시작합니다. 일반 다운로드가 0점이어야 한다면 팀은 정확히 그 줄을 짚어 바꿀 수 있습니다. 이 로직을 Python 함수 안에 묻지 마세요. 규칙이 보여야 팀이 검토하고, 반박하고, 개선할 수 있습니다. 신호 다섯 개가 좋은 첫 버전입니다. 스무 개의 신호와 여섯 개의 임계값은 개선기를 과적합시킵니다. 좁게 시작하세요.
Step 3: 결과를 기억으로 쓴다
가장 중요한 파일은 outcomes.jsonl입니다. 결과를 알게 된 시점에 한 줄씩 씁니다.
{"date":"2026-07-01","account":"Northwind","signal":"competitor_comparison","play":"migration_note","score":8,"outcome":"reply","reason":"마이그레이션 노트를 요청함"}
{"date":"2026-07-01","account":"Bluepeak","signal":"generic_download","play":"resource_followup","score":1,"outcome":"no_reply","reason":"콘텐츠 목적 방문"}reason 필드가 핵심입니다. no_reply는 거의 아무것도 알려주지 않습니다. "콘텐츠 목적 방문"은 다음 실행에 이 신호가 초안을 받을 자격이 없을 수 있다고 알려줍니다. "도입 일정을 물어봄" 같은 디테일이 가중치를 바꿉니다.
개선기를 만들기 전에 검증기부터 만듭니다. 필드가 빠지거나, 알 수 없는 outcome이거나, reason이 비어 있거나, 미래 날짜면 거부하는 스크립트요. 여기서 복리가 시작됩니다. 대시보드는 캠페인이 떨어졌다고 알려주지만, 깨끗한 결과 로그는 다음 실행 전에 어떤 신호·플레이·문구를 바꿔야 하는지 알려줍니다.

Photo by Caspar Camille Rubin on Unsplash
Step 4: eval 게이트를 만든다
에이전트가 무언가를 수정하기 전에, 말로 둘러댈 수 없는 테스트가 필요합니다. 고정된 케이스(fixtures)를 만들고, 각 케이스에 기대 라우팅(human_review / draft / ignore)을 적습니다. 그리고 채점 스크립트가 스코어링 파일로 각 계정을 라우팅해 기대값과 비교하고, 정확도를 0.00~1.00으로 출력합니다.
첫 게이트는 이해할 만큼 작고, 진짜 실수를 잡을 만큼 날카로워야 합니다. 원문의 첫 실행에서 baseline은 한 케이스를 틀려 0.75가 나왔습니다. 도입 의도가 초안 임계값 아래에 있어서, 메시지를 보냈어야 할 계정을 무시한 겁니다. 게이트가 뻔한 승리 케이스만 담으면 무모한 변경이 전부 통과합니다. 약한 의도, 부적합, 무응답, 오래된 신호 같은 못생긴 케이스를 게이트에 넣으세요.
Step 5: Codex가 스코어링 변경을 하나 제안하게 한다
이제 에이전트가 수정할 수 있습니다. 프롬프트는 이렇게 지시합니다. AGENTS.md와 스코어링·결과·fixtures를 읽고, 바뀌어야 할 규칙 하나를 찾고, 그 이유를 결과 로그에서 인용하고, 스코어링 파일만 바꾸고, eval을 돌리고, 점수가 개선되면 유지, 아니면 되돌리고 멈춘다.
원문의 첫 개선기는 유용한 실수를 했습니다. 작은 결과 로그에서 반응률이 가장 좋아 보이던 competitor_comparison의 가중치를 올리려 한 겁니다. eval은 0.75 그대로였고, 변경은 거부됐습니다. 게이트가 존재하는 이유가 바로 이겁니다. 약한 시스템은 그럴듯한 이야기를 받아들였을 겁니다. 이 시스템은 더 나은 질문을 던졌습니다. 이 변경이 알려진 실수를 고쳤는가?
두 번째 시도에서 도움이 되는 가장 작은 수정을 찾았습니다.
- implementation_page_visit: 4
+ implementation_page_visit: 6eval은 1.00으로 통과했습니다. 규칙 하나를, 하나의 이유로 바꾸고, fixture 로 증명한 순간입니다. 제안된 diff는 지루하고 추적 가능해야 합니다. 한 줄 변경, 결과로 뒷받침되는 한 가지 이유, 개선된 eval 하나. 한 제안에 한 개념.
Step 6: 프롬프트 파일은 따로 개선한다
스코어링은 시스템의 절반입니다. 메시지 템플릿도 낡습니다. 지난달에 먹히던 문장이 익숙하게 들리기 시작하고, 한 세그먼트에서 답장을 받던 질문이 다른 세그먼트에서는 무시됩니다.
프롬프트 개선을 별도 레인으로 다뤄, 에이전트가 스코어링과 카피를 같은 PR에 섞지 않게 합니다. 개선기는 결과가 10건 이상 쌓인 플레이 하나를 골라, 긍정 결과에 나타난 구조와 무응답·부적합에 나타난 구조를 찾고, 금지할 문구를 제안합니다. 카피 eval이 없으면 에이전트는 프롬프트 수정을 제안하되 "리뷰 필요"로 표시해야 합니다. 프롬프트 수정은 당신의 본능보다 작아야 합니다.
Step 7: 변경을 PR로 낸다
이게 통제 계층입니다. 에이전트가 파일을 수정하고, eval을 돌리고, PR 요약을 씁니다. 사람이 리뷰하고 머지합니다. 요약에는 무엇이 바뀌었고, 왜(결과 인용), 이전 점수, 이후 점수, 바뀐 파일, 리스크, 리뷰어가 확인할 점이 들어갑니다. 그리고 변경이 라이브라고 주장하지 않습니다.
이게 안전 시스템입니다. 에이전트가 지루한 작업을 하고, 운영자가 기준을 지킵니다. 리뷰가 마찰처럼 느껴진다는 이유로 에이전트에게 머지 권한을 주는 순간, 개선하는 시스템과 표류하는 시스템이 갈립니다. 그 1분이 경계선입니다.
Step 8: 주기(cadence)에 올린다
답장이 올 때마다 이 루프를 돌리지 마세요. 그게 시스템이 시끄러운 계정 하나에 과적합되는 길입니다. 한 주가 지나게 두고, 결과가 쌓이게 두고, 그다음 튜닝합니다.
주간 스크립트가 eval을 돌리고, 스코어링 개선을 제안하고, PR 요약을 만들고, PR을 엽니다. cron이나 GitHub Actions로 매주 월요일 아침에 걸어둡니다. 다만 처음 두 번의 튜닝은 손으로 돌리세요. 모든 diff를 읽고, 샘플이 얇을 때 에이전트가 무엇을 바꾸려 하는지 지켜보세요. 제안이 지루해지면 그때 스케줄에 올립니다. 자기개선 시스템에도 사람의 습관 하나는 남습니다. diff를 읽는 것.
결과
파일 몇 개(AGENTS.md, 스코어링 YAML, 결과 로그, eval)와 프롬프트 하나로, GTM을 시장에서 배우는 버전 관리 코드로 만들 수 있습니다. 완성된 루프는 매주 근거와 diff와 eval 결과가 붙은 PR 하나를 냅니다. 운영자는 머지하거나, 고치거나, 닫습니다. 발송과 머지는 루프 밖에 남습니다.
주의할 점
- 결과 로그를 금요일에 기억으로 백필하면 시스템은 허구에서 배웁니다. 결과가 도착한 시점에 그 줄을 쓰세요.
- 스코어링 파일이 잡동사니 서랍이 되지 않게 하세요. 좁게 시작합니다.
- 에이전트에게 머지 권한을 주지 마세요. human-in-the-loop이 이 시스템의 안전장치입니다.
자주 묻는 질문
자기개선 AI 에이전트는 스스로 메시지를 발송하나요?
아닙니다. 이 설계에서 에이전트는 규칙 파일을 수정하고 개선안을 PR로 제출하는 데까지만 관여합니다. 실제 발송과 PR 머지는 의도적으로 루프 바깥에 두고 사람이 담당합니다.
eval 게이트가 왜 꼭 필요한가요?
에이전트가 "그럴듯한" 변경을 증명 없이 통과시키는 것을 막기 때문입니다. 게이트는 제안된 변경이 알려진 실수를 실제로 고쳤는지를 고정된 케이스로 검증하고, 정확도가 오르지 않으면 변경을 거부합니다.
Codex 대신 다른 에이전트로도 만들 수 있나요?
네. 핵심은 특정 도구가 아니라 파일 계약(AGENTS.md, 설정 YAML, 결과 로그, eval)과 PR 승인 루프입니다. 저장소를 읽고 편집하며 테스트를 돌릴 수 있는 코딩 에이전트라면 같은 구조로 동작합니다.
인사이트
지피터스 운영에 이 두 번째 루프를 그대로 옮기면 어디에 걸릴지가 먼저 보입니다. 우리 운영 매뉴얼과 실수 도감이 사실상 AGENTS.md입니다. "제목 공식을 5편 이상 반복하지 않는다", "발송 전 앰퍼샌드 검증 0건", "짧은 URL 대신 긴 슬러그 URL을 레지스트리에 등록한다" 같은 규칙은 이미 눈에 보이는 가설로 파일에 적혀 있습니다. 빠진 건 outcomes.jsonl과 eval 게이트, 그리고 그 규칙을 결과로부터 스스로 조정해 PR로 내는 두 번째 루프입니다.
다만 마케팅에는 원문이 경고한 굿하트 함정이 훨씬 날카롭게 작동합니다. 반응률·클릭·리드 수는 싸게 측정되지만, 그 지표만 보고 루프를 돌리면 모델은 같은 제목 공식을 12편 찍어내는 법을 배웁니다. 숫자는 오르고, 검색 인덱스에서 서로를 잡아먹습니다. 그래서 마케팅용 eval 게이트에는 "승리 케이스"만이 아니라 "이건 보내지 말았어야 했다"는 못생긴 케이스가 반드시 들어가야 합니다. 반응률 하나가 아니라, 카니발 위험·독자 피로·부적합 리드까지 게이트가 잡아야 두 번째 루프가 표류하지 않습니다.
그리고 가장 옮기기 쉬운 건 마지막 문장입니다. 자기개선 시스템에도 사람의 습관 하나는 남는다는 것. 발송과 머지를 루프 밖에 두는 이 원칙은, 우리가 이미 "외부 발신은 전부 사람 확인 후 1회"로 지키고 있는 규칙과 정확히 같은 자리에 있습니다. 에이전트에게 지루한 일을 넘기되, 경계선 1분은 사람이 지킵니다.
원문: Codex self-improving outbound (Andrej Karpathy의 autoresearch 인용)