English version

Agents and Reinforcement Learning

Date: |Estimated Reading Time: 40 min|Author: Seungheon Doh

Update log
  • 블로그 시작.

Article · Agent의 실행 구조와 정책 학습

“실패하는 테스트를 고쳐 주세요.” 짧은 요청 하나가 긴 선택의 연속을 만듭니다. 어떤 파일을 먼저 읽을지, 오류의 원인을 어디서 찾을지, 코드를 바꾼 뒤 무엇을 확인할지 결정해야 합니다. LLM 기반 Agent는 도구로 행동을 실행하고, 돌아온 결과를 읽으며 다음 선택을 이어 갑니다. 실행이 끝나면 성공과 실패의 기록이 남습니다. 강화학습에서는 이 기록을 활용해, 다음 시도에서 더 나은 선택을 하도록 모델을 학습시킵니다.

이미 학습된 LLM도 추론 중에 오류를 읽고 다시 시도할 수 있습니다. 그런데 왜 Agent를 추가로 학습시킬까요? 일반적인 추론에서는 가중치를 고정한 채 context에 새 정보를 넣어 다음 행동을 바꿉니다. 실패 원인을 알아내더라도 그 경험이 모델 가중치에 자동으로 남지는 않습니다. 기록을 메모리로 보존해 다음 과제에서 참고할 수 있지만, 그 기록을 해석하고 행동을 고르는 능력은 여전히 기존 모델에 달려 있습니다. 추가 학습은 여러 시도의 경험을 가중치에 반영해, 이후 과제에서도 유용한 도구를 고르고 불필요한 시행착오를 줄이는 선택을 더 자주 하도록 만드는 방법입니다. 추론할 때마다 다시 학습해야 한다는 뜻은 아닙니다.

강화학습이 모든 Agent의 필수 조건은 아닙니다. 다만 여러 단계의 행동을 거쳐야 하고, 올바른 행동 순서를 일일이 써 주기는 어려워도 최종 결과를 평가할 수 있다면 유용한 학습 방법이 됩니다. 코드가 그럴듯해 보여도 실제 테스트에는 실패할 수 있고, 같은 정답에 도달하더라도 도구 호출 횟수와 비용은 다를 수 있습니다. 강화학습은 이런 실행 결과를 보상으로 삼아 정책을 개선하고자 합니다. 그렇다면 마지막에 받은 점수 하나를 앞선 수십 번의 판단에 어떻게 연결할까요? 같은 문제에 대한 여러 시도를 비교하면 무엇을 배울 수 있을까요? Agent를 학습시키는 일은 이 질문들에 구체적인 계산으로 답하는 과정입니다.

이 글은 하나의 실행 기록이 실제 학습 신호가 되는 길을 따라갑니다. 모델과 환경의 상호작용에서 출발해 정책 경사를 유도하고, PPO와 GRPO의 목적함수가 LLM의 토큰별 loss로 옮겨지는 과정을 풀어 봅니다. 이어 긴 행동열의 공로를 가리는 문제, 교사 모델에서 배우는 distillation, 경험 수집과 학습을 겹칠 때 생기는 정책 지연을 살펴봅니다. 수식과 작은 실험을 연결하며 끝까지 붙잡을 질문은 하나입니다. Agent가 겪은 경험 중 무엇을, 어떤 근거로, 다음 선택에 남겨야 할까요?

LLM, policy, and environment

  • Policy(정책) \(\pi_\theta(a_t\mid c_t)\): 현재 입력 \(c_t\)에서 행동 \(a_t\)를 선택하는 확률분포다. 이 글에서는 LLM이 이를 구현하며, \(\theta\)는 학습하는 모델 가중치다.
  • Environment(환경): 행동을 실행해 다음 상태·관측·보상·종료 정보를 만드는 외부 시스템이다. 상태 전이는 \(P(s_{t+1}\mid s_t,a_t)\)로 표현한다.
  • State(상태) \(s_t\): 행동 뒤에 환경이 어떻게 변할지를 정하는 데 필요한 정보다. 코딩 환경에서는 현재 작업 파일, 검사 규칙, 남은 실행 예산 등이 해당한다. 모델에 아직 공개되지 않은 정보도 포함할 수 있다.
  • Observation(관측) \(o_t\): 환경이 모델에게 공개한 정보다. 예를 들어 실행한 테스트의 통과 여부와 오류 메시지가 관측이다. 환경은 상태의 일부만 관측으로 내보낸다.
  • Context(입력) \(c_t\): 이번 LLM 호출에 실제로 넣는 입력이다. 문제 설명, 이전 행동, 여러 관측을 함께 포함할 수 있다. 전체 상호작용 기록을 \(h_t\), 입력 구성 함수를 \(C\)라 하면 \(c_t=C(h_t)\)다. 길이 제한에 따라 기록 일부를 생략하거나 요약할 수도 있다.
  • Action(행동) \(a_t\): 코드 수정이나 테스트 호출처럼 정책이 고르는 선택이다. LLM은 이를 토큰열 \(a_t=(y_{t,1},\ldots,y_{t,K_t})\)로 생성한다. \(t\)는 행동 시점, \(K_t\)는 그 행동의 토큰 수다.
  • Episode: 초기화에서 종료까지 한 번의 시도다. 행동 횟수를 \(T\)라 하면 \(t=0,\ldots,T-1\) 동안 진행한다. 한 모델 응답이나 한 테스트 케이스가 아니라, 그것들을 여러 번 묶은 단위다.
  • Rollout: 정책을 실행해 경험을 수집하는 과정, 또는 그때 얻은 표본이다. 완결된 episode일 수도, 중간에 끊긴 부분 기록일 수도 있다.
  • Trajectory(경로 기록) \(\tau\): 실제로 거친 관측·행동·보상 등의 순서 있는 기록이다. 관측과 행동만 적으면 \(\tau=(o_0,a_0,o_1,\ldots,o_T)\)다.
  • Reward(보상) \(r_t\), return(누적 보상) \(G_t\): 전자는 행동 \(a_t\) 뒤에 받은 평가 숫자, 후자는 그 시점부터의 할인합 \(G_t=\sum_{u=t}^{T-1}\gamma^{u-t}r_u\)다. \(\gamma\)는 할인율이며, 이 글의 기본 설정은 \(\gamma=1\)이다.
  • Advantage \(A^\pi(h_t,a_t)=Q^\pi(h_t,a_t)-V^\pi(h_t)\): 특정 행동을 고른 뒤의 기대 return \(Q^\pi\)가 현재 기록의 기준 가치 \(V^\pi\)보다 얼마나 높은지 나타낸다. 실제 학습에서는 추정값 \(\hat A\)를 쓰며, GRPO는 그룹 보상으로 비교값을 만든다.
  • Group과 rollout batch: 같은 문제의 비교 시도 \(G\)개가 한 그룹이다. \(B\)개 문제마다 \(G\)번 수집하면 batch에는 \(N=BG\)개의 trajectory가 들어간다. 글자는 같아도 그룹 크기 \(G\)와 시점별 return \(G_t\)는 무관한 기호이므로 아래 첨자를 보고 읽는다.
  • Loss mask \(m_{ik}\): trajectory \(i\)의 토큰 위치 \(k\)를 학습 target으로 사용할 때 1, 제외할 때 0이다. 이름이 비슷한 attention mask는 학습 target이 아니라 어떤 입력 위치를 읽을 수 있는지를 제어한다.
  • Harness: 모델의 입력 구성·도구 실행·상태 저장·결과 확인·제어 루프를 조직하는 실행 시스템이다. 입력 구성 \(C(h_t)\)도 이 층의 선택이다. 본문에서 각 역할을 구체화한다.
  • Verifier와 value critic: verifier는 결과를 검사해 보상을 정하고, value critic은 그 뒤에 이어질 return을 \(\hat V(h_t)\)로 추정한다. 한쪽은 이미 나온 답을 판정하고, 다른 한쪽은 아직 오지 않은 성과를 내다본다.
  • Behavior / current / reference policy \(\pi_{\mathrm{old}},\pi_\theta,\pi_{\mathrm{ref}}\): 각각 경험을 만든 정책, 지금 최적화하는 정책, KL 정규화의 기준 정책이다. 같은 LLM의 서로 다른 가중치 snapshot이 이 역할들을 맡을 수 있다.
  • Policy lag: 수집 정책 \(\pi_{\mathrm{old}}\)와 현재 learner \(\pi_\theta\) 사이의 버전 지연 또는 정책 차이다. 몇 번의 갱신만큼 뒤처졌는지와 두 분포가 얼마나 벌어졌는지는 각각 따로 센다.

Agent and environment

이 글에서 LLM 기반 Agent는 주어진 목표와 제약 안에서 LLM이 다음 행동을 선택하고, 환경이 돌려준 결과를 관측하며, 완료 또는 중단까지 실행을 이어 가는 시스템이다. 정책은 선택을 담당하고, 환경은 그 선택을 실행한다.

이 정의는 모델의 선택이 실제 실행으로 이어지고, 그 결과가 다시 다음 선택의 입력이 되는 순환을 전제한다. 공개 가이드들은 여기에 실행 흐름의 자율성을 얼마나 강조하는지에 따라 범위를 조금씩 다르게 잡는다.

Anthropic의 Building effective agents는 실행 흐름을 누가 결정하는가를 기준으로 workflow와 agent를 구별한다. Workflow에서는 LLM과 도구가 미리 작성된 코드 경로 안에서 움직인다. 모델이 중간 결과를 만들거나 분기를 선택할 수는 있지만, 전체 작업을 연결하는 구조는 개발자가 설계한다. Agent에서는 모델이 환경의 피드백을 받아 다음에 사용할 도구와 진행 방식을 실행 중에 결정한다. 예를 들어 실패 로그를 보고 어떤 파일을 더 읽을지, 추가 검사가 필요한지 판단하며 작업을 이어 간다. 도구를 쓰거나 반복문을 돈다는 사실만으로는 두 구조가 갈라지지 않는다. 경계는 모델에 맡긴 의사결정의 범위가 어디까지인가에 있다(“What are agents?”, “Agents”).

OpenAI의 A practical guide to building agents는 사용자를 대신해 과제를 수행하는 독립성에서 출발한다. 구체적으로는 LLM이 workflow의 실행을 관리하고, 현재 상황에 맞는 도구를 선택하며, 필요하면 행동을 수정할 수 있어야 한다. 완료 여부를 판단하거나 실패했을 때 실행을 멈추고 사용자에게 제어를 돌려주는 것도 이 역할에 포함된다. 여기서 자율성은 정해진 도구와 제약 안에서 과제를 진행할 판단을 모델에 넘긴 범위를 가리키며, 실행량을 무제한으로 풀어 준다는 뜻과는 거리가 있다(“What is an agent?”).

Google의 Agents 백서(Wiesinger, Marlow & Vuskovic, 2024)는 목표를 위해 환경을 관측하고 도구로 행동하는 애플리케이션으로 Agent를 설명한다. 구성요소는 model, tools, orchestration layer로 나눈다. Model은 추론과 선택을 담당하고, tools는 외부 정보와 실행 기능에 접근하게 하며, orchestration layer는 정보 수집·추론·행동을 반복하는 과정을 연결한다. 개별 모델 호출보다, 목표에 도달하거나 중단할 때까지 이어지는 전체 실행을 정의의 단위로 삼는 것이다(“What is an agent?”, “The orchestration layer”, pp. 5–7).

세 설명은 결국 두 축 위에 놓인다. 하나는 관측·행동·피드백이 연결된 실행 구조이고, 다른 하나는 그 구조 안에서 모델에 부여한 선택의 범위다. 이 글에서는 모델이 현재 기록을 바탕으로 다음 행동을 고르는 부분을 정책 \(\pi_\theta(a_t\mid c_t)\)으로 표현한다. 정책이 어떤 입력을 받고, 어떤 행동을 실행할 수 있으며, 그 결과가 어떻게 다음 입력으로 돌아오는지는 정책을 둘러싼 harness가 조직한다.

Harness: 모델의 판단을 실행으로 연결하는 시스템

Harness(하네스)는 모델을 둘러싸고 과제의 실행을 조직하는 시스템이다. 모델에 보여 줄 입력을 구성하고, 생성된 도구 호출을 실행하며, 결과와 작업 상태를 보존하고, 다음 모델 호출이나 종료로 연결한다. Lilian Weng (2026)은 여기에 추론과 계획의 진행 방식, context 관리, 산출물 저장, 결과 평가까지 포함한다. 이 관점에서 harness는 모델이 한 과제를 끝까지 수행할 수 있게 하는 실행 구조다.

Weng은 harness engineering을 프롬프트 템플릿을 넘어선 runtime과 소프트웨어 시스템의 설계로 설명한다. 긴 실행에서는 모든 로그를 매번 context에 넣기 어렵기 때문에 파일에 상태와 산출물을 남기고 필요한 부분을 다시 읽는다. 여러 작업을 병렬로 수행한다면 작업의 시작·진행 상태·결과를 추적하고 합치는 절차도 필요하다. 이를 이 글의 실행 과정에 대응시키면 다음과 같다.

Harness의 역할구체적으로 정하는 것다음 행동에 미치는 영향
입력과 context 구성지시문, 도구 명세, 읽어 올 기록과 요약모델이 판단에 사용할 정보가 정해진다.
도구 실행과 권한 관리호출 해석, 인자 검증, 실행 가능한 작업생성된 요청이 실제 외부 작업으로 연결된다.
상태와 산출물 보존파일, 변경 내역, 실행 로그, 작업 상태긴 과제에서도 이전 작업을 확인하고 이어 갈 수 있다.
실행 흐름 관리다음 모델 호출, 재시도, 작업 분배, 예산과 종료 조건개별 호출이 하나의 지속적인 과제 수행으로 연결된다.
결과 확인과 피드백테스트·평가 도구와 결과를 돌려주는 절차모델이 진행 상황을 확인하고 후속 행동을 선택한다.

예를 들어, 비어 있지 않은 정수 배열에서 최댓값을 반환하는 함수 findMax를 고치는 과제를 생각해 보겠습니다. 현재 코드는 최댓값 후보를 best = 0으로 초기화하고, 배열을 순회하며 더 큰 값이 나올 때만 후보를 바꿉니다. 입력이 [3, 1, 2]이면 올바르게 3을 반환하지만, [-2, -5, -8]이면 어떤 원소도 0보다 크지 않아 0을 반환합니다. 기대값은 -2입니다. 해결할 문제는 이 초기화 오류이며, 목표는 음수만 있는 배열에서도 올바른 최댓값을 반환하도록 코드를 수정하는 것입니다.

Agent가 처음 받는 사용자 요청은 “저장소의 findMax 함수에서 실패하는 테스트를 확인하고, 함수 코드를 수정해 모든 테스트가 통과하도록 해 주세요”입니다. Harness는 이 요청과 run_tests, read_code, write_code, finish의 도구 명세를 첫 context에 넣습니다. 위에서 설명한 오류 원인이나 실패한 입력은 아직 모델에게 주어지지 않았습니다. 모델은 테스트를 실행하고 코드를 읽어 이를 알아내야 합니다. 여기서 배열은 findMax의 입력이고, 요청·도구 명세·이후에 돌아오는 실행 결과는 LLM의 입력입니다.

이 예시의 테스트는 [3, 1, 2] → 3, [-2, -5, -8] → -2, [0] → 0 세 가지입니다. 다음 표는 Agent가 실패를 확인하고, 원인을 찾아 수정한 뒤, 세 테스트를 다시 통과시키는 한 번의 실행을 보여 줍니다.

순서모델이 결정한 것Harness가 처리한 것
1무엇이 틀렸는지부터 확인하려고 run_tests()를 생성한다.문자열을 호출로 파싱해 격리된 실행기에서 테스트를 돌린다. 긴 출력 중 실패한 입력과 기대값·실제값(findMax([-2, -5, -8]): expected -2, received 0)만 남겨 다음 context에 넣는다.
2로그를 보고 함수 본문을 확인하려고 read_code()를 생성한다.파일을 읽어 내용을 돌려준다. 모델은 파일 시스템에 직접 접근하지 않는다.
3best = 0에서 시작하면 음수만 있는 배열에서 값이 갱신되지 않는다고 판단하고, 초기값을 첫 원소로 바꾸는 write_code(...)를 생성한다.인자를 검증하고 파일에 저장한 뒤 변경 내역을 남긴다. 아직 테스트하지 않은 상태라는 것도 함께 기록한다.
4수정이 맞는지 확인하려고 run_tests()를 다시 생성한다.테스트를 다시 실행해 “3 passed”를 돌려주고, 남은 턴 예산을 확인한다.
5과제가 끝났다고 판단하고 finish(...)를 생성한다.실행을 종료하고 최종 코드를 채점기에 넘긴다.

왼쪽 열은 모델이, 오른쪽 열은 harness가 정한다. 무엇을 확인하고 어떻게 고치며 언제 멈출지는 모델의 선택이다. 그 선택을 실제 파일과 실행기에 전달하고, 결과 중 무엇을 다음 입력으로 보여 줄지는 harness의 설계다. 이 글의 뒤에서 강화학습으로 바꾸려는 것은 왼쪽 열, 즉 정책이다.

이 구분은 정책과 시스템이 성과에 기여하는 방식을 설명해 준다. 같은 모델이라도 실패 로그의 핵심을 context에서 잘라 버리면 다음 수정의 근거를 잃고, 작업 상태를 저장하지 않으면 이미 수행한 검사를 반복할 수 있다. 따라서 Agent의 성능을 비교할 때는 모델 가중치와 함께 harness의 구성도 실험 조건으로 다뤄야 한다. 정책 학습은 주어진 입력에서 행동의 확률을 바꾸고, harness 개선은 모델이 판단하고 실행하는 조건을 바꾼다.

Harness와 environment는 같은 실행을 서로 다른 각도에서 가리킨다. Environment는 정책의 행동을 받아 상태와 관측이 변하는 대상을 가리키고, harness는 모델과 그 대상 사이의 실행을 구성하는 구현을 가리킨다. 예를 들어 저장소와 테스트 실행기는 코딩 정책이 상호작용하는 환경이며, 그 테스트를 어떤 도구로 노출하고 반환 로그를 다음 context에 어떻게 넣을지는 harness 설계다. 실제 구현에서는 두 역할을 맡는 코드가 겹칠 수 있다.

LLM에게 environment는 무엇인가

환경(environment)은 모델이 선택한 행동을 받아, 그 결과와 다음 관측을 만들어 주는 외부 시스템이다. 인터넷이나 물리적 공간일 필요는 없다. 코딩 과제라면 작업 파일, 실행기, 테스트와 채점 규칙, 초기화·종료 규칙이 환경을 이룬다. 문제 설명은 환경을 소개하는 입력이지 환경 전체가 아니다.

수정과 검증을 나누어 보면 환경의 경계도 분명해진다. 정책은 “파일을 수정하라”라는 호출을 생성하고, 환경은 저장된 코드를 바꾼다. 정책이 run_tests()를 선택하면 환경은 현재 코드를 실행해 기대값과 실제값을 반환한다. 테스트는 코드 자체를 바꾸지 않지만, 모델의 판단에 필요한 정보를 추가하고 실행 예산을 소비한다.

