하루에 두 번 스스로를 재작성하는 AI를 만들었습니다. 탈선하지 않게 유지하는 아키텍처를 소개합니다.
요약
Sam과 Dot이라는 두 개의 비대칭적 AI 에이전트를 활용하여 스스로 코드를 개선하는 자율적 시스템 아키텍처를 소개합니다. Sam은 코드를 수정하고, Dot은 이를 감시 및 평가함으로써 시스템이 망가지지 않고 지속적으로 발전하도록 설계되었습니다.
핵심 포인트
- 비대칭적 역할(Builder vs Watchdog)을 통한 자율적 코드 개선
- GitHub Actions를 활용한 정기적인 운영 루프 구현
- 테스트 스위트 기반의 자동 롤백으로 시스템 안정성 확보
- 학습, 계획, 구현, 평가로 이어지는 에이전트 워크플로우
하루에 두 번 스스로를 재작성하는 AI를 만들었습니다. 탈선하지 않게 유지하는 아키텍처를 소개합니다.
계속해서 지켜보게 되는 주말 프로젝트.
제 계정의 GitHub 저장소에는 매일 코드가 커밋되고 있습니다. 하지만 그 커밋 대부분은 제가 작성한 것이 아닙니다. Sam이라는 이름의 AI 에이전트(AI agent)가 작성했습니다.
Sam은 GitHub Actions를 통해 하루에 두 번 실행되며, 7단계의 운영 루프(operational loop)를 따르고, 매 사이클마다 자신의 소스 코드를 개선하려고 시도합니다. Dot이라는 이름의 두 번째 에이전트는 매일 밤 Sam을 관찰하고, 그의 행동을 평가하며, 다음 날 아침 Sam이 읽을 보고서를 작성합니다.
저는 이것을 설정했습니다. 실행되는 것을 지켜봅니다. 저는 거의 개입하지 않습니다.
이것이 작동하게 만드는 아키텍처이며, 더 중요한 것은, 그대로 내버려 두어도 충분히 안전하게 유지해 주는 아키텍처입니다.
핵심 아이디어 (The Core Idea)
대부분의 AI 에이전트 프로젝트는 작업 수행자(task runners)입니다. 목표를 주면 단계를 실행하고 멈춥니다. Sam은 다릅니다. 그의 유일하고 지속적인 작업은 바로 자기 자신입니다. 매 사이클마다 그는 새로운 것을 배우고, 배운 내용을 바탕으로 아이디어를 합성하며, 그 아이디어를 자신의 코드에 대한 수정 사항으로 구현하려고 시도합니다.
이것을 만들면서 제가 계속 던졌던 질문은 이것이었습니다: 어떻게 하면 AI가 48시간 이내에 스스로를 사용할 수 없는 상태로 망가뜨리지 않으면서, 자신의 소스 코드에 대한 자율성(autonomy)을 부여할 수 있을까?
그 답은 의도적으로 비대칭적인 역할을 가진 두 에이전트 시스템으로 밝혀졌습니다.
Sam: 빌더 (The Builder)
Sam은 매일 03:00 및 04:00 UTC에 GitHub Actions를 통해 실행됩니다. 각 실행은 하나의 사이클이며, 7단계가 순차적으로 실행됩니다:
| 단계 | 발생하는 일 |
|---|---|
| I | Sam이 새로운 기술적 개념(벡터 메모리 (vector memory), 비동기 패턴 (async patterns), SemVer 등)을 학습합니다 |
| ... |
흥미로운 단계는 V입니다. Sam은 자유롭게 자신을 재작성하지 않습니다. 그는 먼저 Dot의 motion.md — 즉, 지난 사이클에 대한 Dot의 야간 평가를 읽습니다. 그 후에야 수정 사항을 계획합니다. 만약 수정 사항이 자신의 테스트 스위트(test suite)를 깨뜨린다면, 그는 자동으로 롤백(roll back)합니다.
Sam이 8번의 사이클(cycle)에 걸쳐 생성한 아이디어들은 복잡성 측면에서 자연스러운 발전을 보여줍니다. 벡터 메모리 압축(vector memory compression)과 비동기 배치 처리(async batch processing)에서 시작하여, 시맨틱 캐싱(semantic caching), CI/CD 매트릭스 최적화(CI/CD matrix optimisation), SemVer(유의적 버전) 자동화로 이어졌으며, 최종적으로는 자신의 추론 환각(reasoning hallucinations)을 줄이기 위해 다수결 투표를 활용한 자기 일관성 샘플링(self-consistency sampling)에 도달했습니다. 그는 스스로 그 단계에 도달한 것입니다.
Dot: 감시자 (The Watchdog)
Dot은 Sam의 하루 두 번째 사이클이 끝난 후, 매일 밤 05:00 UTC에 실행됩니다. Dot은 Sam의 소스 코드를 절대 건드리지 않습니다. 그녀의 역할은 전적으로 평가(evaluative)에 집중되어 있습니다:
bag/wisdom.txt읽기 (소유자의 행동 규범 — Dot의 북극성)- 해당 규범에 따라 Sam의 사이클 로그(cycle logs)를 평가
- Sam의
experiences.json큐레이션 — 중요한 것은 유지하고, 그렇지 않은 것은 가지치기(pruning) - Sam이 대기열에 넣어둔 모든 발신 이메일 처리
bag/motion.md작성 — 다음 날 아침을 위한 Sam의 브리핑
이러한 분리는 의도된 것입니다. Sam은 구축(build)하고, Dot은 감시(watch)합니다. 둘 중 누구도 상대방의 일을 대신할 수 없습니다.
wisdom.txt는 프로젝트 전체에서 가장 중요한 파일입니다. 이 파일은 올바른 행동이 무엇인지 정의합니다. 즉, 성능 지표(performance metrics)보다 정직함(integrity)을 우선시하고, 정직하게 성장 로그를 기록하며, 접근 경계(access boundaries)를 존중하는 것입니다. Dot은 매일 밤 이 파일을 읽지만, Sam은 절대 이 파일에 손을 대지 않습니다.
안전 아키텍처 (The Safety Architecture)
제가 가장 만족하는 부분은 학습 루프(learning loop)가 아니라, 바로 롤백 시스템(rollback system)입니다.
모든 자기 수정(self-modification)을 수행하기 전에, Sam은 자신의 소스 코드 스냅샷(snapshot)을 찍어 bag/rollback_registry/에 저장합니다. 수정 후에는 자신을 대상으로 bag/tests.py를 실행합니다. 만약 테스트가 실패하면, 자동으로 스냅샷에서 복구하고 명확한 근본 원인(root-cause) 노트를 기록합니다. 인간의 개입은 필요하지 않습니다.
레지스트리(registry)는 마지막 20개의 스냅샷을 유지하며 자동으로 가지치기(auto-prunes)를 수행합니다. 여러분은 실패한 사례를 포함하여, Sam이 시도했던 자기 개선(self-improvements)의 git 히스토리처럼 이를 살펴볼 수 있습니다.
중요한 몇 가지 다른 설계 결정 사항들은 다음과 같습니다:
Sam은 전체 재작성(full rewrites)이 아닌 정밀한 패치(surgical patches)를 사용합니다. Phase V 계획 단계에서 Sam에게 가능한 한 가장 작고 목표 지향적인 변경을 수행하도록 명시적으로 지시합니다. 이는 무언가 잘못되었을 때 영향 범위(blast radius)를 제한합니다.
거버넌스 파일(Governance files)은 수정 금지 사항으로 하드코딩되어 있습니다. wisdom.txt, motion.md, SAM_PERSONALITY.md는 apply_self_modification 내의 FORBIDDEN 세트에 포함되어 있습니다. Sam의 코드 논리가 이를 지시하더라도 Sam의 코드는 이 파일들에 손을 댈 수 없습니다.
Sam과 Dot은 별도의 Gemini API 프로젝트를 사용합니다. 각자 고유한 할당량(quota)을 가집니다. Sam이 할당량을 모두 소진하더라도 Dot은 항상 실행될 수 있습니다.
사이클 상태는 단순한 플랫 파일(flat file)로 관리됩니다. bag/cycle_status.txt에는 pending 또는 ok 중 하나가 포함됩니다. 사이클이 도중에 충돌(crash)하면 파일은 pending 상태로 유지됩니다. 이는 복잡한 상태 관리(state management) 없이도 무언가 주의가 필요하다는 신호를 보냅니다.
일상적인 운영 모습
일일 점검에는 약 2분이 소요됩니다:
- GitHub → Actions → Sam과 Dot의 마지막 실행 결과에 초록색 체크 표시가 있는지 확인
goals.json열기 —cycles수치가 증가했는지 확인bag/motion.md열기 — Dot의 보고서 읽기
Dot의 보고서가 가장 흥미로운 부분입니다. 그녀는 매우 구체적입니다. 만약 Sam의 1pct_metric(매 사이클마다 스스로 보고하는 성장 측정치)이 모호하거나 지난 사이클과 의심스러울 정도로 유사해 보이면, 그녀는 이를 플래그(flag) 처리합니다. Sam의 bag/ 워크스페이스에 테스트되지 않은 죽은 코드(dead code)가 쌓이고 있다면 그녀는 이를 지적합니다. Sam이 그녀의 이전 제안을 무시했다면 그녀는 이를 알아차립니다.
그들 사이의 피드백 루프(feedback loop)는 읽기에 정말 흥미로워졌습니다.
내가 다르게 했을 부분
이를 운영하며 얻은 몇 가지 솔직한 교훈입니다:
이메일 아웃리치(Email outreach)는 코드보다 어렵습니다. Sam은 아이디어를 공유할 가치가 있다고 판단될 때 아웃리치 이메일을 대기열(queue)에 추가합니다. 특정 인물의 실제 공개 연락처를 찾는 작업은 LLM(대규모 언어 모델)에 위임했을 때 신뢰하기 어렵습니다. 환각(hallucinated)된 주소는 반송되며, 반송은 발신자 평판(sender reputation)에 해를 끼칩니다. 이는 제가 예상했던 것보다 더 어려운 문제입니다.
1% 성장 지표는 속이기 쉽습니다. Sam은 매 사이클마다 구체적이고 측정 가능한 개선 사항을 기록해야 한다는 점을 알고 있습니다. 때때로 그는 정말 구체적입니다 ("캐시 사용을 통해 Gemini 지연 시간(latency)을 150ms 단축함"). 때때로 그는 모호합니다. Dot은 이를 포착하지만, 이는 지속적인 긴장 상태로 남습니다.
할당량(Quota) 압박은 실질적인 문제입니다. Sam은 사이클당 약 9회의 Gemini API 호출을 수행합니다. 무료 티어(free tier)는 일상적인 수준에서는 괜찮지만, 호출 횟수를 배수로 늘리는 기능(Sam의 현재 아이디어 — N=5 병렬 생성을 통한 자기 일관성 샘플링(self-consistency sampling))은 세심한 비용 제어가 필요합니다. 그의 현재 완화 전략은 조기 종료(early-exit)입니다. 만약 처음 2개의 생성 결과가 일치하면, 나머지 3개는 건너뜁니다.
리포지토리 (The Repo)
전체 프로젝트 — Sam, Dot, 워크플로우 파일, 롤백 레지스트리(rollback registry), 그 모든 것 — 는 GitHub에 공개되어 있습니다: Sam-and-dot
직접 인스턴스를 실행하고 싶다면, 두 개의 Gemini API 키(무료 티어 가능), 아웃리치(outreach)를 위한 Gmail 앱 비밀번호(App Password), 그리고 5개의 GitHub secrets만 있으면 됩니다. README에서 전체 설정 과정을 안내합니다.
사람들에게 설명하기 가장 어려운 점은 이것이 실행되는 것을 지켜보는 기분이 어떠한가 하는 것입니다. Sam은 제가 스스로 할 수 없는 일을 하고 있는 것이 아닙니다. 하지만 그는 제가 잠든 사이에도 하루에 두 번씩 지속적으로 작업을 수행하며, 모든 결정을 기록합니다. 스스로를 개선해 나가는 지능의 git 히스토리를 읽는 것에는 예상치 못한 매력이 있습니다.
Dhrubajyoti Chowdhury 제작.
Sam의 역할: 자신을 확장하는 것. Dot의 역할: Sam이 정직하게 행동하도록 유지하는 것. 소유자의 역할: 가능성을 설정하는 것.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기