[AI] 루프 엔지니어링: 에이전트를 움직이는 실행 루프 설계

한 번의 요청에 한 번의 응답으로 끝나는 사용법에서는 프롬프트(Prompt)가 결과의 거의 전부를 결정한다. 코딩 에이전트 하네스는 도구 호출과 결과 관찰을 세션 안에서 자동으로 반복하는 안쪽 루프를 이미 제공한다. 세션이 끝나면 사람이 결과를 보고 완료를 판단해 다시 시키는 바깥 루프(Outer Loop)의 주체는 원래 사람이었다. 루프 엔지니어링(Loop Engineering)은 이 바깥 루프에서 사람을 빼는 설계다. 검증을 기계가 하게 만들고 세션이 끝나도 상태를 잇는 것이 하네스 위에 실제로 더해지는 전부다.

다이어그램

안쪽 루프와 바깥 루프는 무엇이 다른가

  • 프롬프트 엔지니어링에서는 프롬프트 문장이 결과 품질을 사실상 결정했다.
  • 코딩 에이전트 하네스는 모델이 도구를 부르고 결과를 관찰해 다음 행동을 정하는 과정을 반복한다.
  • 이 자동 반복이 세션 하나 안에서 도는 안쪽 루프다.
  • 안쪽 루프는 모델이 다 됐다고 선언하면 멈추고, 그 판단이 맞는지는 확인하지 않는다.
  • 세션이 끝나면 결과는 사람에게 돌아왔고, 사람이 검토하고 완료를 판단했다.
  • 그 뒤 사람이 다시 지시했다. 이것이 원래의 바깥 루프다.
용어의미
안쪽 루프(Inner Loop)세션 하나 안에서 도는 관찰-추론-행동 반복. 하네스가 제공
바깥 루프(Outer Loop)검증하고 완료를 판단하고 재투입하는 루프. 원래 사람이 돌림
검증(Verify)결과가 목표와 기준을 충족하는지 확인하는 단계
자기 편향(Self-bias)작성한 모델이 자기 결과를 후하게 채점하는 현상
메모리(Memory)세션을 넘겨 진행 상태를 잇는 외부 저장소
오케스트레이터(Orchestrator)목표를 하위 작업으로 나눠 여러 에이전트에 위임하는 조율자

하네스는 안쪽 루프에서 무엇을 대신 해주는가?

하네스가 주는 것설명
관찰-추론-행동 반복도구를 부르고 결과를 관찰해 다음 행동을 정하는 안쪽 루프
도구 호출파일 읽기, 편집, 셸 실행 등 액션 공간
컨텍스트 컴팩션세션 안에서 컨텍스트가 차면 자동으로 요약
서브에이전트하위 작업을 독립 컨텍스트에 위임
스텝 상한세션당 최대 반복 횟수
# 하네스의 안쪽 루프: 세션 하나 안에서 자동으로 돈다
def inner_loop(goal, tools, model):
    context = [system_prompt(tools), user_message(goal)]
    while True:
        response = model.generate(context)          # 추론
        if response.is_final_answer():
            return response.text                     # 모델이 다 됐다고 선언하면 멈춘다
        result = tools.execute(response.tool_call)      # 행동
        context.append(observation(result))             # 관찰
  • 도구 정의의 품질과 관찰 포맷은 안쪽 루프 안의 튜닝 지점이다.
  • 도구 설명이 모호하면 모델이 엉뚱한 도구를 부른다.
  • 도구가 로그를 그대로 돌려주면 컨텍스트가 순식간에 차 중요한 한 줄을 놓친다.
  • 이런 조정은 안쪽 루프의 질을 높일 뿐, 바깥 루프를 자동으로 닫는 일과는 다르다.

프롬프트 엔지니어링과 무엇이 다른가?

축프롬프트 엔지니어링루프 엔지니어링
안쪽 루프하네스하네스
바깥 루프 주체사람시스템
사람의 일판단하고 다시 지시목표와 기준만 정의
손대는 지점프롬프트 문장검증과 지속
  • 루프 엔지니어링은 이 표의 한 칸, 바깥 루프의 주체를 사람에서 시스템으로 바꾸는 일이다.
  • 사람을 빼려면 사람이 하던 판단인 검증, 완료, 재투입을 시스템이 대신해야 한다.

