에이전트 = 모델 × 하네스: 평가(Eval) 레이어는 에이전트 옆의 도구가 아니라 에이전트의 일부입니다
요약
성공적인 AI 에이전트 구축을 위해 평가(Eval)와 관측성(Observability) 레이어를 하네스(Harness)의 핵심 구성 요소로 통합해야 함을 강조합니다. 단순 실행을 넘어 피드백 루프를 갖춘 폐쇄형 루프 시스템의 중요성을 설명합니다.
핵심 포인트
- 에이전트는 모델과 하네스(목표, 루프, 도구, 렌즈, 평가)의 결합체임
- 평가와 관측성은 외부 도구가 아닌 하네스 내부의 필수 요소임
- 개방형 루프는 오류를 인지하지 못하지만, 폐쇄형 루프는 스스로 수정 가능함
- 렌즈는 실행 과정을 기록하고, 평가는 행동의 유효성을 판단함
사람들이 왜 자신들의 매끄러운 데모 에이전트가 실제 운영 환경(production)에서는 무너지는지 물을 때마다 제가 계속 되새기는 공식이 하나 있습니다:
에이전트 (Agent) = 모델 (Model) × 하네스 (Harness)
모델은 가공되지 않은 추론 능력입니다 — Claude, GPT 등 무엇이든 될 수 있죠. 모델은 교체 가능하며, 여러분이 통제할 수 없는 곡선을 그리며 계속 발전하고 있습니다. 하네스는 그 외의 모든 것입니다: 목표(goals), 루프(loops), 도구(tools), 스케줄러(scheduler), 재시도 로직(retry logic) 등이 포함됩니다. 중요한 엔지니어링의 대부분은 모델이 아니라 하네스에 존재합니다.
하지만 대부분의 팀이 실수하는 부분이 여기 있습니다. 그들은 하네스를 모델을 실행하기 위한 배관(plumbing) — 즉, 목표 + 루프 + 도구 — 로 정의한 다음, **평가(evals)**와 **관측성(observability)**을 외부 QA로서 옆에 따로 붙입니다. 에이전트가 일을 마친 후, 외부에서 에이전트를 겨냥하여 바라보는 것들 말이죠.
그것이 실수입니다. 여러분의 평가(eval) 레이어와 트레이스(trace) 레이어는 하네스 내부에 있어야 합니다. 그것들은 에이전트 옆에 있는 도구가 아닙니다. 에이전트를 개방형 루프(open loop)가 아닌 폐쇄형 루프(closed loop)로 만드는 에이전트의 절반입니다.
하네스 (Harness) = 목표 (goals) + 루프 (loops) + 도구 (tools) + 렌즈 (lens) + 평가 (evals). 앞의 세 가지는 에이전트가 *행동(act)*하게 해줍니다. 뒤의 두 가지는 그 행동이 유효했는지 알게 해줍니다. 이것이야말로 단순히 실행되는 에이전트를 개선되는 에이전트로 바꾸는 유일한 요소입니다.
이것을 구체적인 사례로 말씀드리겠습니다. 왜냐하면 저도 아주 고생스러운 방식으로 이를 배웠기 때문입니다. 스케줄링된 에이전트가 충돌하는 것을 지켜보며, 제 하네스의 정확히 어떤 부분들이 저를 구했는지 발견하면서 배웠습니다.
개방형 루프(Open loop) vs 폐쇄형 루프(Closed loop)
개방형 루프 (open-loop) 에이전트는 행동하고 다음으로 넘어갑니다. 파일을 쓰고, API를 호출하고, 커밋을 전송합니다 — 그리고 에이전트 자신을 포함해 그 누구도 결과가 올바른지 알지 못합니다. 사람이 무언가 잘못되었다는 것을 알아차렸을 때 비로소 알게 됩니다. 세상에 존재하는 대부분의 "자율적(autonomous)" 에이전트들은 개방형 루프입니다. 이들은 3일 동안 조용히 잘못된 일을 수행하기 직전까지는 매우 인상적입니다.
폐쇄형 루프 (closed-loop) 에이전트는 피드백 경로를 가집니다:
행동 (act) → 관찰 (observe) → 평가 (evaluate) → 수정 (correct) → 더 나은 행동 (act better)
이 시스템을 완성하는 두 가지 요소는 **렌즈(lens)**와 **평가(evals)**입니다. 렌즈는 모든 모델 호출과 도구 단계, 해결된 입력값, 원시 출력값을 기록하여 실행 과정이 절대 블랙박스가 되지 않도록 합니다. 평가(evals)는 기준에 맞춰 점수화되는 판단(judgment)을 제공합니다. (예: 결정론적 검사, 계약 유효성 검사, 모델 기반 심사). 렌즈는 에이전트가 무엇을 했는지 알려주고, 평가는 그것이 좋았는지 아닌지를 알려줍니다. 이 두 가지 모두 수동으로 일주일에 한 번 사람이 체크하는 것이 아니라, 하네스 자체에 연결되어 있어야 합니다.
이것을 깨닫게 해준 사건
저는 스케줄링된 에이전트(scheduled agents) 군단을 운영합니다. 크론 작업(cron) 기반의 백그라운드 워커들로, 각각 타이머에 맞춰 집중적인 작업을 수행하며, 메인 프로세스가 실시간으로 관찰할 수 없는 격리된 세션에서 작동합니다.
그중 하나가 실행 도중에 충돌했습니다.
오픈 루프(open-loop) 환경에서는 이것이 조용한 재앙입니다. 워커가 죽고 아무것도 생산하지 않으며 흔적을 남기지 않습니다. (백그라운드 에이전트를 운영해 본 사람이라면 이 정확한 고통을 알고 있을 겁니다. 즉, 아무도 알아채기 전까지 일주일 동안 '사라지는' 경우 말이죠.)
하지만 렌즈와 평가 레이어가 하네스의 일부였기 때문에 이번에는 다음과 같은 일이 벌어졌습니다:
1. 렌즈 덕분에 실패 기록이 남았습니다. 모든 워커는 트랜스크립트(transcript)를 *먼저 스텁(stub-first)*으로 작성합니다. 즉, 실제 작업을 수행하기 전에 시작하는 순간에 Outcome: IN-PROGRESS라는 기록을 남기는 것입니다. 따라서 단 1초 후에 죽은 워커조차도 흔적을 남겼습니다. 충돌이 눈에 보이지 않는 것이 아니라,
따라서 그 실패한 실행은 단순히 기록만 남긴 것이 아니라, _무효(invalid)로 점수화(scored)_되었으며, 누군가 이를 처리할 때까지 게이트(gate)의 무효 목록에 매 실행마다 계속 나타났습니다. 평가(eval) 레이어는 그 실패가 배경 속으로 조용히 섞여 들어가는 것을 거부했습니다.
그것이 핵심입니다. 렌즈(lens)는 실패를 관찰 가능하게 만들었고, 평가(evals)는 그것을 무시할 수 없게 만들었습니다. 이 중 어느 것도 제가 직접 수동으로 실행한 것이 아닙니다. 이것들은 충돌(crash)을 블랙홀에서 추적 가능한 결함(defect)으로 바꿔놓은 하네스(harness)의 고정된 구성 요소들입니다.
수정 단계(correction step) 마무리하기
실패를 감지하는 것은 관찰(observe) + 평가(evaluate)입니다. 마지막 조각은 _수정(correct)_입니다.
단순한 해결책은 "finally 블록을 추가하여 워커(worker)가 충돌 시 자신의 트랜스크립트(transcript)를 스스로 마무리하게 하는 것"입니다. 하지만 이는 작동하지 않으며, 그 이유는 시사하는 바가 큽니다. 충돌하여 격리된 세션은 이미 사라졌기 때문입니다. finally를 실행해야 할 프로세스 자체가 죽어버린 것입니다. 죽은 워커에게 스스로 뒷정리를 해달라고 요청할 수는 없습니다.
따라서 수정 단계는 워커의 _외부_에서, 그 자체로 하나의 작은 루프(loop)로서 존재해야 합니다. 저는 스위퍼(sweeper)를 작성했습니다. 이는 IN-PROGRESS 상태로 멈춰 있는 트랜스크립트 중, 실행이 증명 가능하게 종료된 것들을 스캔하는 예약된 관리자(janitor)입니다. 실행이 _증명 가능하게 종료되었음_을 확인하기 위해, 가능한 가장 긴 실행 시간을 훨씬 상회하는 안전한 임계값보다 오래된 것들을 대상으로 하며, 이를 통해 여전히 정상적으로 작동 중인 워커와 경합(race)이 발생하는 일을 방지합니다. 그리고 이들을 fail로 마무리합니다.
로직은 의도적으로 단순합니다:
여전히 IN-PROGRESS로 표시된 각 트랜스크립트 스텁(stub)에 대해:
if age > MAX_RUN_TIME + safety_margin: # 실행이 증명 가능하게 종료됨
rewrite Outcome -> "fail (auto-finalized: abandoned mid-run)"
멱등성(Idempotent)을 가지며, 아무것도 삭제하지 않고, 타이머에 따라 실행됩니다. 처음 실행되었을 때, 이 스위퍼는 오랫동안 방치된 스텁들의 백로그(backlog)를 마무리했고, 완료 모드(finished-mode)에서 게이트의 무효 카운트를 알려진 예상 예외 상황들로만 낮추었습니다. 이제 이 루프는 자동으로 닫힌 상태를 유지합니다. 워커가 여전히 충돌할 수는 있지만, 제가 아무것도 건드리지 않아도 그 사체(corpse)는 한 시간 이내에 정리됩니다.
이것이 완전히 연결된 act → observe → evaluate → correct이며, 이 네 단계 중 세 단계가 렌즈(lens) + 평가(eval) 레이어가 제 역할을 수행하는 것입니다.
자기 수정(Self-correcting) ≠ 자기 개선(Self-improving) (그리고 이것이 중요한 이유)
여기서 저는 솔직해져야 합니다. 왜냐하면 이 부분은 과장하고 싶은 유혹이 생기는 지점이기 때문입니다.
제가 구축한 것은 자기 수정(self-correcting) 하네스(harness)입니다. 루프(loop)가 닫힙니다. 시스템은 자신의 표준에서 벗어난 편차를 감지하고, 인간의 개입(human in the loop) 없이 이를 복구합니다. 이것은 실재하며, 자율 에이전트(autonomous agents) 군단 아래에 두어야 할 최소한의 기반(floor)입니다.
하지만 자기 수정이 **자기 개선(self-improving)**을 의미하지는 않습니다. 자기 수정은 시스템이 *기준선을 유지(holds the line)*한다는 것을 의미합니다. 즉, 스스로를 표준 상태로 유지하는 것입니다. 반면 자기 개선은 시스템이 스스로 *기준선을 위로 이동(moves the line up)*시키는 것을 의미합니다. 예를 들어, 특정 체크 항목에 거짓 양성(false positives)이 있음을 인지하고 스스로 루브릭(rubric)을 강화하거나, 특정 작업자(worker)가 계속 퇴보하는 것을 인지하고 해당 작업자의 지침을 조정하는 식입니다. 제 하네스는 그렇게 하지 않습니다. 저는 여전히 모든 개선 사항을 직접 작성합니다. 루프는 스스로 실행되지만, 그 루프는 인간에 의해 설계되었습니다.
그리고 솔직히 말해서, 지금으로서는 여기서 멈추는 것이 맞습니다. 감독 없이 자신의 작업자(workers)와 평가 기준(eval criteria)을 스스로 다시 쓰는 하네스는 전혀 다른, 그리고 훨씬 더 위험한 것입니다. 정확히 말하면 평가(evals)가 동일한 시스템이 작성한 결과물을 채점하게 되기 때문입니다. 판단 대상과 판단 주체가 외부의 닻(anchor)이 없는 동일한 폐쇄형 시스템이 되는 순간, "자체 평가를 통과했다"는 말은 큰 의미를 갖지 못하게 됩니다. 인간이 설정한 계약(human-set contract) 범위 내에서의 자기 수정은 건전한 방식입니다. 계약 자체를 자기 수정하는 것은, 이를 실행하기 전에 강력한 가드레일(guardrails)과 인간의 승인(human gate)이 반드시 필요한 영역입니다.
따라서 완전히 확장된 정직한 공식은 다음과 같습니다:
에이전트(Agent) = 모델(Model) × 하네스(Harness), 여기서 하네스(Harness) = 목표(goals) + 루프(loops) + 도구(tools) + 렌즈(lens) + 평가(evals) 입니다. 그리고 에이전트를 *자기 수정(self-correcting)*하게 만드는 것은 바로 렌즈(lens) + 평가(evals)입니다. 여기서 자기 개선(self-improving) 단계로 나아가는 것은 실질적으로 한 단계 더 나아가는 것이며, 이는 인간이 게이트를 지키는 가운데 의도적으로 진행해야 하는 단계입니다.
핵심 요약(The takeaway)
만약 당신이 에이전트(agent)를 구축하고 있는데, 평가(evals)와 트레이스(traces)를 외부에서 가끔씩만 실행하는 무언가로 취급하고 있다면, 당신은 폐쇄 루프(closed loop)를 가진 것이 아닙니다. 당신은 그저 근처에 몇 개의 QA 스크립트를 둔 개방 루프(open-loop) 에이전트를 가지고 있는 것입니다. 업그레이드는 더 많은 도구를 추가하는 것이 아닙니다. 그것은 관점의 재정립(reframe)입니다:
- 렌즈(Lens)와 평가(evals)는 하네스(harness) 내부에 속해야 하며, 요청 시에만 실행되는 것이 아니라 모든 동작마다 실행되어야 합니다.
- 렌즈는 실패를 관찰 가능하게 만들고, 평가는 실패를 무시할 수 없게 만듭니다 — 이것이 충돌(crash)을 보이지 않는 블랙홀에서 추적 가능한 결함(defect)으로 전환하는 핵심입니다.
- 수정 단계(correction step)를 폐쇄하는 것은 종종 별도의 루프를 의미합니다. 왜냐하면 실패한 요소가 항상 스스로를 뒷수습할 수는 없기 때문입니다.
- 자기 수정(Self-correcting)은 최소한의 기준(floor)이며, 자기 개선(self-improving)은 그보다 더 나아간 의도적인 단계입니다 — 시스템이 스스로 숙제를 채점하기 전에 인간이 게이트를 지키게 하십시오.
에이전트(Agent) = 모델(Model) × 하네스(Harness). 모델은 스스로 개선되고 있습니다. 당신의 _에이전트_가 개선되는지의 여부는 당신의 하네스에 관한 문제이며, 구체적으로는 당신이 루프를 폐쇄형으로 연결(wired the loop closed)했는지에 관한 문제입니다.
이 포스트의 두 레이어는 제가 하나의 단위로 사용하는 두 가지 도구에 대응합니다. agent-eval은 평가 프레임워크(eval framework)로, 에이전트의 출력(output)(계약 검증, 드리프트(drift), 환각(hallucination), 노후화(staleness))을 점수화하고 게이트를 통과시킵니다. 위 사고 사례에서의 validate --finished 체크가 바로 이 도구의 역할입니다. AgentLens는 트레이스 레이어(trace layer)로, 에이전트가 거기에 어떻게 도달했는지(모든 모델 및 도구 단계, 해결된 입력값, 가공되지 않은 출력값)를 캡처하여 평가 신호(eval signal)를 실제로 디버깅할 수 있게 합니다. agent-eval은 무언가 고장 났음을 알려주고, AgentLens는 그 이유를 알려줍니다. 이들은 의도적으로 함께 제공됩니다. 하나의 피드백 루프를 구성하는 두 개의 절반이며, 이것이 바로 이 포스트의 핵심 논지입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기