# 루프 엔지니어링: 모델을 똑똑하게 만드는 일이 아니라, 실패가 쌓이지 않게 만드는 일

ReAct 루프 하나와 도구 몇 개만으로도 데모는 꽤 잘 돌아갑니다.
문제는 데모가 끝난 다음입니다.

사용자가 파일을 올립니다. 시스템은 그 안의 구조를 읽어야 합니다. 사용자가 추가 이미지를 보냅니다. 어느 문맥에 속한 입력인지 찾아야 합니다. 기준 데이터와 맞춰야 합니다. 사용자의 실제 입력을 해석해야 합니다. 판단을 내려야 합니다. 마지막에는 사람이 납득할 수 있는 설명까지 붙어야 합니다.

이쯤 되면 더 이상 “LLM에게 잘 물어보면 된다”의 문제가 아닙니다.

한 번의 모델 호출이 아니라, 여러 단계의 판단이 서로 기대고 있습니다. 앞 단계의 작은 흔들림이 뒤 단계의 확신처럼 포장될 수 있습니다. 문서 구조 파악이 애매했는데 최종 판단이 그럴듯하게 나오고, 입력 매칭이 틀렸는데 설명은 친절하게 보일 수 있습니다. 사용자는 친절한 오판을 신뢰하게 됩니다.

그래서 필요한 것이 루프 엔지니어링입니다.

루프 엔지니어링은 모델을 더 화려하게 쓰는 기술이 아닙니다. 모델 주변에 실행 루프, 상태, 검증, 복구, 권한, 메모리, 관찰 포맷을 설계해서 실패가 조용히 누적되지 않게 만드는 시스템 설계입니다.

Daily Dose of Data Science의 「The Anatomy of an Agent Harness」는 이것을 agent harness라는 말로 설명합니다. 핵심 문장은 간단합니다. 모델 바깥의 모든 것이 harness입니다. 도구, 컨텍스트, 상태 저장, 오류 처리, 검증 루프, 가드레일, subagent orchestration까지 전부 포함됩니다.

저는 이 관점을 “루프 엔지니어링”으로 받아들이는 편이 더 실무적이라고 봅니다. 특히 문서 파싱, 이미지 해석, 심사, 검토, 의료, 세무, 법률처럼 한 번의 그럴듯한 답보다 누적된 신뢰가 중요한 제품에서는 그렇습니다.

## 전체 그림

루프 엔지니어링의 기본 단위는 `LoopRun`입니다.
사용자 요청 하나가 들어오면 시스템은 하나의 실행 흐름을 만들고, 그 안에서 여러 개의 `LoopStep`을 거칩니다.

“`mermaid
flowchart TD
A[“User Request”] –> B[“LoopRun 생성”]
B –> C[“Input Guard
파일, 권한, 크기, 형식 확인”]
C –> D[“Context Assembly
필요한 기억과 근거만 로드”]
D –> E[“Tool / Model Step
파싱, OCR, 검색, 추론”]
E –> F[“Observation Packaging
status, summary, artifacts, next_actions”]
F –> G[“Verifier Gate
규칙, 테스트, 근거, confidence 확인”]
G –>|pass| H[“State Update
다음 단계로 진행”]
G –>|recoverable| I[“Repair Loop
재시도, 다른 도구, 좁은 모델 호출”]
G –>|needs human| J[“Review Needed
사용자 확인 요청”]
G –>|fatal| K[“Safe Failure
멈추고 원인 표시”]
I –> F
H –> L{“Done?”}
L –>|no| D
L –>|yes| M[“Final Output
근거와 남은 불확실성 포함”]
“`

여기서 중요한 것은 루프가 “생각 → 행동 → 관찰”만 반복하지 않는다는 점입니다.
각 행동 뒤에는 반드시 관찰이 정리되고, 검증이 끼어들고, 상태가 업데이트되어야 합니다.

모델은 일을 합니다.
루프는 일이 망가지지 않게 합니다.

LoopRun 전체 실행 흐름
그림 1. LoopRun은 한 번의 답변이 아니라, 관찰과 검증을 반복하는 실행 흐름이다.

## 왜 단순 ReAct로는 부족한가

짧은 작업에서는 단순 ReAct가 잘 먹힙니다.

검색 한 번 하고, 계산 한 번 하고, 답을 쓰는 정도라면 괜찮습니다. 컨텍스트도 작고, 도구도 적고, 틀렸을 때 되돌아갈 거리도 짧습니다.

하지만 실제 제품의 작업은 보통 이렇게 생겼습니다.