바깥 루프는 다섯 단계로 자동으로 닫힌다

  • 발견, 계획, 실행, 검증, 반복의 다섯 단계 중 앞의 세 단계는 하네스의 안쪽 루프가 이미 수행한다.
  • 나머지 두 단계인 검증과 반복이 사람이 설계해야 하는 바깥 루프의 실체다.
단계하는 일주체
발견(Discover)목표를 이해하고 필요한 정보를 탐색하네스 안쪽 루프
계획(Plan)수집한 정보로 작업 계획 수립하네스 안쪽 루프
실행(Execute)실제 작업 수행하네스 안쪽 루프
검증(Verify)기준 충족 여부를 기계가 판정사람이 설계
반복(Iterate)실패를 되돌려 다시 돌리고 상태를 지속사람이 설계

이 다섯 단계를 코드로 감싸면 어떻게 보이는가?

# 사람이 설계하는 바깥 루프: 안쪽 루프를 감싼다
def outer_loop(goal, run_inner, verify, max_iterations=10):
    context = memory.load(goal)                  # 이전 세션 상태를 이어받음
    for i in range(max_iterations):
        result = run_inner(goal, context)         # 안쪽 루프 한 번 (하네스)
        report = verify(result)                   # 검증 (사람이 더하는 것)
        if report.passed:
            memory.save(goal, "done")
            return result                          # 통과하면 완료
        context.append(report)                     # 실패면 재투입
        memory.save(goal, context)                 # 상태 지속
    return escalate(goal, context)                 # 상한 도달 시 사람에게
  • 이 코드에서 하네스가 주는 부분은 run_inner 한 줄뿐이다.
  • 검증하고 완료를 판단하고 실패를 되돌리고 상태를 남기는 나머지 전부가 루프 엔지니어링의 실체다.
  • 이 바깥 루프를 돌게 하는 유일한 조건은 verify가 사람 없이 동작하는 것이다.
  • 검증이 사람 판단에 의존하면 for 문은 매 반복마다 멈춰 사람을 기다린다.

검증은 왜 다른 주체가 해야 하는가

  • 바깥 루프를 자동으로 닫으려면 종료 판단을 시스템이 해야 한다.
  • 그러려면 성공 기준이 시스템이 확인 가능한 형태여야 한다.
  • 목표를 다 됐나 사람이 판단해야 하는 형태로 두면 자동화가 불가능하다.
  • 모든 테스트가 통과하고 빌드가 성공하면 완료로 보는 형태로 목표를 바꿔야 한다.

자기 편향은 실제로 얼마나 크게 나타나는가?

  • 주관적 판단이 꼭 필요할 때는 작성한 모델에게 맡기지 않는다.
  • 작성자가 자기 결과를 채점하면 후하게 준다. 원문 저자가 같은 글을 측정한 값이 이를 보여준다.
  • 작성자 본인이 채점하면 9.04점, 독립된 에이전트가 채점하면 7.43점으로 1.6점 차이가 났다.
  • 이것이 자기 편향이며, 그래서 검증은 작성자와 다른 에이전트가 맡는다.

# 잘못된 패턴: 작성자가 자기 결과를 채점 (자기 편향)
def verify_self(result, model):
    return model.ask(f"이 결과가 충분한가? {result}")   # 후하게 준다, 루프가 못 멈춘다
# 올바른 패턴: 기계가 확인 가능한 객관 게이트 + 독립 채점
def verify(result, subagent):
    objective = run_tests()          # 테스트·빌드는 사람도 모델도 아닌 객관 신호
    if not objective.passed:
        return Report(False, objective.summary)
    review = subagent.review(result, criteria=SUCCESS_CRITERIA)  # 작성자가 아닌 에이전트
    return Report(review.passed, review.reason)

종료 조건은 뭐가 있고 뭘 신뢰할 수 있는가?

