AI 입문가이드
20개 사례로 프롬프트 테스트하기: Python에서의 정확 일치 채점
20개 사례 테스트 세트를 만들고, 짧은 Python 스크립트로 정확 일치 방식으로 프롬프트를 채점하고, 프롬프트 변경이 실제로 도움이 되었는지 확인하세요.

이 페이지의 내용
프롬프트가 시도해 본 두 메시지에서 잘 동작했습니다. 그렇다고 해서 잘 동작한다고 할 수 있을까요? 아직 아닙니다. 정답을 아는 실제 메시지 20개에 대해 실행하고, 몇 개를 맞히는지 세고, 틀린 것들을 읽어 보세요. 짧은 Python 스크립트가 개수를 세고, 프롬프트를 바꿨을 때 같은 스크립트가 그 변경이 도움이 되었는지 알려 주므로 감에 의존하지 않아도 됩니다.
성공 기준 정의와 평가 구축에 관한 Anthropic 문서(2026년 11월 7일 확인)는 이를 나름의 표현으로 설명합니다. 테스트를 여러분의 작업에 맞게 구체적으로 만들고, 까다로운 사례를 포함하며, 손으로 채점한 몇 개보다 자동으로 채점되는 많은 질문을 선호하라고 합니다. 아래는 오늘 바로 실행할 수 있는 그 방법의 가장 작은 버전입니다.

