앞 글에서는 Jev를 도메인에 맞추는 마지막 단계로 사람의 수정 데이터를 모아 전용 모델을 학습하는 방법을 제안했다. 범용 API로 데이터가 없는 시기를 건너고, 업무가 반복되면 더 싸고 좁은 로컬 모델로 넘기는 구조다.
이번에는 그 전환을 이 블로그의 실제 글로 시험했다. 한국어 글 75편의 제목과 요약을 읽고 agent-engineering 분야에 해당하는지 분류했다. 기존 태그를 사람이 붙인 정답으로 놓고 Jev와 문자 n-gram 로컬 분류기를 비교했다.
첫 결과는 공교롭게도 같았다. 둘 다 75편 중 52편을 맞혀 정확도 69.3%였다. 그러나 같은 문제를 틀린 것은 아니었다. 오답을 읽어 보니 모델 비교보다 먼저 해결할 문제가 나타났다. 정답으로 사용한 기존 태그가 지금 정의한 분류 기준과 일치하지 않았다.
이 글은 Jev가 69.3% 또는 90.7% 정확도라는 주장이 아니다. 표본은 한 사이트의 글 75편이고, 사후 라벨 검토에는 Jev 결과를 본 영향이 들어갔다. 여기서 확인한 것은 범용 모델을 라벨러로 써서 전용 모델을 만드는 과정이 어디서 오염되는지, 그리고 무엇을 분리해서 측정해야 하는지다.
제목과 요약만으로 분야를 판정했다
실험 과제는 다음 문장으로 고정했다.
이 글의 주제가 AI 에이전트 또는 에이전트 하네스의 엔지니어링인가? 실행 루프, 도구, 컨텍스트, 메모리, 평가, 안전, 코딩 에이전트 운영을 포함한다. 모델 출시, 일반 AI 논평, 검색 인프라, 개발자 경력은 에이전트 시스템 엔지니어링이 주제가 아닌 한 제외한다.
글 전문은 사용하지 않았다. 편집자가 새 글의 제목과 요약을 작성한 시점에 자동 태그를 제안하는 상황을 가정했다. 75편 중 기존 agent-engineering 태그가 있는 글은 40편, 없는 글은 35편이었다.
Jev에는 글마다 Noul 하나를 보냈다. true 확률이 0.5 이상이면 해당 분야로 분류했다. 모델은 jev-1.13.0이고 75개 호출을 8개씩 병렬로 실행해 전체 벽시계 시간은 14.8초였다. 이 시간에는 한국에서 API까지의 네트워크 왕복과 Node 프로세스가 모두 포함된다.
로컬 기준선은 외부 모델을 내려받지 않는 문자 2~5-gram multinomial Naive Bayes다. 한글 형태소 분석도 임베딩도 쓰지 않았다. 작은 데이터에서 얼마나 빨리 쓸 만해지는지 보기 위한 의도적으로 단순한 기준선이다.
실험 코드는 experiments/jev-bootstrap에 두었다. 데이터 생성, Jev 호출, 로컬 학습, 임계값 비교를 각각 다시 실행할 수 있다.
기존 태그를 정답으로 쓰면 둘 다 69.3%였다
| 분류기 | 평가 방법 | 정확도 | TP | TN | FP | FN |
|---|---|---|---|---|---|---|
| Jev | 기존 태그, 임계값 0.5 | 69.3% | 25 | 27 | 8 | 15 |
| 로컬 n-gram | 기존 태그, leave-one-out | 69.3% | 25 | 27 | 8 | 15 |
혼동 행렬까지 같지만 오답 목록은 달랐다. 로컬 모델은 표현이 비슷한 글에 끌렸다. Jev는 분류 문장의 의미를 더 잘 적용했지만, 기존 태그와 충돌했다.
예를 들어 Jev는 다음 글을 해당 분야라고 판단했다.
MCP 도구 설계컨텍스트 엔지니어링AI 평가크로스 에이전트 리뷰에이전트 메모리OpenViking의 에이전트 컨텍스트 검색
이 글들에는 기존 agent-engineering 태그가 없었다. 그러나 이번에 적은 과제 정의에는 대부분 들어간다. 반대 방향도 있었다. 모델 출시와 마이그레이션 글 일부에는 해당 태그가 있었지만, 과제 정의는 모델 출시를 주제에서 제외했다.
모델이 틀렸다고 집계한 23편 안에 태그 체계의 변화가 섞여 있었다. 오래된 글을 쓸 때 사용한 태그 기준과 이번 분류를 위해 작성한 기준이 같지 않았던 것이다.
모델 출력으로 정답을 고치면 평가가 모델 쪽으로 기운다
불일치한 글을 제목과 요약, 과제 정의에 맞춰 다시 검토했다. 16편의 라벨을 바꿨다. 모델 출시가 주제인 글은 음성으로, 에이전트 메모리와 컨텍스트 운영이 주제인 글은 양성으로 정리했다.
수정된 라벨에서 Jev의 정확도는 90.7%가 됐다. 임계값 0.5에서 32개의 양성과 36개의 음성을 맞혔고, 거짓 양성은 1개, 거짓 음성은 6개였다. 로컬 모델의 leave-one-out 정확도는 70.7%였다.
| 분류기 | 검토 후 라벨 | 정확도 |
|---|---|---|
| Jev, 임계값 0.5 | 75편 | 90.7% |
| 로컬 n-gram, leave-one-out | 75편 | 70.7% |
이 표만 보면 Jev가 압도적으로 좋아 보인다. 그대로 성능 주장에 쓰면 안 된다. 검토할 항목을 Jev와 기존 태그가 충돌한 사례에서 골랐고, 검토자는 Jev의 확률도 이미 봤다. Jev가 제기한 반례로 정답표를 고쳤으니 수정된 정답표가 Jev와 더 비슷해지는 것은 자연스럽다.
이것은 LLM으로 학습 데이터를 만들 때 흔히 생길 수 있는 순환이다.
모델이 라벨을 제안한다
↓
사람은 모델과 다른 사례를 주로 검토한다
↓
애매한 기준이 모델의 해석 쪽으로 정리된다
↓
같은 모델을 정답표에 평가하면 점수가 오른다
사람이 확인했으므로 라벨이 모두 틀렸다는 뜻은 아니다. 문제는 그 라벨로 같은 모델의 정확도를 독립적으로 입증할 수 없다는 것이다. 수정 뒤 90.7%는 운영용 라벨 정리의 결과이지, 깨끗한 보류 세트에서 얻은 벤치마크가 아니다.
로컬 모델은 라벨 48개에서도 따라오지 못했다
검토한 라벨을 기준으로 로컬 모델의 학습 표본 수를 8개부터 48개까지 늘렸다. 각 크기에서 양성과 음성 비율을 맞춰 100번 나누고, 나머지 글로 평가했다.
| 학습 글 수 | 평균 정확도 | 10~90백분위 |
|---|---|---|
| 8 | 56.4% | 49.3~67.2% |
| 16 | 62.6% | 54.2~71.2% |
| 24 | 67.3% | 60.8~72.5% |
| 32 | 69.0% | 62.8~74.4% |
| 40 | 69.5% | 60.0~77.1% |
| 48 | 69.7% | 59.3~77.8% |
표본을 늘리면 평균은 올랐지만 32개 이후에는 거의 멈췄다. 48개를 학습해도 분할에 따라 정확도가 59.3%에서 77.8%까지 흔들렸다. 이 데이터와 이 모델로는 Jev를 대체할 전환점이 나오지 않았다.
원인은 두 가지를 나눠 봐야 한다. 첫째, 데이터가 75편뿐이다. 둘째, 문자 빈도만 보는 Naive Bayes는 제목과 요약의 의미를 충분히 일반화하지 못한다. 더 강한 임베딩이나 작은 언어 모델을 미세조정하면 결과가 달라질 수 있다. 그러나 그 시점부터 학습과 서빙 비용도 함께 생긴다.
이 실험이 말해 주는 범위는 좁다. 수십 개의 라벨과 아주 단순한 로컬 분류기만으로는 범용 의미 판단 API를 곧바로 대체하지 못했다. 전용 모델 전환을 계획할 때 “라벨이 조금 쌓였다”와 “보류 세트에서 운영 기준을 넘었다”를 구분해야 한다.
임계값은 정확도보다 운영 방식을 바꾼다
검토 후 라벨에서 Jev 임계값을 0.2부터 0.8까지 바꿨다. 사후 검토 편향이 있는 데이터이므로 절대 성능보다 거짓 양성과 거짓 음성이 어떻게 바뀌는지만 봐야 한다.
| 임계값 | 정확도 | Precision | Recall | FP | FN |
|---|---|---|---|---|---|
| 0.3 | 88.0% | 87.2% | 89.5% | 5 | 4 |
| 0.4 | 90.7% | 94.3% | 86.8% | 2 | 5 |
| 0.5 | 90.7% | 97.0% | 84.2% | 1 | 6 |
| 0.7 | 85.3% | 100% | 71.1% | 0 | 11 |
자동 태그 제안이라면 거짓 양성 한두 건은 사람이 쉽게 지울 수 있으므로 recall이 높은 0.3이 나을 수 있다. 규정 위반 탐지처럼 잘못 붙인 라벨의 비용이 크다면 0.7에서 거짓 양성을 없애고 많은 항목을 미분류로 남기는 편이 맞을 수 있다.
같은 모델과 데이터에서도 임계값은 “최고 정확도” 하나로 정해지지 않는다. 놓친 항목과 잘못 처리한 항목의 비용이 다르기 때문이다.
부트스트랩에는 세 개의 데이터셋이 필요하다
이번 실험을 다시 설계한다면 데이터를 하나의 표로 관리하지 않는다.
1. 기준 정의용 세트
경계 사례를 놓고 사람이 분류 규칙을 합의하는 데 쓴다. 모델을 평가하지 않는다. 컨텍스트 엔지니어링은 포함하지만 일반 RAG 인프라는 제외한다처럼 애매한 경계를 문장으로 고정한다.
2. 학습용 세트
Jev가 먼저 라벨을 붙일 수 있다. 사람은 무작위 표본, 낮은 확률, 모델 간 불일치, 고위험 사례를 섞어 검토한다. Jev와 다른 사례만 검토하면 이번 실험과 같은 선택 편향이 생긴다.
3. 독립 보류 세트
모델 출력을 보지 않은 사람이 먼저 라벨을 붙인다. 질문 문구와 임계값, 로컬 모델을 고치는 동안 열어 보지 않는다. Jev에서 로컬 모델로 전환할지는 이 세트에서 결정한다.
가능하면 라벨러를 두 명 이상 두고, 불일치율도 기록해야 한다. 사람끼리 합의하지 못하는 항목에서 모델 하나의 정확도를 소수점으로 비교해도 의미가 작다.
Jev를 제거하는 조건
전용 모델은 Jev보다 점수가 조금 높은 순간이 아니라 전체 운영비가 낮아지는 순간에 넘겨받아야 한다.
전용 모델의 총비용
= 라벨 검수 + 학습 + 서빙 + 재학습 + 오류 처리
Jev의 총비용
= API 호출 + 사람 검토 + 외부 전송 제약 + 오류 처리
같은 보류 세트에서 다음 조건을 함께 본다.
- 고위험 미탐이 허용 범위 안인가
- 사람 검토량이 실제로 줄었는가
- 호출량이 늘어도 로컬 서빙 비용이 낮은가
- 새 주제나 표현이 들어왔을 때 성능 저하를 감지할 수 있는가
- 모델 둘이 불일치할 때 어느 쪽을 사람에게 보낼지 정했는가
이번에는 전환하지 않는 것이 맞다. 로컬 모델은 학습 데이터 48개에서 평균 69.7%였고 변동도 컸다. Jev는 즉시 더 나은 의미 분류를 제공했지만, 그 정확도를 독립적으로 확정할 보류 세트가 없다. 다음 데이터는 무작위로 사람에게 먼저 라벨을 받아야 한다.
정리
Jev로 도메인 데이터를 만들고 전용 모델로 옮기는 경로는 가능하다. 그러나 첫 병목은 학습 코드가 아니었다. 무엇을 양성으로 볼지 정한 기준과 과거 태그가 달랐고, 모델의 출력을 본 뒤 정답을 고치자 평가가 같은 모델에 유리해졌다.
범용 모델은 라벨이 없는 시기에 후보를 빠르게 만든다. 사람은 무작위 표본과 불일치를 함께 검토하고, 독립 보류 세트는 따로 잠가야 한다. 로컬 모델은 그 보류 세트에서 비용, 오류, 사람 개입을 모두 줄였을 때만 넘겨받는다.
이 실험에서는 그 시점에 도달하지 못했다. 대신 전환 전에 가장 먼저 만들어야 할 것이 분류기가 아니라 모델의 답을 보지 않고 만든 정답표라는 점을 확인했다.