
| 내용 | 설명 |
|---|---|
| 🔁 LLM 활용한 증강 적극 권장 | 단순 rule-based 증강보다 의미 있는 다양성 확보 가능 |
| 🧠 Solar API는 증강용으로 제공 | 학습에 바로 쓰는 용도보다 데이터 다양화 목적 |
| 🔢 few-shot + 카테고리 정보 동시 제공 | 요약 스타일 유지, 안정성 향상 효과 |
| 📈 summary만 증강할 경우에도 few-shot 활용 필요 | 단일 문장만 넣으면 모델이 요약 스타일 벗어날 가능성 있음 |
| 🧪 프롬프트 엔지니어링은 json 등 포맷만 잘 잡으면 OK | 어떤 구조가 best인지는 샘플 실험 → 비교 후 결정 |
| 👥 팀원별 프롬프트 실험 권장 | 다양한 스타일 실험 → best prompting 전략 도출 |
| 목적 | 증강 방식 | 프롬프트 전략 |
|---|---|---|
| dialogue 다양화 | 동일 summary, dialogue paraphrase | dialogue few-shot 사용 |
| summary 다양화 | 동일 dialogue, summary variation | summary few-shot 필요 |
| 전체 데이터 확장 | 새로운 dialogue-sum 쌍 생성 | 카테고리 + 두세 개 few-shot 제공 |
temperature=1.1, top_p=0.9, frequency_penalty=0.1
| 파라미터 | 의미 | 설정한 이유 |
|---|---|---|
🔥 temperature=1.1 | 창의성(랜덤성) 조절 높을수록 다양한 표현 시도 | 표현 다양화 목적이기 때문에 1.0 이상 설정이 타당 |
🎯 top_p=0.9 | nucleus sampling. 상위 90% 확률에 해당하는 토큰들 중에서 샘플링 | 높은 다양성을 유지하면서도 의미를 크게 벗어나지 않도록 함 |
🚫 frequency_penalty=0.1 | 반복 억제. 이전에 나온 단어를 다시 생성하는 걸 약간 페널티 | 동일 문장/어절 반복 방지용. 0.1이면 적절히 억제하면서 자연스러움 유지 |
🔁 요약: "너무 무작위하지 않으면서도, 말하는 방식만 다르게 표현"하는 데 최적화된 설정입니다.
| 항목 | 설명 | 검토 결과 |
|---|---|---|
| ✅ 입력 데이터 범위 | train.csv의 2000~3999행 | 적절함 |
| ✅ 증강 방식 구분 | ① dialogue 표현 다양화, ② summary 재생성 | 전략 분리 좋음 |
| ✅ 스타일 고정 | dialogue: 구어체 / summary: 문어체 (존댓말) | 👍 일관성 유지 필수 조건 만족 |
| ✅ system_prompt | 역할 + 규칙 + 스타일 고정 | 🧠 역할 분리 OK |
| ✅ few-shot 구조 | user-assistant pair에 instruction 포함 | 🌟 SFT 구조와 일치 |
| ✅ instruction 위치 | user message 내부 | 🆗 HuggingFace/Solar 구조에 최적화 |
system_prompt: 역할, 구어체/문어체 규칙, 출력 포맷 고정build_prompt(mode="dialogue" or "summary"): 증강 목적별 프롬프트 생성augment_data(mode="dialogue" or "summary"): 증강 실행set_few_shot_sample(): 샘플 한 개 자동 추출main(): train.csv에서 2000~3999행 불러와 증강 실행import pandas as pd
import os
import sys
from dotenv import load_dotenv
from openai import OpenAI
from tqdm import tqdm
# === 경로 및 환경변수 설정 ===
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(ROOT_DIR)
load_dotenv()
UPSTAGE_API_KEY = os.getenv('UPSTAGE_API_KEY')
# === 전역 변수 ===
sample_dialogue1 = None
sample_summary1 = None
# === 샘플 1개 설정 ===
def set_few_shot_sample(df):
global sample_dialogue1, sample_summary1
row = df.sample(1).iloc[0]
sample_dialogue1 = row["dialogue"]
sample_summary1 = row["summary"]
# === 프롬프트 구성 ===
def build_prompt(input_text, mode="dialogue"):
if mode == "dialogue":
system_prompt = (
"당신은 한국어 일상 대화를 자연스럽게 재작성하는 전문가입니다.\n"
"주어진 대화의 의미는 유지하되, 표현을 자연스럽고 다르게 바꿔야 합니다.\n"
"1. 대화는 구어체를 유지해야 합니다.\n"
"2. 대화의 발화 수와 #PersonN# 포맷은 그대로 유지해야 합니다.\n"
"3. 존댓말을 사용하세요."
)
few_shot_user = (
"Instructions:\n"
"1. 의미는 바꾸지 말고 표현만 다양화하세요.\n"
"2. 구어체로 작성하세요.\n"
"3. 발화 순서와 수를 바꾸지 마세요.\n\n"
"Original Dialogue:\n"
f"{sample_dialogue1.strip()}\n\n"
"Rewritten Dialogue:\n"
)
few_shot_assistant = sample_dialogue1.strip()
user_prompt = (
"Original Dialogue:\n"
f"{input_text.strip()}\n\n"
"Rewritten Dialogue:\n"
)
elif mode == "summary":
system_prompt = (
"당신은 일상 대화를 문어체로 요약하는 요약 전문가입니다.\n"
"대화는 구어체지만, 요약은 문어체로 간결하고 명확하게 작성해야 합니다.\n"
"3인칭 관찰자 시점으로 존댓말을 사용하세요."
)
few_shot_user = (
"Instructions:\n"
"1. 요약은 문어체로 작성하세요.\n"
"2. 대화의 핵심만 담고, 관찰자 시점으로 쓰세요.\n\n"
"Dialogue:\n"
f"{sample_dialogue1.strip()}\n\n"
"Summary:\n"
)
few_shot_assistant = sample_summary1.strip()
user_prompt = (
"Dialogue:\n"
f"{input_text.strip()}\n\n"
"Summary:\n"
)
else:
raise ValueError("mode must be 'dialogue' or 'summary'")
return [
{"role": "system", "content": system_prompt},
{"role": "user", "content": few_shot_user},
{"role": "assistant", "content": few_shot_assistant},
{"role": "user", "content": user_prompt},
]
# === 증강 실행 ===
def augment_data(df, mode="dialogue"):
client = OpenAI(api_key=UPSTAGE_API_KEY, base_url="https://api.upstage.ai/v1/solar")
result = {
"fname": [],
"dialogue": [],
"summary": [],
"topic": [],
"augmented": []
}
for idx, row in tqdm(df.iterrows(), total=len(df)):
try:
dialogue = row["dialogue"]
summary = row["summary"]
topic = row["topic"]
fname = row["fname"]
if mode == "dialogue":
input_text = dialogue
elif mode == "summary":
input_text = dialogue
else:
raise ValueError("Invalid mode")
messages = build_prompt(input_text, mode=mode)
response = client.chat.completions.create(
model="solar-1-mini-chat",
messages=messages,
temperature=1.1,
top_p=0.9,
frequency_penalty=0.1,
stream=False
)
output = response.choices[0].message.content.strip()
if not output:
print(f"[{idx}] Empty response.")
continue
result["fname"].append(fname)
result["dialogue"].append(dialogue)
result["summary"].append(summary)
result["topic"].append(topic)
result["augmented"].append(output)
except Exception as e:
print(f"[{idx}] Error: {e}")
continue
suffix = "dialogue_aug" if mode == "dialogue" else "summary_aug"
output_path = os.path.join(ROOT_DIR, "data", f"train_solar_{suffix}_2000_3999.csv")
pd.DataFrame(result).to_csv(output_path, index=False)
print(f"✅ 저장 완료: {output_path}")
# === 메인 실행 ===
if __name__ == "__main__":
df = pd.read_csv(os.path.join(ROOT_DIR, "data", "train.csv"))
df = df.iloc[2000:4000].reset_index(drop=True)
set_few_shot_sample(df)
# ✅ 여기를 바꿔서 두 번 돌릴 수 있음
augment_data(df, mode="dialogue") # → 대화 표현 다양화
# augment_data(df, mode="summary") # → 요약 재생성