혼동하기 쉬운 말코딩 환경에서의 예서로 다른 이유
환경 상태 \(s_t\)현재 코드·검사 규칙·남은 예산 등 전이에 필요한 정보아직 모델에 보여 주지 않은 내용도 포함할 수 있다.
관측 \(o_t\)테스트 실패와 오류 위치를 담은 실행 결과환경이 공개한 정보이지 상태 전체가 아니다.
Context \(c_t\)문제·이전 호출·실행 결과로 구성한 이번 모델 입력여러 관측을 포함할 수 있고, 길이 제한 때문에 일부를 잃을 수도 있다.
도구(tool)read_code, write_code, run_tests환경에 접근하는 인터페이스이지 환경 전체가 아니다.
보상(reward)최종 채점에서 통과하면 1, 아니면 0실패 로그를 어떤 숫자로 평가할지는 별도 설계다.

이러한 구분은 환경 인터페이스에도 나타난다. Gymnasium의 Env.reset은 초기 관측을 반환하고, Env.step은 행동 뒤의 관측·보상·종료 정보를 별도로 반환한다. 테스트 실패 로그도 다음 판단에 쓰는 관측이며, 그 실행에 몇 점을 줄지는 보상 규칙이 정한다.

이 선택–실행의 연결을 실제로 수행하는 것이 앞 절의 harness다. 호출을 해석하고 도구를 실행하며, 반환값을 다음 context에 넣고 반복을 제어한다. 여기까지의 반복에서는 입력 \(c_t\)와 환경 상태 \(s_t\)가 바뀔 뿐, 모델 가중치 \(\theta\)는 그대로다.

LLM의 행동을 MDP로 적으면

여기까지의 요소를 모으면 코드 수정 과정이 하나의 의사결정 문제가 된다. 현재 코드와 실행 예산은 상태 \(s_t\), 모델이 고른 호출은 행동 \(a_t\), 실행기가 코드를 바꾸고 결과를 돌려주는 규칙은 전이 \(P(s_{t+1}\mid s_t,a_t)\)에 대응한다. 이를 상태 집합 \(\mathcal S\), 행동 집합 \(\mathcal A\), 전이, 보상의 조건부 기대 \(r(s,a)\), 할인율 \(\gamma\)로 정리한 모형이 Markov decision process(MDP)다. 유한한 시도를 다루므로 초기 분포와 종료 조건도 지정한다.

이 모형을 LLM에 연결하는 지점은 행동의 표현이다. LLM이 생성하는 행동은 토큰열이므로, 어휘 \(V\)에 대해 하나의 행동은 다음과 같다.

\[a=(y_1,\ldots,y_K)\in\bigcup_{K\le K_{\max}}V^{K}\]

유한하지만 조합적으로 거대하다. 어휘가 10만 개이고 길이가 50이면 후보의 수는 \(10^{250}\)이다. 그래서 각 행동의 값을 표로 저장하는 접근은 처음부터 불가능하고, 정책을 토큰 단위의 조건부 분포로 인수분해해서 표현한다.

\[\pi_\theta(a\mid h)=\prod_{k=1}^{K}\pi_\theta(y_k\mid h,\,y_{<k})\]

이 인수분해 덕분에 행동을 표본추출하고 로그확률과 그 미분을 계산할 수 있다. 가변 길이 행동의 확률에는 종료 토큰이나 명시된 중단 규칙도 포함한다. 이 글이 정책 경사에 집중하는 이유는 이 표현이 사전학습 언어 모델과 자연스럽게 연결되기 때문이다. 큰 행동 공간이 Q-learning을 수학적으로 금지하지는 않는다. 토큰 단위 가치 함수나 후보 행동 집합을 쓰는 구성도 가능하지만, 행동의 최대값 계산과 가치 추정의 오차를 별도로 다뤄야 한다.

같은 토큰열이 무엇으로 해석되는지는 실행기가 정한다. 수정된 파일 내용을 출력하면 산출물이고, run_tests()를 호출하면 실행 요청이다. “수정을 마쳤습니다”라는 최종 답변은 사용자에게 전달된다. 셋 다 문자열이라는 한 가지 표현을 쓰고, 갈라지는 지점은 실행기가 그 문자열에 무엇을 하느냐다. 뒤의 그림에서는 코드 수정과 테스트 실행을 각각 명시적인 행동으로 표시한다.

같은 “토큰열 하나”가환경이 하는 일이 글의 예
산출물로 쓰인다검사·채점의 입력이 된다수정된 소스 파일
호출로 파싱된다실제 함수를 실행하고 결과를 관측으로 돌려준다run_tests()
최종 응답이 된다사용자에게 전달하고 episode를 끝낸다finish({status: …}), 또는 그냥 답변

행동을 확률로 표현했으니, 그 확률이 무엇에 조건화되는지도 정해야 한다. 코드와 실행 상태를 모두 공개한다면 완전 관측 MDP로 다룰 수 있다. 숨긴 채점 입력이나 실행기의 내부 상태를 모델이 볼 수 없다면 부분 관측 MDP(POMDP)로 모델링한다. 두 경우를 가르는 것은 다음 선택에 필요한 정보 중 무엇이 실제로 모델에 도착했는지이며, LLM을 쓴다는 사실 자체는 부분 관측을 만들지 않는다.

초기 과제, 관측, 행동을 모두 보존한 완전한 기록 \(h_t\)를 상태로 삼으면 history MDP가 된다. 반면 실제 입력은 보통 \(c_t=C(h_t)\)라는 잘리거나 요약된 context이고, 실행 정책은 \(\pi_\theta(a_t\mid C(h_t))\)다. 본문에서는 표기를 줄여 \(\pi_\theta(a_t\mid h_t)\)로 쓰되, 정책 내부에 이 context 구성이 포함된 것으로 읽는다. 전체 기록이 Markov라는 사실은 요약된 입력도 Markov라는 뜻이 아니다.

예를 들어 오류 위치와 실행 조건이 다른 로그를 모두 “테스트 실패”로 요약하면, 원인을 구분하고 다음 행동을 고르는 데 필요한 정보를 잃는다. POMDP의 belief state \(b_t(s)=P(s_t=s\mid h_t)\)는 알려진 환경 모형 아래 충분한 통계량이 될 수 있지만, 자연어 요약이 그 역할을 한다고 가정할 수는 없다. Context 관리를 바꾸면 다음 행동의 근거도 바뀐다.

이 글에서는 완료 보고 또는 정해진 예산의 소진으로 실행이 끝나는 설정을 사용한다. 기본 보상은 중간에는 0, 종료 시 과제에 성공하면 1로 두고 할인율은 \(\gamma=1\)을 사용한다. 실행이 유한하므로 늦은 행동의 보상도 앞선 행동과 같은 무게로 센다.

이후의 정책 경사는 두 가지에서 출발한다. 실제 사용한 입력에서 행동의 확률을 알고, 같은 환경에서 그 행동의 결과를 다시 수집하면 된다. 완전한 상태 관측이나 미분 가능한 환경은 전제하지 않는다.

정책과 harness는 서로 다른 설계 대상이지만 실행에서는 함께 작동하므로, 학습 효과를 평가할 때는 어떤 입력 구성과 어떤 도구 위에서 얻은 결과인지도 함께 기록한다.

수식에서 \(a_t\)라고 쓴 행동을 실제로 실행하려면 한 단계가 더 필요하다. 모델이 만든 문자열을 어떤 도구 호출로 해석하고, 반환값을 어떤 형태로 다음 입력에 넣을지 정해야 한다.

Reasoning, acting, and observing

run_tests()라는 문자열도 실행기에 전달되기 전까지는 모델이 생성한 토큰일 뿐이다. Harness는 이 출력을 호출로 파싱하고, 인자를 검증하고, 실제 함수를 실행한 뒤 결과를 모델에게 돌려준다. 도구 사용을 구현한다는 것은 모델의 출력 형식만이 아니라 이 왕복 과정 전체를 설계하는 일이다.

앞에서 정의한 harness의 다섯 구성요소가 여기서 한꺼번에 등장한다. 도구 명세가 무엇을 부를 수 있는지 정하고, 파서가 생성물을 호출로 바꾸고, 실행 환경이 그 호출을 수행하고, context 관리가 반환값을 다음 입력에 넣고, 제어 루프가 계속할지 멈출지 정한다.

이 구현의 선택은 앞의 의사결정 모형을 구체화한다. 도구 명세는 가능한 행동 \(\mathcal A\)를, context 관리는 모델 입력 \(C(h_t)\)를, 실행 예산은 종료 조건을 정한다. 같은 LLM이라도 이 조건이 다르면 다른 문제를 푸는 셈이다. 이후 정책 학습의 효과를 비교할 때도 harness를 함께 고정해야 한다.

도구는 이름만으로 충분하지 않다. 무엇을 하는지, 어떤 인자가 필요한지, 결과와 오류가 어떤 형태로 돌아오는지를 정의해야 한다. 다음은 특정 API에 종속되지 않은 축약 예제다. 실제 API에서는 호출 ID를 사용해 요청과 결과를 연결한다. OpenAI function calling.

Algorithm 1. Agent 실행 루프

입력: 모델, context, 도구, 턴 예산 · 출력: 실행 기록과 종료 사유

tool = {
    "name": "run_tests",
    "description": "현재 작업의 테스트 결과를 반환한다",
    "parameters": {},  # 인자 없이 전체 테스트 실행
}

def run_agent(context, max_turns):
    for turn in range(max_turns):
        message = model(context, tools=[tool])
        context.append(message)

        if message.is_final:
            return context, "finished"

        call = validate(message.tool_call)
        result = execute(call.name, call.arguments)
        context.append(tool_result(call.id, result))

    return context, "budget_exhausted"

구조화된 function calling은 이름과 인자를 정해진 형식으로 내보낸다. 텍스트 action 방식에서는 Action: search[…] 같은 문자열을 parser가 읽는다. 코드 실행 방식에서는 모델이 만든 프로그램 하나가 여러 도구를 조합한다. Programmatic tool calling은 반복과 집계 작업을 코드에서 처리해 필요한 결과만 context로 돌려주는 선택이다. MCP는 추론 방식이나 강화학습 알고리즘이 아니라 도구를 연결하는 규약이다. Anthropic advanced tool use.

올바른 형식은 적절한 행동의 일부일 뿐이다. 테스트 도구를 형식에 맞게 호출해도, 수정한 동작과 무관한 테스트만 고르면 검증에 도움이 되지 않는다. 서로 독립인 두 입력은 병렬로 검사할 수 있지만, 수정한 코드를 검사하려면 코드 수정이 먼저 끝나야 한다. 모델은 형식뿐 아니라 입력 선택, 순서, 오류 복구를 함께 익혀야 한다.

추론과 행동: ReAct

호출이 성공하면 남는 질문은 그 결과로 무엇을 할 것인가다. 모델은 반환된 결과를 해석하고, 추가로 확인할 것이 있는지 또는 수정할 근거가 충분한지 판단해야 한다. ReAct는 이런 추론과 행동의 결합을 다루는 구성이다.

Yao et al. (2023)은 추론 텍스트와 환경 행동을 함께 생성하는 ReAct를 제안했다(Chapter 2). 행동으로 얻은 관측이 추론을 갱신하고, 갱신된 추론이 다음 행동을 고른다. 이 구성이 요구하는 것은 둘의 교대이지 매 호출 앞에 붙는 긴 사고 문장이 아니다.

자기평가와 수정

이 반복에는 자신의 수정안을 다시 검토하는 선택도 들어간다. 수정 뒤 다른 테스트가 실패하면, 모델은 수정 과정에서 놓친 조건을 피드백으로 정리한다. 현재 코드를 다시 고치는 일은 이번 시도를 바꾸고, 그 피드백을 남기는 일은 다음 시도를 바꾼다.

Madaan et al. (2023)의 Self-Refine은 같은 모델이 피드백을 만들고 출력을 반복 수정하는 방법으로, 추가 가중치 학습 없이 실행된다(Abstract).

Shinn et al. (2023)의 Reflexion은 언어 피드백을 기억에 남겨 이후 시도에 사용한다(Abstract). 두 방법에서 실행을 바꾸는 것은 피드백이고, 가중치를 건드리는 optimizer는 여기에 없다.

이 피드백은 어디까지나 모델의 해석이다. “문제가 해결됐다”는 평가 문장을 생성하는 것과 실제 코드가 테스트를 통과하는 것은 다르다. 그래서 이 글은 자기평가와, 결과를 검사하는 verifier와, 미래 return을 예측하는 value critic에 각각 다른 이름을 붙인다. 피드백이 context에 쌓이는 동안 모델 가중치는 그대로다. 같은 실수를 다음 과제에서도 덜 하게 만들려면 실행 중 수정과는 다른 학습 과정이 필요하다.

From execution to learning

강화학습의 목적은 과제 분포에서 얻는 기대 return을 높이도록 정책을 바꾸는 것이다. 한 실행에서 실패를 복구한 경험은 다음 학습의 표본이 된다. 다양한 과제에서 이런 경험을 반복 수집하면 특정 입력에서의 일회성 수정이 아니라 행동 선택의 경향이 바뀐다.

지도 미세조정(SFT)은 주어진 context에서 예시 행동의 확률을 높인다. 강화학습(RL)은 정책이 만들어 낸 시도를 평가하고 그 결과에 따라 선택 확률을 바꾼다. 행동 과정을 직접 써 주기는 어렵지만 최종 결과를 검사할 수 있을 때, 이 차이가 유용하다.

추론 중 적응은 입력 기록이 바뀌는 일이다. Parameter 학습은 정책을 구현하는 가중치가 바뀌는 일이다. 자기평가나 실패 메모는 입력 기록을 바꿀 뿐이고, optimizer update는 parameter 학습에서만 일어난다.

한 번의 복구를, 반복 가능한 능력으로

같은 실패 기록에 세 가지 개입이 가능하다. 실행 중에는 반례를 입력에 추가하고, SFT에서는 올바른 수정 행동을 정답으로 주며, RL에서는 모델이 직접 이어 간 시도의 결과를 채점한다. 각각 현재 기록 \(h_t\), 시연 행동의 확률, 보상에 따른 행동 확률에 작용한다.

같은 오류를 다루는 방법제공하는 학습·실행 신호변하는 것
실행 중 복구수정 후에도 테스트가 실패했다는 로그를 context에 추가현재 기록 \(h_t\)
교사 시연으로 SFT해당 기록에서 교사가 생성한 올바른 패치를 정답으로 제공모방한 행동의 확률, 가중치 \(\theta\)
환경 보상으로 RL학생이 직접 만든 수정 과정을 실행하고 최종 성공을 채점보상에 따른 행동 확률, 가중치 \(\theta\)

도구 인자부터 틀리는 모델이라면 명세와 시연 데이터를 먼저 점검한다. 유효한 호출은 만들지만 실패 이후의 선택과 복구가 부족하다면, 그때 환경 보상으로 학습하는 방법을 비교한다. RL은 Agent의 필수 구성요소가 아니라, 이런 선택을 개선하는 학습 방법이다.

결과를 검사할 수 있다는 조건은 RL의 보상 설계로 이어진다. Lambert et al. (2024)은 검증 가능한 결과를 보상으로 사용하는 RLVR을 설명한다(Chapter 6). 코딩 과제에서는 최종 산출물의 테스트 통과 여부가 그런 신호다. 다만 검사 입력이 충분한지, 성공하는 경로를 탐색으로 찾을 수 있는지는 따로 확인할 문제다.

SFT와 RL의 관계를 공개 연구에서는 어떻게 다루는가

Chu et al. (2025)은 해당 게임·내비게이션 실험에서 RL의 규칙 변형 일반화와 SFT의 형식 안정화라는 서로 다른 역할을 보고했다(Abstract). 이는 두 방법의 역할 차이이지 모든 Agent 과제에서의 우열이 아니다. DeepSeek-AI (2025)의 R1-Zero는 초기 SFT 없이 시작하지만(Chapter 2.2), 최종 R1은 cold-start 데이터를 사용한다(Chapter 2.3.1). 어떤 초기화가 맞는지는 정책의 기본 능력과 학습 과제에 달려 있다.

이제 필요한 것은 “한 번의 풀이”를 학습 가능한 데이터로 표현하는 일이다. 어떤 관측에서 어떤 행동을 골랐고, 그 시도가 어떤 결과로 끝났는지를 남겨야 행동의 확률과 보상을 연결할 수 있다. 이 기록을 모아 학습하고, 별도 과제 집합에서 새로운 문제에 대한 일반화를 평가한다.

Trajectory and return

Episode는 한 번의 시도, rollout은 실행, trajectory는 그 기록

환경을 초기화한 뒤 정책이 행동을 선택하고 관측을 받으며 종료 조건에 도달할 때까지가 episode, 즉 한 번의 시도다. 그동안 정책을 실제로 실행해 경험을 수집하는 일을 rollout이라고 한다. 문헌에서 “rollout 네 개”라고 하면 그 실행으로 얻은 표본 네 개를 뜻하기도 한다.

Trajectory \(\tau\)는 방문한 관측과 선택한 행동, 받은 보상 등의 순서 있는 기록이다. Episode가 실행의 시작과 끝을 정한다면 trajectory는 그 안에서 어떤 경로를 거쳤는가를 담는다. 같은 문제를 네 번 풀면 네 episode와 네 trajectory가 생긴다. 한 episode 안에서 테스트를 세 번 해도 rollout은 하나고 trajectory도 하나다.

아래는 코드 수정 과제에서 얻을 수 있는 짧은 경로다. \(t\)는 도구 호출 또는 종료 행동의 번호이며 토큰 번호가 아니다. 이 글에서는 \(r_t\)를 행동 \(a_t\)를 실행한 뒤 받은 보상으로 표기한다. 다른 문헌이 같은 보상을 \(r_{t+1}\)로 쓰더라도 시점의 의미는 같다.

\(t\)모델이 고른 \(a_t\)환경이 돌려준 \(o_{t+1}\)\(r_t\)종료?
0run_tests()테스트 실패와 오류 로그0아니오
1read_code()현재 파일 내용0아니오
2write_code(...)수정 내용 저장, 아직 미검사0아니오
3run_tests()테스트 통과0아니오
4finish(...)실행 종료·최종 코드 채점1예

여기서 테스트 통과 로그를 본 시점과 보상을 받은 시점을 의도적으로 나누었다. 보상은 종료할 때 최종 코드를 채점해 한 번만 준다. 중간 테스트마다 점수를 주는 환경도 만들 수 있지만 그것은 다른 보상 설계다. 그림 1은 이런 실행 기록을 더 잘게 나누어 학습에 쓰이는 토큰을 센다.