1. 사용자가 애매한 입력을 준다.
2. 파일이나 이미지 품질이 일정하지 않다.
3. 여러 도구가 순서대로 실행된다.
4. 중간 결과가 다음 판단의 전제가 된다.
5. 마지막 출력은 사용자에게 확신처럼 보인다.

이 구조에서는 각 단계 성공률이 99%여도 전체 성공률은 빠르게 내려갑니다. 10단계 작업이면 단순 계산으로도 약 90% 수준까지 떨어집니다. 게다가 현실의 각 단계는 99%도 아닙니다. 입력 파일은 깨지고, OCR은 흔들리고, 모델은 애매한 근거를 자신 있게 말합니다.

루프 엔지니어링은 이 문제를 정면으로 봅니다.

“모델이 틀릴 수 있다”가 출발점입니다.
그래서 루프는 매 단계마다 묻습니다.

– 지금 무엇을 했는가?
– 어떤 근거가 생겼는가?
– 다음 단계가 이 근거를 믿어도 되는가?
– 실패라면 복구 가능한 실패인가?
– 사용자에게 확인을 받아야 하는가?
– 여기서 멈추는 것이 더 안전한가?

이 질문들이 코드와 데이터 구조로 들어가야 합니다.

## 루프 엔지니어링의 7개 구성요소

제가 보는 루프 엔지니어링의 핵심 구성요소는 일곱 가지입니다.

루프 엔지니어링 7개 구성요소
그림 2. 루프 엔지니어링은 orchestration, tool contract, observation, state, verification, recovery, eval replay가 함께 맞물린다.

### 1. Orchestration Loop

루프의 심장입니다.
입력을 받고, 필요한 컨텍스트를 모으고, 도구나 모델을 호출하고, 결과를 관찰로 정리하고, 검증한 뒤 다음 단계를 결정합니다.

겉으로는 while loop일 수 있습니다. 하지만 중요한 것은 while이 아니라 그 안의 계약입니다.

좋은 루프는 모든 단계가 같은 모양의 기록을 남깁니다.

“`json
{
“step”: “match_input_context”,
“status”: “warning”,
“summary”: “Direct identifier was not found; inferred context from OCR and layout candidates.”,
“confidence”: 0.62,
“artifacts”: [“ocr_blocks.json”, “normalized_input.jpg”],
“next_actions”: [“retry_with_image_normalization”, “ask_user_if_confidence_below_threshold”],
“evidence_refs”: [“ocr:block:17”, “image:region_crop:bottom_right”]
}
“`

이런 기록이 없으면 나중에 실패를 디버깅할 수 없습니다. 더 나쁘게는 실패했는지도 모릅니다.

### 2. Tool Contract

도구는 모델의 손입니다.
그런데 손이 너무 많거나 모양이 제각각이면 모델은 혼란스러워집니다.

도구 설계에서 중요한 것은 세 가지입니다.

– 이름이 명확해야 합니다.
– 입력 스키마가 좁아야 합니다.
– 출력이 항상 같은 구조여야 합니다.

`do_everything_with_file` 같은 도구는 편해 보이지만 루프에는 나쁩니다. 실패 지점이 숨습니다. 반대로 너무 잘게 쪼개도 루프가 길어집니다.

고위험 작업은 작게 쪼개고, 반복적인 읽기/검색/파싱은 중간 크기의 도구로 묶는 것이 좋습니다.

### 3. Observation Design

루프의 품질은 관찰 포맷에서 갈립니다.

많은 시스템은 도구 결과를 그냥 텍스트로 모델에게 돌려줍니다. 이러면 모델은 긴 로그 속에서 중요한 신호를 찾아야 합니다. 컨텍스트는 낭비되고, 오류 복구는 우연에 가까워집니다.

관찰은 사람이 읽는 로그가 아니라 다음 판단을 위한 입력이어야 합니다.

최소한 다음 필드가 있어야 합니다.

– `status`: success, warning, error
– `summary`: 한 줄 요약
– `confidence`: 다음 단계가 믿어도 되는 정도
– `artifacts`: 파일, 이미지, DB row, trace id
– `next_actions`: 가능한 다음 행동
– `evidence_refs`: 판단 근거로 돌아갈 수 있는 참조

이 구조가 있어야 모델도, 규칙 기반 verifier도, 나중의 평가 도구도 같은 사실을 볼 수 있습니다.

### 4. State Management

상태가 없으면 루프는 기억력이 없습니다.