테스트 세트 만들기: 메시지 20개와 기대하는 답#
고객 메시지를 긍정, 부정, 혼합의 세 무더기로 분류한다고 해 봅시다. cases.csv라는 파일을 열고 실제로 받을 수 있는 메시지 20개를 적으세요. 각 메시지에는 여러분이 붙일 레이블을 함께 적습니다. 무엇이든 실행하기 전에 레이블을 먼저 적으세요. 모델의 답을 "정답"으로 복사하면 테스트는 모델과 의견이 일치할 수밖에 없습니다.
text,label
"Arrived a day early and works perfectly. Thank you!",positive
"The charger stopped working after two days.",negative
"Great screen, but the battery barely lasts until lunch.",mixed
"Support answered in five minutes and fixed it.",positive
"I waited three weeks and nobody replied.",negative
"Oh great, another update that deletes my settings.",negative
"Nice design. Pity about the price.",mixed
"Exactly what I ordered.",positive
"The box was crushed, but the headphones inside are fine and sound great.",mixed
"Refund took 10 days. Never again.",negative
"Love it!!",positive
"Cheaply made, but honestly it does the job for the price.",mixed
"Worst purchase of the year.",negative
"Five stars. Would buy again.",positive
"Fast delivery, wrong colour.",mixed
"It's fine. Not amazing, not terrible.",mixed
"Zero issues in six months of daily use.",positive
"The app crashes every time I open the camera.",negative
"Thanks for nothing.",negative
"Setup was a pain, but once it ran, it's been rock solid.",mixed구성을 보세요: 긍정 6개, 부정 7개, 혼합 7개. 빈정대는 문장("Oh great, another update…", "Thanks for nothing.")과 경계선에 있는 문장("It's fine. Not amazing, not terrible.")은 의도적으로 넣었습니다. 뻔한 메시지로만 구성된 세트는 100% 점수를 받고 아무것도 가르쳐 주지 않습니다. 실제 메시지는 여러분의 받은편지함, 티켓, 채팅 내보내기에서 가져오세요. 엣지 케이스는 이미 성가시다고 알고 있는 것들입니다.
왜 20개일까요? 이는 시작 크기일 뿐 문서에서 나온 숫자가 아닙니다(문서의 예시는 트윗 1,000개를 사용합니다). 20개는 30분 안에 손으로 작성할 수 있을 만큼 작고, 운 좋은 답 하나가 점수를 결정하지 않을 만큼 큽니다.
스크립트: 각 사례를 보내고, 비교하고, 틀린 것을 출력하기#
계획은 네 단계이고, 코드는 이를 한 줄씩 따릅니다.
순서대로 배열하기
평가 루프를 순서대로 정리하기
항목을 드래그하거나 화살표를 사용하세요
- CSV에서 20개 사례 불러오기
- 각 메시지를 여러분의 프롬프트와 함께 모델로 보내기
- 답을 여러분의 레이블과 비교하기
- 정확도와 실패한 사례 출력하기
이 루프는 첫 모델 호출 전에 레이블이 존재할 때만 동작하며, 실패 사례가 마지막에 오는 이유는 그것이 여러분이 읽고 조치할 대상이기 때문입니다.
SDK는 pip install openai로 설치하고 키는 CHEAPTOKENS_라는 환경 변수에 보관하세요. OpenAI 호환 API는 모두 같은 방식으로 동작합니다. 여기서는 스크립트가 CheapTokens와 GLM-5.3-Flash를 가리킵니다(설정 세부 사항은 문서에 있습니다).
import csv
import os
from openai import OpenAI
client = OpenAI(
base_url='https://api.cheaptokens.dev/v1',
api_key=os.environ['CHEAPTOKENS_API_KEY'],
)
MODEL = 'zai-org/GLM-5.3-Flash'
PROMPT = (
'Classify the customer message as positive, negative or mixed. '
'Answer with one word only.'
)
def ask(text):
r = client.chat.completions.create(
model=MODEL,
temperature=0,
max_tokens=100,
messages=[
{'role': 'system', 'content': PROMPT},
{'role': 'user', 'content': text},
],
)
return r.choices[0].message.content or ''
with open('cases.csv', newline='', encoding='utf-8') as f:
cases = list(csv.DictReader(f))
correct, failed = 0, []
for case in cases:
got = ask(case['text'])
ok = got.strip().strip('.').lower() == case['label']
correct += ok
if not ok:
failed.append((case['text'], case['label'], got.strip()))
print(f'Accuracy: {correct}/{len(cases)} = {correct / len(cases):.0%}')
for text, want, got in failed:
print(f'- {text!r}: expected {want}, got {got!r}')세 가지 세부 사항은 다시 볼 가치가 있습니다.
- **
temperature=0**는 답을 최대한 일정하게 유지하므로, 점수 변화는 주사위가 아니라 여러분의 프롬프트에서 비롯됩니다. - **
max_tokens=100**는 한 단어 레이블에 필요한 양보다 훨씬 많습니다. 답이 비어 있거나 잘려서 돌아오면finish_reason를 확인하세요. finish_reason "length" 가이드에 무엇을 올려야 하는지 나와 있습니다. - 채점 줄은 문서의 레시피로,
strip().lower()를 정답과 비교하며, 한 가지를 더합니다. 끝에 붙은 마침표도 제거하는데, "Negative."와 "negative"는 여러분에게 같은 답이기 때문입니다.
실행하면 무엇이 보일까요? 정확도 한 줄, 그다음 틀린 사례마다 한 줄입니다. 첫 실행이 이렇게 출력된다고 해 봅시다:
Accuracy: 14/20 = 70%
- 'Oh great, another update that deletes my settings.': expected negative, got 'positive'
- "It's fine. Not amazing, not terrible.": expected mixed, got 'positive'
…(여기 숫자는 출력 형태를 보여 주기 위한 가정이며, 여러분의 결과는 다를 것입니다.) 빈정거림과 경계선 표현은 짧은 프롬프트가 흔히 놓치는 메시지 유형입니다. 요점은 더 이상 추측하지 않는다는 것입니다. 목록이 생겼습니다.
한 가지만 바꾸고 다시 실행하기#
이제 유용한 부분입니다. 틀린 사례를 읽고, 원인을 하나 고르고, 프롬프트를 한 곳에서 바꾼 뒤 다시 실행하세요. 한 번에 하나씩 바꾸세요. 그렇지 않으면 어떤 수정이 점수를 움직였는지 알 수 없습니다.
비교하기
프롬프트 v1 → v2: 규칙 하나와 예시 두 개 추가
v1
Classify the customer message as positive, negative or mixed.
Answer with one word only.v2
Classify the customer message as positive, negative or mixed.
Sarcasm counts as negative. Praise plus a complaint is mixed.
Answer with one word only.
Message: Lovely colour, but it arrived with a scratch.
Answer: mixed
Message: Sure, thanks a lot. Now my order is lost.
Answer: negative두 예시는 지어낸 것이며 이는 의도적입니다. cases.csv의 메시지를 절대 프롬프트에 예시로 넣지 마세요. 그러면 모델이 여러분이 건네준 답으로 채점받게 되어 점수가 부풀려집니다. 이것이 퓨샷 기법이며, 테스트 세트가 그것이 효과가 있었는지 알려 줍니다. v1 프롬프트가 여전히 모호하다면, 측정하기 전에 좋은 프롬프트 작성법부터 시작하세요.
v2를 PROMPT에 붙여 넣고(삼중 따옴표는 여러 줄에 쓸 수 있습니다) 스크립트를 다시 실행하세요. Accuracy: 17/가 출력된다고 해 봅시다. 세 사례가 더 맞았으므로 v2가 더 나아 보입니다. 이를 얼마나 신뢰해야 할까요? 20개 사례 세트에서 각 사례는 5점의 가치가 있으므로 70% → 85%는 메시지 세 개입니다. 이는 좋은 힌트일 뿐 증거는 아닙니다. 점수가 떨어졌다면 똑같이 값진 것을 배웠고 더 나쁜 프롬프트를 배포하는 일을 피한 것입니다.
같은 세트, 다른 모델: 점수가 유지될까?#
같은 파일이 두 번째 질문에도 답합니다. 이 작업에 필요 이상으로 큰 모델에 비용을 지불하고 있는가? 한 줄을 바꾸고 다시 실행하세요:
MODEL = 'deepseek-ai/DeepSeek-V4-Flash-0731'20개 사례에서 정확도가 같다면, 리더보드가 아니라 여러분의 데이터로부터 이 작업에 대한 답을 얻은 것입니다. 떨어졌다면 무엇을 결정하기 전에 어떤 메시지가 깨졌는지 살펴보세요.
이 모든 것의 비용은 얼마일까요? 사례당 입력 토큰 약 150개(지시문과 메시지)와 한 단어 레이블에 출력 토큰 약 5개라고 가정해 봅시다. 20개 사례를 한 번 실행하는 데 입력 3,000개와 출력 100개이며, GLM-5.3-Flash에서 $0.000064에 해당합니다. 세트를 열 번 다시 실행하면 200회 요청입니다. 아래 표는 모든 모델에 대해 이 작업량을 보여 주며, 옆에 OpenRouter도 있습니다. 이 작업량에서 입력과 출력을 합쳐 계산하면 표의 모든 모델이 OpenRouter의 기준 가격보다 저렴합니다.
| 모델 | 입력 $/1M | 출력 $/1M | 요청당 | 200회 요청 | OpenRouter, 200회 요청 |
|---|---|---|---|---|---|
| GLM-5.3-Flash | $0.02 | $0.04 | $0.0000032 | $0.00064 | $0.0011 |
| DeepSeek-V4-Flash | $0.015 | $0.10 | $0.0000028 | $0.00055 | $0.0022 |
| MiniMax-M2.7 | $0.05 | $0.15 | $0.0000083 | $0.0017 | $0.0198 |
요청당 입력 150개 및 출력 5개 토큰입니다. 100만 토큰당 가격은 현재 기준이며 당사 요금제에 따라 함께 변경됩니다. OpenRouter 열은 동일한 작업량에 대한 참고 가격을 보여줍니다.
그중 두 개가 이 글에서 사용됩니다. GLM-5.3-Flash는 390K 컨텍스트와 답변당 최대 8,192 출력 토큰을 가지며, DeepSeek-V4-Flash는 380K 컨텍스트와 최대 32,768 출력 토큰, 하루 중 어느 시간에도 동일한 가격, 그리고 다른 모든 모델과 같은 잔액을 가집니다. 현재 가격은 가격 페이지에, 전체 목록은 모델에 있습니다.
정확 일치가 통하지 않는 곳#
정확 일치가 통하는 이유는 정답이 고정된 목록의 한 단어이기 때문입니다. 요약, 재작성, 설명처럼 개방형 출력에는 비교할 단일 문자열이 없습니다. 문서는 또 다른 경로인 모델에 의한 채점을 설명하며, 답을 작성한 모델과 다른 모델을 채점자로 사용할 것을 권장합니다. 그래도 정확 일치부터 시작하세요. 짧고 고정된 답을 강제할 수 있는 곳이라면 어디든 그것이 실행할 수 있는 가장 저렴하고 명확한 테스트입니다. 문서의 경험칙은 자동으로 채점되는 질문이 많을수록 손으로 채점한 소수의 질문보다 낫다는 것입니다.
한 가지 습관이 더 있습니다. v2가 더 이상 개선되지 않으면 같은 20개 메시지에 대해 계속 다듬지 마세요. 5–10개의 새 메시지, 이상적으로는 프로덕션에서 나온 실제 실패 사례를 추가하고 다시 실행하세요.
빠른 확인
v2는 같은 사례에서 17/20점, v1은 15/20점을 받았습니다. 가장 안전한 결론은 무엇일까요?
정답 보기
정답: v2가 더 나아 보이지만, 20개 중 두 사례는 작은 차이입니다. 새 사례를 추가하고 다시 실행하세요
각 사례는 5점이므로 두 사례 차이는 판결이 아니라 더 자세히 살펴보라는 신호입니다. v2가 한 번도 본 적 없는 새 사례가 다음 확인입니다.



