트랜스포머·PEFT 2일 과정7장 · SFT 데이터 구성과 Chat Template5 / 18← 이전목차다음 →MetaContents

7장. SFT 데이터 구성과 Chat Template

데이터 형식: Instruction, messages, prompt-completion

같은 주소도 "서울시 ○○구 ○○로 1"이라고 한 줄로 적을 수도 있고, 시·구·도로명 칸을 나눈 택배 송장에 적을 수도 있습니다. 내용은 같지만 받는 쪽이 어떤 양식을 읽는지에 맞춰야 합니다. SFT 데이터도 같은 문답을 여러 양식으로 담을 수 있고, 학습 도구가 읽는 양식에 맞춥니다. 파일은 보통 한 줄에 예시 하나씩 JSON 으로 적는 JSONL 로 저장합니다.

Instruction, messages, prompt-completion 세 형식을 나란히 놓은 비교 그림

그림 왼쪽의 Instruction 형식은 사람이 만들기 쉽고, 이 장의 원본 CSV(질문 열, 답변 열)가 이와 비슷합니다. 가운데 messages 형식은 역할 표시가 있어 system 규칙과 여러 턴 대화를 담을 수 있습니다. 오른쪽 prompt-completion 형식은 messages 를 질문 쪽과 답 쪽으로 나눠 담습니다. TRL 의 SFTTrainer 는 이렇게 나눠 둔 데이터를 받으면 completion(답) 부분만 학습하도록 알아서 처리합니다.

세 형식 견주기

형식한 줄의 모양장점이 과정에서
Instruction{"instruction": ..., "input": ..., "output": ...}사람이 읽고 만들기 쉬움원본 CSV 가 이와 비슷함
messages{"messages": [{"role": "user", ...}, {"role": "assistant", ...}]}여러 턴, system 메시지 표현실습 3 에서 템플릿 확인
prompt-completion{"prompt": [user 메시지], "completion": [assistant 메시지]}답(completion)만 학습하도록 자동 처리실습 2 에서 만들고 8장 학습에 사용

짧은 예시

Python
import json

# 같은 문답 하나
question = "환불은 언제까지 신청할 수 있나요?"
answer = "수령 후 7일 이내에 신청하실 수 있습니다."

# 1) Instruction 형식: 지시, 입력, 답을 칸으로 나눈다(입력이 없으면 빈 문자열)
instruction = {"instruction": question, "input": "", "output": answer}
# 2) messages 형식: 역할(role)과 내용(content)의 목록
conversation = {"messages": [{"role": "user", "content": question},
                             {"role": "assistant", "content": answer}]}
# 3) prompt-completion 형식: messages 를 질문 쪽과 답 쪽으로 나눈다
prompt_completion = {"prompt": [{"role": "user", "content": question}],
                     "completion": [{"role": "assistant", "content": answer}]}

# json.dumps(사전, ensure_ascii=False): 한글을 \uXXXX 로 바꾸지 않고 그대로 JSON 글자로 만든다
# JSONL 파일이라면 이 세 줄이 각각 한 줄씩 들어간다
for name, record in [("Instruction", instruction), ("messages", conversation), ("prompt-completion", prompt_completion)]:
    print(name, json.dumps(record, ensure_ascii=False))
# 결과: Instruction {"instruction": "환불은 ...", "input": "", "output": "수령 후 ..."}
#       messages {"messages": [{"role": "user", ...}, {"role": "assistant", ...}]}
#       prompt-completion {"prompt": [{"role": "user", ...}], "completion": [{"role": "assistant", ...}]}

이 코드가 뜻하는 것

같은 주소를 한 줄 메모, 송장, 칸이 둘로 나뉜 송장에 옮겨 적은 셈입니다. 내용은 하나도 달라지지 않았고 담는 그릇만 다릅니다. prompt-completion 형식은 messages 의 user 부분을 prompt 에, assistant 부분을 completion 에 나눠 넣은 것뿐입니다.

줄하는 일쉽게 말하면
instruction = {...}지시·입력·답 칸에 담는다한 줄 메모
conversation = {"messages": [...]}역할 표시와 함께 차례로 담는다대화 대본
prompt_completion = {...}질문 쪽과 답 쪽을 나눠 담는다문제지와 답안지
json.dumps(record, ensure_ascii=False)사전을 JSON 글자 한 줄로 만든다JSONL 파일의 한 줄

주의할 점

  • ensure_ascii=False 를 빼면 한글이 환불 처럼 바뀌어 사람이 읽기 어렵습니다. 파일로 저장할 때도 encoding="utf-8" 을 함께 줍니다.
  • 학습 도구마다 기대하는 열 이름이 다릅니다. TRL 은 messages, prompt·completion, text 같은 정해진 이름을 찾으므로 열 이름을 마음대로 바꾸지 않습니다.
← 이전 절7장 · 좋은 SFT 데이터의 조건다음 절 →7장 · 데이터 불러오기와 점검