Rollout은 반드시 완결된 episode일 필요는 없다. 수집기를 일정 스텝 뒤 끊으면 trajectory의 일부만 얻는다. 그러므로 저장할 때는 과제 자체의 종료인 termination과 수집상의 중단인 truncation을 구분해야 한다. Gymnasium Env.step의 두 종료 플래그 설명은 이 구분을 명시한다. 과제 규칙 자체가 “다섯 번 안에 풀기”라면 남은 횟수를 상태에 포함하고 소진을 terminal로 정할 수 있다. 반대로 계속할 수 있는 과제를 수집 편의상 잘랐다면, 남은 return이 0이라고 자동으로 간주해서는 안 된다.

\[G_t=\sum_{u=t}^{T-1}\gamma^{u-t}r_u,\qquad R(\tau)=G_0.\]

Return \(G_t\)은 지금부터 종료까지 받을 보상의 할인합이다. reward라는 말은 한 시점에서 받은 숫자에만 쓴다. 이 글의 기본 설정은 유한한 \(T\), \(\gamma=1\), 마지막 성공 보상뿐이므로 성공한 경로의 모든 행동에서 \(G_t=1\)이다. 행동들은 같은 \(G_t\)를 공유하지만 각각의 기여는 제각각이다. 유용한 선택과 우연히 함께 나온 선택을 가려내는 문제가 뒤의 credit assignment로 이어진다.

Group과 batch는 무엇을 세는가

Group은 같은 문제와 초기 상태에서 독립된 실행기를 사용해 얻은 \(G\)개의 시도다. GRPO는 이 안에서 보상을 비교한다. Rollout batch는 학습을 위해 한 차례 모은 경험의 묶음이다. \(B\)개 문제마다 \(G\)번 실행하면 총 \(N=BG\)개의 trajectory가 된다. 한 episode에서 테스트를 여러 번 실행하는 것은 \(G\)에도 \(B\)에도 세어지지 않는다.

Minibatch는 수집한 batch를 나눈 학습 부분집합, microbatch는 메모리에 맞춰 한 번에 계산하는 더 작은 조각이다. 여러 microbatch의 gradient를 모은 뒤 한 번 가중치를 바꾸는 것이 gradient accumulation이며, 실제 갱신 한 번을 optimizer step이라고 한다. 고정한 수집 데이터를 한 바퀴 사용하는 것은 여기서 epoch라고 부른다. PPO 원문의 Schulman et al. (2017)의 Chapter 5, Algorithm 1에서는 한 iteration 안에 경험 수집과 그 경험을 여러 epoch·minibatch로 최적화하는 두 반복문이 겹쳐 돈다. 본문의 \(B,G,N\)은 이 글의 표기이며 원문의 actor 수·시간 길이 기호와는 다르다.

이제 학습에 사용할 기록을 수식으로 옮긴다. 시각 \(t\)까지의 상호작용을 \(h_t\), 다음 행동을 \(a_t\)라 하면, 정책은 \(\pi_\theta(a_t\mid h_t)\)다. 이 확률은 실제로 구성한 context에 대한 것이며, 모델이 환경의 전체 상태 \(s_t\)를 본다고 가정하지 않는다.

\[a_t\sim\pi_\theta(\cdot\mid h_t),\qquad \tau=(o_0,a_0,o_1,a_1,\ldots,o_T)\]

행동 확률에 로그를 취하면 생성 토큰의 로그확률을 더하는 형태가 된다. 도구 호출도 같은 분해를 따르며, 실제 토큰 수는 tokenizer와 호출 형식에 따라 달라진다.

\[\log\pi_\theta(a_t\mid h_t)=\sum_{k=1}^{K_t}\log\pi_\theta(y_{t,k}\mid h_t,\,y_{t,<k})\]

그래서 이 글에는 두 개의 시간축이 있다. 환경과 주고받는 축은 도구 호출 또는 제출물 단위이고, likelihood를 계산하는 축은 토큰 단위다. 앞으로 나오는 수식은 행동 단위로 쓰지만 구현은 토큰 단위로 한다. 그 대응을 잃으면 뒤에서 다룰 masking과 clipping이 엉뚱한 위치에 걸린다.

관측과 행동에 최종 채점 결과를 연결하면 하나의 학습 표본이 된다. 여기서는 중간 보상은 모두 0이고, 종료 시 최종 코드가 검사를 통과하면 1을 준다. 이진 보상 아래에서는 기대 return을 높이는 것과 성공 확률을 높이는 것이 같다.

\[R(\tau)=\mathbf{1}\{\text{최종 검사 통과}\},\qquad J(\theta)=\mathbb{E}_{\tau\sim\pi_\theta}[R(\tau)]\]

\(J\)의 기대값 아래에는 두 종류의 무작위성이 겹쳐 있다. 하나는 과제 분포다. 어떤 코딩테스트 문제를 뽑는가. 다른 하나는 정책과 환경의 확률성이다. 같은 과제에서도 매번 다른 행동열이 나온다. 하나의 과제에서 성공률을 올리는 것과 새로운 과제에서 성공률을 올리는 것은 다른 목표이며, 뒤에서 held-out 평가를 따로 두는 이유가 여기 있다.

이 단순한 설정에서 \(J\)는 과제 분포에 대한 성공 확률이다. 일반적인 return은 할인된 보상의 합이지만, 우선 유한한 episode와 할인율 1을 사용한다. 모델은 테스트 실행기를 미분할 필요가 없다. 결과를 받았을 때 자신이 선택한 행동의 확률을 미분하면 된다.

그림 1. 성공한 episode를 학습 단위로 자르면

아래는 harness 예시에서 본 최댓값 함수 수정 과제의 성공 episode다. 여기서 볼 것은 코드의 세부 동작이 아니라 모델이 생성한 행동과 환경이 반환한 관측의 경계다. 각 줄을 누르면 그 토큰이 정책 loss에서 맡는 역할이 나온다.

토큰 수는 이 시나리오에 고정한 예시 값이고 특정 tokenizer의 측정치가 아니다. 비율은 그 값에서 그대로 계산한다. 정책 loss의 target에서 제외한 토큰도 attention에서는 그대로 보인다.

이 기록에서 모델이 선택한 것은 호출과 응답이다. 테스트 결과는 환경이 넣었다. 따라서 정책 경사를 계산할 때 도구 관측의 토큰을 모델의 행동처럼 취급해서는 안 된다.

Jin et al. (2025)도 Search-R1에서 검색 결과를 context에는 유지하되 정책 loss의 target에서는 제외한다(Chapter 3.1, Loss Masking for Retrieved Tokens). 코딩 도구가 반환한 테스트 로그에도 같은 구분이 적용된다. 이 masking은 정책 loss에 대한 것이고, 관측을 예측하는 별도 보조 loss는 그와 별개로 둘 수 있다.

이렇게 하면 각 시도에서 두 가지를 얻는다. 정책이 선택한 행동들의 로그확률과, 그 시도가 받은 보상이다. 이 기록 방식은 Agent 밖에서도 그대로 쓰인다. 응답 하나를 채점하는 RLHF나 RLVR도 같은 표기의 특수한 경우이므로, 알고리즘으로 넘어가기 전에 그 관계를 먼저 정리한다.

RLHF, RLVR, DPO, and agentic RL

한 번의 응답을 채점하는 문제

Prompt \(x\)를 받고 응답 \(y\) 하나를 생성해 \(R(x,y)\)로 채점하는 문제는 응답 전체를 하나의 행동으로 보는 contextual bandit으로 적을 수 있다. 앞 절의 trajectory에서 초기 관측 \(o_0=x\)와 행동 하나만 남은 경우다.

\[J(\theta)=\mathbb E_{x\sim\mathcal D}\,\mathbb E_{y\sim\pi_\theta(\cdot\mid x)}\bigl[R(x,y)\bigr]\]

토큰 단위로 풀면 prefix가 늘어나는 순차 과정이지만, 생성 도중 외부 도구 관측이 끼어들지 않는다. Agent에서는 검색이나 코드 실행의 결과가 다음 입력을 바꾼다. 자기 출력만 이어 붙이는 생성에는 이 분기가 없다.

이름은 서로 다른 축을 가리킨다

RLHF는 인간 피드백에서 학습 신호를 얻는 접근을, RLVR은 검사 가능한 결과를 이용하는 보상을, Agentic RL은 환경과 상호작용하는 정책의 학습을 강조한다. 셋은 같은 자리를 두고 겨루는 알고리즘 이름이 아니다. DPO는 또 다른 축인 최적화 방법의 이름이다.

이름어느 축의 이름인가학습 신호대표 구성
RLHF신호의 출처: 사람의 판단응답 비교로 학습한 reward model의 점수SFT → 선호 reward model → PPO (Ouyang et al., 2022)
RLVR보상의 종류: 검사 가능한 결과정답 비교, 테스트 통과 같은 규칙 기반 검사수학 정답 확인, 코드 테스트 (Lambert et al., 2024)
DPO최적화 방법: 선호쌍에 대한 직접 loss선호한 응답과 덜 선호한 응답의 쌍고정된 선호 데이터로 학습, 별도 reward model과 online rollout 없음 (Rafailov et al., 2023)
Agentic RL문제의 구조: 환경과의 여러 차례 상호작용과제 결과, 필요하면 선호나 중간 신호도구 관측이 끼어드는 multi-turn trajectory

그래서 코딩 agent 하나가 여러 이름에 동시에 해당한다. 테스트 통과를 보상으로 쓰면서 인간 선호로 학습한 reward model도 함께 사용한다면 RLVR이면서 RLHF이고, 도구와 상호작용하므로 Agentic RL이기도 하다. 최적화에 PPO를 쓰든 GRPO를 쓰든 이 분류는 바뀌지 않는다. Ouyang et al. (2022)의 SFT·선호 보상 모델·PPO 구성은 대표 사례이지 모든 RLHF의 필수 파이프라인은 아니다.

KL로 정규화한 보상 최적화

RLHF에서 흔히 쓰는 목적함수는 학습한 보상 \(r_\phi\)를 높이되, 기준 정책 \(\pi_{\mathrm{ref}}\)(보통 학습을 시작한 SFT 모델)에서 너무 멀어지지 않도록 KL 벌점을 더한다. 뒤의 GRPO에서 다시 만나는 형태다.

\[\max_\theta\;\mathbb E_{x\sim\mathcal D,\,y\sim\pi_\theta(\cdot\mid x)}\bigl[r_\phi(x,y)\bigr]-\beta\,\mathbb E_{x\sim\mathcal D}\Bigl[D_{\mathrm{KL}}\bigl(\pi_\theta(\cdot\mid x)\,\Vert\,\pi_{\mathrm{ref}}(\cdot\mid x)\bigr)\Bigr]\]

이 목적함수의 최적 정책은 \(\pi^*(y\mid x)\propto\pi_{\mathrm{ref}}(y\mid x)\exp\bigl(r_\phi(x,y)/\beta\bigr)\) 꼴이다. 거꾸로 읽으면 보상을 두 정책의 로그확률비로 표현할 수 있다는 뜻이며, DPO는 이 관계에서 출발한다.

DPO는 이 지도에서 어디에 있는가

DPO는 선호한 응답 \(y_w\)와 덜 선호한 응답 \(y_l\)의 쌍을 사용한다. 위의 관계를 Bradley–Terry 선호 모형에 대입하면, 별도 reward model을 학습하고 그 모델로 online rollout을 채점하는 단계가 다음의 직접적인 선호 loss로 바뀐다. 원형 DPO는 고정된 선호 데이터로 학습할 수 있다(Rafailov et al., 2023).

\[\mathcal L_{\mathrm{DPO}}(\theta)=-\mathbb E_{(x,y_w,y_l)}\left[\log\sigma\!\left(\beta\log\frac{\pi_\theta(y_w\mid x)}{\pi_{\mathrm{ref}}(y_w\mid x)}-\beta\log\frac{\pi_\theta(y_l\mid x)}{\pi_{\mathrm{ref}}(y_l\mid x)}\right)\right]\]

도구 trajectory로도 선호쌍을 만들 수 있다. 다만 loss에 들어가는 것은 정책이 생성한 행동 토큰이고, 환경 관측은 정책이 맞혀야 할 정답이 아니다. 서로 다른 trajectory의 관측과 행동이 섞이지 않게 구성하고, 사용한 확률 모형과 데이터 수집 절차를 함께 적는다. 고정된 선호 데이터만 쓰면 정책이 자기 행동 때문에 마주친 새 상태는 데이터에 들어오지 않고, 선호쌍을 반복해서 새로 수집하는 online 변형은 그 상태까지 담는다. Loss가 무엇인지와 데이터를 어떻게 모으는지는 별개의 선택이다.

보상을 사용하는 정책 경사 계열에서는 행동의 로그확률과 보상이 계산의 재료가 된다. DPO는 스칼라 보상을 직접 넣는 대신 선호쌍과 두 정책의 로그확률비를 사용한다. 다음 절에서는 전자, 곧 표본 보상에서 LLM 가중치의 개선 방향을 추정하는 과정을 다룬다.

Learning from sampled outcomes

정책 경사(policy gradient)는 기대 return을 정책의 파라미터로 미분해 개선 방향을 구하는 방법이다. Trajectory의 확률은 모델이 선택한 행동과 환경의 전이로 분해된다. 환경 규칙을 고정하면 모델이 생성한 행동의 로그확률만 미분해도 기대 return의 gradient를 추정할 수 있다.

기대값을 표본으로 계산할 수 있는 형태로

먼저 한 과제를 고정하자. 보상 함수가 주어지면 바꿀 수 있는 것은 각 경로가 나올 확률이다. 성공 경로에 더 많은 확률을 배정하면 기대 보상이 커진다. 다만 가능한 경로를 모두 합산하기는 어려우므로, 이 합을 정책에서 뽑은 표본의 평균으로 바꾸어야 한다.

\[\begin{aligned} J(\theta)&=\sum_\tau p_\theta(\tau)R(\tau)\\ \nabla_\theta J&=\sum_\tau R(\tau)\nabla_\theta p_\theta(\tau)\\ &=\sum_\tau p_\theta(\tau)R(\tau)\underbrace{\frac{\nabla_\theta p_\theta(\tau)}{p_\theta(\tau)}}_{\nabla_\theta\log p_\theta(\tau)}\\ &=\mathbb E_{\tau\sim p_\theta}\left[R(\tau)\nabla_\theta\log p_\theta(\tau)\right]\\ &=\mathbb E_{\tau\sim\pi_\theta}\left[R(\tau)\sum_t\nabla_\theta\log\pi_\theta(a_t\mid h_t)\right]. \end{aligned}\]

둘째 줄에서는 보상을 고정하고 경로 확률을 미분했다. 셋째 줄은 확률을 곱하고 나누어 합 안에 \(p_\theta(\tau)\)를 만든다. 이 항이 있으면 넷째 줄을 “정책으로 경로를 뽑아 괄호 안을 평균한다”로 읽을 수 있다. 마지막 줄에서는 경로 확률의 곱에 로그를 취해 행동별 로그확률의 합으로 바꾼다. 환경의 전이 항은 고정되어 있으므로 미분에서 사라진다. Williams (1992)의 REINFORCE를 이 trajectory 표기로 전개한 것이다.

환경 항이 사라지는 이유는 경로 확률을 쪼개 보면 드러난다. 환경의 관측 생성 규칙을 \(P(o_{t+1}\mid h_t,a_t)\)라 하면 경로 확률은 다음과 같이 분해된다.

\[p_\theta(\tau)=p(o_0)\prod_t\pi_\theta(a_t\mid h_t)P(o_{t+1}\mid h_t,a_t)\]

환경이 \(\theta\)에 직접 의존하지 않는다는 가정 아래 그 항의 log-gradient는 0이다. 정책이 방문하는 환경의 분포가 간접적으로 바뀌는 효과는 trajectory 확률에 포함된다. 보상 함수를 학습 도중 바꾸거나 환경에 학습 가능한 다른 구성요소가 있으면 이 단순한 전개가 무엇을 고정하는지 다시 명시해야 한다.

실제로는 \(N\)개의 경로를 수집해 \(R_i\sum_t\nabla_\theta\log\pi_\theta(a_{i,t}\mid h_{i,t})\)를 평균한다. 여기서 로그확률의 gradient는 관측된 행동을 더 자주 생성하게 하는 방향이고, 보상은 그 방향에 주는 가중치다. Optimizer가 loss를 최소화한다면 앞에 음수를 붙인다.

두 행동만 있을 때의 gradient

그림 2는 이 계산을 한 번의 결정으로 줄인 것이다. \(\pi_\theta(A)=p=\sigma(z)\), \(\pi_\theta(B)=1-p\)이고, 보상 1을 받을 확률을 각각 \(q_A=0.75\), \(q_B=0.35\)로 두자. \(z\)는 A와 B 사이의 logit 차이다.

\[\begin{aligned} J(z)&=p q_A+(1-p)q_B\\ \frac{\partial J}{\partial z}&=(q_A-q_B)\,p(1-p),\\ \frac{\partial\log\pi(a)}{\partial z}&=\mathbf1\{a=A\}-p. \end{aligned}\]

\(p=0.5\)이면 정확한 gradient는 \((0.75-0.35)\times0.25=0.1\)이다. 한 표본의 추정값은 \(R(\mathbf1\{a=A\}-p)\)다. A를 골라 성공하면 +0.5, B를 골라 성공하면 −0.5, 실패하면 0이다. 성공한 B도 그 표본에서는 강화되지만, 반복해서 평균하면 더 자주 성공하는 A를 늘리는 방향이 남는다. 그림의 점들이 이 표본 평균을 반복 계산한 값이다.

Baseline: 방향은 유지하고 잡음을 줄이기

문제는 분산이다. 우연히 성공한 한 번의 결과가 긴 행동열 전체에 영향을 준다. 성공률이 이미 높은 문제에서 보상 1은 특별하지 않고, 거의 항상 실패하는 문제에서는 같은 보상 1이 큰 성과다. 이 차이를 반영하기 위해 보상에서 기준값 baseline을 뺀다.

\[\hat g=\frac1N\sum_{i=1}^{N}\sum_t\bigl(G_{i,t}-b(h_{i,t})\bigr)\nabla_\theta\log\pi_\theta(a_{i,t}\mid h_{i,t})\]

앞 식의 전체 보상 \(R(\tau)\)가 시점별 return \(G_t\)로 바뀐 것은, 행동을 고르기 전에 받은 보상이 그 행동의 결과가 아니기 때문이다. 해당 기록에서 행동을 평균하면 과거 보상에 곱해진 score의 기대값은 0이므로, 이후 보상만 남겨도 된다. 여기서는 \(\gamma=1\)을 사용한다. 여기에 기록별 기준 \(b(h_t)\)를 빼면 “이 상태에서 기대한 것보다 얼마나 잘했는가”가 가중치가 된다.

\(G_{i,t}\)는 그 행동 이후의 return이다. 선택한 행동에 의존하지 않는 baseline은 적절한 조건에서 gradient의 기대값을 그대로 둔 채 분산만 줄인다. 좋은 기준값으로는 해당 기록에서 기대하는 return인 \(V^\pi(h_t)\)가 있다. 실제 return과 기대의 차이가 advantage 추정의 출발점이다.

