[Agent Eval 구현 노트 2] Multi-step replay의 경계와 teacher forcing

시리즈 허브 · 구현 노트 2/4

Multi-step 평가가 어려운 이유

한 번의 사용자 요청도 여러 번의 모델 판단으로 이어질 수 있다.

사용자 요청
  → action A 선택
  → tool A 결과
  → action B 선택
  → tool B 결과
  → 최종 응답

두 번째 판단을 재현하려면 첫 번째 tool call과 output이 conversation history에 있어야 한다. 그러나 두 번째 판단의 expected action까지 request에 섞이면 모델이 정답을 보게 된다.

따라서 평가 시스템은 다음 둘을 명시적으로 구분해야 한다.

  • Replay fixture: 현재 step 이전에 이미 관측됐다고 가정하는 history
  • Expectation: 현재 step 이후에 나와야 하며 scorer만 볼 수 있는 정답

Turn, step, path

용어를 먼저 고정하면 구현 경계가 단순해진다.

  • Turn은 한 번의 사용자 utterance에서 시작한다.
  • Step은 에이전트가 action을 결정하는 한 번의 판단이다.
  • Path는 같은 turn에서 허용되는 step sequence다.
  • Alternative는 동일한 사용자 의도를 만족하는 다른 path다.

Single-step과 multi-step을 서로 다른 파일 형식으로 나누기보다 step 수로 구분하면 loader와 schema를 공유할 수 있다.

Projection sequence

정답 누출 없이 multi-step을 재현하는 시퀀스 다이어그램

Projection layer는 검증된 test case를 다음 두 결과로 바꾼다.

ExecutionPlan
├── requests[]       # runtime에 전달
└── expectedPaths[]  # scorer에만 전달

Step 0 request에는 사용자 입력과 request context만 들어간다. Step N request에는 0..N-1의 고정된 messages, tool calls와 tool outputs가 포함된다. Step N의 expectation은 request 밖에 둔다.

이 분리는 보안상의 prompt leakage만 막는 것이 아니다. Runtime client와 scorer가 서로의 데이터 구조를 알지 않게 해 다음 변경을 독립적으로 만들 수 있다.

  • Runtime request contract 변경
  • Scoring field 추가 또는 제외
  • Alternative path 정책 변경
  • Report format 변경

하지만 이 projection이 정답 누출을 막는다고 해서 실제 trajectory가 되는 것은 아니다. Step N은 모델이 앞에서 실제로 만든 결과가 아니라 TC에 고정된 0..N-1 history를 받는다. 따라서 첫 step이 틀려도 다음 step은 올바른 과거를 전달받을 수 있다.

이 구조가 답하는 질문은 “올바른 중간 observation이 주어졌을 때 다음 판단을 잘하는가?”다. 처음부터 끝까지 agent가 스스로 올바른 상태를 만들었는지는 별도의 stateful episode에서 평가해야 한다.

History를 누적하는 규칙

각 step을 projection할 때 다음 불변식을 지킨다.

  1. 아직 실행되지 않은 step의 output은 request에 넣지 않는다.
  2. 이전 step의 output은 authoritative evidence가 있을 때만 넣는다.
  3. Current expectation은 history로 serialize하지 않는다.
  4. Request context는 turn의 실제 조건을 유지한다.
  5. Time과 encoded context는 runtime contract에 맞게 변환하되 원본 의미를 바꾸지 않는다.

Tool output 전체가 필요하지 않다면 다음 판단에 필요한 최소 계약만 저장하는 방법도 있다. 다만 평가 당시와 production runtime이 실제로 읽는 필드가 무엇인지 확실해야 한다. 근거 없이 fixture를 축약하면 replay가 실제 경로를 재현하지 못한다.

Alternative projection과 실제 trial을 구분한다

같은 요청에 정상 path가 두 개 있다고 가정하자.

Preferred:   A → B → Final
Alternative: A → C → Final

Preferred의 B output을 Alternative의 C 이후 history에 섞어서는 안 된다. 각 path의 replay fixture는 독립적으로 만들어야 한다. 그렇지 않으면 실제로 존재할 수 없는 conversation state를 평가하게 된다.

그러나 “독립된 fixture를 만든다”와 “path마다 모델을 다시 호출한다”는 다른 문제다. 초기 구현처럼 preferred가 실패한 뒤 alternative 전용 history로 새 invocation을 실행하고 하나라도 맞으면 통과시키면, alternative는 허용 정답이 아니라 추가 시도가 된다. Path 수가 많을수록 성공 기회가 늘어나는 숨은 pass@k다.

허용 path는 원칙적으로 한 번 생성한 actual trajectory에 대한 여러 oracle이어야 한다.

잘못된 방식
  preferred용 trial → 실패
  alternative용 새 trial → 성공
  case PASS

원하는 방식
  actual trial 1회
    → preferred outcome과 비교
    → alternative outcomes와 비교
    → 하나의 oracle과 일치하면 PASS

Cross-turn replay에서도 현재처럼 preferred의 pinned history를 항상 이어받으면 deterministic한 component test는 가능하지만, 앞 turn에서 실제 선택한 alternative의 결과가 다음 turn에 전파되지는 않는다. 실제 대화를 평가하려면 evaluator가 임의로 history를 고르는 대신 environment가 actual trajectory를 소유해야 한다.

실제 실행과 fixture replay의 경계

모든 tool을 실제로 실행하면 외부 상태와 비용 때문에 재현성이 떨어질 수 있다. 반대로 모든 output을 fixture로 고정하면 runtime orchestration 문제를 놓친다.

일반적으로 다음 기준이 유용하다.

대상 처리 방식
현재 평가하려는 agent decision 실제 runtime 호출
이전 step의 이미 검증된 tool result Replay suite에서는 fixture
안전하고 결정적인 local tool 목적에 따라 실제 실행 가능
외부 상태를 변경하는 action Replay에서는 fixture, episode에서는 stateful backend
최종 자연어 응답에 필요한 결과 계약이 확인된 fixture

어디까지 실제 실행할지는 평가 목표에 따라 다르지만, artifact에는 실제 호출과 fixture 사용을 구분해 남겨야 한다.

Replay 다음에는 environment boundary가 필요하다

TC에서 tool output을 제거하려면 다음 output을 생성할 주체가 필요하다. 선택지는 stateful simulator, 격리된 service sandbox 또는 제한된 실제 환경이다.

actual action
  → environment.execute(action, current state)
  → actual tool observation + next state
  → 다음 agent input

따라서 기존 projector는 ReplayExecutor의 입력을 만드는 계층으로 유지하고, 실제 action과 state를 이어가는 EpisodeExecutor를 별도로 두는 편이 명확하다. Replay의 재현성을 버리지 않으면서 end-to-end 성공률과 decision regression을 같은 숫자로 섞지 않을 수 있다.

테스트해야 할 불변식

  • Step N request에 N의 expectation이 포함되지 않는다.
  • Step N request에는 0..N-1 history만 들어간다.
  • Preferred와 alternative의 history가 공유되지 않는다.
  • Tool output reference는 완료된 이전 step만 가리킨다.
  • Projection은 같은 test case에 대해 deterministic하다.
  • 원본 test case를 수정하지 않고 immutable plan을 반환한다.

Projection을 별도 계층으로 두면 “평가 데이터가 유효한가”와 “runtime에 무엇을 보낼 것인가”, “결과를 어떻게 채점할 것인가”를 각각 테스트할 수 있다.

이전: 구현 노트 1. 평가 계약과 검증 경계

다음: 구현 노트 3. 경로 채점의 함정과 discovery continuation