대화 히스토리만 믿으면 안 됩니다. 긴 작업에서는 중간 결과가 컨텍스트 안에서 밀려나고, 요약 과정에서 사라지고, 다음 세션에서 끊깁니다.

상태는 대화가 아니라 제품 데이터로 남아야 합니다.

예를 들어 복합 입력을 다루는 AI 애플리케이션에서는 다음 상태가 분리되어야 합니다.

– 원본 파일
– 정규화된 이미지
– 추출된 텍스트와 레이아웃 블록
– 입력 문맥 후보
– 기준 데이터 IR
– 사용자 입력 후보
– 최종 판단
– 설명
– 검증 결과
– 사용자 확인 이력

이걸 하나의 “결과 JSON”으로 뭉치면 편합니다. 하지만 나중에 어디가 틀렸는지 알 수 없습니다. 루프 엔지니어링은 상태를 단계별로 남깁니다.

### 5. Verification Gate

검증 루프는 장식이 아닙니다.
제품의 품질을 결정하는 핵심 부품입니다.

검증에는 세 층이 있습니다.

첫째, deterministic verification입니다.
테스트, 타입 체크, 스키마 검증, 좌표 범위 확인, 식별자 consistency 같은 것들입니다.

둘째, evidence verification입니다.
“이 값은 어느 파일, 어느 영역, 어느 텍스트에서 왔는가?”를 확인합니다.

셋째, semantic verification입니다.
설명이 입력과 결론을 제대로 연결하는지, 판단이 말이 되는지, 모델이 근거 없는 확신을 붙이지 않았는지 봅니다. 이 영역에서는 LLM-as-judge나 별도 critic 모델을 쓸 수 있습니다.

중요한 원칙은 하나입니다.
최종 사용자가 보는 확신보다 내부 검증이 먼저 강해야 합니다.

### 6. Recovery Contract

실패는 네 종류로 나누어야 합니다.

– transient failure: 네트워크, rate limit, 일시적 모델 실패
– recoverable failure: 입력을 조금 바꾸거나 다른 도구를 쓰면 복구 가능
– user-fixable failure: 사용자가 확인하거나 다시 찍어야 함
– fatal failure: 시스템이 멈추고 원인을 남겨야 함

모든 실패를 재시도하면 비용이 터집니다.
모든 실패를 사용자에게 넘기면 제품이 피곤해집니다.
모든 실패를 무시하면 신뢰가 깨집니다.

그래서 복구 계약이 필요합니다.

예를 들어 이미지에서 입력 문맥을 찾는 confidence가 낮으면 무조건 최종 판단으로 넘어가면 안 됩니다. 먼저 이미지 normalization으로 한 번 재시도하고, 그래도 낮으면 후보를 사용자에게 보여주는 식이어야 합니다.

### 7. Eval Replay

루프는 평가 없이는 좋아지지 않습니다.

좋은 루프 엔지니어링은 매 작업을 다음 평가 데이터로 바꿉니다.
실패한 문서, 애매했던 이미지, 사용자가 수정한 판단 결과, 사람이 다시 확인한 설명은 모두 eval fixture가 됩니다.

측정해야 할 지표는 단순 정확도만이 아닙니다.

– end-to-end completion rate
– false auto-accept rate
– needs_review rate
– retry count
– cost per successful run
– latency per stage
– explanation correction rate
– user confirmation burden

이 지표가 있어야 개선이 취향이 아니라 실험이 됩니다.

## 개발 중인 애플리케이션에 적용하면 어떻게 보이는가

제가 개발 중인 애플리케이션에서도 이 구조는 크게 네 개의 루프로 나눠볼 수 있었습니다. 구체적인 제품 형태와 도메인은 중요하지 않습니다. 핵심은 복합 입력에서 근거를 뽑고, 그 근거로 판단을 만들고, 사람이 확인할 수 있는 형태로 되돌려주는 흐름입니다.

“`mermaid
flowchart LR
A[“Reference Intake Loop
기준 자료 구조화”] –> B[“Input Interpretation Loop
사용자 입력 해석”]
B –> C[“Human Review Loop
확인과 설명”]
C –> D[“Improvement Loop
수정 이력과 재검증”]
D –> E[“Eval Replay Loop
실패 사례 재검증”]
E –> A
“`

복합 입력 애플리케이션 루프 스택
그림 3. 복합 입력 제품에서는 기준 자료 구조화, 입력 해석, 사람 검토, 재평가 루프가 이어진다.

### Reference Intake Loop

기준 자료를 읽는 단계입니다.

