byteforce

CPN 한국어 자습서 · 러닝패스 2 / 4 — Building with the Claude API

프롬프트 평가

코드 기반 채점

Code based grading

형식·문법처럼 정확히 따질 수 있는 부분은 코드로 채점합니다. json.loads·ast.parse·re.compile로 문법을 검증해 통과면 10, 실패면 0. 모델 채점과 코드 채점을 평균내 최종 점수를 냅니다.

전체 내레이션영상 나레이션 한국어 번역 (전체)

Stephen Grider · Anthropic 기술 스태프

이제 코드 grader를 구현합니다. 코드 grader는 모델 출력을 받아, 부가 설명 없이 순수 Python·JSON·정규식만 왔는지, 그리고 그 코드의 문법이 유효한지 확인합니다. Python 문법을 어떻게 검증하냐고요? 작은 트릭을 씁니다. validate_json·validate_python·validate_regex 세 헬퍼 함수를 만들고, 각각 출력을 JSON으로 파싱하거나, Python 추상 구문 트리(AST)로 파싱하거나, 정규식으로 컴파일해 봅니다. 성공하면 만점 10, 파싱 중 에러가 나면 문법 검사 실패로 보고 0을 돌려줍니다.

한 가지 더. 어떤 검증기를 돌릴지 알려면, 데이터셋의 각 test case가 기대 형식을 담고 있어야 합니다. 그래서 데이터셋에 format 키를 추가합니다 — 이 출력은 Python, 이건 JSON, 이건 regex 식으로요. 파일을 손으로 고칠 수도 있지만, 나중에 큰 데이터셋을 생성하려고 데이터셋 생성 프롬프트 쪽을 고칩니다.

1단계, JSON·Python·정규식 검증 함수를 추가합니다. run_test_case 셀 위에 새 셀을 만들고 세 함수를 넣습니다. 맨 위에서 두 헬퍼 모듈(ast, re)을 import하고, 세 검증기를 정의한 뒤, 맨 아래에 어떤 검증기를 쓸지 고르는 범용 함수 grade_syntax를 둡니다. test case의 format을 보고 알맞은 함수를 호출합니다.

2단계, 데이터셋에 format 키를 넣습니다. generate_dataset의 예시 출력에서 task 뒤에 쉼표를 찍고 format 키를 더해 JSON·Python·regex 중 하나를 넣게 합니다. 셀을 다시 실행해 데이터셋을 생성하면, 각 task에 맞는 format이 정확히 붙어 나옵니다.

3단계, 초안 프롬프트를 보강합니다. 지금은 그냥 "과제를 풀어라"라서 JSON·Python이 아닌 내용이 섞여 와 검증을 늘 실패할 수 있습니다. 그래서 "Python·JSON·정규식만으로 답하고, 주석·설명을 달지 말라"는 지시를 더합니다. 그리고 우리가 정말 원하는 raw 콘텐츠만 받으려고 또다시 prefill + stop sequence를 씁니다.

assistant 메시지에 백틱 세 개를 넣는데, 보통은 그 뒤에 JSON·Bash·Python 같은 걸 붙이죠. 그런데 이번엔 어떤 형식이 올지 미리 모릅니다 — Python일지 JSON일지 regex일지. 그래서 작은 편법으로 그냥 "code"를 넣습니다. 그러면 "여기엔 코드가 올 거다"라고 Claude에 알려 주면서도 형식을 특정하지 않아도 됩니다. 닫는 stop sequence로 백틱 세 개를 더합니다.

마지막으로 모델 채점과 코드 채점 점수를 합칩니다. run_test_case에서 model grader 아래에 syntax 채점을 둡니다 — grade_syntax에 output과 test case를 넘깁니다. 그리고 기존 score를 model_score로 이름을 바꾸고, 두 점수의 평균을 score로 씁니다. (model_score + syntax_score) / 2죠. 이게 코드 채점을 더하는 데 필요한 전부입니다.

전부 테스트해 봅니다. run_eval을 호출해 전체 평균을 계산하는 셀을 다시 돌리면, 잠시 뒤 최종 점수 8.166이 나옵니다. 그럼 이게 좋은 걸까요? 사실은 모릅니다. 알 수 있는 유일한 방법은 이제 프롬프트를 바꿔 더 나은 점수가 나오는지 보는 것입니다. 다음 실습에서 프롬프트를 조금 바꿔 점수를 올려 보겠습니다.

이 장에서 배우는 것What you'll learn

약 6분
1

문법 검증 = 파싱 시도 — 성공 10, 에러 0

2

json.loads · ast.parse · re.compile

3

test case에 format 키 → 어떤 검증기를 쓸지 결정

4