baseline이 지켜야 할 조건은 하나다. 그 샘플이 실제로 고른 행동에 의존하지 않아야 한다. 그룹의 평균 보상처럼 자기 자신의 보상까지 포함해 계산한 값을 빼면 이 조건이 깨지고, 같은 초기 과제에서 독립적으로 수집한 trajectory에 자기 포함 평균만 빼는 경우 기대 gradient가 \((G-1)/G\)배로 줄어든다. 표준편차 정규화나 clipping까지 넣으면 이 배율만으로 설명할 수 없다. 그룹이 크면 무시할 만하지만 4번 시도의 그룹에서는 25% 축소다. 자기 보상을 뺀 leave-one-out 평균은 이 조건을 지킨다.

이 조건이 필요한 이유는 기록 \(h\)를 고정하고 행동에 독립적인 \(b(h)\)를 넣어 보면 드러난다. 합과 미분의 교환 등 통상적인 조건 아래 다음 항은 0이다.

\[\mathbb E_{a\sim\pi_\theta}[b(h)\nabla\log\pi_\theta(a\mid h)]=b(h)\nabla\sum_a\pi_\theta(a\mid h)=0.\]

\(b(h)\)는 행동에 대한 합 밖으로 나오고, 남은 \(\sum_a\pi_\theta(a\mid h)=1\)을 미분하면 0이다. 자기 보상을 포함한 평균은 행동에 따라 값이 달라지므로 이렇게 꺼낼 수 없다. 같은 context에서 독립 샘플을 뽑는 단순한 경우 그 차이가 앞의 \((G-1)/G\) 축소로 나타나고, 표준편차로 나누면 추가적인 데이터 의존 가중치가 생긴다. 세 선택의 차이는 그림 2에서 직접 비교한다.

그림 2. 정책 경사 추정의 평균과 분산

행동 A와 B 중 하나를 고르는 한 단계 모형이다. 보상 1을 받을 확률은 A에서 0.75, B에서 0.35로 고정한다. 먼저 batch 크기를 바꿔 추정값의 흩어짐을 보고, baseline을 바꿔 평균의 위치를 비교하자.

점 하나는 한 batch에서 얻은 logit gradient 추정값이다. 같은 조건에서 160개 batch를 뽑는다. 검은 선은 정확한 gradient, 주황 선은 자기 포함 평균을 뺀 추정량의 기대값이다. 성공률은 코드 테스트 결과가 아니라 이 확률 모형의 가정이다.

여기까지의 추정은 경험을 만든 정책과 미분하는 정책이 같다는 전제에 서 있다. 그런데 가중치를 한 번 업데이트하면 방금 모은 기록도 이전 정책의 경험이 된다. 그 기록을 다시 쓰려면 이 차이를 처리해야 한다.

Who generated the experience?

방금 수집한 batch에서 행동 A를 고른 비율은 수집 당시 정책의 확률을 반영한다. 업데이트 후 그 행동의 확률이 커졌다면, 같은 batch를 단순 평균해도 새 정책의 경험 분포가 되지는 않는다. On-policy와 off-policy의 구분은 이 데이터의 출처에서 시작한다.

경험을 수집한 행동 정책을 \(\mu\), 평가하거나 개선하려는 대상 정책을 \(\pi_\theta\)라 한다. 두 정책이 일치하는 경험을 사용하는 경우를 on-policy, 다른 행동 정책의 경험으로 대상 정책을 학습하는 경우를 off-policy라고 한다. 구분의 기준은 데이터의 나이가 아니라 행동을 생성한 정책이다.

고정된 context에서 행동 A의 수집 확률이 0.2이고 대상 정책의 확률이 0.6이라면, A 샘플의 가중치는 3이다. 수집 과정에서 적게 등장한 만큼 대상 정책의 평균을 계산할 때 더 큰 비중을 준다. 이것이 importance sampling이다.

\[\mathbb{E}_{a\sim\pi}[f(a)]=\mathbb{E}_{a\sim\mu}\!\left[\frac{\pi(a)}{\mu(a)}f(a)\right]\]

기대값을 합으로 펼치면 확률비가 하는 일이 드러난다. 각 행동의 수집 빈도 \(\mu(a)\)에 \(\pi(a)/\mu(a)\)를 곱하면 대상 빈도 \(\pi(a)\)가 남는다.

\[\sum_a\mu(a)\frac{\pi(a)}{\mu(a)}f(a)=\sum_a\pi(a)f(a).\]

아래 실험의 기본값은 \(\mu(A)=0.2\), \(\pi(A)=0.6\)이다. A에는 3, B에는 0.5의 가중치가 붙는다. 정확한 기대값으로 계산하면 \(0.2\times3\times0.75+0.8\times0.5\times0.35=0.59\)이며, 대상 정책에서 직접 계산한 \(0.6\times0.75+0.4\times0.35\)와 같다. 실제 실험은 24개 표본으로 계산하므로 이 값 주변에서 오차를 갖는다.

대상 정책이 선택할 수 있는 행동에 대해 수집 정책도 양의 확률을 가져야 한다. 수집 확률이 0이면 보정할 샘플이 없다. 긴 trajectory에서는 행동뿐 아니라 방문한 기록의 분포도 달라진다. 정확한 trajectory 보정은 여러 확률비의 곱을 요구하고 분산이 커질 수 있다. 한 토큰의 ratio는 그 곱의 한 항일 뿐이다.

각 행동의 확률은 앞에서 본 것처럼 생성 토큰 확률의 곱이므로, 행동 단위 ratio도 토큰 ratio의 곱으로 계산된다. Trajectory 전체에서는 그 곱이 다음과 같이 쌓인다.

\[w(\tau)=\prod_t\frac{\pi_\theta(a_t\mid h_t)}{\mu(a_t\mid h_t)}\]

동일한 환경과 초기 분포, support 조건 아래 이 전체 ratio는 trajectory의 기대값 보정에 쓰인다. 환경의 전이 항은 분자와 분모에서 약분된다. PPO가 최적화하는 토큰별 또는 행동별 local surrogate는 이 곱을 쓰지 않고, 그 자리에서의 근사로 전체 방문 분포 보정을 대신한다. Top-p처럼 support를 줄이는 sampling은 특히 주의가 필요하다.

수집 정책과 대상 정책이 다를 때의 평균

그림 2의 두 행동 모형에서 μ로 24개 표본을 수집하고 π의 기대 보상을 추정한다. μ를 고정한 채 π를 움직이면 같은 기록의 가중치가 어떻게 바뀌는지 볼 수 있다.

보정 추정값은 유한 표본에서 실제 기대 보상보다 멀어질 수도 있고 1을 넘을 수도 있다. H는 별도 모형에서 독립적인 중요도 가중치를 곱하는 횟수다. 위 막대와 ESS는 한 단계 표본에 대한 값이므로 H를 바꿔도 변하지 않는다.

구분묻는 것예
On / off-policy어떤 정책이 행동을 생성했는가현재 학생 / 예전 학생 / 교사
Online / offline RL학습하며 새 환경 경험을 수집하는가새 rollout 수집 / 고정된 기록만 사용

고정된 문제 목록에서 매번 새 trajectory를 생성하면 offline RL이 아니다. 반대로 새 데이터를 계속 모으면서 replay buffer의 오래된 경험을 함께 쓰는 online off-policy RL도 가능하다. Distillation에서도 on-policy라는 말을 쓰는데, 학생이 자기 sequence를 생성했다는 뜻이지 반드시 환경 보상으로 RL을 했다는 뜻은 아니다.

이후 본문에서 네 기호는 각각 다른 것을 가리킨다. \(\pi_\theta\)는 현재 학습 정책, \(\pi_{\mathrm{old}}\)는 수집 시점의 snapshot, \(\mu\)는 실제 sampling 분포, \(\pi_{\mathrm{ref}}\)는 정책이 지나치게 벗어나지 않도록 비교하는 기준 모델이다. 단순한 동기 학습에서는 \(\mu=\pi_{\mathrm{old}}\)로 시작할 수 있지만, temperature와 top-p, 생성 엔진의 차이가 있으면 실제 확률을 더 주의해 다뤄야 한다. DeepSeek-AI (2025)의 Chapter 3.1.

확률비는 분포 차이를 보정하지만, 수집 정책과 현재 정책이 멀어질수록 추정의 분산이 커질 수 있다. 그래서 오래된 기록을 무제한 재사용하는 대신, 최근 batch를 몇 번만 쓰면서 변화의 유인을 제한하는 쪽을 택한다.

Proximal policy optimization

경험 수집이 비싸다면 한 batch에서 gradient 한 번만 계산하는 것은 아쉽다. 하지만 같은 데이터로 계속 업데이트하면 현재 정책은 데이터를 만든 정책에서 멀어진다. PPO는 clipped surrogate라는 목적함수로 이 재사용의 폭을 제한한다.

Schulman et al. (2017)의 PPO는 경험 수집과 최적화를 번갈아 수행한다(Chapter 5, Algorithm 1). 수집한 batch를 여러 epoch의 minibatch update에 사용하되, 식 (7)의 clipped surrogate로 특정 샘플의 확률을 계속 밀어 올리거나 내릴 때 얻는 이득을 제한한다.

\[\rho_t(\theta)=\frac{\pi_\theta(a_t\mid h_t)}{\pi_{\mathrm{old}}(a_t\mid h_t)}\] \[L^{\mathrm{clip}}(\theta)=\mathbb{E}_{\mathrm{old}}\!\left[\min\!\left(\rho_t\hat A_t,\operatorname{clip}(\rho_t,1-\epsilon,1+\epsilon)\hat A_t\right)\right]\]

좋았던 행동은 \(\hat A_t>0\)이다. 그 행동의 확률을 높이면 ratio가 커지고 목적함수도 커진다. 하지만 \(1+\epsilon\)을 넘으면 그 샘플에서 더 얻을 이득이 평평해진다. 나빴던 행동은 반대다. 확률을 줄이는 방향에서 \(1-\epsilon\) 아래로 내려가면 추가 이득이 사라진다. 어느 쪽에서도 함수가 통째로 잘리지는 않고, 한계를 넘은 방향에서만 기울기가 0이 된다.

\(\min\)이 선택하는 항을 advantage의 부호별로 나누면 clipping의 모양이 드러난다. 양수를 곱하면 대소관계가 유지되고, 음수를 곱하면 뒤집힌다.

\[\ell(\rho,A)=\begin{cases} A\min(\rho,1+\epsilon),&A\ge0,\\ A\max(\rho,1-\epsilon),&A<0. \end{cases}\]

\(A=1\), \(\epsilon=0.2\)이면 \(\rho\)가 1.2를 넘은 뒤에도 목적함수는 1.2에 머문다. 반대로 \(A=-1\)이면 \(\rho\)를 0.8 아래로 낮춰도 목적함수는 −0.8이다. 잘한 행동의 확률을 더 높이거나 못한 행동의 확률을 더 낮추는 데서 추가 이득이 사라지고, 반대 방향의 변화에만 기울기가 남는다.

그림 4. Advantage의 부호에 따른 PPO clipping

수집 당시 확률을 0.31로 고정하고 현재 확률을 바꾼다. Advantage의 부호를 바꾸면 어느 방향에서 목적함수가 평평해지는지 비교할 수 있다.

아래 표는 현재 슬라이더 값에서 두 후보 항과 최솟값을 계산한다. Clipping은 이 샘플의 목적함수에 작용하며, 확률 자체를 구간 안에 고정하지 않는다.

PPO는 보통 on-policy 계열로 분류된다. 최근 정책으로 rollout을 모은 뒤 제한된 횟수만 재사용하고 다시 수집하기 때문이다. 그러나 batch 안의 두 번째 update부터는 수집 정책과 현재 정책이 이미 다르다. PPO가 감당하는 범위는 이 국소적인 불일치까지이고, 임의의 오래된 기록을 안전하게 재사용하는 일은 일반적인 off-policy 학습의 몫이다.

같은 상대 상한 \(1+\epsilon\)에서 양의 advantage를 가진 보상 항이 포화되기 전 확률의 절대 증가량은 \(\epsilon\pi_{\mathrm{old}}(a\mid h)\)다. 예를 들어 \(\epsilon=0.2\)이면 확률 0.01인 토큰은 0.002, 0.5인 토큰은 0.1만큼 증가한 지점에서 그 항이 평평해진다. 이는 실제 확률을 그 값에 고정하는 제약이 아니다. DAPO Chapter 3.1은 낮은 확률의 토큰을 키우는 유인이 일찍 포화되는 현상과 관측된 entropy 감소를 연결한다. 다만 entropy가 실제로 얼마나 줄어드는지는 clipping의 비대칭성 말고도 여러 요인에 달려 있다.

Yu et al. (2025)은 DAPO에서 상·하단 clipping 폭을 분리하고 상단을 넓히는 Clip-Higher를 제안했다(Chapter 3.1). 낮은 확률의 토큰을 강화할 여유를 늘리려는 설계다. 이 결과는 clipping 폭이 업데이트의 크기뿐 아니라 탐색에도 작용한다는 근거다. 성능이 오른 것은 이 설정에서이고, entropy를 높이는 조작 일반의 효과는 별개 문제다.

아직 \(\hat A_t\)를 어떻게 계산할지는 정하지 않았다. PPO에서는 흔히 미래 return을 예측하는 value model \(V_\phi\)를 함께 학습하고 GAE로 advantage를 추정한다.

Value 추정이 있다면 한 단계 보상과 다음 value를 현재 value와 비교할 수 있다. 이 차이를 TD residual이라 한다.

\[\delta_t=r_t+\gamma V_\phi(h_{t+1})-V_\phi(h_t),\qquad \hat A_t^{\mathrm{GAE}}=\sum_{l=0}^{T-t-1}(\gamma\lambda)^l\delta_{t+l}.\]

\(\lambda\)는 얼마나 먼 residual을 누적할지 조절하며, value가 정확하지 않을 때 이 선택이 곧 편향과 분산의 절충이 된다. 실제 terminal에서는 다음 value를 0으로 두지만, 계속될 과정을 수집 한도 때문에 잘랐다면 같은 처리를 자동 적용하지 않는다. Time limit을 과제의 종료로 정의했는지도 명시해야 한다(GAE 원문).

Clipping은 실제 KL의 엄격한 상한도, 성능의 단조 향상도 보장하지 않는다. 직접 정하는 것은 probability ratio에서 해당 표본의 surrogate 이득이 포화되기 시작하는 구간이며, 실제 update의 크기와 advantage 추정기는 별도로 정해진다. Value model 없이 같은 문제의 여러 시도를 비교해 기준을 만드는 것이 GRPO로 이어지는 선택이다.

Group relative policy optimization

GRPO(Group Relative Policy Optimization)는 같은 문제에서 수집한 여러 rollout의 보상을 비교해 advantage를 구성한다. 문제마다 별도의 기준을 얻으므로, 쉬운 문제의 성공과 어려운 문제의 성공은 서로 다른 기준에 대해 채점된다. 이 그룹 비교가 value model의 예측을 대신한다.

Shao et al. (2024)은 DeepSeekMath에서 같은 문제의 보상으로 비교 기준을 구성하는 GRPO를 제안했다(Chapter 4.1.1). 이 방식은 value critic의 메모리와 학습 비용을 줄이는 대신, 과제마다 여러 rollout을 수집해야 한다.

Critic-free에서 없어지는 것은 value critic이지 채점기가 아니다. 그룹의 점수를 매길 verifier나 reward model은 여전히 필요하다.

\[\bar R=\frac1G\sum_{i=1}^G R_i,\qquad \hat A_i=\frac{R_i-\bar R}{\operatorname{std}(R_1,\ldots,R_G)+\varepsilon_{\mathrm{num}}}\]

\(\varepsilon_{\mathrm{num}}\)은 0으로 나누는 것을 피하는 작은 수이며, 기호만 비슷한 PPO의 clipping 폭과는 무관하다. Outcome reward를 사용하는 기본 설명에서는 한 trajectory의 모든 생성 토큰에 같은 \(\hat A_i\)를 적용하고 PPO와 비슷한 clipped surrogate를 최적화한다. 원형 GRPO에는 reference policy에 대한 KL 항도 있다.

예를 들어 보상이 \((1,0,0,1)\)이면 평균은 0.5, 표준편차도 0.5이므로 advantage는 \((1,-1,-1,1)\)이다. 성공 하나만 남겨 \((1,0,0,0)\)으로 바꾸면 평균은 0.25이고, 성공한 시도의 advantage는 \(\sqrt3\), 나머지는 \(-1/\sqrt3\)이 된다. 같은 보상 1도 비교 그룹에 따라 다른 크기의 신호를 받는다.

Yu et al. (2025)은 보상이 모두 같은 그룹을 제외하고, 비교 신호가 있는 그룹으로 batch를 채우는 dynamic sampling을 제안했다(DAPO Chapter 3.2). 필요한 수집량은 목표 batch 크기뿐 아니라 이런 그룹이 얼마나 자주 나오는지에도 달려 있다.

과제가 너무 쉽거나 어려우면 많은 rollout을 만들고도 보상 비교에 사용할 그룹은 적을 수 있다. 이때 추가로 수집하거나 버린 경험의 비용도 학습 비용에 포함해야 한다. 그래서 유효 그룹 비율을 함께 기록한다.

그룹 비교가 해결하지 못하는 문제도 남는다. 성공한 경로에 불필요한 호출이 섞여 있어도 같은 advantage를 받을 수 있고, 그룹 표준편차나 응답 길이로 나누면 샘플의 상대 가중치가 달라진다. 보상은 시도를 비교할 뿐이고, 각 토큰의 학습 기여는 그다음에 따로 정한다.

왜 reference model과의 KL이 따로 붙는가

보상을 높이는 것만 최적화하면 학습 과제에 유리한 출력으로 정책이 치우칠 수 있다. 이를 완화하려고 기준 정책 \(\pi_{\mathrm{ref}}\)와의 차이에 KL 벌점을 더하기도 한다. 원형 GRPO도 이 항을 포함한다. 기준 모델은 초기 모델로 고정하거나 명시한 단계마다 갱신할 수 있다.

\[J_{\mathrm{total}}(\theta)=J_{\mathrm{RL}}(\theta)-\beta\,\mathbb E_{h}\!\left[D_{\mathrm{KL}}\bigl(\pi_\theta(\cdot\mid h)\,\Vert\,\pi_{\mathrm{ref}}(\cdot\mid h)\bigr)\right]\]

이 항이 막는 현상은 PPO의 clipping이 막는 현상과 다르다. Clipping은 수집 정책에서 한 batch 안에서 너무 멀리 가지 않게 하는 국소적 장치이고, KL 벌점은 학습 전체에 걸쳐 선택한 기준 모델에서 멀어지지 않게 하는 장치다. 기준 모델을 고정했는지 갱신했는지, 갱신했다면 그 규칙이 무엇인지는 함께 보고해야 한다. \(\beta\)가 크면 기준 정책에서 벗어나는 변화에 더 큰 비용을 매긴다. 다만 KL 정규화가 닿는 범위는 관측한 prefix까지이고, 다른 과제의 능력이 남아 있는지는 따로 확인해야 한다. 최근 공개 자료 중에는 이 항을 빼는 설정도 있으며, 보편적인 정답 값은 없다. 그룹의 보상이 모두 같아 비교 신호가 0이 된 batch에서도 이 항은 그대로 살아 있다.

