Image: AI generated
AI 에이전트에게 큰 작업을 맡겨 본 사람은 안다. 루프가 무너지는 지점은 늘 같다. 모델이 스스로 “다 했습니다"라고 선언하는 순간이다. 실제로는 안 끝났는데.
reins는 그 완료 선언 권한을 AI에게서 빼앗아 기계에게 넘긴 퀘스트 CLI 프레임워크다. 작업 목록을 게임의 퀘스트처럼 항목 하나하나로 쪼개고, AI에게 하나씩 시키고, “끝났는가"는 AI의 말이 아니라 기계 검사로 판정한다. 그리고 그 심장에는 턴(turn) 이라는 작은 단위가 있다.
본문에 계속 나올 말 두 개만 먼저 챙기자.
- 게이트(gate) — 제출물을 기계적으로 검사해서 통과(PASS)/탈락(FAIL)을 판정하는 검사기. 사람의 인상평도, AI의 자기평가도 아니다.
- 래칫(ratchet) — 한 방향으로만 도는 톱니바퀴. 한 번 통과로 잠긴 항목은 다시 열리지 않는다는 뜻으로 쓴다.
이 글은 턴 하나가 실제로 어떤 과정을 거치는지를 처음부터 끝까지 따라간다. 턴은 작아 보이지만, 뜯어 보면 reins 전체의 축소판이다.
Reins Engineering 핵심 6요소
reins가 서 있는 공학을 한 줄로 줄이면 이렇다 — 완료 선언 권한을 AI에게서 결정론적 기계 게이트로 옮기는 공학. 여기서 “결정론적"은 어려운 말이 아니다. 같은 입력이면 언제나 같은 결과가 나온다는 뜻이다. 테스트는 통과 아니면 실패고, 어제와 오늘의 판정이 기분에 따라 달라지지 않는다.
프롬프트 엔지니어링(말을 고르는 일) → 컨텍스트 엔지니어링(맥락을 주는 일) → 하네스 엔지니어링(울타리를 치는 일)의 계보에서, Reins는 방향을 잡는 고삐다. 이 공학은 여섯 개의 요소로 조립된다.
| # | 요소 | 한 줄 | 정본 문장 |
|---|---|---|---|
| 1 | 기계 판정 완료 | 완료조건은 기계가 yes/no로 답할 수 있어야 하고, 판정도 기계가 한다 — AI의 종료 판단권 박탈 | “완료는 주장이 아니라 게이트가 판정한다” |
| 2 | 결정론적 피드백 | 의견이 아니라 사실 — “어디가, 무엇이어야 하는데, 실제로 무엇이었다"가 수정 방향을 알려주는 신호가 된다 | “의견을 주면 아첨하고, 사실을 주면 수정한다” |
| 3 | 방향 컨텍스트 (매뉴얼 + 예시) | 피드백이 교정 신호라면 매뉴얼·예시는 방향 신호 — 하나가 다른 하나를 대신하지 못한다 | “병목은 지능이 아니라 컨텍스트다” |
| 4 | Ratchet Pattern (계약 잠금) | 통과한 항목은 불변, 남은 작업량은 줄기만 한다 — 끝나는 것이 구조로 보장된다 | remaining(t+1) ≤ remaining(t) |
| 5 | 진행 영속 | 진행상태는 프로세스 밖(디스크)에 산다 — AI가 죽어도 진척은 남는다 | “Agents are disposable; progress is cumulative.” |
| 6 | 치즈 방어 (도메인 게이트) | 기계 검사여도 껍데기만 보면 꼼수에 뚫린다 — 게이트는 그 도메인의 진짜 사실을 재검증해야 한다 | “게이트는 도메인을 가진다” |
표의 용어가 아직 낯설어도 괜찮다. 턴은 이 여섯이 한 사이클 안에서 만나는 최소 단위라서, 턴 하나를 끝까지 따라가면 여섯 요소가 전부 제자리에서 만난다. 미리 지도만 그려 두면 — 턴의 첫 단계인 compose가 방향 컨텍스트와 결정론적 피드백을 조립하고, judge가 기계 판정을 내리고(치즈 방어는 이 게이트의 설계 품질이다), record가 래칫을 잠그고 진행을 영속화한다.
Reins Turn이란 무엇인가?
Reins Turn은 퀘스트 항목 하나에 대한 시도 한 번이 생성 → 판정 → 기록으로 종결되는, reins의 최소 실행 단위다. 루프는 턴의 반복일 뿐이고, 퀘스트의 진척은 턴의 누적일 뿐이다. 그래서 정의는 한 줄이면 된다.
Turn N = N번째로 기록된 Attempt. 기록되지 않은 것은 턴이 아니다.
Attempt는 “시도 기록 한 건"이다. 여기서 미묘한 점 하나 — 턴은 “LLM을 한 번 불렀다"가 아니다. 턴의 존재 조건은 호출이 아니라 기록이다. LLM을 호출했어도 그 결과가 래칫에 기록되지 않았으면 그 턴은 없었던 것이다. 반대로 사람이 손으로 제출한 결과라도 기록되면 그것은 턴이다. LLM 없이도. 턴을 세는 자는 모델이 아니라 래칫이다.
이 정의 하나가 뒤에 나올 모든 성질 — 드라이버 무관성, 재시작 내성, 감사 가능성 — 의 뿌리다. 지금은 이름만 스쳐 가자. 하나씩 제자리에서 다시 만난다.
한 턴은 정확히 네 단계다
턴 하나는 네 단계를 차례로 지난다. 각 단계의 이름은 영어지만 하는 일은 단순하다 — 조립하고(compose), 생성하고(generate), 판정하고(judge), 기록한다(record).
| 단계 | 하는 일 | 성질 |
|---|---|---|
| ① compose | 직전 턴까지의 기록(Log)을 읽어 LLM에게 줄 프롬프트를 조립 | 순수 함수 |
| ② generate | LLM을 한 번 호출해 결과물을 생성 | 유일한 확률 단계 |
| ③ judge | 게이트가 결과물을 판정 (PASS / REVIEW / FAIL) | 결정론 |
| ④ record | 판정을 래칫에 적용하고 디스크에 저장 | 유일한 비가역 단계 |
“순수 함수"는 같은 입력이면 항상 같은 출력이 나오고 다른 부수효과가 없다는 뜻이고, “비가역"은 한 번 실행되면 되돌릴 수 없다는 뜻이다. 그러면 표의 핵심이 보인다 — 네 단계 중 확률적인 것은 ②뿐이고, 비가역적인 것은 ④뿐이다. 생성은 판정하지 못하고, 판정은 생성하지 못한다. AI의 불확실성은 한 칸에 가두고, 되돌릴 수 없는 결정은 다른 한 칸에 가둔 것이다.
한 가지 특이한 설계도 짚어 두자. 이 네 단계 캐스케이드는 Go 코드 두 벌로 구현되어 있지 않다. pkg/cli/turn.md라는 사람이 읽을 수 있는 문서 하나(TANGEUL 문서)로 정의되어 있고, 이 문서가 바이너리에 내장되어(go:embed) 런타임에 해석된다. “턴이 어떻게 도는가"의 정본이 코드가 아니라 읽을 수 있는 문서라는 뜻이다 — 이 선택의 이유는 글 끝에서 돌아온다.
① compose — 컨텍스트는 Log에서만 온다
Log는 지금까지의 모든 턴이 기록된, 디스크에 남는 장부다. 그리고 턴 N의 프롬프트를 조립하는 입력은 딱 하나, 이 Log뿐이다. 프로그램 메모리 어딘가에 숨어 있다가 프로세스가 죽으면 사라지는 상태 — 그런 것은 존재하지 않는다.
Log에서 조립되는 프롬프트는 세 겹이다.
- 해야 할 일 — 이 항목에서 무엇을 만들어야 하는지 (작성 지시와 검증 컨텍스트)
- 매뉴얼 — 전역 시스템 프롬프트에, 직전 턴이 FAIL이었다면 그 실패 원인 규칙에 해당하는 코칭(규칙별 매뉴얼)을 더한 것
- 피드백 꼬리 — 직전 FAIL의 사실들. “어디가, 무엇이어야 하는데, 실제로 무엇이었다”
앞의 6요소로 말하면, 매뉴얼이 방향 컨텍스트고 피드백 꼬리가 결정론적 피드백이다. 이 둘이 매 턴 Log에서 기계적으로 조립된다.
미묘하지만 중요한 규칙이 하나 있다. compose가 기준으로 삼는 것은 마지막 Attempt가 아니라 마지막 판정까지 끝난(judged) Attempt다. 중간에 LLM 서버 장애 같은 생성 에러가 끼어 있어도, 재시도가 보는 것은 인프라 에러 메시지가 아니라 직전 FAIL의 사실 피드백이다. 운영 장애가 작업의 컨텍스트를 오염시키지 않는다.
② generate — LLM은 생성만 한다
조립된 프롬프트로 LLM 백엔드를 한 번 호출한다. 백엔드가 HTTP API(ollama/xai/gemini)든 명령줄 도구(claude/grok/codex/geminicli)든 상관없다. 어느 쪽이든 역할은 생성기로 고정이다. 프레임워크는 LLM에게 PASS 권한을 줄 수 있는 API 자체를 노출하지 않는다. 판정 권한을 “주지 않기로 한” 것이 아니라, 줄 방법이 없다. 이것이 6요소의 1번(기계 판정 완료)이 구조가 되는 방식이다.
어느 백엔드를 쓸지조차 턴마다 Log에서 다시 계산된다. 기본 모델로 계속 실패하는 항목은 더 강한 모델로 올려 보내는데(에스컬레이션), 이 결정도 “과거 FAIL의 원인 규칙 중 에스컬레이션 대상이 있는가?“를 매 턴 Log에서 읽어 내린다. 어딘가에 켜져 있는 스위치도, 루프 안의 지역 변수도 없다. 같은 프로그램에 같은 Log면 같은 백엔드가 선택된다. 프로세스를 죽였다 다시 켜도 똑같이 동작하는 성질 — 재시작 내성이 공짜로 따라온다.
③ judge — 게이트만이 판정한다
결과물을 판정하는 것은 게이트다. 게이트는 위반 탐지 규칙의 집합이다. 각 규칙은 자기가 맡은 문제를 발견하면 발화(fire)하고, 사실 하나를 남긴다 — 어디가(Where), 무엇이어야 하는데(Expected), 실제로 무엇이었다(Actual).
집계는 결정론이다. Fail 규칙이 하나라도 발화하면 FAIL. 아니고 Review 규칙이 발화하면 REVIEW(사람이 확인할 회색지대). 아무것도 발화하지 않으면 PASS. 같은 제출물에 같은 규칙이면 항상 같은 판정이다. 물어볼 때마다 답이 달라지는 검사자는 여기 없다.
규칙끼리 서로 얽히는 복잡한 도메인 — 한 위반이 다른 검사를 무의미하게 만드는 경우 — 에서는 판정을 논증 그래프(toulmin) 기반으로 올리고, 판정 로직 자체를 감사 가능한 문서(gate.md)로 옮길 수도 있다. 어느 형태든 변하지 않는 것은 하나다. 판정 주체는 기계다.
④ record — 유일한 비가역 단계
판정을 래칫에 적용하고, 디스크에 저장하고, 종결된 항목을 내보낸다(export). 여기가 턴에서 유일하게 되돌릴 수 없는 지점이다.
- PASS / REVIEW / SKIPPED / BLOCKED → 잠금. 래칫은 일방향이라 되돌아가지 않는다.
- FAIL → 시도 횟수(
Tries)가 1 늘고 항목은 할 일(TODO)로 남는다. 최대 시도(기본 3회)에 도달하면 DONE으로 잠근다. “이 항목은 이 방식으로는 안 된다"도 종결의 한 형태다 — 안 되는 항목 하나가 루프 전체를 영원히 붙잡게 두지 않는다. - 생성 에러 → Log에 Attempt로 기록은 되지만(무슨 일이 있었는지 추적은 남긴다) 시도 횟수를 소모하지 않는다. LLM 서버가 죽은 것은 항목의 잘못이 아니라 운영 장애이기 때문이다. 장애가 계속되면 별도의 안전장치(연속 N회 생성 실패 시 루프 중단, 서킷 브레이커)가 멈춘다.
이 단계가 있어야 다음 턴의 compose가 읽을 Log가 생긴다. record는 턴의 마무리이자 다음 턴의 생성자다.
실패는 의견이 아니라 팩트다
FAIL이 어떤 모양으로 돌아오는가 — 이것이 턴이 수렴하는(재시도할수록 정답에 가까워지는) 열쇠다. “품질이 아쉽네요” 같은 의견이 아니라 이런 것이다.
FAIL. root cause = who-anchor-present
Fact: where=who.anchors expected="source substring" actual="김찬호 대리"
읽는 법은 간단하다. 어느 필드가(where), 무엇이어야 하는데(expected — 원문에 실제로 있는 문자열), 실제로 무엇이었다(actual). 위치 + 기대값 + 실제값. LLM에게는 아첨할 대상이 없는 피드백이다 — 숫자와 위치는 감정이 아니기 때문이다. 아첨하는 모델을 논쟁이 아니라 수렴으로 이끄는 것이 이 구조화된 팩트다.
덤으로 하나 더. 모델에게 먹이는 FAIL 텍스트는 사람이 submit 명령을 쳤을 때 화면에 출력되는 문자열과 완전히 동일한 렌더링이다(feedback parity). 사람이 보는 피드백과 모델이 보는 피드백이 절대 어긋나지 않는다. “AI한테는 뭐라고 갔길래 이렇게 고쳤지?“라는 미스터리가 구조적으로 없다.
세 개의 진입점, 하나의 턴
턴을 굴리는 운전자를 드라이버라 부르자. reins에는 드라이버가 셋 있다. 사람이 직접 프롬프트를 받아 보는 next, 사람이 결과를 제출하는 submit, 무인으로 도는 자동 loop. 그런데 이 셋은 서로 다른 세 구현이 아니다. 같은 턴 문서로 들어가는 세 개의 진입점이다. 수동과 자동을 가르는 것은 문서 안의 규칙 딱 하나다.
이것이 주는 실전 성질은 이렇다. 퀘스트 중간에 드라이버를 바꿔도 프롬프트가 바이트 단위로 동일하다. 어제는 자동 loop로 돌리다가 오늘은 사람이 next로 이어받아도, 같은 Log 상태면 같은 프롬프트가 나온다. 컨텍스트가 Log에서만 오기 때문에 가능한 일이고(①단계에서 봤다), 기대가 아니라 증명된 성질이다 — 드라이버를 바꿔 가며 출력을 비교하는 테스트(driver-swap golden test)가 바이트 동일성을 검증한다.
턴 하나를 끝까지 따라가 보기
이론은 끝났다. 실제 턴 하나를 처음부터 끝까지 보자. 문서에서 이메일 주소를 추출하는 퀘스트의 항목 하나이고, 직전 턴이 “이메일 형식이 아니다"로 FAIL이었던 두 번째 시도다.
[턴 시작 판정] 항목이 TODO인가? 시도가 남았는가? → 진행
① compose Log에서 마지막 judged Attempt를 찾음 → FAIL, 원인 = email-format
매뉴얼 = 전역 프롬프트 + email-format 규칙의 코칭
프롬프트 = 해야 할 일 + "FAIL. Fact: where=email
expected='valid email format' actual='kim at example'"
② generate LLM 호출 → {"email":"kim@example.com", ...}
③ judge 규칙 순회: email-format 통과, source-lacks-email 통과, freemail 통과
→ 발화한 Fail 규칙 없음 → PASS
④ record 래칫 잠금(비가역) → Attempt #2 기록 → 저장 → export
직전 실패의 사실(“kim at example은 유효한 이메일 형식이 아니다”)을 받은 모델이 정확히 그 지점을 고쳤고, 게이트가 통과를 확인했고, 래칫이 잠갔다. 이제 이 항목은 영원히 PASS다. 다음 턴은 이 항목을 건너뛰고, 남은 작업량은 줄기만 한다. 모든 항목이 종결 상태(PASS든, REVIEW든, 최대 시도 도달이든)가 되면 루프가 끝난다. “AI가 끝났다고 느끼면"이 아니라 남은 항목이 0이 되면 끝난다. 수렴이 구조로 보장된다.
Loop Engineering — 업계가 같은 문제에 이름을 붙였다
2026년 6월, 에이전트를 다루는 방식의 전환에 이름 하나가 붙었다. Peter Steinberger가 “You shouldn’t be prompting coding agents anymore. You should be designing loops that prompt your agents”(더는 코딩 에이전트에게 프롬프트를 치지 마라. 에이전트를 프롬프트하는 루프를 설계하라)라고 썼고, 같은 달 초 Claude Code를 만든 Anthropic의 Boris Cherny는 한 행사에서 “I don’t prompt Claude anymore. I have loops running… My job is to write loops”(나는 더 이상 Claude에게 프롬프트하지 않는다. 루프들이 돌고 있다. 내 일은 루프를 쓰는 것이다)라고 말했다. 며칠 뒤 Google의 Addy Osmani가 이 흐름에 Loop Engineering이라는 이름을 붙였다 — 에이전트에게 프롬프트를 치는 사람에서, 에이전트를 프롬프트하는 시스템을 설계하는 사람으로.
이 담론은 하나의 이행 서사를 그린다. 프롬프트 엔지니어링(말을 고르는 일) → 컨텍스트 엔지니어링(보여줄 정보를 고르는 일) → 하네스 엔지니어링(실행 환경을 만드는 일) → 루프 엔지니어링(관찰·행동·검증·복구의 사이클 자체를 설계하는 일). 레버리지가 단어에서 정보로, 정보에서 환경으로, 환경에서 사이클로 한 겹씩 바깥으로 이동해 온 것이다.
Osmani가 제시한 좋은 루프의 해부는, 여기까지 읽은 독자에게는 낯설지 않을 것이다. 상태를 대화가 아니라 디스크나 보드에 외부화하라. 만드는 에이전트와 검증하는 에이전트를 분리하라. 종료는 코딩 에이전트의 자기 선언이 아니라 별도 판정자가 확인하게 하라. 턴과 나란히 놓으면 대응이 선명하다.
| Loop Engineering의 권고 | reins 턴의 구조화 |
|---|---|
| 상태를 디스크·보드에 외부화하라 (모델은 잊는다) | Log는 기억 보조가 아니라 턴의 유일한 입력 — compose는 Log의 순수 함수 |
| 만드는 자와 검증하는 자를 분리하라 (서브에이전트) | 검증자가 또 다른 LLM이 아니라 결정론 게이트 — PASS 권한 API 자체가 없다 |
| 테스트 가능한 종료 조건을 정의하라 | 래칫의 단조성이 수렴을 불변식으로 보장 — 조건이 아니라 구조 |
| 복구 가능한 실패와 치명적 실패를 구분하라 | record 규칙에 내장 — FAIL은 시도 소모, 생성 에러는 서킷 브레이커 몫 |
차이의 핵심은 권고와 구조의 거리다. 루프 엔지니어링 문헌 스스로도 검증의 위계를 인정한다 — AI에게 판정을 맡기는 LLM-as-judge는 “속거나 행위자와 담합할 수 있으므로”(can be gamed or can collude with the actor) 결정론 검사가 가능한 곳엔 반드시 결정론 검사를 넣으라고. 그러나 그것은 모범 사례, 즉 설계자의 선의에 맡겨진 권고로 남는다. 검증자 서브에이전트도 결국 LLM이라면 담합의 문은 열려 있다. reins는 그 문을 설계로 닫는다. 판정은 게이트만 하고, 프레임워크는 LLM에게 PASS를 줄 방법 자체를 노출하지 않는다.
그리고 루프 엔지니어링이 루프 전체를 말할 때, reins는 그 루프의 한 바퀴를 계약으로 만든다. “내 일은 루프를 쓰는 것"이라는 Cherny의 말에서 한 발 더 나아가려면, 루프가 무엇을 한 번 도는 것인지 — 무엇이 확률이고 무엇이 결정론이며 무엇이 비가역인지 — 가 먼저 정의되어야 한다. 그 정의의 이름이 턴이다.
왜 이 단위인가
턴을 이렇게 조이면 세 가지를 얻는다. 앞에서 스쳐 간 이름들이 여기서 제자리를 찾는다.
- 감사 가능성 — “자동 loop는 수동 next와 뭐가 다른가?“의 답이 코드 두 벌을 비교하는 일이 아니라 문서 속 규칙 한 줄이다. PASS를 잠글 수 있는 경로가 문서에 정확히 하나뿐임을 눈으로 확인할 수 있다. 턴의 정본을 코드가 아니라 읽을 수 있는 문서로 둔 이유가 이것이다.
- 재시작 내성 — 턴의 모든 입력이 디스크의 Log에서 파생되므로, 프로세스가 죽어도 같은 Log에서 같은 턴이 재현된다.
- 에이전트 일회용화 — 에이전트(LLM·드라이버)는 갈아끼워도 진척은 누적되고 되돌아가지 않는다. “Agents are disposable; progress is cumulative.”
거꾸로 말하면, 턴이 흐릿한 시스템 — 컨텍스트가 세션 메모리에 숨고, 완료를 모델이 자기 선언하고, 재시도가 대화 히스토리에 기대는 시스템 — 은 이 셋을 전부 잃는다.
턴은 작아 보인다. 그러나 생성(확률)과 판정(결정론)과 기록(비가역)을 한 사이클 안에서 분리하고 직렬화하는 최소 단위라는 점에서, 턴을 이해하면 reins 전체를 이해한 것이다.
관련 글
- reins — 퀘스트 CLI에서 도메인만 남기고, 래칫은 프레임워크로 — 이 글의 주인공인 프레임워크 본편.
- Ratchet Pattern — 에이전트가 끝까지 가게 만드는 방법 — 계약 잠금(6요소의 4번)의 본편.
- 퀘스트 CLI 만드는 법 — 완료를 기계가 판정하게 만드는 도구를 직접 짓기 — 퀘스트 5부품·게이트 설계·치즈 방어의 실전 청사진.
- IFEval을 역이용하는 래칫 코드 — 결정론적 피드백 + 방향 컨텍스트가 수렴을 만드는 실험.
- Reins Engineering — 고삐 있는 AI — 프롬프트→컨텍스트→하네스→Reins 계보의 선언.
- TANGEUL — 마크다운으로 짜고 사람이 감사하는 규칙 — 턴의 정본이 문서인 이유.
더 읽을거리 (외부)
- Building Effective Agents — Anthropic — 에이전트 루프 설계의 고전. “워크플로(결정론 오케스트레이션)와 에이전트(모델 주도)“의 구분이 이 글의 생성/판정 분리와 공명한다.
- Agentic Loops: From ReAct to Loop Engineering — Data Science Dojo — ReAct에서 루프 엔지니어링까지, 에이전트 루프 계보의 정리.
- The Anthropic leader who built Claude Code says he ditched prompting — now he just writes loops — The New Stack — Boris Cherny의 전환을 다룬 업계 보도.
출처
- Loop Engineering — Addy Osmani — 2026-06. 용어의 명명과 좋은 루프의 해부(자동화·워크트리·스킬·서브에이전트·별도 판정자·상태 외부화).
- What Is Loop Engineering? A Complete Guide from Prompt to Harness Engineering — Tosea.ai — 프롬프트→컨텍스트→하네스→루프의 4단계 이행, 결정론 검증 우선 위계, LLM-as-judge의 담합 위험.
- Claude Code’s Creators Explain Agent Loops — The Neuron — Boris Cherny·Cat Wu의 루프 운용 상세:
/loop·/goal, 디스크·Linear 상태 외부화, 만드는 자/검증하는 자 분리.
변경이력
- 2026-07-07: 초판