프롬프트에 “형식만, 설명 금지” 명시 + prefill ```code

5

최종 점수 = (model + syntax) / 2

6

평균 8.166 — 좋은지 나쁜지는 바꿔 봐야 안다

먼저 짚고 갈 용어
code grader (코드 채점)
출력을 코드로 검사. 여기선 문법 유효성을 파싱으로 확인.
ast.parse
문자열을 Python 추상 구문 트리로 파싱. 성공하면 문법이 유효하다는 뜻.
re.compile
문자열을 정규식으로 컴파일. 성공하면 유효한 정규식.
format (키)
test case가 기대하는 출력 형식(json·python·regex). 검증기 선택에 쓴다.

코드 채점이란

Validate by parsing

형식·문법은 코드로 결정적으로 따질 수 있습니다. 트릭은 단순합니다 — 출력을 해당 형식으로 파싱해 보고, 성공하면 10, 에러가 나면 0을 줍니다.

구문 검증 데모 · 파싱 성공이면 10, 에러면 0

모델 채점과 달리 코드 채점은 결정적입니다 — 같은 입력엔 늘 같은 점수. 형식·문법처럼 정답이 분명한 기준에 적합합니다.

001_prompt_evals.ipynb · 검증기 + grade_syntax
import ast
import re

def validate_json(text):
    try:
        json.loads(text)
        return 10
    except json.JSONDecodeError:
        return 0

def validate_python(text):
    try:
        ast.parse(text)
        return 10
    except SyntaxError:
        return 0

def validate_regex(text):
    try:
        re.compile(text)
        return 10
    except re.error:
        return 0

def grade_syntax(output, test_case):
    fmt = test_case["format"]
    if fmt == "python":
        return validate_python(output)
    elif fmt == "json":
        return validate_json(output)
    else:
        return validate_regex(output)

format 키 + 프롬프트 보강

Format key & prompt fix

어떤 검증기를 돌릴지 알려면, 각 test case가 기대 형식을 담아야 합니다. 데이터셋 생성 프롬프트에 format 키를 추가합니다.

데이터셋에 format 키 추가
# generate_dataset 프롬프트의 예시 출력에 format 키 추가
```json
[ { "task": "Description of task", "format": "json | python | regex" } ]
```
# → 각 test case가 어떤 검증기를 쓸지 알 수 있게 됨

또, 지금 초안 프롬프트는 "과제를 풀어라"뿐이라 설명이 섞여 와 검증을 늘 실패합니다. "형식만, 설명 금지"를 명시하고, 형식을 모르니 prefill은 ```code로 둡니다.

run_prompt · 형식 명시 + ```code prefill
def run_prompt(test_case):
    prompt = f"""
Please solve the following task:

{test_case["task"]}

* Respond only with Python, JSON, or a plain Regex
* Do not add any comments or commentary or explanation
"""
    messages = []
    add_user_message(messages, prompt)
    add_assistant_message(messages, "```code")   # 형식을 모르니 언어 없이 generic 코드펜스

    output = chat(messages, stop_sequences=["```"])
    return output

두 점수 합치기

Merge the scores

이제 run_test_case에서 모델 채점과 코드 채점을 모두 돌리고, 두 점수의 평균을 최종 점수로 씁니다.

run_test_case · model + syntax 평균
def run_test_case(test_case):
    output = run_prompt(test_case)

    model_grade = grade_by_model(test_case, output)
    model_score = model_grade["score"]
    reasoning = model_grade["reasoning"]

    syntax_score = grade_syntax(output, test_case)   # 0 또는 10

    score = (model_score + syntax_score) / 2   # 두 채점 평균

    return {
        "output": output,
        "test_case": test_case,
        "score": score,
        "reasoning": reasoning,
    }
출력 · 최종 평균
Average score: 8.166
좋은 점수일까?

8.166이 좋은지 나쁜지는 지금은 모릅니다. 알 수 있는 유일한 방법은 프롬프트를 바꿔 점수가 오르는지 보는 것 — 다음 실습의 주제입니다.

정리 & 점검

Recap & check
핵심 정리
  • 문법 검증 = 파싱 시도. json.loads/ast.parse/re.compile 성공 10, 에러 0.
  • test case의 format 키로 알맞은 검증기를 고른다.
  • 프롬프트에 "형식만, 설명 금지"를 명시하고 prefill ```code + stop ```.
  • 최종 점수 = (model + syntax) / 2. 코드 채점은 결정적이다.

Q1코드 채점에서 Python 문법이 유효한지 어떻게 확인하나요?

Q2어떤 검증기를 돌릴지 결정하려면 test case에 무엇이 필요한가요?

Q3형식을 미리 모를 때 prefill로 쓴 방법은?

MEMBER SESSION REQUIRED · REGISTRATION IS FREE

여기부터는 등록한 분에게 열립니다.

전 코스는 계속 무료입니다. 등록하면 이 코스의 남은 76개 레슨을 끝까지 읽을 수 있습니다.

등록하고 이어서 읽기

이미 등록하셨다면 그때 쓰신 이메일을 넣어 주세요.