Skip to content
게으른 엔지니어의 기술 블로그
Go back

OpenAI Decisions API는 빨랐지만, 내 병합 기준에는 맞지 않았다

Read in English →

판단 전용 모델로 바꿀 수 있을까 · 2/4편

공개 전인 Obsidian 플러그인을 하나 만들고 있다. 원문 자료를 넣으면 LLM이 읽고 개념별 노트로 정리해주는 도구다. 자료가 쌓이다 보면 같은 대상을 다룬 노트가 두 개 생기기도 하는데, 그때마다 플러그인은 두 노트를 OpenAI API(gpt-6-luna)에 보내 “같은 개념이니 합칠까, 다른 개념이니 따로 둘까”를 묻는다. 답 하나를 받으려고 LLM 호출 전체를 쓰는 셈이라, 이런 판단만 전담하는 모델로 바꿀 수 있는지 계속 보고 있다.

지난 글에서는 판단 전용 모델 Jev의 오픈소스 재현판인 Laya를 시험했다. 이번에는 그 뒤에 계정이 열린 TypeSafe의 Jev와, 10월 6일 공개 베타로 나온 OpenAI Decisions API를 같은 문제에 붙였다. 결론부터 말하면 Decisions API는 셋 중 가장 빨랐고 매번 똑같은 답을 냈다. 하지만 내 플러그인이 실제로 쓰는 판단 기준에서는 틀린 답에도 높은 확신을 붙였다. 도구가 나쁘다기보다, 내가 던진 질문의 모양이 이 도구와 맞지 않았다.

쉬운 문제에서는 Jev와 gpt-6-luna 둘 다 만점

시험 데이터는 두 묶음이다. 하나는 지난 글의 Laya 시험에 쓴 23쌍으로, 같은 기사에서 두 번 만들어진 진짜 중복 17쌍과 제목만 같은 합성 쌍 6개다. 다른 하나는 플러그인이 실제로 중복 후보로 검사했던 노트 쌍 40개다(한국어 28쌍, 영어 12쌍). 40쌍은 두 노트를 직접 읽고 정답을 정했는데, 같은 개념이 15쌍, 다른 개념이 18쌍, 판단이 갈리는 애매한 쌍이 7쌍이었다.

10월 초에 Jev와 gpt-6-luna를 이 데이터에 돌렸을 때는 둘 다 23쌍 전부, 그리고 정답이 분명한 33쌍 전부를 맞혔다. 차이는 속도와 확신이었다. Jev는 한 번 판단에 0.27초 안팎, gpt-6-luna는 1.3초 안팎이 걸렸다. Jev는 자신 없는 판단에 낮은 확신을 붙이는 편이어서, 확신 0.8 이상인 답만 따르면 33쌍 중 29쌍을 오답 없이 처리했다. 나머지 4쌍만 LLM에 넘기면 되는 구조다.

OpenAI Decisions API — 0.13초, 매번 똑같은 답

Decisions API는 LLM처럼 문장을 생성하지 않고, 정해진 질문에 정해진 형식으로만 답하는 OpenAI의 새 엔드포인트다. 참·거짓 확률(predicate), 선택지 중 하나(choice), 단계 점수(score) 세 가지로 답하고, 모델은 gpt-6-luna 하나뿐이다. 공지에 따르면 Responses API로 gpt-6-luna를 부를 때보다 최대 10배 빠르고, 요금은 입력 토큰 100만 개당 0.10달러이며 출력 토큰은 과금하지 않는다. Jev와 같은 종류의 “판단 전용” 도구를 OpenAI가 직접 낸 셈이다.

같은 질문과 같은 선택지 설명으로 돌려보니 한 번 판단에 0.13초 안팎이 걸렸다. Jev의 절반, 일반 호출의 10분의 1 수준이다. 같은 쌍을 세 번씩 물었는데 답뿐 아니라 확신 값까지 세 번 모두 똑같았다. 쉬운 23쌍은 전부 맞혔다.

선택지 순서만 바꿨는데 정답이 16/33에서 32/33으로 (선택지 순서 편향)

40쌍에서 이상한 결과가 나왔다. “같다 / 다르다” 순서로 선택지를 주자 40쌍 중 39쌍을 “같다”로 답했고, 정답이 분명한 33쌍 중 16쌍만 맞혔다. 선택지 순서만 “다르다 / 같다”로 바꿔 다시 물으니 32쌍을 맞혔다. “병합 / 따로” 질문도 31쌍에서 33쌍이 됐다. 정답이 “같다”인 쌍은 어느 순서로 물어도 다 맞혔으니, 병합 쪽 선택지가 앞에 오면 그쪽으로 끌려가는 쏠림이었다.

