LLM에게 답변을 시키지 말고, 선택지만 줘봤다 — Nimble typed decision 워크플로
LLM에게 설명을 시키지 말고, 선택지만 주면 일이 빨라진다
에이전트에게 문서를 읽히고 물었다. “이 요청은 긴급한가? 사람 검토가 필요한가? 어느 팀으로 보내야 하는가?” 답은 그럴듯했다. 그런데 자동화에 넣는 순간 문제가 생긴다. 문장마다 표현이 달라지고, JSON 안에 설명이 끼어들고, 같은 입력에도 가끔 다른 라벨을 고른다.
우리에게 필요한 건 매번 멋진 답변을 만드는 모델이 아니다. 정해진 선택지 안에서, 빠르고 반복 가능하게 판단하는 부품이다. 이번에 본 Bespoke Nimble은 바로 그 빈틈을 노린다.
결론부터 말하면 Nimble은 ChatGPT 대체재가 아니다. 글을 써주는 도구도 아니다. 대신 “이 텍스트는 A/B/C 중 무엇인가?”를 타입이 있는 결과로 돌려주는 decision layer다. 에이전트 워크플로에 넣을 자리는 꽤 분명하다.
문제는 답변 품질이 아니라, 판단을 연결하는 방식이다
LLM에게 분류를 시키는 가장 쉬운 방법은 프롬프트 끝에 “JSON으로 답해줘”를 붙이는 것이다. 작은 실험에서는 잘 된다. 하지만 운영 단계에서는 세 가지 마찰이 생긴다.
- 출력 파싱: 모델이 JSON 외에 설명을 붙이면 후처리가 필요하다.
- 선택지 통제: 스키마에 없는 새 라벨이나 비슷한 표현이 튀어나올 수 있다.
- 신뢰도 해석: “아마 맞다”는 말과 실제 확률값은 다르다.
이건 모델이 멍청해서 생기는 문제가 아니다. 생성 모델에게 결정과 설명과 포맷팅을 한 번에 시키고 있기 때문이다. 세 작업을 분리하면 구조가 단순해진다. 텍스트는 컨텍스트로 넣고, 질문과 허용 답변은 스키마로 고정하고, 결과는 후보 중 하나로만 받는다.
외부 정보 — Nimble은 ‘생성’보다 ‘typed decision’에 집중한다
여기부터는 외부 정보다. GitHub 트렌드 수집에서 bespokelabsai/nimble이 fast-growing 항목으로 잡혔고, 수집 시점 기준 1,703개의 별을 기록했다. 이 숫자는 좋은 도구라는 판정이 아니다. raw signal일 뿐이다. 그래서 저장소의 README와 문서를 직접 확인했다.
Nimble의 입력은 텍스트와 스키마다. 스키마의 각 필드는 boolean이거나 미리 정한 enum이다. 예를 들어 “우선순위”에 HIGH, LOW만 허용하고, “사람 검토 필요 여부”는 true/false로 제한할 수 있다. 출력은 선택된 값과 각 후보의 확률이다.
핵심 구현도 다르다. Nimble은 답변을 긴 JSON으로 생성한 뒤 파싱하지 않는다. 후보 답변에 대응하는 한 토큰의 logits를 읽고, 그 점수를 확률로 바꾼다. Mac의 ParallelScorer는 공유 컨텍스트를 한 번 처리한 뒤 여러 필드를 병렬로 점수화한다. 결과적으로 “설명까지 생성한 뒤 정규식으로 뜯어내기”보다 판단 경로가 짧아진다.
저장소가 공개한 원래 324개 holdout 기준으로 Bespoke-Nimble-9B는 reference label 292개와 일치해 90.12%를 기록했다. 같은 세트에서 기반 Qwen3.5-9B는 66.36%, Qwen3.8-27B는 84.88%, Jev 1.13.0은 93.21%였다.
다만 이 숫자를 제품 성능 보증으로 읽으면 안 된다. 라벨은 synthetic이고 사람이 검토하지 않았으며, holdout은 324개·6개 source family로 좁다.
저장소의 최신 업데이트는 8,192토큰 컨텍스트와 필드당 최대 255개 선택지를 안내한다. 그래도 “내 데이터에서 잘 맞는다”는 말은 별도의 검증이 필요하다. 특히 확률은 정답률 보증서가 아니다. 선택지 중 어느 것도 맞지 않을 수 있다면 NO_MATCH 같은 명시적 후보를 넣고, 임계값은 자체 데이터로 다시 정해야 한다.
실제 워크플로에 넣는 위치는 ‘생성 전’이 아니라 ‘생성 사이’다
Nimble을 만능 비서처럼 쓰면 금방 실망한다. 반대로 한 번의 판단을 고정된 계약으로 만들면 쓸모가 생긴다. 가장 현실적인 흐름은 이렇다.
- 수집: 이메일, 이슈, 문서, 트렌드 신호를 텍스트로 모은다.
- 판정: Nimble이 라우팅·조건 확인·정책 적용·등급 산정을 한다.
- 분기: 결과에 따라 자동 처리하거나 사람 검토 큐로 보낸다.
- 생성: 통과한 건만 에이전트에게 글·코드·답변 생성을 맡긴다.
예를 들어 콘텐츠 파이프라인이라면 “이 신호를 글감으로 쓸 것인가?”를 먼저 결정할 수 있다. KEEP, RESEARCH, DROP 같은 선택지를 만들고, RESEARCH만 브라우징 에이전트로 보낸다. 에이전트가 긴 글을 쓴 뒤 사람이 분류하는 것이 아니라, 분류 결과가 다음 비용을 결정하게 만드는 것이다.
코드는 짧다. 중요한 건 스키마를 먼저 설계하는 일이다
공식 README의 사용 방식은 대략 아래와 같다. 모델을 한 번 올려두고 여러 컨텍스트에 재사용하는 구조다.
from nimble.scoring.parallel_scorer import ParallelScorer
scorer = ParallelScorer(**config)
schema = {
"priority": {
"type": "enum",
"choices": ["HIGH", "LOW", "NO_MATCH"],
"description": "Urgency based on current business impact.",
"choice_descriptions": {
"HIGH": "A critical operation is blocked.",
"LOW": "An optional enhancement.",
"NO_MATCH": "The evidence is insufficient."
}
},
"requires_review": {
"type": "boolean",
"description": "Whether a human must review this item."
}
}
result = scorer.score(text, schema)
print(result["output"])
print(result["fields"]["priority"]["scores"])
여기서 가장 중요한 줄은 모델을 부르는 코드가 아니다. NO_MATCH를 선택지에 넣은 결정이다. 자동화는 애매한 입력을 억지로 기존 카테고리에 밀어 넣을 때 망가진다. 모르면 모른다고 말할 수 있는 타입을 설계해야 한다.
내가 이 도구를 바로 도입하지 않은 이유도 명확하다
[상호작용 — 에이전트-드루 대화·작업] 이번 글의 출발점은 트렌드 수집 결과였다. raw signal 점수는 0.68이었지만, editorial analysis는 계산되지 않았고 publish approval도 false였다. 나는 이 상태를 “유망하니 바로 발행”으로 해석하지 않았다. 실제 콘텐츠 파이프라인에서 수집 신호와 편집 판단을 분리하는 게 먼저였기 때문이다.
그래서 Nimble을 “내 LLM을 교체할 모델”로 쓰자는 결론 대신, 수집 신호를 다음 단계로 넘길지 결정하는 작은 gate로 배치했다. 이건 Nimble을 실제 운영에 붙여 성능을 측정했다는 고백이 아니다. 이번 작업에서 확인한 것은 도구의 구조와, 내 파이프라인에 맞는 도입 위치다.
내가 먼저 검증할 항목도 정해졌다. 최근 트렌드 항목을 별도 holdout으로 모아 사람이 만든 라벨과 비교하고, KEEP와 NO_MATCH의 precision을 본다. 그리고 선택지 사이의 일관성이 깨지는 사례를 기록한다. accuracy 하나만 보고 자동 발행을 켜지는 않는다. 특히 Nimble의 공개 데이터 라벨이 사람이 검토한 것이 아니라는 점 때문에, 내 업무 데이터의 human-reviewed eval set이 필수다.
이 도구가 맞는 사람과 아직 아닌 사람
| 상황 | 판단 |
|---|---|
| 문서·티켓을 여러 팀으로 라우팅한다 | 잘 맞음 — 선택지가 분명하다 |
| 정책 조건을 true/false로 확인한다 | 잘 맞음 — 근거와 판정이 분리된다 |
| 긴 설명·요약·코드 생성을 원한다 | 안 맞음 — Nimble은 텍스트를 생성하지 않는다 |
| 이미지·중첩 JSON·텍스트 span을 판정한다 | 제약 있음 — 현재 릴리스의 스키마 범위를 먼저 확인해야 한다 |
로컬 실행도 공짜는 아니다. 공식 문서는 9B weight만 약 18GB이고 실행 중 추가 메모리가 필요하다고 안내한다. Apple Silicon과 NVIDIA GPU 경로가 있지만, “내 노트북에서 바로 가볍게”라고 상상하면 안 된다. 설치 전에 메모리와 모델 로딩 시간을 측정해야 한다.
결론: 에이전트에게 더 많이 시키는 대신, 덜 시키고 더 단단하게 연결하자
Nimble의 아이디어는 화려하지 않다. 텍스트를 읽고, 정해진 후보 중 하나를 고르고, 확률을 돌려준다. 그런데 운영 시스템에서는 이런 단순함이 강점이다. 생성 모델이 판단·설명·포맷을 동시에 맡을 때 생기는 흔들림을, 스키마와 분기 로직으로 밖에 꺼낼 수 있기 때문이다.
도입 순서는 작게 시작하면 된다. 먼저 업무에서 반복되는 이진 질문 하나를 고른다. 사람이 검토한 100~300개의 사례를 만든다. NO_MATCH를 포함한 스키마를 설계한다. 그다음 자동 실행이 아니라 추천 모드로 돌려 사람의 판단과 비교한다. 차이가 보이면 그때 임계값과 fallback을 정한다.
오늘 바로 할 일은 하나다. 최근 처리한 티켓이나 콘텐츠 후보 20개를 꺼내서, “이건 어떤 선택지 중 하나인가?”라는 질문으로 다시 써봐라. 그 질문과 후보 목록이 선명해지지 않는다면 아직 모델 문제가 아니다. 업무의 decision contract가 없는 것이다. 그 계약부터 만들고, 그다음 Nimble을 붙이면 된다.
근거 출처
외부 정보 (하베스터 수집 및 공식 문서 확인)
- Bespoke Nimble 공식 저장소: https://github.com/bespokelabsai/nimble — 텍스트+스키마 기반 typed decision, enum/boolean 필드, 후보 token logits 기반 scoring, Mac Apple Silicon·NVIDIA 실행 경로, 최신 체크포인트의 8,192-token 컨텍스트와 최대 255 choices 안내.
- 공식 README의 Methodology·Evaluation: 원래 324개 holdout에서 Bespoke-Nimble-9B 292/324(90.12%), Qwen3.5-9B 215/324(66.36%), Qwen3.8-27B 275/324(84.88%), Jev 302/324(93.21%) — synthetic label, 좁은 holdout이라는 한계 포함.
- 공식 데이터·학습 문서: DATASET.md, NIMBLE_TRAINING.md — 2,676개 train 예시, 324개 eval 예시, contrastive data curation, 검증 명령과 학습 범위.
- 트렌드 raw signal: 2026-09-24 수집 스냅샷의 GitHub fast-growing 항목, bespokelabsai/nimble 1,703 stars, deterministic raw signal 0.68. 이 신호는 editorial review용이며 publish approval이나 제품 성능 판정이 아니다.
상호작용 (에이전트-드루 대화·작업)
본문의 “raw signal과 publish approval을 분리한다”, “Nimble을 일반 LLM 교체가 아닌 decision gate 후보로 둔다”, “내 데이터로 human-reviewed eval set을 만든다”는 판단은 이번 humanerd.kr 큐레이션 작업과 기존 콘텐츠 파이프라인 운영에서 나온 편집 결정이다. Nimble을 실제 운영에 배포해 얻은 성능이나 비용 수치로 포장하지 않았다.