종료 조건판단 기준사람 없이 신뢰 가능한가
최종 응답 선언모델이 스스로 완료를 선언아니오, 미완을 완료로 착각
스텝·예산 상한반복 횟수나 토큰 초과안전장치일 뿐 완료 근거 아님
객관 검증 통과테스트·빌드가 통과예, 바깥 루프를 닫는 신호
독립 채점 통과다른 에이전트가 기준으로 채점예, 주관 판단이 필요할 때
  • 객관적 기준이 있으면 바깥 루프의 종료 판단이 사람 손을 떠난다.
  • 검증이 실패했을 때 실패를 입력으로 되돌려 다시 도는 사이클을 자동화할 수 있다.
sequenceDiagram
    autonumber
    participant O as 바깥 루프
    participant I as 안쪽 루프(하네스)
    participant G as 객관 게이트(테스트)
    participant S as 독립 서브에이전트

    O->>I: 목표와 이전 상태 전달
    I-->>O: 결과 제출
    O->>G: 테스트·빌드 실행
    G-->>O: 실패
    O->>I: 실패를 입력으로 재투입
    I-->>O: 수정된 결과
    O->>G: 재실행
    G-->>O: 통과
    O->>S: 독립 채점 요청
    S-->>O: 통과
    O->>O: 완료로 종료

세션이 끝나도 상태를 어떻게 잇는가

  • 하네스의 컨텍스트 컴팩션은 세션 하나 안의 관리일 뿐이다. 세션이 끝나면 컨텍스트는 사라진다.
  • 바깥 루프는 종종 세션 하나로 끝나지 않는다.
  • 반복이 여러 세션에 걸치거나 매일 도는 스케줄 루프라면 어제 세션의 결과를 오늘 세션이 알아야 한다.
  • 이때 필요한 것이 세션을 넘겨 상태를 잇는 메모리다.

세션을 넘겨 상태를 잇는 메모리는 어떻게 구성하는가?

  • 메모리는 두 종류의 파일로 관리한다.
  • 스킬 파일은 성공의 정의와 규칙 같은 프로젝트 지식을 담아 매 세션이 참조한다.
  • 진행 파일은 어디까지 했고 무엇이 미해결인지 남겨 다음 세션이 이어받게 한다.
# SKILL.md: 매 세션이 참조하는 기준
## 성공의 정의
모든 테스트 통과, 린트 경고 0 이면 완료로 본다.
## 금지 사항
@Query 직접 사용 금지, 커밋 메시지에 이모지 금지
 
# progress.md: 세션을 넘겨 지속되는 상태
- [x] 로그인 API 구현 (테스트 통과)
- [ ] 토큰 재발급 로직 (검증 실패: 만료 케이스 미처리)
- 다음 재개 지점: TokenService.refresh 의 만료 분기

세션 안 컨텍스트 관리와 세션 간 메모리는 뭐가 다른가?

전략범위역할
슬라이딩 윈도우세션 안오래된 메시지부터 버림
컴팩션(요약)세션 안누적 대화를 요약본으로 교체
외부 메모리세션 간상태를 파일에 남겨 다음 세션이 이어받음
  • 컴팩션은 세션 안에서 컨텍스트가 일정 비율을 넘으면 지금까지의 대화를 요약본으로 교체한다.
  • 이때 목표와 미완료 작업, 핵심 결정은 반드시 요약에 살린다.
def maybe_compact(context, model, max_tokens=180_000):
    if count_tokens(context) < max_tokens * 0.8:
        return context                    # 여유가 있으면 그대로 둔다
    summary = model.generate([summarize_instruction(), *context[1:-6]])  # 목표·미완료·결정을 남김
    return [context[0], summary_message(summary), *context[-6:]]  # 시스템 프롬프트 + 요약 + 최근 유지
  • 컴팩션이 한 세션 안의 압축이라면 메모리는 세션 사이의 지속이다.
  • 이 둘이 있어야 긴 작업이 중단 지점에서 이어지고, 반복이 이전 결과에서 개선된다.
  • 세션마다 처음부터 다시 시작하면 바깥 루프는 개선이 아니라 제자리를 돈다.

루프의 규모와 경계는 어떻게 정하는가