이제 업데이트에 쓸 재료가 갖춰졌다. 생성 토큰의 확률, 수집 정책과의 ratio, 그룹에서 계산한 advantage가 있다. 이들을 실제 텐서로 옮길 때는 어떤 위치에 loss를 걸고 무엇으로 나눌지까지 정해야 한다.

From trajectories to tensors

LLM에서는 행동의 확률을 생성 토큰의 확률로 분해한다. 따라서 trajectory에 붙은 보상을 실제 loss로 옮기려면 토큰별 로그확률, 학습 대상 mask, advantage, 평균을 취할 단위를 정해야 한다. 다음 계산은 네 rollout으로 이루어진 한 그룹을 사용하며, outcome-GRPO의 비교 신호와 PPO의 token-level clipping에 집중한다.

1. 수집 버퍼에는 답변 문자열보다 많은 것이 필요하다

먼저 behavior policy \(\pi_{\mathrm{old}}\)를 고정하고 경험을 모은다. 버퍼에는 문제·group ID·trajectory ID, 각 모델 호출에 실제로 넣은 context의 token ID, 생성 token ID, 각 생성 토큰의 수집 로그확률, 도구 호출과 반환값, 보상, 종료 사유를 저장한다. 환경과 채점기 버전, 정책 checkpoint, tokenizer·chat template, sampling 설정도 함께 식별할 수 있어야 한다. 성공한 최종 코드만 저장하면 어느 입력에서 어떤 행동을 골랐는지 복구할 수 없다.

GLM-5 Team (2026)은 텍스트를 다시 토큰화할 때 수집 당시의 토큰열과 달라질 수 있음을 지적한다(Chapter 4.1.2, Token-in-Token-out vs. Text-in-Text-out). 정리된 대화문만 남긴 버퍼로는 이 차이를 복구할 수 없으므로, 모델 호출에 실제로 사용한 token ID를 그대로 보존한다.

2. 네 개의 시도에서 advantage를 계산한다

같은 문제와 초기 코드를 네 개의 격리된 실행기에 복제하고 rollout을 수집했다고 하자. 보상은 \((1,0,0,0)\), 학습할 생성 토큰 수는 \((2,4,4,6)\)이다. 토큰 수는 손계산용이며 실제 tool call의 길이가 아니다. 그룹의 평균은 \(1/4\), 모집단 표준편차는 \(\sqrt{3}/4\)이므로, 수치 안정화 상수를 무시하면 advantage는 다음과 같다.

\[\hat A=(\sqrt3,-1/\sqrt3,-1/\sqrt3,-1/\sqrt3)\approx(1.732,-0.577,-0.577,-0.577).\]

보상 0이 음의 advantage가 된 것은 같은 그룹 안에 성공이 있기 때문이다. 네 번 모두 실패하면 centered advantage는 모두 0이다. 반면 baseline 없는 REINFORCE에서 보상 0인 샘플은 처음부터 gradient가 0이다. “실패에서 배운다”는 설명은 어떤 비교 기준을 쓰는지까지 적어야 완성된다.

Shao et al. (2024)에 따르면 outcome-GRPO는 최종 보상을 그룹 안에서 정규화하고, 같은 응답의 각 토큰에 그 값을 배정한다(Chapter 4.1.2, Outcome Supervision RL with GRPO). 여기서는 이를 도구 관측을 제외한 한 episode의 모델 생성 토큰 전체에 적용한다. \(G\)개 보상을 모두 모아 계산한 뒤 minibatch로 나누어야 하며, 임의의 microbatch 안에서 다시 정규화하면 비교 집단이 바뀐다.

3. 토큰 하나의 계산과 업데이트 방향

성공한 기록의 토큰 하나에서 저장된 로그확률이 \(\ell_{\mathrm{old}}\), 현재 로그확률이 \(\ell_\theta\)라면 \(\rho=\exp(\ell_\theta-\ell_{\mathrm{old}})\)다. \(\rho=1.3\), clipping 폭이 0.2이면 surrogate 기여는 \(\min(1.3\times1.732,1.2\times1.732)=2.078\)이다. 이 샘플의 보상 항은 더 커지는 방향으로 평평하다. 같은 ratio에서 실패한 기록은 \(\min(1.3\times-0.577,1.2\times-0.577)=-0.750\)이다. 나빴던 선택의 확률이 증가한 경우이므로 이를 되돌리는 gradient가 남는다.

수식의 \(L\)은 최대화할 surrogate다. 일반적인 optimizer가 최소화하는 loss에는 부호를 바꿔 넣는다. 또한 “이 토큰의 항이 평평하다”는 말은 그 항 하나에만 해당한다. 다른 토큰과 KL 항의 gradient는 같은 공유 파라미터를 계속 움직인다.

Schulman et al. (2017)은 Chapter 3의 식 (7)에서 clipped surrogate를 정의한다. 양의 advantage와 음의 advantage에 똑같이 min을 적용하므로, 두 경우의 포화 방향은 반대가 된다. 본문은 그 구조를 토큰 조건부 확률에 적용한다. 토큰별 ratio 하나는 전체 trajectory의 importance ratio 곱과 같지 않으며, 이 local surrogate를 현재 정책의 정확한 기대 return이라고 부르지 않는다.

4. 같은 이름 아래 다른 평균

생성 토큰 mask를 \(m_{ik}\), 그 개수를 \(L_i=\sum_k m_{ik}\), 토큰별 clipped 기여를 \(u_{ik}\)라 하자. 여기서는 문제 하나만 쓰므로 \(B=1,N=G=4\)다. 다음 세 reduction은 길이가 다를 때 서로 다른 가중치를 준다. 알고리즘 전체가 아니라 같은 토큰별 기여를 어떻게 평균하는지만 통제해 비교한다.

Reduction최대화하는 항위 예제에서 토큰 하나의 계수
응답마다 평균\(\frac1G\sum_i\frac1{L_i}\sum_k m_{ik}u_{ik}\)성공 응답: \(1/8\), 마지막 실패 응답: \(1/24\)
전체 생성 토큰 평균\(\frac{\sum_{i,k}m_{ik}u_{ik}}{\sum_iL_i}\)모든 생성 토큰: \(1/16\)
고정 상수로 나누기\(\frac1{GC}\sum_{i,k}m_{ik}u_{ik}\)\(C=6\)이면 모두 \(1/24\)

마지막 두 방식은 한 batch 안에서는 공통 배율만 다르지만, 전체 토큰 수가 batch마다 달라지면 배율도 달라진다. 첫 방식은 같은 batch 안에서도 짧은 응답의 토큰을 더 크게 가중한다. 기대 보상 \(J=\mathbb E[R]\)에서 유도한 score-function gradient에는 원래 trajectory별 토큰 합이 들어간다. 길이 평균은 그 합을 빠르게 계산하는 장치가 아니라 토큰마다의 가중치를 바꾸는 선택이다.

분모가 바꾸는 학습 가중치

Shao et al. (2024)의 GRPO 목적함수에는 그룹 평균 안쪽에 \(1/|o_i|\)가 들어간다(Chapter 4.1.1, 식 (3)). 응답마다 토큰 기여를 먼저 평균하므로 짧은 응답의 토큰에 더 큰 계수가 붙는다. 이를 Agent에 적용할 때 한 tool call을 응답으로 볼지, 한 episode의 전체 생성을 응답으로 볼지도 명시해야 한다.

Yu et al. (2025)은 한 문제에서 수집한 그룹의 전체 토큰 수로 나눈다(DAPO Chapter 3.3, 식 (12)). 위 표의 둘째 행이다. 여러 문제를 묶으면 문제별 토큰 평균을 다시 평균하는 것과 batch 전체 토큰을 한꺼번에 평균하는 것이 달라진다. 후자는 토큰이 많은 문제에 더 큰 총가중치를 준다.

Liu et al. (2025)은 길이 정규화의 영향을 분석하고 고정 상수를 분모로 쓰는 Dr. GRPO를 제안한다(Chapter 3.1–3.2). 다만 이 방법은 그룹 표준편차로 나누는 단계까지 제거하므로, 같은 advantage를 유지한 채 분모만 비교한 위 표는 Dr. GRPO의 한 부분만 보여준다.

차이는 숫자로도 드러난다. 모든 유효 토큰에서 \(\rho=1\)이면 위 세 방식의 최소화 loss는 각각 \(0\), \(1/(2\sqrt3)\approx0.2887\), \(1/(3\sqrt3)\approx0.1925\)다. Loss가 0이어도 gradient가 0이라는 뜻은 아니다. 첫 방식에서 advantage들의 합은 0이지만, 서로 다른 토큰·prefix에 대한 로그확률의 미분은 서로 다르므로 일반적으로 상쇄되지 않는다. 서로 다른 reduction의 loss 숫자를 성능 점수처럼 직접 비교하지 말자.

5. Trajectory를 padding된 텐서로 옮긴다

먼저 context를 중간에 자르거나 다시 쓰지 않고, 한 trajectory를 하나의 인과적 토큰열로 표현할 수 있다고 가정하자. \(N=BG\)는 trajectory 수, \(S\)는 padding 후 전체 길이, \(V\)는 어휘 크기다. \(S\)는 관측까지 포함한 길이이고, \(L_i\)는 그 안에서 학습 대상이 되는 생성 토큰 수다.

텐서Shape의미
input_ids\([N,S]\)문제·모델 출력·도구 관측을 실제 순서로 연결한 token ID
attention_mask\([N,S]\)실제 입력 1, padding 0. 인과적 attention 제약은 별도로 적용된다.
generated_mask\([N,S]\)정책이 표본추출한 학습 대상 토큰만 1. 도구 결과·prompt·padding은 0.
logits\([N,S,V]\)각 위치까지 읽은 뒤 다음 토큰에 대한 현재 모델의 점수
new_logp, old_logp, mask\([N,S-1]\)다음 토큰 정렬을 마친 로그확률과 유효 target 위치
rewards, advantage\([N]\)trajectory당 보상과 그룹 비교값. 토큰 위치로 broadcast한다.

다음 토큰 정렬(next-token shift)이 가장 흔한 오류 지점이다. 위치 \(j\)의 logits는 위치 \(j+1\)의 token ID를 예측한다. 그러므로 logits[:, :-1]과 input_ids[:, 1:]을 짝지으며, target의 역할을 표시한 mask도 generated_mask[:, 1:]로 옮긴다. 관측의 마지막 토큰 위치는 다음 모델 출력의 첫 토큰을 예측한다. 이때 loss 여부는 logits가 놓인 위치의 역할이 아니라 예측 대상 토큰의 역할로 결정한다.

이 target 구분은 Jin et al. (2025)이 검색 결과를 policy loss에서 제외한 것과 같은 이유다(Chapter 3.1, Loss Masking for Retrieved Tokens). 도구 관측은 읽어야 할 입력이지만, 정책이 표본추출한 행동은 아니다. Loss mask를 0으로 두어도 관측은 attention에 그대로 남고, 관측을 읽은 hidden state도 역전파 경로에 남는다.

실제 harness가 중간 context를 요약·삭제했다면 한 대화를 통째로 연결한 forward는 수집 당시 조건부 확률을 재현하지 못한다. 그때는 모델 호출별 실제 입력과 생성 구간을 각각 재생하고, 생성 토큰을 원래 trajectory·group에 연결해 loss를 모은다. 여러 기록을 한 행에 packing하는 경우에도 행 수를 trajectory 수로 착각하지 말고, 기록 사이 attention 경계·position ID·ID 매핑을 보존해야 한다.

6. 고정할 것과 미분할 것을 코드로 분리한다

Algorithm 2. 그룹 보상에서 토큰 정책 loss 계산

입력: 토큰·mask·수집 로그확률·그룹 보상 · 출력: 정책 업데이트 1회

import torch

# Python / PyTorch 스타일의 핵심 계산. 완전한 trainer가 아니다.
# 가정: N=B*G, 각 group이 연속된 G개 행, 동일한 수집 정책,
# context 재작성 없음, 오른쪽 padding, temperature=1, top-k/p 제한 없음.
# old_logp: 수집 때 저장한 값. 이미 target ids[:, 1:]에 정렬된 [N, S-1].
# KL·entropy·value loss는 제외(beta=0). 이번에는 batch 전체 토큰 평균.

with torch.no_grad():
    r = rewards.reshape(B, G).float()
    centered = r - r.mean(dim=1, keepdim=True)
    std = r.std(dim=1, correction=0, keepdim=True)
    advantage = (centered / (std + 1e-6)).reshape(N)

logits = student(input_ids, attention_mask=attention_mask).logits
target = input_ids[:, 1:]
new_logp = logits[:, :-1].float().log_softmax(dim=-1)
new_logp = new_logp.gather(-1, target.unsqueeze(-1)).squeeze(-1)
mask = generated_mask[:, 1:].bool() & attention_mask[:, 1:].bool()
assert mask.any(dim=1).all()  # 이 예제에서는 각 기록에 학습 토큰이 있다.

# padding의 임의 logp에 exp를 적용한 뒤 0을 곱하지 않는다.
# 먼저 유효한 생성 위치만 선택한다.
delta = new_logp[mask] - old_logp.detach()[mask]
assert torch.isfinite(delta).all()
ratio = delta.exp()
assert torch.isfinite(ratio).all()
adv_token = advantage.detach()[:, None].expand_as(new_logp)[mask]
unclipped = ratio * adv_token
clipped = ratio.clamp(1 - 0.2, 1 + 0.2) * adv_token
policy_loss = -torch.minimum(unclipped, clipped).mean()

optimizer.zero_grad()
policy_loss.backward()
optimizer.step()

현재 모델의 logits → log_softmax → gather → ratio → loss만 미분한다. 보상·그룹 통계·수집 로그확률은 이번 업데이트에서 고정한다. 샘플링된 정수 token ID나 JavaScript 테스트 실행기까지 역전파하지 않는다. 대신 이미 선택한 토큰에 현재 정책이 부여하는 확률을 미분하는 것이 score-function 방법의 핵심이다.

위 코드는 전체 batch가 메모리에 들어간다는 설명용 가정이다. Minibatch로 나누더라도 advantage는 먼저 완전한 그룹에서 계산해야 한다. Microbatch별 토큰 수가 다르면 각 mean()을 단순 평균해서는 전체 토큰 평균을 재현할 수 없다. 전체 optimizer step의 유효 토큰 수를 분모로 두고 각 조각의 합을 누적하는 식으로 reduction을 보존해야 한다. 분산 학습에서도 rank별 평균을 다시 평균한 값과 전역 토큰 평균은 서로 다른 수다.

7. 첫 optimizer step 전에 통과시킬 검사

확률 재현: 같은 정책 snapshot과 같은 입력·확률 정의라면 업데이트 전 ratio는 1 근처여야 한다. 아니라면 학습률보다 token shift, chat template, context 변경, padding, dropout과 추론 엔진 차이를 먼저 본다. 위 코드는 순수 softmax sampling을 가정한다. Temperature나 top-p로 수집 분포를 바꿨다면 저장 로그확률이 그 분포의 것인지 원래 모델의 것인지 명시하고, 무엇을 ratio로 보정하는지도 함께 정해야 한다.

경계와 부호: prompt·도구·padding의 policy target 수는 0인지, 생성된 종료 토큰을 누락하지 않았는지, group ID별로 같은 과제를 비교하는지 확인한다. 보상이 모두 같으면 이 구성의 advantage와 policy loss gradient는 0이어야 한다. 양의 advantage에서 ratio가 과도하게 커지면 보상 항이 포화해야 하고, 음의 advantage에서 ratio가 커지면 이를 되돌리는 gradient가 남아야 한다.

규제항 분리: \(\pi_{\mathrm{old}}\)는 경험을 만든 정책이고 \(\pi_{\mathrm{ref}}\)는 KL의 기준 정책이다. 이름이 비슷해도 두 정책이 맡는 역할은 따로 있다. KL을 추가하려면 방향·prefix 분포·표본 추정법·reduction을 각각 정의한 뒤 더해야 한다. 계산이 정의되지 않은 reference_kl 변수 하나로 이 선택을 숨기지 않는 것이 재현 가능한 구현의 출발점이다.

KL 추정값이 음수로 나왔다면

고정 prefix에서 정확한 \(D_{\mathrm{KL}}(\pi_\theta\Vert\pi_{\mathrm{ref}})\)는 음수가 아니다. 그러나 \(y\sim\pi_\theta\)에서 뽑은 한 토큰의 \(\log\pi_\theta(y)-\log\pi_{\mathrm{ref}}(y)\)는 음수일 수 있다. KL은 이 차이의 기대값이고, 부호는 표본 단위가 아니라 기대값 수준에서만 정해진다. 또 샘플이 \(\pi_{\mathrm{old}}\)에서 왔다면 이 평균을 현재 정책의 정확한 KL로 부를 수 없다.

\(z=\pi_{\mathrm{ref}}(y)/\pi_\theta(y)\)에 대한 \(z-1-\log z\)는 표본마다 비음수이고, support와 적분 가능성 조건 아래 현재 정책에서 표본추출한 기대값은 같은 KL이다. 다만 값의 불편성과 샘플을 고정한 자동미분 gradient의 정확성은 별도 문제다. 수집 분포, importance 보정, stop-gradient 처리를 명시해야 한다. Shao et al. (2024)은 Chapter 4.1.1의 식 (4)에서 이 추정량을 KL 항으로 사용한다.

이 계산이 맞으면 보상을 받은 경로의 토큰까지 gradient가 도달한다. 그러나 계산의 정확성과 학습 신호의 유용성은 별개다. 성공한 경로 안에서 어떤 테스트와 수정이 정말 필요했는지는 최종 보상 하나만으로 곧바로 알 수 없다.

Exploration and credit assignment

방금 계산에서는 성공한 trajectory의 모든 생성 토큰에 같은 advantage를 배정했다. 그 경로에 불필요한 반복 호출이 있었다면 그 호출도 같은 크기로 강화된다. 이것만으로 REINFORCE 추정량이 틀리는 것은 아니지만, 제한된 표본으로 필요한 확인과 우연히 함께 나온 행동을 구분하기는 어렵다. 이것이 credit assignment의 문제다.

\[Q^\pi(h,a)=\mathbb E[G_t\mid h_t=h,a_t=a],\qquad A^\pi(h,a)=Q^\pi(h,a)-V^\pi(h).\]

\(Q^\pi\)는 그 행동 뒤의 나머지 과정도 현재 정책으로 수행했을 때의 기대 return이다. 기준선은 이상적인 정책이 복구할 수 있는지를 묻는 \(Q^*\)가 아니라 현재 정책의 실력이다. 초보 모델이 테스트 로그를 해석하지 못한다면, 유익한 테스트 호출도 현재의 \(Q^\pi\)에서는 낮게 평가될 수 있다. 정보 수집과 그 정보에 따른 수정 능력을 함께 배워야 하는 이유다.

희소 보상에서는 알고리즘보다 먼저 성공을 관측해야 한다