이런 쏠림은 Decisions API만의 문제가 아니다. TypeSafe도 Jev 1.13의 약점을 정리한 문서에 “the order of a Choice’s options can affect the answer, and jev-1.13 leans toward the option that comes first”라고 적어 두고, 선택지 순서를 바꿔 답이 그대로인지 확인하라고 권한다. 대응은 간단하다. 보수적인 선택지(“따로”)를 앞에 두거나, 두 순서로 다 물어서 답이 같을 때만 따르면 된다. Decisions API는 빨라서 두 번 물어도 Jev 한 번보다 빠르다.

그런데 내가 묻던 질문은 플러그인의 질문이 아니었다 (LLM 벤치마크)

애매한 쌍들의 정답을 다시 정하다가 더 근본적인 문제를 발견했다. 플러그인은 “같은 개념인가”를 묻는 프롬프트에 꽤 구체적인 규칙을 넣어 두고 있었다. 출처가 서로 다른 두 노트가 같은 일반 주제(예: 심리적 안전감)를 각자 다른 사례로 설명하면 다른 개념으로 본다. 같은 사건을 다룬 서로 다른 기사에서 나왔다면 같은 개념이다. 한쪽이 다른 쪽의 하위 주제면 같은 개념이 아니다. 그리고 애매하면 따로 둔다. 예전에 병합 판단이 엇갈린 사례들을 정리하면서 넣은 규칙이다.

그동안 세 모델에 던진 질문에는 이 규칙이 하나도 들어 있지 않았다. “같은 개념인가”를 상식선에서 물었을 뿐이다. 앞의 숫자들은 “일반적인 중복 판단”의 성적이지, 플러그인이 실제로 하는 판단의 성적이 아니었다. 그래서 애매한 쌍들의 정답을 이 규칙으로 다시 정하고, 플러그인이 보내는 프롬프트를 글자 그대로, 같은 메시지 형식으로 세 모델에 다시 보냈다. gpt-6-luna는 실제로 쓰는 설정대로 reasoning effort를 high로 맞췄다.

플러그인 프롬프트 그대로 다시 — 틀린 답에 확신 0.94 (confidence 캘리브레이션)

40쌍을 세 번씩 돌린 결과다.

모델정답한 번 판단 시간
gpt-6-luna (지금 플러그인이 쓰는 방식)120번 중 106번약 2.4초
Jev120번 중 107번약 0.3초
Decisions API, “다르다” 먼저40번 중 33번약 0.15초
Decisions API, “같다” 먼저40번 중 37번약 0.15초

정답 수만 보면 큰 차이가 없다. 갈린 건 틀릴 때의 모습이다. Jev는 틀린 답 대부분에 0.1~0.5 정도의 낮은 확신을 붙였다. 확신 0.9 이상인 답만 따르면, 정답 자체가 의심스러운 세 쌍을 뺀 37쌍 중 22쌍을 오답 없이 처리하고, 나머지는 LLM에 넘기면 된다. 반면 Decisions API는 하위 주제 관계인 쌍 두 개를 “같다”로 틀리면서 확신 0.94, 0.96을 붙였다. 확신 값으로 걸러서 자신 없는 답만 LLM에 넘기는 방식이 이 조건에서는 통하지 않는다. 앞에서 본 순서 쏠림도 이번에는 방향이 일정하지 않았다.

덤으로 찾은 플러그인 버그 — 같은 제품의 노트를 합치지 못했다 (중복 노트 병합)

결과를 보다가 눈에 띄는 쌍 두 개가 있었다. “Claude Code”와 “클로드 코드”, “스페이스X”와 “스페이스엑스”다. 이름만 다르게 적힌 같은 제품, 같은 회사인데 gpt-6-luna와 Jev는 두 쌍 모두 세 번 다 “다른 개념”이라고 답했다. Decisions API도 Claude Code 쌍에는 확신 1.0으로 “다르다”고 답했다. gpt-6-luna에게 이유까지 받아 보니 이랬다.

두 노트는 같은 제품인 Claude Code를 다루지만, A는 Uber의 도입과 예산 소진 사례를, B는 … 개인 PC 데이터 활용 사례를 설명합니다. 구체적 사건이나 사례의 사실이 겹치지 않으므로 별개의 개념으로 판단합니다.

모델이 틀린 게 아니라 규칙이 잘못 적용된 것이었다. “같은 구체적 사건을 다루는가”라는 기준은 심리적 안전감 같은 일반 주제를 위한 것이다(이 규칙이 생긴 과정은 이 글에 적었다). 그런데 적용 범위가 적혀 있지 않아 제품이나 회사 노트에도 그대로 쓰였다. 같은 제품은 어떤 기사에서 나왔든 같은 대상이다. 이 Claude Code 쌍은 예전에도 한 번 합쳐지지 않던 쌍이다. 그때는 제품·회사 노트를 아예 비교 대상에서 빼 두던 범위 설정이 원인이었고, 그걸 고쳐서 이제 후보로는 올라오는데 이번에는 판단 단계에서 막힌 것이다.