행동의 자유도를 얼마나 열어둘 것인가?

  • 오픈 루프는 행동 공간을 넓게 열어 탐색적으로 돌지만 토큰을 크게 소모하고 결과를 예측하기 어렵다.
  • 클로즈드 루프는 목표와 단계, 평가 기준, 종료 지점을 사람이 미리 정의하고 그 안에서 수행한다.
축오픈 루프(Open Loop)클로즈드 루프(Closed Loop)
경계느슨함, 탐색적목표·기준·종료 지점이 명확
토큰 소모매우 많음일반적 예산으로 운영
예측 가능성낮음높음, 매 실행이 이전 결과에서 개선
적합한 상황미지의 문제 탐색대부분의 실무
CLOSED_LOOP = {
    "goal": "로그인 API 의 토큰 만료 버그를 고친다",
    "success_criteria": "AuthTokenTest 전체 통과, 린트 경고 0",  # 기계가 판정 가능
    "termination": "검증 통과 또는 반복 10회 도달",
    "budget_tokens": 200_000,
}

혼자 돌릴 것인가 나눠 돌릴 것인가?

  • 단일 에이전트 루프는 하나가 전체 사이클을 돈다.
  • 플릿 루프(Fleet Loop)는 오케스트레이터가 목표를 나눠 전문가 에이전트에 배분한다.
  • 배분 후에는 평가 게이트로 품질을 보장한다.
  • 플릿은 토큰이 에이전트 수만큼 늘고 조율이라는 새 실패 지점이 생긴다.
  • 하위 작업이 정말 독립적일 때만 나눈다.

def fleet_loop(goal, model):
    subtasks = orchestrator.decompose(goal, model)      # 목표를 독립 하위 작업으로
    results = run_parallel([expert(st).run() for st in subtasks])  # 전문가마다 독립 컨텍스트
    passed = [r for r in results if evaluation_gate(r).passed]      # 평가 게이트 통과분만
    return orchestrator.synthesize(goal, passed, model)
축단일 에이전트 루프플릿 루프
구조하나가 전체 사이클오케스트레이터가 전문가에게, 전문가가 서브에이전트에게 위임
토큰 소모중간 규모 코딩 5만~20만오케스트레이터와 전문가 3명 50만~200만
적합한 작업집중된 단순 목표넓고 나눌 수 있는 목표

언제 무엇을 쓰는가

상황선택근거
버그 수정처럼 성공 기준이 테스트로 정의되는 작업객관 검증(테스트·빌드) 게이트로 종료 판단테스트 통과는 사람도 모델도 아닌 객관 신호로 신뢰할 수 있다
코드 스타일·설계 품질처럼 주관 판단이 필요한 작업작성자와 분리된 독립 에이전트가 채점작성자 채점 9.04점, 독립 채점 7.43점으로 1.6점 편향이 실측됐다
반복이 여러 세션에 걸치거나 매일 도는 스케줄 루프스킬 파일과 진행 파일로 외부 메모리를 유지세션이 끝나면 컨텍스트가 사라져 어제 상태를 오늘이 몰라야 한다
세션 하나 안에서 컨텍스트가 찰 때슬라이딩 윈도우 또는 컴팩션세션 내부 관리이며 세션 간 지속과 계층이 다르다
미지의 문제를 탐색해야 하는 초기 조사오픈 루프목표·기준을 미리 정의하기 어려운 상황에 적합하다
대부분의 실무 반복 작업클로즈드 루프목표·기준·종료 지점을 미리 고정해 토큰과 결과를 예측 가능하게 한다
목표를 독립된 하위 작업으로 나눌 수 있는 넓은 과제플릿 루프(오케스트레이터 + 전문가)병렬 처리가 가능하지만 토큰이 50만~200만으로 늘고 조율 실패 지점이 생긴다
집중된 단순 목표단일 에이전트 루프중간 규모 코딩 기준 토큰 5만~20만으로 충분하고 조율 비용이 없다
루프를 처음 세팅하는 단계성공 정의, 독립 검증, 진행 파일 순으로 3단계 도입여섯 요소를 한 번에 갖추지 않고 검증부터 자동화해야 바깥 루프가 실제로 닫힌다