초기 정책이 한 번도 성공하지 못하면 실패 경로와 견줄 성공 경로 자체가 없고, 행동의 기여를 나누는 일은 그다음 문제가 된다. 한 과제의 rollout이 독립이고 성공 확률이 \(p\), 그룹 크기가 \(G\)라면 이진 보상에서 성공·실패가 섞인 그룹을 얻을 확률은 다음과 같다.

\[P(\text{혼합 그룹})=1-p^G-(1-p)^G.\]

이는 모두 성공할 확률과 모두 실패할 확률을 1에서 뺀 직접 계산이다. \(p=0.5,G=4\)이면 87.5%지만 \(p=0.01,G=4\)이면 약 3.94%다. \(G=16\)으로 늘려도 약 14.85%이며, 한 그룹을 만드는 비용은 네 배가 된다. 쉬운 문제만 모으거나 그룹을 무조건 키우는 대신, 초기 정책의 능력과 과제 난이도와 수집 비용을 함께 놓고 정해야 한다.

성공·실패가 섞인 그룹만 선택하는 dynamic sampling은 유효한 보상 신호를 늘릴 수 있지만, 원래 과제 분포를 그대로 평균하는 절차는 아니다. 어려운 과제를 버렸다면 그 비율과 추가 수집 비용을 함께 보고해야 한다. “유효 batch당 성능”만 비교하면 거절된 rollout의 비용을 숨기게 된다. Yu et al. (2025)의 Chapter 3.2.

최종 보상만으로 부족할 때

성공 표본이 적거나 행동열이 길다면 중간 의사결정에 대한 정보를 따로 구한다. Value를 예측하거나, 과정에 점수를 주거나, 같은 상태에서 행동을 달리해 후속 결과를 비교하면 된다. 각 방법은 추가 감독이나 실행 비용을 요구한다.

접근Credit assignment를 위해 묻는 질문추가 가정과 비용
Value와 GAE새로운 관측을 얻기 전후에 예상 성공률이 얼마나 바뀌었는가?방문 기록에서 미래 return을 예측할 수 있어야 한다. 부정확한 value와 bootstrapping은 편향을 넣을 수 있다.
과정 보상이 입력 실행·코드 수정이 지금 단계에서 좋은 행동인가?중간 단계의 라벨 또는 judge가 필요하다. 그럴듯한 설명을 보상하면 실제 성공과 어긋날 수 있다.
분기 rollout같은 코드에서 변수 변화를 확인하는 경우와 바로 수정하는 경우를 이어 실행하면?환경 snapshot과 추가 실행 예산이 필요하다. 이후 정책과 남은 예산을 맞춰야 비교가 해석된다.

분기 rollout은 행동 간 기대 결과 차이를 추정하는 방법이지만, 한 번의 성공과 실패만으로 인과적 기여를 확정하지는 못한다. 두 분기 이후의 sampling이 다르고 환경도 확률적일 수 있다. 복제 가능한 코딩 환경은 이 실험을 설계하기 좋지만, 외부 거래나 사용자와의 대화에서는 같은 상태를 다시 만들기 어렵다.

중간 보상을 더하면 같은 문제를 푸는가