규칙에 “같은 제품·회사·인물·작품 같은 고유한 대상은 출처나 다루는 사건이 달라도 같은 대상”이라는 예외를 넣어 gpt-6-luna로 다시 돌려봤다. 처음 넣은 문구는 두 쌍을 고쳤지만, 같은 기사에서 나온 상위·하위 주제 쌍 하나를 “같다”로 바꾸는 부작용을 냈다. 예외 문단을 규칙 맨 앞에 두는 바람에 “구체적 사실이 겹치는가”가 앞에 서고, 바로 아래의 “하위 주제는 같은 개념이 아니다”가 묻힌 것으로 보였다. 예외를 규칙 뒤의 별도 항목으로 옮기고 “하위 주제 관계는 여전히 다른 개념”이라고 덧붙이자, 두 쌍은 고쳐지고 부작용은 사라졌다. 정답은 120번 중 106번에서 111번으로 올랐다. 이 수정은 아직 시험 단계이고 플러그인에는 넣지 않았다.

Decisions API는 나쁜 도구일까 — 질문 하나에 판단을 여러 개 담았다 (프롬프트 설계)

이 결과만 보고 Decisions API가 쓸모없다고 하기는 어렵다. 질문 모양을 돌아보면 이유가 보인다. 내가 보낸 건 “같은 개념인가”라는 선택지 질문 하나였지만, 그 지시문 안에는 판단이 여러 개 들어 있었다. 같은 고유한 대상인가, 한쪽이 다른 쪽의 하위 주제인가, 구체적 사실이 겹치는가, 애매하면 어느 쪽인가. gpt-6-luna를 일반 호출로 부르면 reasoning으로 이 조건들을 하나씩 따져 볼 수 있다. 반면 Decisions API 응답의 사용량 기록에는 reasoning 토큰이 0으로 찍혀 있었다. 조건을 차례로 따지는 과정 없이 한 번에 답을 낸다는 뜻이다.

두 회사 문서도 같은 방향을 말한다. OpenAI는 Decisions API 가이드에 “Separate different concerns into different questions”라고 적었고, TypeSafe는 Jev 문서에서 피해야 할 패턴으로 “Hiding several judgments inside one question”을 꼽는다. 판단과 상관없는 내용이 입력에 많으면 정확도가 떨어진다는 경고도 있다. 내 입력에는 노트 본문 전체에 메타데이터와 관련 링크 목록까지 들어 있었다.

그러니 이번 결과는 “Decisions API는 판단을 못 한다”가 아니라 “조건 여러 개를 한 질문에 담은 지금의 기준에는 맞지 않는다”에 가깝다. 해볼 만한 방향은 분명하다. 판단을 “같은 고유한 대상을 다루는가”, “한쪽이 다른 쪽의 하위 주제인가”, “구체적 사실이 겹치는가” 같은 참·거짓 질문 여러 개로 나누고, 그 답을 조합하는 건 코드가 맡는다. 입력도 판단에 필요한 본문만 남기고 줄인다.

Jev도 같다. Jev는 고객 데이터로 파인튜닝할 수 없고, API 문서에서도 temperature 같은 조절 값은 찾지 못했다. 손댈 수 있는 건 지시문과 선택지 설명, 그리고 입력을 어떻게 나눠 담느냐뿐이다. 그래서 Jev를 더 다듬을 방법도 결국 같은 방향이다. 질문을 나누고, 입력을 줄이고, 선택지 순서를 바꿔 확인하는 것이다. 이 방향이 실제로 효과가 있는지는 아직 재보지 않았다. 다음 실험거리다.

남는 생각

이번에 가장 크게 배운 건 벤치마크는 내가 던진 질문의 성적만 알려준다는 점이다. 처음 몇 번의 실험에서 세 모델은 모두 훌륭했다. 그런데 그건 상식적인 “같은 개념인가”에 대한 성적이었고, 플러그인이 실제로 묻는 질문을 그대로 보내자 그림이 달라졌다. 그 과정에서 플러그인 규칙 자체의 구멍까지 드러났다.

그리고 “맞지 않는다”와 “나쁘다”는 다르다. Decisions API는 빠르고, 같은 질문에 늘 같은 답을 내고, 입력 토큰만 과금한다. 판단이 하나로 깔끔하게 떨어지는 문제라면 지금도 좋은 선택지다. 내 문제에 맞추려면 질문을 그 도구의 모양에 맞게 다시 짜야 한다. 공개 베타인 만큼 정식 출시 뒤에 다시 볼 생각이다.


Share this post:

판단 전용 모델로 바꿀 수 있을까

  1. 1. 틀렸는데, 확신은 0.9였다
  2. 2. OpenAI Decisions API는 빨랐지만, 내 병합 기준에는 맞지 않았다
  3. 3. Decisions API는 질문을 셋으로 나누자 Luna만큼 맞혔다
  4. 4. Decisions API와 Jev로 끊긴 문장을 판정하자, 오탐이 네 배였다