여기서 목표는 Markdown을 얻는 것이 아닙니다.
AI와 규칙 기반 verifier가 함께 읽을 수 있는 domain IR을 만드는 것입니다.

필요한 구조는 대략 이렇습니다.

– source file index
– source segment or region
– section key
– target value region
– supporting explanation region
– source text
– bounding box
– parser confidence
– review-needed reason

파서는 먼저 deterministic하게 돌아야 합니다. 좌표, 텍스트 블록, 레이아웃, 번호 패턴을 이용합니다. 모델은 전체 문서를 한 번에 “이해”하는 용도가 아니라, low-confidence region이나 suspicious region을 고치는 데 쓰는 것이 안전합니다.

Upstage Document Parse Enhanced 같은 도구는 이 지점에서 강합니다. 표, 그림, 복잡한 레이아웃을 LLM이 읽기 쉬운 구조로 바꿔줄 수 있기 때문입니다. 하지만 이 도구도 최종 판정자가 아니라 파서 후보 중 하나여야 합니다.

루프는 이렇게 흘러야 합니다.

“`text
source document
-> coordinate/text/visual primitives
-> domain IR
-> consistency verifier
-> suspicious region repair
-> review-needed region list
-> approved reference data
“`

### Input Interpretation Loop

사용자 입력을 해석하는 단계는 더 위험합니다.

이미지나 파일에는 기울기, 그림자, 잘린 모서리, 흐린 글씨, 여러 정보가 섞인 화면이 있습니다. 모델이 그럴듯하게 값을 읽었다고 해서 바로 최종 판단으로 넘기면 안 됩니다.

루프는 이렇게 쪼개야 합니다.

“`text
input normalize
-> context detection
-> target region detection
-> reference lookup
-> user signal extraction
-> decision
-> evidence verifier
-> response generation
“`

각 단계는 다음 단계에 넘길 수 있는 confidence를 남겨야 합니다.

예를 들어 입력 문맥 인식이 흔들렸다면 최종 판단의 confidence는 내려가야 합니다. 기준 데이터 lookup이 불확실하면 사용자 입력을 아무리 잘 읽어도 자동 확정하면 안 됩니다. 사용자 입력 자체가 애매하면 설명보다 먼저 확인 UI가 나와야 합니다.

이게 루프 엔지니어링의 태도입니다.
모르는 것을 친절하게 말하지 말고, 모른다고 구조적으로 표시합니다.

### Human Review Loop

사람이 보는 화면은 최종 출력이 아니라 검증된 상태의 표현이어야 합니다.

“결론은 이렇습니다”만 보여주면 부족합니다.

좋은 결과 화면은 내부 루프의 근거를 적당히 압축해서 보여줍니다.

– 어떤 입력으로 인식했는지
– 기준 값은 어디서 가져왔는지
– 사용자 입력은 무엇으로 읽었는지
– 왜 그렇게 판단했는지
– 어느 부분이 불확실한지
– 사용자가 고칠 수 있는 항목은 무엇인지

이때 모든 trace를 다 보여줄 필요는 없습니다. 하지만 trace가 없으면 좋은 UI도 만들 수 없습니다.

### Eval Replay Loop

제품이 좋아지는 루프는 사용 후에 시작됩니다.

사용자가 판단 결과를 수정했다면 그건 실패 신호입니다.
사용자가 입력 문맥을 다시 선택했다면 context detection fixture입니다.
기준 자료를 다시 등록했다면 parser eval입니다.

이 데이터가 다음 배포 전 replay되어야 합니다.

루프 엔지니어링의 최종 산출물은 코드만이 아닙니다.
실패가 자동으로 평가 데이터가 되는 구조입니다.

## 이론: 얇은 harness와 두꺼운 harness 사이

agent harness 설계에는 오래된 긴장이 있습니다.

모델을 믿을 것인가, 흐름을 코드로 통제할 것인가.

얇은 harness는 모델에게 많은 판단을 맡깁니다. 구현이 단순하고, 모델이 좋아질수록 성능이 자연스럽게 올라갈 수 있습니다.

두꺼운 harness는 흐름을 명시적으로 통제합니다. 상태 기계, 검증 단계, 라우팅, 권한, 복구 정책을 코드로 둡니다. 비용은 높지만 중요한 실패를 더 잘 잡습니다.

신뢰가 중요한 애플리케이션에서는 하이브리드가 맞습니다.

기준 데이터 lookup, 최종 판단, 사용자에게 자동 확정되는 결과는 두꺼워야 합니다.
설명 문장 개선, 애매한 레이아웃 repair, 실패 사례 triage는 얇아도 됩니다.