“테스트를 돌릴 때마다 +0.1”을 주면 검증 습관을 얻을 수도 있지만 테스트만 반복하는 정책도 유리해진다. 최종 성공 문제를 그대로 두고 신호를 바꾸는 고전적 조건은 potential-based shaping이다. 상태별 잠재함수 \(\Phi\)에 대해 \(r'_t=r_t+\gamma\Phi(h_{t+1})-\Phi(h_t)\)로 둔다. Ng, Harada & Russell (1999).

\[\sum_{t=0}^{T-1}\gamma^t r'_t=\sum_{t=0}^{T-1}\gamma^t r_t-\Phi(h_0)+\gamma^T\Phi(h_T).\]

중간 항이 소거된다. 유한 episode에서 terminal potential을 0으로 두면 shaping된 return은 원래 return과 초기 상태에만 의존하는 상수만큼만 다르고, 그래서 정책 간 순위가 보존된다. 이 결론은 종료 potential과 시간 처리를 그대로 지킬 때만 유지되고, 학습된 process reward는 이 형태를 저절로 만족하지 않는다. 그래서 보상을 추가할 때는 “원래 목표의 학습을 돕는가, 목표 자체를 바꾸는가”를 먼저 물어야 한다.

테스트 실행은 코드를 바꾸지 않는데 왜 가치가 있는가

행동의 가치는 코드 변경량이 아니라 이후 의사결정에 미치는 영향으로 정해진다. 테스트 관측 \(o\)를 받고 후속 행동 \(a'\)를 고를 수 있다면, 한 단계 단순화에서 정보의 가치는 \(\mathbb E_o[\max_{a'}Q(h,o,a')]-\max_{a'}\mathbb E_o[Q(h,o,a')]-c\)로 생각할 수 있다. 관측 뒤에 선택할 수 있는 유연성에서 검사 비용 \(c\)를 뺀 값이다. 이는 알려진 \(Q\)와 최선의 후속 선택을 가정한 설명용 식이다. 실제 LLM이 정보를 해석하지 못하면 그 잠재적 이득을 실현하지 못한다.

환경에서 비교 신호를 얻으려면 탐색과 채점 비용을 치러야 한다. 좋은 교사가 이미 있다면 출발점을 바꿀 수 있다. 학생이 성공 경로를 스스로 발견할 때까지 기다리는 대신, 교사의 수정 과정이나 다음 행동 분포를 그대로 학습 신호로 쓰면 된다.

Distillation

Distillation은 교사 모델의 출력이나 분포를 학생 모델의 학습 신호로 사용하는 접근이다. Agent에서는 최종 답뿐 아니라 도구 선택과 호출 인자, 후속 행동까지 모방 대상이 된다. 교사가 생성한 trajectory를 검증해 SFT 데이터로 쓰는 방식부터 시작할 수 있다.

\[\mathcal L_{\mathrm{SFT}}=-\mathbb E_{\tau\sim\pi_{\mathrm{teacher}}}\!\left[\sum_{k\in\mathcal M(\tau)}\log\pi_\theta(y_k\mid h_k)\right]\]

\(\mathcal M\)은 학생에게 모방시킬 모델 생성 토큰의 위치다. 도구가 반환한 파일 내용은 context로 사용하고 행동 정답으로 모방하지 않는다. 그림 1의 생성 구간과 관측 구간 구분을 여기서도 사용한다. 이 경로는 텍스트와 tool call을 반환하는 API 교사로도 구성할 수 있다. 다만 교사의 긴 reasoning trace나 비공개 내부 사고가 모두 제공된다고 가정해서는 안 된다. 실제로 관측할 수 있는 출력을 기준으로 학습 데이터를 만든다.

Distillation에서 on-policy와 off-policy는 무엇을 가리키는가

교사 데이터를 쓰더라도 경험의 출처는 여전히 중요하다. 교사가 생성한 경로를 학생이 모방할 수도 있고, 학생이 직접 만든 경로에서 교사에게 다음 행동을 물을 수도 있다. 앞의 on-policy·off-policy 구분은 이 차이를 나타낸다. 감독이 교사에게서 오는지 환경 보상에서 오는지는 별도의 문제다.

학습 설정 하나는 서로 다른 두 가지를 따로 정한다. ① 누가 기록을 만들었는가(behavior policy): 교사인가, 과거의 학생인가, 지금의 학생인가. ② 그 위치에서 어떤 감독을 주는가(supervision): 정답 토큰 하나인가, 교사의 분포 전체인가, 환경이 매긴 스칼라 보상인가. Distillation에서 “on-policy”는 환경 보상 RL이 아니라 ①에만 답하는 말이다. 학생이 자기 sequence를 생성했고, ②는 여전히 교사가 채운다.

학습 방식① 기록을 만든 정책② 그 위치의 감독 신호필요한 접근 권한
교사 trajectory SFT
(off-policy distillation)
교사 \(\pi_{\mathrm{teacher}}\)교사가 실제로 낸 토큰 1개 (hard target)교사의 출력 텍스트·tool call만 있으면 된다. 한 번 만들어 두면 재사용할 수 있다.
Sequence-level KD교사, 또는 교사가 표본추출한 여러 후보선택된 sequence의 토큰교사 sampling 비용. 여전히 학생의 방문 분포와는 무관하다.
On-policy distillation현재 학생 \(\pi_\theta\)그 prefix에서의 교사 분포 \(\pi_{\mathrm{teacher}}(\cdot\mid h)\)교사를 학습 loop 안에서 계속 호출해야 하고, dense token KL을 쓰려면 logits 접근과 vocabulary 정렬이 필요하다.
환경 보상 RL현재 학생 또는 그 snapshotepisode당 스칼라 보상 1개실행 환경과 verifier. 교사는 필요 없다.

①과 ②는 따로 정해지므로, 설정의 이름 하나로 둘을 동시에 읽으면 혼동이 생긴다. 예를 들어 “교사가 학생 답에 10점 만점의 점수를 매긴다”는 설정은 ①이 학생이므로 on-policy지만, ②는 스칼라 한 개이므로 dense KL을 최소화하는 목적함수와 같지 않다. 반대로 “학생이 만든 답 중 통과한 것만 골라 SFT한다”(rejection sampling / self-distillation)는 ①이 학생이면서 ②는 hard target이다.

왜 교사의 경로만으로는 부족한가

학생이 교사와 다른 행동을 한 번 고르면, 이후에는 교사 시연에 없던 관측과 실패를 마주할 수 있다. 학습 중에는 교사의 prefix가 주어지지만(teacher forcing), 배포 시에는 학생의 이전 출력이 다음 입력을 만든다.

Agarwal et al. (2024)은 교사 데이터로 학습할 때와 학생이 직접 생성할 때의 분포 차이를 지적하고(Chapter 1), 학생이 만든 sequence에서 교사 분포로 감독하는 GKD를 제안했다(Chapter 3.1). 학생이 직접 방문한 입력에서 무엇을 생성해야 하는지 감독을 제공하는 셈이다.

학생이 sequence를 생성하더라도 감독은 교사 분포에서 온다. 이 절의 on-policy distillation은 환경 보상에서 정책 경사를 추정하는 대신, 학생이 방문한 prefix에서 교사와의 분포 차이를 줄인다.

\[\mathcal L_{\mathrm{local}}=\mathbb E_{h\sim d_{\pi_\theta}}\!\left[D\bigl(\pi_{\mathrm{teacher}}(\cdot\mid h),\,\pi_\theta(\cdot\mid h)\bigr)\right]\]

달라진 것은 기대값의 아래첨자다. 이제 기대값은 \(d_{\pi_\theta}\), 즉 학생의 방문 분포 위에서 잡힌다. 하지만 실제 구현은 수집한 prefix를 고정한 뒤 그 위에서 \(D\)만 미분하므로, 방문 분포가 \(\theta\)에 의존한다는 사실은 미분에 들어가지 않는다. 그 항까지 다루려면 policy gradient 항이 다시 등장한다.

그 항까지 포함해 전체를 미분하면 항이 둘로 나뉜다. log-derivative trick을 그대로 적용한 결과이며 특정 논문의 결과가 아니다.

\[\nabla_\theta\,\mathbb E_{h\sim d_{\pi_\theta}}[D(h;\theta)]=\underbrace{\mathbb E_{h\sim d_{\pi_\theta}}[\nabla_\theta D(h;\theta)]}_{\text{구현하는 항}}+\underbrace{\mathbb E_{h\sim d_{\pi_\theta}}\!\left[D(h;\theta)\,\nabla_\theta\log d_{\pi_\theta}(h)\right]}_{\text{보통 생략하는 항}}\]

둘째 항 자체는 \(D\)를 return으로 가중한 score-function 항이다. Loss를 최소화하는 음의 gradient 방향에서 보면 \(-D\)를 보상으로 삼는 policy gradient에 대응한다. divergence가 작아지는 기록을 더 자주 방문하도록 정책을 미는 항이다. 수집한 prefix를 고정한 뒤 첫째 항만 계산하는 통상적인 구현은 이 항을 버린다. 그래서 on-policy distillation이 실제로 최적화하는 것은 학생의 방문 분포가 아니라 현재 방문 분포 위에서의 조건부 분포 일치다.

Divergence의 방향과 신호의 밀도

\(D\)의 자리에는 여러 divergence가 들어갈 수 있고, 방향에 따라 성질이 다르다. Forward KL \(D_{\mathrm{KL}}(\pi_{\mathrm{teacher}}\Vert\pi_\theta)\)는 교사가 확률을 준 모든 곳에 학생도 확률을 두게 만들고(mode-covering), reverse KL \(D_{\mathrm{KL}}(\pi_\theta\Vert\pi_{\mathrm{teacher}})\)는 교사가 매우 낮은 확률을 준 곳에 학생이 확률을 두는 것을 크게 벌한다. 이를 mode-covering·mode-seeking 경향으로 설명하기도 한다. 다만 토큰별 KL 방향 하나가 전체 Agent 전략의 다양성까지 정하지는 않는다. 표현 제약이 없다면 두 KL 모두 전역 최적점에서 교사 분포와 일치하고, 방향의 차이는 그 최적점에 이르는 경로에서 나타난다.

감독의 밀도도 다르다. Hard target은 위치마다 정답 1개, dense KL은 위치마다 vocabulary 전체 분포, 환경 보상 RL은 episode마다 스칼라 1개를 준다. 한 위치에서 활용하는 감독의 형태와 수는 이렇게 다르지만, vocabulary 크기만으로 유효 정보량이나 sample efficiency의 배율을 계산할 수는 없다. 밀도는 내용의 정확성과도 별개다. 교사가 학생의 낯선 실수 경로에서 무엇이 옳은지 모른다면, dense KL은 vocabulary 전체에 퍼진 오답을 준다.

비용의 비대칭도 크다. Off-policy 데이터는 한 번 만들어 두면 여러 학생과 여러 실험에서 재사용할 수 있다. On-policy distillation은 학생이 바뀔 때마다 새 sequence를 만들어야 하므로 교사가 학습 loop 안에 상주해야 한다. 그리고 학생이 계속 업데이트되므로, 조금 전에 모은 학생 sequence는 이미 조금 과거의 정책이 만든 것이다. 수집과 업데이트 사이의 policy lag는 학생 데이터를 사용할 때도 관리해야 한다.

RL 앞과 뒤에 들어가는 distillation

교사에게서 배우는 방법은 학습의 어느 단계에 놓이느냐에 따라 목적이 달라진다. 초기 정책의 능력을 높일 수도 있고, 여러 전문 모델의 능력을 모으거나 이전 단계에서 얻은 능력을 유지하는 데 쓸 수도 있다.

RL 이전의 cold start

교사 데이터를 RL 앞에 두는 이유 중 하나는 초기 정책이 너무 자주 실패해 비교 신호 자체가 생기지 않기 때문이다. DeepSeek-R1이 밝힌 이유는 이와 조금 다르다. DeepSeek-AI (2025)는 base 모델에서 곧바로 RL을 시작할 때의 “초기 불안정한 cold start 구간”을 피하려고, 수천 건의 cold-start 데이터로 DeepSeek-V3-Base를 먼저 미세조정했다고 밝혔다(Chapter 2.3.1).

이 데이터는 새로 라벨링 작업을 벌여 만든 것이 아니라 이미 가진 모델과 사람의 후처리를 조합해 만들었다. 긴 chain-of-thought 예시를 넣은 few-shot prompting, 검증과 반성을 포함한 답을 직접 요청하는 prompting, R1-Zero의 출력을 읽을 수 있는 형식으로 수집하기, 사람의 후처리로 다듬기의 네 가지다(Chapter 2.3.1). 기록을 만든 것은 학생이 아닌 다른 모델(prompting한 모델과 R1-Zero)과 사람의 후처리이고 감독은 hard target이므로, cold start는 off-policy distillation의 한 사례다.

보고된 이득도 두 가지로 나뉜다. 하나는 가독성이다. R1-Zero는 언어가 섞인 출력을 냈으므로 cold-start 데이터에 추론 과정과 요약을 분리한 형식을 강제했다. 다른 하나는 성능이다. 사람의 사전 지식으로 형식을 설계한 cold-start 데이터로 시작하자 R1-Zero보다 나은 성능을 관측했다고 보고한다(Chapter 2.3.1). cold start가 하는 일은 최종 성능을 만드는 것이 아니라 이후 학습이 진행될 수 있는 형식과 초기 능력을 갖추는 것이다. R1-Zero는 cold start 없이도 학습되었으므로(Chapter 2.2), 이 단계는 필요조건이 아니라 가독성과 성능을 위한 설계 선택이다.

학생이 도구 호출 형식조차 자주 틀려 run_tests()가 파싱되지 않는다면, 그룹을 아무리 키워도 비교할 성공이 나오지 않는다. 이때 필요한 것은 새 optimizer가 아니라 형식과 기본 절차를 맞추는 소량의 시연이다. 실패 로그 해석이 부족하다면 그 상태에서의 복구 시연을 넣을지 추가 탐색을 줄지가 비교 대상이 된다.

규모가 작은 학생에서는 이 선택의 무게가 더 커진다. 같은 보고서는 R1으로 선별한 80만 건(추론 60만, 비추론 20만. 비추론 데이터는 DeepSeek-V3의 SFT 데이터 일부를 재사용한다)으로 소형 모델을 RL 단계 없이 SFT만으로 미세조정한 결과를 제시하고(Chapter 2.3.3, Chapter 2.4), 32B 학생에서 대규모 RL만 적용한 경우와 distillation을 비교한다. AIME 2024 pass@1에서 전자는 47.0%, 후자는 72.6%다(Chapter 4.1, Table 6). 다만 같은 절은 “distillation은 경제적이고 효과적이지만, 지능의 경계를 넘어서려면 더 강한 base 모델과 더 큰 규모의 RL이 필요할 수 있다”고 덧붙인다. 교사를 넘어서는 능력이 목표인 경우에는 RL 단계가 그대로 남는다.

초기 정책을 만들기: Qwen3의 두 단계

Qwen Team (2025)은 교사 응답으로 학습하는 off-policy 단계 뒤에, 학생이 생성한 sequence에서 교사 분포에 맞추는 on-policy 단계를 사용했다(Chapter 4.5, Strong-to-Weak Distillation). 첫 단계가 교사의 경로를 제공한다면 둘째 단계는 학생이 실제로 만드는 경로에서 학습을 이어 간다.

같은 보고서의 비교에서는 distillation이 RL보다 나은 결과와 약 10분의 1의 GPU 시간을 기록했다(Chapter 4.7, Table 21). 다만 이 비교는 해당 학생 모델과 학습 조건에서 이미 좋은 교사가 있다고 전제하므로, 교사를 만드는 비용은 10분의 1이라는 숫자 바깥에 있다.

초기화 이후에는 여러 능력을 하나의 모델에 모아야 할 수도 있다. Qwen Team (2026)은 Qwen3-Coder-Next에서 분야별 expert를 배포 모델로 통합하는 데 distillation을 사용했다(Chapter 4.2.5). 이 경우 목적은 단순한 모델 크기 축소가 아니라 전문 능력의 통합이다.

학습이 진행되면서 이전 능력이 떨어지는 경우에는 과거 checkpoint를 교사로 삼을 수 있다. GLM-5 Team (2026)은 이러한 cross-stage distillation을 사용한다(Chapter 3.5).

GLM-5는 이 단계에서 GRPO의 group size를 1로 두는데, advantage를 그룹 비교가 아니라 교사와의 격차에서 직접 얻기 때문이다. 앞의 GRPO에서 본 outcome-GRPO라면 group size 1은 비교 대상이 사라져 신호가 0이 되는 설정이지만, 여기서는 그 비교 대상 자리에 교사가 들어간다.

앞의 네 사례에서 distillation이 맡은 자리는 초기화, 능력 통합, 능력 유지이고, 어느 쪽이든 환경 보상 RL과 함께 쓸 수 있다. 학습 순서는 교사가 제공할 수 있는 행동과 분포, 학생의 기본 능력, 환경에서 얻을 수 있는 보상의 품질을 보고 정한다.

어떤 신호를 선택하든 학습에는 반복 가능한 수집 절차가 필요하다. 환경 보상 RL을 기준으로 초기 정책 준비와 rollout 수집, loss 계산이 하나의 loop로 어떻게 맞물리는지가 다음 절의 내용이다.

Agentic RL in practice

앞의 loss 계산은 이미 수집된 batch에서 시작했다. 실제 학습기는 그 batch를 만드는 과정까지 책임져야 한다. 과제를 뽑고 초기 환경을 복제한 뒤, 고정한 수집 정책으로 각 시도를 실행한다. 결과를 채점하고 그룹 advantage를 계산해 정책을 업데이트하면, 다음 수집부터 새 정책을 사용한다.

Algorithm 3. Rollout 수집과 정책 업데이트

입력: 초기 정책, 과제 분포, 환경과 채점기 · 출력: 학습된 정책

student = initialize_from_pretrained_or_distilled_model()

for iteration in range(num_iterations):
    behavior = snapshot(student)
    tasks = sample_tasks()
    trajectories = []

    for group_id, task in enumerate(tasks):
        for sample_id in range(group_size):
            # 같은 초기 상태를 복제하고 서로 다른 sampling seed로 실행한다.
            env = reset_isolated_environment(task)
            trace = rollout(
                policy=behavior,
                env=env,
                tools=tools,
                budget=budget,
                seed=make_seed(iteration, group_id, sample_id),
            )
            reward = verify_final_outcome(env, trace)
            trajectories.append({
                "group_id": group_id,
                "task_id": task.id,
                "sample_id": sample_id,
                "trace": trace,
                "reward": reward,
            })

    # 완전한 그룹에서 advantage를 계산한 뒤 학습 batch로 나눈다.
    advantages = estimate_group_advantages(trajectories)
    batch = collate_trajectories(trajectories, advantages)
    update_student(
        student=student,
        batch=batch,
        loss_mask=batch.generated_mask,
    )
    evaluate_on_separate_tasks(student)

한 도구 행동은 여러 토큰으로 생성된다. 환경과의 시간축은 도구 호출 단위이고, 모델의 likelihood는 토큰 단위다. 두 시간축을 대응시키고 각 입력과 출력의 경계를 보존해야 한다. 어떤 토큰이 보상에 직접 기여했는지 모르는 terminal-reward 학습에서는 이 경계가 특히 중요하다.

이 반복에서 보상 0은 원인에 따라 다르게 해석해야 한다. 같은 0 안에 요구사항을 만족하지 못한 제출과 실행기가 죽어 테스트를 돌리지도 못한 시도가 섞여 있다. 후자를 모델의 오답으로 처리하면 행동의 품질과 무관한 잡음이 학습 신호에 섞인다.

GLM-5 Team (2026)은 환경 붕괴로 생긴 샘플을 구분해 학습에서 제외한다(Chapter 4.1.2). 반면 정상 실행에서 어려운 문제를 풀지 못한 기록은 그대로 정책의 경험이다. 이 둘을 다르게 처리하려면 로그가 환경 오류와 정책 실패를 서로 다른 사건으로 남겨야 한다.

검증기도 과제의 일부다. 테스트를 통과하도록 보상하면 모델은 그 조건을 만족하는 행동을 찾고, 통과는 조건의 충족일 뿐 요구사항 전체의 증명은 아니다. 그래서 보상의 증가는 실제 문제 해결 능력의 증가와 함께 확인해야 한다. 숨겨진 평가 과제, 정답 누출 검사, 원래 동작의 회귀 검사가 필요하다.

Qwen Team (2026)은 Qwen3-Coder-Next에서 저장소의 외부 연결이나 commit 기록을 통해 정답 commit에 접근하는 보상 우회 사례를 보고했다(Chapter 4.2.4, Reward Shaping). 보상은 높아졌지만 의도한 코드 수정 능력이 개선된 것은 아닐 수 있다. 학습용 채점 규칙뿐 아니라 그 규칙에 접근하는 경로도 실험 조건에 포함해야 한다.

이 행동들은 의도한 과제와 보상 규칙 사이의 틈을 이용한다. 정답이 환경 안에 있고 그것에 도달하는 경로가 열려 있는 한, 정책이 그 경로를 발견해 이용할 여지는 남는다. 그래서 보상 곡선이 올라갈 때 함께 확인해야 하는 것은 “무엇을 통해 올라갔는가”다.

검색 Agent도 구조는 같다. 호출 인자는 검색어, 관측은 검색 결과, 최종 산출물은 답과 근거가 된다. Search-R1은 검색 결과를 loss에서 제외하면서 PPO와 GRPO를 적용한다. 다만 그 실험은 특정 모델과 QA 환경에서 얻은 결과이므로, 검색에서의 우열은 코딩이나 장기 업무에서 다시 확인해야 한다.

수집과 채점이 정확해지면 다음 문제는 실행 시간이다. 같은 과제에서도 바로 완료하는 경로와 여러 번 재검사하는 경로의 길이가 다르다. 이 차이가 커지면 모든 시도가 끝날 때까지 기다리는 동기식 수집이 병목이 될 수 있다.

Throughput and policy lag

동기식 학습에서는 같은 batch의 마지막 rollout이 끝나야 업데이트를 시작한다. 먼저 끝난 worker는 그동안 기다린다. 생성과 학습을 겹치면 이 대기를 줄일 수 있지만, 늦게 끝나는 worker가 이전 가중치로 만든 기록을 현재 정책의 학습에 사용하게 된다.

먼저 도착한 rollout과 정책 지연

네 rollout은 모두 정책 v0에서 시작한다. 동기식은 네 개를 기다리고, 비동기식은 두 개가 도착하면 첫 업데이트를 수행한다. 이 첫 업데이트 이후 늦게 도착한 기록의 버전을 비교한다.

첫 batch만 그린 모형이며 업데이트 시간은 0이다. τ=0이면 늦은 기록을 버리지만 첫 업데이트는 여전히 일찍 시작한다. 지속적인 처리량과 학습 효율은 후속 수집까지 포함해 측정해야 한다.

완료된 기록으로 먼저 업데이트하면 처리량을 얻는 대신 수집 정책과 학습 정책 사이에 차이가 생긴다. 앞의 off-policy 문제가 알고리즘 선택이 아니라 시스템의 실행 순서에서 다시 나타난다.

Espeholt et al. (2018)은 IMPALA에서 actor와 learner를 분리하고 그 정책 차이를 V-trace로 보정했다. LLM의 장기 rollout도 유사한 불일치를 만들지만, 여기서 쓰이는 보정은 보통 V-trace가 아니라 token-level PPO clipping이다.

GLM-5 Team (2026)은 토큰 기록을 그대로 전달하는 TITO와 오래된 샘플을 거르는 policy lag 필터를 별개의 장치로 함께 쓴다(Chapter 4.1.2). TITO는 수집한 행동과 학습 target의 일치를 지키고, 지연 필터는 수집 정책과 현재 정책의 차이를 다룬다. 정확한 token ID를 보존해도 그 차이는 그대로 남기 때문에 두 장치가 모두 필요하다.

위 실험은 허용 지연을 바꿨을 때 어떤 샘플이 남는지 보여 준다. 임계값을 낮추면 오래된 경험을 덜 쓰지만 폐기 비용이 늘 수 있다. 적절한 값은 실행 시간의 편차와 정책 변화 속도에 따라 달라진다.

정책 버전이 같아도 sampling 규칙이 다르면 분포가 어긋날 수 있다. DeepSeek-AI (2025)는 top-p·top-k로 제한한 sampling support를 다루는 Keep Sampling Mask와, 정책 차이가 큰 negative sequence를 제외하는 Off-Policy Sequence Masking을 설명한다(Chapter 3.1). 이름은 같은 mask지만, 환경 관측을 policy target에서 제외하는 mask와 달리 이 둘이 다루는 것은 수집 분포와 학습 분포의 어긋남이다.

앞의 실험에서 본 support 조건이 여기서 실제 시스템의 문제로 돌아온다. Top-p로 잘라 낸 행동에는 수집 확률이 0인 영역이 생긴다. Keep Sampling Mask는 수집 때의 truncation mask를 현재 정책에도 적용해 두 정책의 행동 부분공간을 맞추고, Off-Policy Sequence Masking은 정책 차이가 큰 negative sequence의 loss를 제외한다. 둘 다 PPO의 min-clipping과는 다른 장치이며, 후자처럼 샘플을 제외하는 방법에는 편향과 분산의 절충이 따른다.

학습 처리량을 비교하려면 샘플 수뿐 아니라 생성 길이와 도구 실행 시간도 알아야 한다. 완성된 정책을 평가할 때도 마찬가지로 한 시도에 허용한 계산량을 고정해야, 더 많은 계산이 만든 개선과 학습이 만든 개선이 섞이지 않는다.

Reasoning effort

추론 시 계산은 한 응답 안의 reasoning, 외부 도구와의 상호작용, 여러 후보의 sampling에 배분할 수 있다. 같은 가중치에서도 이 예산에 따라 성공률과 비용이 달라진다. Reasoning effort는 이런 작업량을 유도하는 제어이며, 평가에서는 실제 토큰 수와 호출 횟수, 지연을 함께 측정해야 한다.

OpenAI의 Reasoning 문서는 추론량 제어를 설명하고, Anthropic의 “How effort works”는 effort가 추론뿐 아니라 응답과 도구 호출에도 영향을 줄 수 있다고 설명한다. Gemini의 Thinking 문서도 모델별로 지원하는 제어를 구분한다. 모델이 다르면 같은 “high”가 가리키는 계산 예산도 다르므로, 같은 라벨은 같은 조건이 아니다. 문서 확인일은 2026년 9월 8일이며 지원 설정은 바뀔 수 있다.

배포 예산은 학습 데이터의 조건과도 맞아야 한다. 긴 교사 경로로 학습한 학생에게 매우 적은 호출만 허용하면, 학습한 절차를 끝까지 실행하지 못한다. 반대로 간단한 과제에 항상 긴 추론과 여러 후보를 허용하면 성공 여부가 같아도 비용이 커진다.

\[J_{\mathrm{cost}}=\mathbb E\!\left[R_{\mathrm{success}}-\lambda_{\mathrm{tok}}C_{\mathrm{tokens}}-\lambda_{\mathrm{tool}}C_{\mathrm{tools}}\right]\]

이 식은 비용까지 넣었을 때의 교육용 목적함수이고, 업체가 실제로 쓰는 reward 식은 아니다. 토큰과 도구 호출에 큰 벌점을 주면 필요한 검증까지 생략할 수 있다. 성공률과 비용을 별도로 측정하고 어떤 절충이 필요한지 정하는 편이 해석하기 쉽다.

정책을 비교할 때는 같은 추론·도구·후보 예산에서 성공률을 보거나, 예산별 성공률–비용 곡선을 비교한다. 단일 설정의 보상 숫자 하나에는 능력의 몫과 계산량의 몫이 함께 들어 있다.

Choosing a training recipe

지금까지 선택한 요소들을 묶으면 하나의 학습 설정이 된다. 어떤 정책에서 시작할지, 어떤 경험을 모을지, 무슨 신호로 업데이트할지, 얼마의 실행 예산으로 평가할지를 함께 정해야 한다. REINFORCE·PPO·GRPO라는 이름이 정하는 것은 그중 업데이트 규칙 하나뿐이다.

방법비교 기준추가 비용과 주의점
REINFORCE + baseline샘플 return − baseline긴 trajectory에서 높은 분산; 기본형은 새 정책 경험 필요
PPO흔히 value + GAEValue 학습 비용; 제한된 batch 재사용과 divergence 관리
GRPO동일 과제의 그룹 보상그룹 rollout 비용; 동일 보상 그룹과 거친 credit assignment
Distillation교사 행동 또는 분포교사 접근 비용·오류·학생 방문 분포 차이

이 표에서 비교할 대상은 알고리즘의 이름이 아니라 비용과 가정이다. Value 예측이 어려운지, 같은 문제에서 여러 시도를 수집하기 비싼지, 좋은 교사에 접근할 수 있는지에 따라 유리한 구성이 달라진다. 어느 방법이 낫다는 결론은 초기 checkpoint와 평가 조건을 맞춘 실험에서 얻어야 한다.

실행 결과로 정답을 검증할 수 있는 과제와, 별도의 평가 기준으로 품질을 판단해야 하는 과제는 보상 설계가 다르다. 어느 쪽이든 데이터의 다양성과 보상의 신뢰성은 서로 다른 축이므로 따로 설계한다.

Kimi K2 보고서는 도메인·도구·agent 구성을 다양화하는 데이터 생성 과정을 설명하고(Agentic Capabilities), 규칙으로 채점하기 어려운 과제에는 rubric 기반 모델 판단을 사용한다(General Reinforcement Learning). 전자는 어떤 경험을 얻는지, 후자는 그 경험을 어떻게 평가하는지에 관한 선택이다.

Rubric judge의 점수는 코드 실행 결과와 달리 모델의 판단을 한 번 더 거쳐 나온 값이고, 그 판단 오류는 그대로 보상에 들어간다. 과제 범위를 넓힐 때 새 채점기가 실제 성공을 얼마나 잘 반영하는지 함께 검사하는 이유다.

학습 설정을 정했다면 구현에 들어가기 전에 점검 순서부터 잡는다. 환경이 재현되는지, 초기 정책이 유효한 호출을 만드는지, 기록이 loss와 맞게 연결되는지를 먼저 확인한다. 이 조건이 충족된 뒤에야 알고리즘이나 수집 방식의 차이를 해석할 수 있다.

What to do first, and what to measure

실험을 시작할 때는 가장 앞에서 실패한 조건부터 고치는 편이 원인을 좁히기 쉽다. 실행기가 불안정한 상태에서 보상 함수를 바꾸거나, 로그확률이 잘못 정렬된 상태에서 PPO와 GRPO를 비교하면 무엇이 개선을 만들었는지 알기 어렵다. 아래 항목은 앞의 논의를 실제 점검 순서로 정리한 것이다.

실험 전 점검: 환경·기록·초기 정책·평가

0. 무엇이 실패를 만드는지 먼저 센다

학습을 시작하기 전에 현재 모델과 harness로 과제 집합을 한 번 돌리고, 실패를 원인별로 분류한다. 원인별 기록이 있어야 어디에 개입할지 정할 수 있고, 아래 표는 실패 유형마다 어디부터 볼지 정리한 것이다.

관측한 실패먼저 확인할 것
도구 호출 형식·인자가 틀림도구 명세, 파서, 유효한 호출의 시연 데이터
실행기 자체가 고장 남환경 재현성, 실패 사유 로깅, 인프라 오류의 별도 처리
검증기는 통과하지만 코드가 틀림채점 입력의 충분성, 정답 누출, 별도 평가셋
유효한 행동을 만들지만 수정·복구에 실패함방문 상태와 실패 경로를 분석한 뒤 시연 학습·RL을 비교

실패 비율은 어떤 개입이 얼마나 듣는지까지 말해 주지 않는다. 원인별 빈도와 수정 비용을 함께 보고, 한 조건씩 바꾸어 실제 개선을 확인한다.

1. 환경과 검증기를 학습보다 먼저 완성한다

환경 고장으로 인한 실패를 모델의 실패와 같은 0점으로 채점하면, 보상에 능력과 무관한 잡음이 들어간다. GLM-5가 실패 이유를 샘플마다 기록하는 이유가 이것이다. 반대로 어려워서 실패한 기록까지 버리면 상대 비교에 필요한 신호를 잃을 수 있다. 두 0점을 구분할 수 있는 로깅을 먼저 만든다. 검증기 쪽에서는 정답 누출 경로를 닫는다. Qwen3-Coder-Next의 사례처럼 정답이 환경 안에 남아 있으면 정책이 그 경로를 이용해 보상을 얻을 수 있다.

2. 기록의 정확성을 학습의 전제로 둔다

생성 당시의 token ID, log-probability, sampling 설정, policy version을 보존한다. 문자열만 저장했다가 다시 tokenize하면 실제로 생성한 행동과 학습하는 토큰의 경계가 어긋난다. GLM-5의 token-in/token-out은 이 문제에 이름을 붙인 것이다. 수집 당시 정보를 남기지 않으면 텍스트만으로 같은 로그확률을 되살린다는 보장이 없다.

3. 초기 정책이 유효한 행동을 만드는지 확인한다

호출 형식과 인자에서 실패하는 정책에 환경 보상 RL을 적용하면 성공 경험 자체가 거의 만들어지지 않는다. 도구 명세를 고치고, 좋은 교사가 있다면 검증된 trajectory로 초기화하는 방법을 먼저 비교한다. 이 단계에서 필요한 것은 교사의 출력 텍스트와 tool call뿐이므로 API 교사로도 구성할 수 있다. RL 이전의 cold start와 Qwen3의 off-policy 단계가 이 자리에 해당한다.

4. 격차를 재고 distillation과 RL 중에서 고른다

좋은 교사가 있고 학생이 교사의 경로에서 자주 벗어난다면 on-policy distillation을 비교할 이유가 있다. 감독이 학생의 방문 상태까지 닿는다고 해서 곧바로 성능 향상으로 이어지는 것은 아니므로 비교 실험이 필요하다. 교사 시연을 넘어 환경에서 새로운 전략을 탐색하려는 경우에는 환경 보상 RL을 함께 후보에 올린다. 둘은 같이 쓸 수 있어서, 공개 사례들은 초기화·전문 능력 통합·능력 유지의 세 자리에 distillation을 각각 배치한다.

상황먼저 비교할 방법확인해야 할 조건
도구 형식 자체가 자주 틀린다도구 명세 수정 + 교사 trajectory SFT교사 출력의 검증. 형식이 맞아도 행동이 옳은지는 별개다.
유효한 행동은 내지만 교사보다 훨씬 못한다On-policy distillation교사 logits 접근과 vocabulary 정렬. 학생 sequence의 policy lag.
교사가 없거나 교사가 천장이다환경 보상 RL검증 가능한 과제, 정답 누출 차단, 그룹 rollout 비용.
이전 단계의 능력이 무너졌다Cross-stage distillation어떤 checkpoint를 교사로 삼을지, 그리고 무엇을 회복 대상으로 정의할지.

5. 처음부터 비동기로 시작하지 않는다

동기식이나 아주 제한된 지연으로 시작해 token·reward·mask의 대응이 맞는지 먼저 확인한다. 수집이 실제 병목이라는 것을 측정한 뒤에 확장하면 문제가 생겼을 때 원인을 좁히기 쉽다. 확장할 때는 허용 지연 τ를 하나의 hyperparameter로 놓고 폐기되는 샘플 비율을 함께 본다. 앞의 실험에서 τ를 0으로 내리면 첫 업데이트는 일찍 시작하면서도 뒤늦게 도착한 기록은 버리게 된다.

6. 보상과 평가를 분리해서 본다

보상은 학습이 최적화하는 대상이고, 평가는 우리가 알고 싶은 것이다. 학습에 노출된 채점 결과만 보면 보상 상승이 별도 평가에서도 유지되는지 알 수 없다. Anthropic의 평가 문서는 모델이 transcript에서 무엇을 말했는지와 환경의 최종 상태를 구분하라고 말한다.

Anthropic의 “Demystifying evals for AI agents” 중 “The structure of an evaluation”은 이 구분을 평가 설계의 출발점으로 둔다. 이 글에서는 “고쳤다”는 마지막 문장과 저장된 산출물이 요구사항을 만족하는가를 분리한다. 같은 문서의 “How to think about non-determinism”은 반복 실행을 평가해야 하는 이유를 다룬다. 결과 판정의 정확성과 반복 시도의 신뢰성은 별도 축이다.

한 번 잰 성공률 숫자는 결론이 아니다. 같은 과제를 여러 번 돌렸을 때의 변동, 비용과 지연, 기존 능력의 회귀를 함께 보고, model·tool schema·context 관리·effort·turn 제한은 고정하거나 바뀐 항목을 기록한다. Agent의 성능은 모델과 harness가 함께 만든 결과이므로, harness가 바뀐 채로 잰 두 숫자는 같은 축의 값이 아니다.

7. 무엇을 기록할지 미리 정한다

  • 학습 쪽: entropy(DAPO의 entropy collapse), reference model과의 KL, ratio 분포, 유효 그룹 비율(그룹 내 보상이 모두 같지는 않은 과제의 비율 — 이 값이 낮으면 rollout 계산의 대부분이 gradient 없이 버려진다), 응답 길이 분포와 잘린 샘플의 비율, policy lag 분포, 폐기된 샘플 수와 그 이유.
  • 환경 쪽: 과제별 실패 이유(모델 실패 / 환경 고장 / 시간 초과), 도구 호출당 소요 시간, 재현 실패율.
  • 평가 쪽: held-out 성공률과 반복 시행의 분산, 토큰·도구 호출 비용, 기존 과제의 회귀, 정답 누출 검사 결과.

KL 제거, 길이 penalty, stale sample 임계값에는 보편적인 정답 값이 없다. 위 지표가 없으면 보상 곡선이 흔들릴 때 어느 항을 건드려야 하는지 알 수 없고, 그 상태에서 hyperparameter를 바꾸는 것은 관찰이 아니라 추측이다.

피해야 할 패턴

패턴왜 문제인가
알고리즘 교체를 첫 개입으로 삼는다환경·기록·초기 정책이 원인이라면 PPO를 GRPO로 바꿔도 같은 실패가 남는다. 실패 유형별 점검표를 0번에 둔 이유다.
보상 곡선만 보고 성공을 선언한다정답 누출과 verifier 우회는 보상을 정확히 올린다. 숨긴 평가와 회귀 검사가 함께 필요하다.
“on-policy”라는 단어 하나로 방법을 묶는다기록을 만든 정책과 감독 신호는 다른 축이다. 교사 분포로 배우는 것과 환경 보상으로 배우는 것은 목적함수가 다르다.
성공과 비용의 원시 지표를 남기지 않는다결합 보상을 쓸 수는 있지만, 각 성분이 없으면 성공률과 비용 중 무엇이 개선됐는지 분리할 수 없다. 잘린 응답의 채점은 특히 잡음을 만든다.
다른 회사의 수치를 그대로 목표로 삼는다공개된 값은 그 모델·데이터·harness에서의 결과다. 1/10 GPU 시간 같은 수치도 그 조건에 붙어 있다.
실패 기록을 전부 버린다환경 고장은 걸러야 하지만, 어려워서 실패한 기록도 학습에 유용할 수 있다. 음의 advantage인지, 0인지는 baseline과 그룹 구성에 달려 있다. 둘을 구분하지 않으면 둘 다 잘못 처리된다.

이 점검을 통과하면 학습기가 의도대로 동작한다는 것까지는 말할 수 있다. 실행이 정확해도 연구 가설은 그대로 남아 있으므로, 다음 차례는 어떤 능력이 왜 개선되었는지 갈라 볼 비교 실험이다.

A research protocol

예를 들어 RL 이후 코드 수정 과제의 성공률이 올랐다고 하자. 모델이 오류의 원인을 더 잘 찾게 되었을 수도 있고, 더 많은 테스트를 실행하게 되었을 수도 있다. “코딩 성능이 좋아졌다”는 결과는 둘 중 어느 쪽인지 말해 주지 않는다. 연구 질문을 “성공 경로만 모방한 정책보다 RL로 학습한 정책이 잘못된 첫 패치 이후 오류를 발견하고 복구할 확률이 높은가?”로 좁히면 필요한 비교가 분명해진다. 아래는 실제로 돌린 실험의 보고가 아니라 이를 위한 실험 설계 예시다.

비교군과 데이터 분할

기본 instruct 정책, 검증된 성공 trajectory로 SFT한 정책, 같은 SFT checkpoint에서 시작한 RL 정책을 비교한다. 가능하면 RL과 같은 수집 예산으로 성공 샘플을 추가 모방하는 rejection-sampling SFT도 넣는다. 그래야 새 데이터를 더 모아서 얻은 이득과 보상 가중 업데이트가 만든 이득이 갈린다. 교사 데이터 생성 비용과 실패·폐기 rollout 비용도 포함한다.

코딩테스트 문제 단위로 train·validation·test를 나눈다. 같은 문제의 테스트 입력만 바꾼 것은 새 문제에 대한 일반화 평가가 아니다. 문제 설명을 바꾸거나 코드 변수명만 바꾼 복제도 같은 묶음으로 취급한다. Validation은 설정과 checkpoint 선택에 쓰고 test는 선택이 끝난 뒤 평가한다. 실제 저장소 문제로 확장하면 저장소 단위 분할과 사전학습 노출도 추가로 확인해야 한다.

검증할 설명필요한 비교설명이 약해지는 결과
실패 이후 복구가 좋아졌다일반 시작과 표준화한 잘못된 패치에서 시작하는 진단 과제를 각각 평가일반 성공률만 오르고 복구 성공률은 그대로다.
학습법 때문에 좋아졌다초기 checkpoint·harness·평가 예산을 맞추고, 추가 성공 데이터 SFT와 비교더 많은 데이터나 호출 예산만으로 같은 향상이 나온다.
검증기보다 문제 해결을 배웠다학습에 쓰지 않은 회귀 테스트와 외부 행동 검사를 사용학습 verifier만 좋아지고 별도 검사에서는 개선이 없다.
계산 효율이 좋아졌다누적 생성 토큰·환경 실행 시간·GPU 시간에 대한 성공률 곡선업데이트 횟수로는 우세하지만 같은 총비용에서는 우세하지 않다.

복구 능력은 자연적으로 실패한 실행만 골라 비교하면 왜곡될 수 있다. 정책마다 실패하는 과제 자체가 다르기 때문이다. 같은 잘못된 패치에서 시작하는 진단은 이 선택 문제를 줄이지만 자연 사용 분포와는 다르다. 따라서 전체 과제 성공률과 진단 결과를 함께 보고한다. 학생이 방문한 상태에 대한 감독이라는 질문은 DAgger(Ross et al., 2011)의 문제의식과도 연결된다. 다만 GKD와 DAgger는 감독 형식도 구체적 절차도 서로 다른 알고리즘이다.

학습 데이터는 얼마나 필요한가

논문에서 말하는 “데이터 1만 개”는 서로 다른 양일 수 있다. Distillation에서는 선별한 질문–응답 쌍이나 성공 trajectory를 세고, online RL에서는 반복해서 rollout을 생성할 과제 목록을 세는 경우가 많다. 실제 비용을 비교하려면 고유 과제 수, 생성한 전체 시도 수, 필터링 후 학습에 쓴 시도 수, 생성 토큰 수를 함께 봐야 한다.

공개 사례보고한 규모와 단위어떤 학습에 사용했는가
s1 (Chapter 2)선별한 질문–추론 응답 1,000쌍. 초기 질문 풀은 59,029개.교사 추론을 이용한 SFT. 단일 응답 reasoning 사례이며, 1,000번의 교사 호출만으로 데이터 수집을 끝냈다는 뜻은 아니다.
SWE-smith (Chapter 4)32B 모델 학습에 사용한 성공 trajectory 5,016개. 고유 과제 8,686개에 대해 총 17,906번 시도한 풀에서 선별.실제 저장소·도구 실행을 포함한 교사 trajectory SFT. 별도 비교 실험에서는 성공 trajectory 500개도 사용했다.
DeepSeek-R1 (Chapter 2.3.1, Chapter 2.3.3–2.4)RL 초기화에는 수천 개의 cold-start 예제. 소형 모델 distillation에는 약 80만 개의 SFT 샘플.초기화 데이터와 최종 distillation 데이터의 목적이 다르다. 80만 개는 추론 약 60만·비추론 약 20만으로 구성되며 RL의 고유 과제 수가 아니다.
SimpleRL-Zoo (Chapter 2.1, Appendix B)난이도별 학습 문제 약 8,000개. 기본 설정은 prompt batch 1,024개, 문제당 rollout 8개.수학 문제의 online GRPO. 한 수집 batch만으로도 8,192개의 응답을 생성한다. 학습 문제 수와 전체 생성 응답 수를 구별해야 한다.
Qwen3-Coder-Next (Appendix A.1)PR 기반 환경 과제 807,693개, 별도 버그 합성 과제 851,898개를 보고.대규모 agentic training을 위한 과제 자산의 규모다. 표에 나온 과제 수만으로 RL이 실제 소비한 rollout 수나 학습 횟수를 알 수는 없다.

이 사례들에서 하나의 “보통 필요한 개수”를 평균내기는 어렵다. 수천 개의 선별된 시연으로 특정 행동을 가르치는 실험과 수십만 과제로 범용 정책을 학습하는 시스템은 목표가 다르다. 특히 s1의 1,000개와 SWE-smith의 5,016개는 최종 학습 데이터의 크기다. 후보를 만들고 실패를 버리는 비용은 그보다 크다. 위 숫자는 각 논문에 명시된 버전을 기준으로 확인했다(2026년 9월 8일).

과제 수를 rollout 예산으로 바꾸기

한 번 수집할 때 \(B\)개의 과제를 뽑고 과제마다 \(G\)개의 rollout을 만들며, 이를 \(K\)번 반복한다고 하자. 추가 수집이나 재시도가 없다면 생성한 전체 trajectory 수는 다음과 같다. \(K\)는 optimizer step 수가 아니라 수집 반복 횟수다.

\[N_{\mathrm{rollout}}=KBG,\qquad C_{\mathrm{generated}}\approx KBG\,\bar L.\]

\(\bar L\)은 trajectory 하나의 평균 생성 토큰 수다. 예를 들어 \(B=32\), \(G=4\), \(K=100\)이면 12,800개의 trajectory를 생성한다. 평균 길이가 2,000토큰이면 생성량은 약 2,560만 토큰이다. 고유 과제가 1,000개뿐이어도 같은 문제를 다시 뽑아 이만큼의 경험을 만들 수 있다. 도구 출력과 입력 prefill, 역전파, 검증기 실행 비용은 이 생성 토큰 계산에 별도로 더해야 한다.

Dynamic sampling으로 그룹 중 일부만 채택한다면 실제 수집량은 더 커진다. 그룹 채택률을 일정한 \(\alpha\)로 근사할 때, 채택 rollout \(KBG\)개를 모으려면 대략 \(KBG/\alpha\)개를 생성해야 한다. 성공 시연만 남기는 distillation도 마찬가지다. 후보의 최종 채택률이 25%라면 시연 1,000개를 얻는 데 평균적으로 약 4,000번의 시도가 필요하다. 이 계산은 예산 추정이며, 학습 중 채택률 변화는 실제 로그로 갱신한다.

On-policy distillation은 고정 시연 파일의 크기만으로 표현하기 어렵다. 학생이 새로 방문한 context마다 교사를 다시 평가하므로 학생의 rollout 수, 교사가 감독한 생성 위치 수, 교사 forward의 입력 길이를 함께 기록한다. 학생 토큰 1개를 감독하는 비용도 교사 전체 vocabulary 분포를 얻는 방식에 따라 달라진다.

첫 실험에서는 규모 자체도 비교 변수로 둔다

이 설정으로 첫 실험을 한다면, 먼저 50–100개 과제로 환경과 verifier, mask 정렬을 확인한 뒤 본 실험의 데이터 규모를 늘리겠다. Distillation은 검증된 trajectory 500 → 1,000 → 5,000개, RL은 고유 학습 과제 1,000 → 5,000 → 10,000개처럼 포함관계가 있는 부분집합으로 비교할 수 있다. 이 숫자들은 앞의 공개 사례를 참고해 잡은 비교 구간이고, 어느 규모에서 성능이 나오는지는 그 비교로 확인할 문제다. 긴 저장소 과제라면 더 작은 규모에서 시작해 실행 비용을 먼저 측정한다.

Distillation에서 전체 학습 토큰 예산을 맞춘 비교와 각 데이터셋을 같은 epoch만큼 학습한 비교는 서로 다른 질문이므로 따로 돌린다. RL에서는 고유 과제 수를 바꾸되 전체 rollout 예산을 맞추어야, 더 다양한 과제를 본 효과와 단순히 더 많이 실행한 효과를 나눌 수 있다. 두 경우 모두 validation에서 개선이 포화되는지 보고 다음 규모를 정하며, test는 이 선택에 사용하지 않는다.

pass@1, pass@k, 최종 선택의 성공률

한 번 실행해서 성공할 확률이 \(p\)이고 같은 과제에서 독립적으로 \(k\)번 시도하면, 적어도 하나가 성공할 확률은 \(1-(1-p)^k\)다. 이것은 성공 후보가 존재할 확률이지, 시스템이 그 후보를 정확히 선택해 사용자에게 전달할 확률이 아니다. 여러 후보 중 judge가 고른 하나를 제출한다면 최종 선택 성공률을 따로 측정해야 한다.

Chen et al. (2021)에 따르면, 한 과제에서 생성한 \(n\)개 후보 중 \(c\)개가 통과했을 때 pass@k는 다음과 같이 추정할 수 있다(Chapter 3.1, \(n\ge k\)). 실패 후보 \(n-c\)개에서만 \(k\)개를 고르는 경우를 전체 조합에서 제외한 식이다.

\[\widehat{\operatorname{pass@}k}=1-\frac{\binom{n-c}{k}}{\binom nk},\qquad \binom{n-c}{k}=0\ \text{if }n-c<k.\]

\(n=10,c=2,k=3\)이면 \(1-56/120\approx0.533\)이고, 표본 성공률 \(c/n\)을 그대로 \(1-(1-c/n)^k\)에 넣으면 0.488이 나온다. 여러 과제의 pass@k는 과제별 추정량을 먼저 구해 평균한다. 평균 pass@1을 비선형 식에 넣어 계산하지 않는다. 이전 시도의 실패 로그를 다음 시도에 제공했다면 독립 sampling 가정도 달라지므로 “최대 k회 복구 프로토콜의 성공률”을 직접 보고하는 편이 맞다.

점수 차이의 크기와 불확실성

서로 독립인 과제 200개에서 한 번씩 평가해 성공률이 50%였다면, 단순 이항 근사의 표준오차는 \(\sqrt{0.5(1-0.5)/200}\approx0.035\)다. 대략적인 95% 구간의 반폭은 6.9%p다. 한 번의 실행에서 나온 작은 점수 차이를 믿기 어려운 이유가 이 계산에 있다. 동일 과제의 두 정책을 비교할 때는 두 개의 독립 구간을 비교하는 대신 과제별 성공률 차이를 짝지어 분석한다.

같은 문제를 100번 푼 것은 서로 다른 문제 100개를 푼 것과 다르다. 문제 간 일반화를 평가할 때는 문제별 반복 결과를 같은 묶음으로 유지하고, 문제를 단위로 재표본추출하는 bootstrap을 고려한다. 학습 seed에서 오는 변동과 평가 sampling에서 오는 변동도 따로 적는다. 여러 학습 seed를 감당하지 못했다면 단일 학습 run의 결과임을 명시한다. 이러한 불확실성과 집계의 중요성은 Agarwal et al. (2021)의 RL 평가 논의와 연결된다.

최소한의 재현 자료

독자가 같은 실험을 다시 실행하려면 모델 이름만으로는 부족하다. 초기·최종 checkpoint 식별자, 과제 분할, 환경 이미지와 저장소 commit, tool schema와 prompt, context 구성, sampling과 종료 설정, reward 각 성분, loss reduction, optimizer 설정, seed, 원시 평가 결과를 남긴다. 환경 오류를 재시도하거나 제외한 규칙도 필요하다. 정책이 학습 결과로 고장 난 명령을 내보낸 경우와 정책과 무관한 서버 장애를 같은 규칙으로 묶어 제거하면 비교가 왜곡된다.

학습 곡선에는 성공률과 비용을 따로 두고, 유효 그룹 비율·생성 길이·entropy·ratio·clipping 비율을 함께 확인한다. 예를 들어 보상은 오르지만 외부 회귀 검사 점수는 그대로라면 reward exploit을 의심할 근거가 된다. Entropy 감소만으로 실패라고 결론 내릴 수는 없지만, 성공이 정체되고 유효 그룹도 줄면 탐색이 부족한지 조사할 이유가 생긴다.

References

출처를 단 문단은 원문의 한국어 요약이며 직접인용이나 공인 번역이 아니다. 알고리즘의 출처, 특정 시스템에서 보고한 관찰, 이 글의 유도와 실험 제안은 서로 다른 항목으로 나누어 적었다. 링크를 따라갈 때는 버전과 절 번호를 함께 본다. 2026년 9월 8일에 기존 공개 사례와 함께 핵심 알고리즘, 새로 추가한 평가·shaping 문헌을 원문과 대조했다. 대조한 범위는 인용한 내용이 원문에 그대로 있는지까지이고, 독립 재현이나 결과 검증은 하지 않았다.

연구 설계와 추가 연결

정책 경사와 학습

Agent 실행과 자기평가

Distillation과 공개 학습 시스템

공식 시스템·도구·평가 문서