다르게 말하면, 사용자의 신뢰를 직접 건드리는 곳은 deterministic하고 검증 가능해야 합니다.
모델은 그 주변에서 판단을 보조해야 합니다.

얇은 harness와 두꺼운 harness 비교
그림 4. 신뢰를 직접 건드리는 영역은 두껍게 통제하고, 표현 개선처럼 보조적인 영역은 얇게 둘 수 있다.

## 구현 순서

처음부터 거대한 agent platform을 만들 필요는 없습니다.

첫 번째 구현 단위는 작아야 합니다.

### 1단계: LoopRun과 LoopStep을 저장한다

세 endpoint부터 감쌉니다.

– `/v1/ingest-reference`
– `/v1/match-input`
– `/v1/decide`

각 endpoint가 내부적으로 어떤 단계를 거쳤는지 저장합니다.

### 2단계: observation 포맷을 통일한다

모든 단계 결과가 같은 필드를 갖게 합니다.

“`text
status
summary
confidence
artifacts
next_actions
evidence_refs
error_type
stop_condition
“`

이 작업만 해도 디버깅 품질이 달라집니다.

### 3단계: verifier gate를 넣는다

처음부터 모든 걸 검증하려고 하면 오래 걸립니다.
가장 위험한 세 가지부터 시작합니다.

– 기준 데이터 source mapping이 있는가?
– 사용자 입력이 올바른 문맥으로 매칭됐는가?
– 자동 판단에 입력 근거가 있는가?

### 4단계: replay eval을 만든다

owned fixture를 넣고, 배포 전후로 같은 루프를 돌립니다.

여기서 봐야 하는 것은 단순 성공 개수가 아닙니다.

“`text
auto_decision_correct
false_auto_accept
needs_review
retry_count
cost
latency
explanation_quality
“`

### 5단계: repair loop를 제한적으로 켠다

모델 기반 repair는 마지막에 켜는 것이 좋습니다.

파서가 실패한 모든 입력을 모델에게 넘기는 것이 아니라, verifier가 특정한 실패 유형을 발견했을 때만 좁게 호출합니다.

예를 들어:

– target region은 찾았지만 section bundle이 깨진 경우
– OCR text는 있는데 번호 grouping이 깨진 경우
– 표 구조가 line-less라 deterministic parser가 놓친 경우

이렇게 해야 비용과 오판을 통제할 수 있습니다.

## 좋은 루프의 기준

좋은 루프는 조용히 성공하는 루프가 아닙니다.
좋은 루프는 실패를 정확한 이름으로 남기는 루프입니다.

실패 이름이 정확하면 복구가 쉬워집니다.
복구가 쉬우면 사용자 확인이 줄어듭니다.
사용자 확인이 줄어들면 제품이 자연스러워집니다.
제품이 자연스러워지면 모델이 잘해서 그런 것처럼 보입니다.

하지만 실제로는 harness가 잘한 것입니다.

루프 엔지니어링은 보이지 않는 제품 경험입니다.
사용자는 `LoopRun`을 보지 않습니다. `evidence_refs`도 보지 않습니다. verifier gate도 모릅니다.

대신 사용자는 이렇게 느낍니다.

입력을 넣었더니 맞는 문맥을 찾았다.
판단 이유가 말이 된다.
애매한 건 애매하다고 물어본다.
한 번 고쳐주면 다음부터 나아진다.

이게 제가 원하는 AI 애플리케이션의 신뢰입니다.

## 결론

AI 제품의 품질은 모델 선택에서 끝나지 않습니다.
오히려 모델을 부른 다음부터 진짜 제품 설계가 시작됩니다.

루프 엔지니어링은 그 설계를 이름 붙인 것입니다.

입력을 어떻게 정규화할지.
어떤 도구를 언제 부를지.
결과를 어떤 관찰로 남길지.
무엇을 검증할지.
언제 재시도할지.
언제 사용자에게 넘길지.
어떤 실패를 다음 eval로 만들지.

이 질문들에 대한 답이 쌓이면 agent harness가 됩니다.

그리고 신뢰가 중요한 제품에서는 harness가 곧 제품입니다.

참고:

– Daily Dose of Data Science, 「The Anatomy of an Agent Harness」: https://www.dailydoseofds.com/p/the-anatomy-of-an-agent-harness/
– Upstage, 「Introducing Document Parse: Enhanced mode」: https://www.upstage.ai/blog/en/document-parse-enhanced