일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
- one-shot
- sk네트웍스familyai캠프12기
- few-shot
- 21주차
- Fine-tuning
- Langchain
- sk네트웍스family
- FastAPI
- 전처리
- Rag
- AWS
- 컴파일
- 어셈블
- 중복인클루드
- 최종프로젝트
- sk네트웍스familyai캠프
- C++
- 주간회고
- 배포
- zero-shot
- Docker
- #include
- 임베딩
- openai
- 회고록
- 12기
- ai캠프
- 소스코드
- 헤더가드
- sk네트웍스ai캠프
- Today
- Total
ansir 님의 블로그
[ SK 네트웍스 Family AI 캠프 수업 내용 복습 ] LLM의 기초(LLM의 이해) 2025-05-07 본문
[ SK 네트웍스 Family AI 캠프 수업 내용 복습 ] LLM의 기초(LLM의 이해) 2025-05-07
ansir 2025. 5. 8. 17:27
import os
from openai import OpenAI # OpenAI 라이브러리에서 OpenAI 클래스 임포트
# 환경 변수에 OpenAI API 키를 설정
os.environ["OPENAI_API_KEY"] = "sk-proj-..." # 보안을 위해 실제 사용 시 노출 금지
# OpenAI 클라이언트 객체 생성
client = OpenAI(
api_key=os.environ.get("OPENAI_API_KEY") # 환경 변수에서 API 키를 가져옴
)
# ChatGPT API 호출: 사용자 메시지에 대한 응답 생성
completion = client.chat.completions.create(
model="gpt-3.5-turbo", # 사용할 언어 모델 지정
messages=[
{
"role": "user", # 대화 역할: 사용자
"content": "API 잘 동작합니까?" # 사용자 메시지
}
]
)
# 생성된 응답 출력
print(completion.choices[0].message.content)
코드 설명
- os.environ["OPENAI_API_KEY"] 설정
- API 키를 직접 코드에 하드코딩하고 os.environ을 통해 환경 변수처럼 사용하고 있습니다. 실제 서비스에서는 보안상 .env 파일이나 시크릿 환경 변수로 관리하는 것이 안전합니다.
- OpenAI(api_key=...)
- OpenAI 라이브러리의 클라이언트를 초기화합니다. 이 객체를 통해 모델과의 대화를 관리할 수 있습니다.
- client.chat.completions.create(...)
- GPT 모델(gpt-3.5-turbo)에게 사용자 메시지를 보내고 응답을 생성합니다.
- 메시지는 리스트 형태로 전달하며, 각 요소는 대화 내역의 하나를 의미합니다 (role, content 필수).
- print(...)
- 응답 객체 중 가장 첫 번째 결과(choices[0])의 텍스트 메시지를 출력합니다.
프롬프트 엔지니어링 (Prompt Engineering)
프롬프트 엔지니어링이란, AI 모델이 원하는 방식으로 정확한 응답을 생성할 수 있도록 프롬프트(입력)를 설계하는 기법입니다.
특히 대규모 언어모델(LLM, 예: GPT)과 대화할 때 맥락 전달, 출력 형식 유도, 단계적 사고 구조를 활용하면 품질 높은 결과를 얻을 수 있습니다.
1. 맥락을 함께 주기
프롬프트에 '대상', '목적', '상황'을 포함해 설명함으로써 모델이 더 정확하게 이해하고 답변할 수 있도록 유도합니다.
- 예시
당신은 초등학교 5학년을 가르치는 수학 선생님입니다. 곱셈의 개념을 학생들에게 설명해야 합니다.
어렵지 않게, 실생활 예시를 들어 알려주세요.
- 의도
모델이 "누구를 위해", "무엇을", "어떤 상황에서" 설명해야 하는지를 명확히 알게 하여 더 적합한 답변을 생성하게 합니다.
2. 예시 포함 (Few-shot prompting)
기대하는 출력의 예시를 미리 보여주어 모델이 그 패턴을 따라가도록 유도합니다.
- 예시
아래와 같은 형식으로 요약해 주세요:
입력: 파이썬은 인터프리터 언어입니다. 다양한 라이브러리를 제공하며, 과학, 웹, 자동화 등 여러 분야에 쓰입니다.
출력: 파이썬은 다양한 분야에서 활용되는 인터프리터 언어입니다.
입력: 머신러닝은 데이터를 기반으로 예측 모델을 학습하는 기술입니다.
출력:
- 의도
모델이 입력-출력 간의 예시를 학습하여, 출력 형식과 요약 방식을 그대로 따르도록 유도합니다.
3. 단계별 사고 유도 (Step-by-step prompting)
"단계별로 설명해줘", "천천히 하나씩 알려줘" 같은 프롬프트를 통해 모델이 복잡한 문제를 구조적으로 풀어내도록 유도합니다.
- 예시
피타고라스의 정리를 초등학생도 이해할 수 있도록 3단계로 나눠서 설명해줘.
- 의도
복잡한 개념이나 문제를 단계적으로 나누어 생각하게 함으로써 더 명확하고 논리적인 응답을 생성하게 합니다.
보충 설명: 왜 이런 기법들이 중요한가?
GPT 같은 언어 모델은 문맥에 민감하게 반응하며, 사용자의 의도를 명확히 전달받지 못하면 엉뚱한 답을 할 수 있습니다.
따라서 프롬프트 엔지니어링은 단순히 "질문하는 기술"을 넘어서, 모델과의 협업을 위한 커뮤니케이션 전략입니다.
개별 서비스 구축
현대의 AI 기술은 다양한 분야에 개별화된 서비스를 구현하는 데 강력하게 활용됩니다. 아래는 대표적인 LLM 기반 개별 서비스 유형과 그 설명입니다.
1. 사용자 맞춤형 챗봇
정의
사용자의 성향, 선호, 목적에 맞게 동작하는 대화형 AI 시스템입니다.
특징
- 사용자 프로필, 이전 대화 기록, 사용 패턴 등을 반영하여 응답 생성
- 특정 도메인(예: 의료 상담, 법률 자문, 쇼핑 안내 등)에 특화 가능
- 음성, 텍스트, GUI 등 다양한 입력/출력 인터페이스 연동 가능
활용 예시
- 개인 금융 상담 챗봇
- 취향 기반 상품 추천 챗봇
- 학습 스타일에 맞춘 교육용 튜터봇
2. 실시간 질의 응답 시스템
정의
사용자의 질문에 대해 실시간으로 정확한 정보를 찾아 응답하는 시스템입니다.
특징
- 사전 학습된 모델 + 실시간 문서 검색(RAG, 검색 기반 생성) 결합
- DB나 웹사이트, 내부 문서 등 다양한 소스에서 정보 탐색
- 빠른 응답성과 높은 정확도 필요
활용 예시
- 고객 지원 Q&A 시스템
- 사내 지식 검색 (예: 인사 규정, 매뉴얼 자동 응답)
- 개발자 문서/오픈 API 문서 질의 응답 서비스
3. 문서 자동 요약 및 분석
정의
긴 문서를 자동으로 요약하거나 핵심 정보를 추출·분석해주는 서비스입니다.
특징
- 추출 요약 vs 생성 요약 방식 적용 가능
- 키워드 추출, 감성 분석, 주제 분류 등도 함께 적용 가능
- 실시간 또는 일괄 분석 형태로 구성 가능
활용 예시
- 뉴스 기사 요약 시스템
- 회의록 핵심 정리 서비스
- 기업 보고서 내용 자동 분석 및 리포트 생성
추가 설명: 서비스 구축 시 고려사항
- 사용자 데이터 보호 및 개인정보 처리
- 모델 선택 및 미세조정 필요 여부
- 서비스 배포 인프라 구성(AWS, GCP, 로컬 등)
- 응답 속도 및 정확성 튜닝 (캐시, 인덱싱, 프롬프트 엔지니어링 등)
프롬프트 엔지니어링 + 파인튜닝
프롬프트 엔지니어링과 **파인튜닝(Fine-tuning)**은 LLM을 원하는 방향으로 더 정밀하게 제어하고 활용하기 위한 상보적 전략입니다. 이 둘을 적절히 병행하면, 일반적인 언어모델을 특정 도메인이나 사용 목적에 최적화된 모델로 발전시킬 수 있습니다.
1. 프롬프트 세심하게 작성
정의
모델에게 전달하는 입력 프롬프트를 정교하게 설계하여 원하는 출력 형식을 유도하는 기법입니다.
구체적 방법
- 역할(role), 목적(goal), **맥락(context)**을 명확히 전달
- Few-shot 예시 제공으로 일관된 응답 유도
- 단계별 요청을 통해 사고 흐름 유도
- 출력 형식 명시: 예) JSON 형식으로 출력해줘, bullet point로 정리해줘
예시
너는 사용자의 고객 이탈 여부를 판단하는 AI야. 아래 정보를 보고 예/아니오로 답해줘.
- 이용기간: 12개월
- 최근 이용률: 낮음
- 결제 수단 변경: O
답:
활용 이유
- 모델을 파인튜닝하지 않고도 다양한 태스크에 적용 가능
- 빠르고 유연하며 반복 실험이 쉬움
2. OpenAI에 파인튜닝 API를 통해 진행
정의
OpenAI에서 제공하는 파인튜닝 API를 활용하여, 사용자가 제공한 데이터로 모델의 일부를 재학습시키는 과정입니다.
진행 방식
- 데이터 준비
- JSONL 형식으로 구성
- 형식 예:
- {"messages":[{"role":"user","content":"날씨 알려줘"},{"role":"assistant","content":"오늘 서울의 날씨는 맑고 23도입니다."}]}
- 데이터 업로드
- openai file upload CLI 또는 Python SDK 이용
- 파인튜닝 실행
- openai fine_tunes.create 명령어 사용
- base 모델 지정 (gpt-3.5-turbo, davinci-002 등)
- 파인튜닝 완료 후 사용
- 생성된 모델 ID로 API 호출
장점
- 반복적인 프롬프트 없이도 일관된 응답을 유도
- 특정 업무/도메인에 특화된 고정된 표현, 말투, 지식 반영 가능
주의 사항
- 데이터 수집/정제 품질이 매우 중요
- GPT-4는 아직 파인튜닝이 지원되지 않거나 제한적
- 비용 발생
두 전략의 관계
항목 | 프롬프트 엔지니어링 | 파인튜닝 |
학습 필요 여부 | 없음 | 필요 |
유연성 | 높음 | 중간 |
반복 입력 필요 | 있음 | 없음 |
반응 일관성 | 낮을 수 있음 | 높음 |
사용 시기 | 초기 실험/테스트 | 고정된 응답이 필요한 서비스 구축 시 |
결론
- 프롬프트 엔지니어링은 빠르고 유연한 방법으로, 초기 테스트나 경량화된 서비스에 적합
- 파인튜닝은 반복적인 패턴을 정형화하고, 사용자의 도메인에 완전히 맞춘 맞춤형 모델을 만들 때 적합
- 둘을 함께 활용하면 효율성과 일관성 모두를 확보할 수 있음
외부 정보 연동 (Vector DB 기반 RAG 방식)
정의
외부 문서나 데이터베이스의 정보를 LLM과 연동하여, 사용자 질문에 보다 정확하고 맥락 있는 응답을 생성하는 방식입니다. 이 접근은 특히 RAG (Retrieval-Augmented Generation) 구조를 활용할 때 유용하며, Vector DB를 핵심 컴포넌트로 사용합니다.
핵심 흐름: RAG 구조
- *RAG (Retrieval-Augmented Generation)**는
LLM이 기존 지식에만 의존하지 않고, 외부 문서에서 관련 정보를 검색하여 응답에 활용하는 방식입니다.
절차
- 사용자 입력 → 쿼리 임베딩(Embedding)
- Vector DB에서 유사 문서 검색 (Retrieval)
- 검색 결과 + 사용자 질문 → 프롬프트로 생성
- LLM이 답변 생성 (Generation)
이 전체 흐름에서 "Vector DB"는 검색 대상 문서의 의미 기반 인덱싱을 담당합니다.
Vector DB란?
정의
문서, 문장, 문단 등을 **벡터로 변환(임베딩)**하여 저장하고, 질문과 유사한 의미의 벡터를 빠르게 검색할 수 있도록 지원하는 데이터베이스입니다.
주요 기능
- 텍스트를 임베딩하여 저장
- 의미적 유사도에 따라 검색
- 검색 결과를 메타데이터와 함께 반환
대표적인 Vector DB 종류
- FAISS: Facebook에서 만든 오픈소스 벡터 검색 라이브러리 (로컬에서 빠른 테스트 가능)
- Pinecone: 클라우드 기반 벡터 DB
- Weaviate: GraphQL 지원, 다양한 통합 기능
- ChromaDB: LLM 응용에 적합한 lightweight 오픈소스 벡터DB
프롬프트 기반 문서 연동 예시
너는 친절한 문서 비서야. 아래 문서 내용을 참고해서 사용자 질문에 정확히 답해줘.
[문서 요약]
- 클라이언트가 계약 해지 시에는 30일 이전 통보가 필요함
- 환불은 남은 기간에 따라 계산됨
[질문]
해지하면 환불 받을 수 있나요?
→ 이처럼 외부 문서를 프롬프트에 직접 삽입하는 방식이 초기 형태이며, 이 과정을 자동화·확장한 것이 Vector DB 기반 RAG 방식입니다.
기술적 구현 요약
- 텍스트 임베딩 생성
- OpenAI의 text-embedding-3-small 모델, Sentence-BERT 등 사용
- Vector DB에 삽입
- 문서별로 임베딩 벡터와 함께 메타 정보 저장
- 질문 입력 시 벡터 검색
- 질문을 임베딩 후 가장 유사한 문서를 Vector DB에서 검색
- LLM 프롬프트 구성
- 검색된 문서 내용을 프롬프트에 포함 → 정확한 답변 유도
장점
- 모델을 파인튜닝하지 않아도 도메인 지식을 반영 가능
- 문서 변경 시에도 즉시 반영 가능 (유지관리 용이)
- 문서 분량이 방대해도 임베딩 단위로 처리 가능
보완 설명: RAG vs Fine-tuning
항목 | RAG (Vector DB) | Fine-tuning |
목적 | 외부 지식 실시간 반영 | 패턴/말투 학습 |
문서 변경 반영 | 즉시 가능 | 재학습 필요 |
비용 | 상대적으로 저렴 | 고비용 가능 |
구성 난이도 | 중간 (검색+프롬프트 조합) | 높음 (데이터 정제 + 학습 파이프라인 구축) |
결론
- 도메인 문서가 수시로 갱신되거나, 문서 기반 응답이 필요한 서비스에는 RAG + Vector DB 연동 방식이 가장 실용적입니다.
- 파인튜닝 없이 지식 확장이 가능하므로, 유지 비용 및 개발 효율 측면에서도 이점이 큽니다.
VectorDB (벡터 데이터베이스)
정의
- *VectorDB(벡터 데이터베이스)**는 텍스트, 이미지, 오디오 등 비정형 데이터를 벡터(embedding) 형태로 변환하여 저장하고, 유사도 검색을 빠르게 수행할 수 있도록 설계된 데이터베이스입니다.
LLM 기반의 RAG(Retrieval-Augmented Generation) 구조에서 외부 지식을 검색하고 반영하는 핵심 기술로 사용됩니다.
핵심 개념
1. 임베딩(Embedding)
- 텍스트 등 데이터를 고차원 숫자 벡터로 변환하는 과정
- 의미적으로 유사한 문장은 벡터 공간에서 가깝게 위치함
2. 벡터 검색(Vector Search)
- 사용자의 질문도 임베딩한 후, 데이터베이스에 저장된 벡터들과의 **거리(코사인 유사도, L2 거리 등)**를 비교하여 가장 유사한 항목을 반환
VectorDB의 역할
- 문서 또는 문장을 벡터로 저장
- 입력 쿼리 벡터와 의미적으로 가장 가까운 벡터를 검색
- 검색된 결과를 LLM에 프롬프트로 넘겨 정확하고 맥락 있는 응답 생성
주요 VectorDB 종류
이름 | 특징 |
FAISS | Facebook에서 개발한 오픈소스 벡터 검색 라이브러리. 로컬 테스트에 적합하고 매우 빠름 |
Chroma | 경량화된 오픈소스 벡터DB. LLM 응용에 특화되어 있고 Python API 제공 |
Pinecone | 클라우드 기반의 확장형 서비스. 대규모 서비스 운영에 적합 |
Weaviate | GraphQL 및 REST API 지원, 다양한 통합 기능 탑재 |
Milvus | 대용량 벡터 처리에 최적화된 고성능 오픈소스 DB |
간단한 동작 예시
- 문서 저장 시
- "환불 규정은 계약 해지 시 환불 가능하다고 명시되어 있습니다."
- → 임베딩 생성 → 벡터DB에 저장
- 사용자 질문
- "해지하면 환불되나요?" → 임베딩 후 벡터 검색
- 가장 유사한 문서 반환 → LLM에 전달하여 응답 생성
장점
- 빠르고 의미 기반 검색 가능 (단순 키워드 검색보다 정확)
- 문서가 많아도 실시간 응답 가능
- LLM을 파인튜닝하지 않고도 지식 확장 가능
- 유지보수 및 문서 업데이트가 용이
결론
VectorDB는 RAG 구조의 핵심 요소로, 외부 문서를 연동한 LLM 기반 응답 시스템 구축에 필수적입니다. 특히 자주 바뀌는 문서나 대량의 비정형 데이터를 다룰 때 효과적입니다.
ChatGPT API 사용 방법
# 'openai' 라이브러리에서 OpenAI 클래스를 임포트합니다.
from openai import OpenAI
# 환경 변수에 OpenAI API 키를 설정합니다. (이 키는 실제 프로젝트에서만 사용해야 하며, 보안에 유의해야 합니다)
os.environ["OPENAI_API_KEY"] = "private api key"
# 'OpenAI' 클래스를 사용하여 OpenAI 클라이언트를 초기화합니다.
# 'api_key'는 위에서 설정한 환경 변수에서 읽어오며, 이를 통해 API와 통신합니다.
client = OpenAI(
api_key=os.environ.get("OPENAI_API_KEY")
)
설명
- 라이브러리 임포트: openai 라이브러리에서 OpenAI 클래스를 임포트하여 OpenAI API와 상호작용할 수 있습니다.
- API 키 설정: os.environ["OPENAI_API_KEY"]를 통해 OpenAI의 API 키를 환경 변수로 설정합니다. 이렇게 설정된 API 키는 보안적으로 더 안전한 방법으로 관리됩니다.
- 클라이언트 생성: OpenAI 클래스에 API 키를 전달하여 클라이언트를 생성합니다. 이 클라이언트를 통해 OpenAI API와 직접 통신할 수 있습니다.
주의 사항
- 코드에서 사용된 API 키는 비공개로 관리해야 하며, 공개적으로 공유되면 보안 위험이 발생할 수 있습니다.
- 실제 API 키를 사용할 때는 환경 변수나 설정 파일을 이용하여 API 키를 안전하게 관리하는 것이 중요합니다.
# GPT 대화 객체 생성 - ChatGPT 대화창
response = client.chat.completions.create(
model="gpt-3.5-turbo", # 모델로 GPT-3.5-turbo를 사용
messages = [ # 대화에 대한 메시지 목록
{'role': 'system', 'content': '너는 위트있는 AI 비서야. 설명도 잘하고 농담도 잘해'}, # 시스템 역할: 모델의 성격 정의
{'role': 'user', 'content': '내가 과거로 가면 꼭 가야할 곳이 어디야?'}, # 사용자의 질문
{'role': 'assistant', 'content': '기원전 5세기 아테네 - 민주주의와 철학( 소크라테스, 플라톤 )의 탄생지'}, # 이전 응답: 과거로 가야 할 곳 제시
{'role': 'user', 'content': '거기 가서 잘 살려면 뭘 준비해 가야해?'} # 추가 질문: 아테네에서 잘 살려면 필요한 준비
]
)
상세 설명
- client.chat.completions.create():
- OpenAI API를 통해 GPT-3.5 모델을 사용해 대화형 응답을 생성하는 메서드입니다.
- model="gpt-3.5-turbo":
- gpt-3.5-turbo 모델을 사용하여 대화 기반 응답을 생성합니다. 이 모델은 빠르고 비용 효율적입니다.
- messages:
- messages 리스트에는 시스템, 사용자, 어시스턴트의 역할과 내용이 포함된 여러 메시지가 들어갑니다. 이를 통해 대화의 흐름과 성격을 정의합니다.
- role:
- system: 모델이 따라야 할 성격이나 톤을 정의합니다. 이 예제에서는 모델을 "위트있는 AI 비서"로 설정하여 설명과 농담을 잘할 수 있도록 합니다.
- user: 사용자의 메시지를 나타냅니다.
- assistant: 모델이 이전에 응답한 내용을 나타냅니다.
흐름
- 시스템 메시지: 모델은 "위트있는 AI 비서"로 설정되었기 때문에, 유머와 친근함을 섞어 답변합니다.
- 사용자 메시지: 사용자가 "과거로 가면 꼭 가야할 곳"에 대해 묻습니다.
- 어시스턴트 응답: AI는 "기원전 5세기 아테네"를 추천합니다.
- 두 번째 사용자 메시지: 사용자가 아테네에서 어떻게 잘 살 수 있을지 묻습니다.
이 코드를 실행하면, 마지막 사용자 질문에 대한 모델의 답변이 생성됩니다.
response.choices[0].message.content
과거로 가서 잘 살아남기 위해서는 몇 가지 팁이 있어. 우선 현대의 의류나 기기는 눈에 띄게 사용하지 않는 게 좋을 거야.
그리고 그 시대에 흔하게 쓰이는 언어나 풍습을 익히는 것도 좋은 아이디어야.
아마도 알파벳도 익혀두면 도움이 될 거야. 그리고 최대한 적응력을 갖추고 융통성을 발휘하는 것도 중요하겠지.
현대인의 생각과 가치관을 완전히 떼어놓고 그 시대에 맞춰 생각하고 행동하는 게 중요할 거야.
그렇게 하면 과거에서도 잘 적응할 수 있을 거야.
API 설정
import openai
import os
# OpenAI API 키를 환경 변수에서 가져옵니다.
openai.api_key = os.environ.get("OPENAI_API_KEY")
- os.environ.get("OPENAI_API_KEY")는 환경 변수에서 API 키를 안전하게 가져오는 방식입니다. API 키를 코드에 하드코딩하지 않도록 해야 합니다.
스트리밍
import openai
import os
# OpenAI API 키를 환경 변수에서 가져옵니다.
openai.api_key = os.environ.get("OPENAI_API_KEY")
user_prompt = "행복이란 무엇인가요? 철학적으로 설명해주세요"
pre_prompt = "한국어로 친절하고 자세하게 답변해줘 \n\n"
# ChatCompletion을 사용하여 대화 생성 요청을 합니다.
stream = openai.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "너는 고상한 철학자야"},
{"role": "user", "content": pre_prompt + user_prompt}
],
stream=True, # 실시간 응답 스트리밍
temperature=0.6, # 창의성 조절
top_p=1, # 확률 분포 제한 없음
frequency_penalty=0, # 같은 단어 반복 억제
presence_penalty=0, # 새로운 주제로 유도
max_tokens=2048 # 최대 토큰 수
)
# 스트리밍된 결과를 실시간으로 출력
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.get("content"): # content가 존재하는지 확인
print(chunk.choices[0].delta["content"], end="")
코드 설명
- API 키 설정:
- openai.api_key = os.environ.get("OPENAI_API_KEY")는 환경 변수에서 OpenAI API 키를 가져오는 부분입니다. API 키가 환경 변수로 설정되어 있어야 합니다.
- 사용자 프롬프트 설정:
- user_prompt는 사용자에게 질문하는 내용입니다. pre_prompt는 응답 스타일을 정하는 부분으로, 한국어로 친절하고 자세하게 답변해달라는 요청을 포함하고 있습니다.
- ChatCompletion 생성:
- openai.chat.completion.create 메서드를 호출하여, model="gpt-3.5-turbo" 모델을 사용하고 있습니다.
- messages에는 시스템 메시지와 사용자 메시지가 포함되어 있습니다. 시스템 메시지(role: system)는 모델이 어떤 역할을 해야 하는지 정의하고, 사용자 메시지(role: user)는 모델이 답변할 질문을 제공합니다.
- 스트리밍 응답:
- stream=True는 모델이 응답을 스트리밍 형태로 제공하도록 설정합니다. 이 경우, 응답이 실시간으로 출력됩니다.
- for chunk in stream을 사용하여 응답을 하나씩 처리하고, chunk.choices[0].delta.get("content")로 실제 응답 내용이 있는지 확인한 뒤 출력합니다.
- 출력:
- 각 응답 덩어리(chunk)에서 content 부분을 출력하며, 실시간으로 결과를 받는 방식입니다.
실행 환경 및 확인 사항
- 환경 변수 설정:
- OPENAI_API_KEY 환경 변수를 제대로 설정해야 하며, API 키가 올바르게 설정되었는지 확인해야 합니다.
- 로컬 환경에서 실행 중이라면, .env 파일이나 시스템 환경 변수에서 API 키를 설정해줘야 합니다.
- 실행 시 결과:
- 이 코드는 OpenAI API에서 응답을 실시간으로 받으므로, 실행 중에 모델이 생성하는 응답을 실시간으로 출력합니다.
- 예를 들어, "행복이란 무엇인가요?"라는 질문에 대해 철학적인 답변이 나올 것입니다.
- 비동기 처리:
- 스트리밍 응답을 사용할 때는 비동기 방식으로 처리되고, chunk를 통해 데이터가 점차적으로 반환됩니다. 따라서 응답이 끝날 때까지 기다리면 점진적인 결과를 볼 수 있습니다.
행복이란 매우 복잡하고 다양한 개념이지만, 철학적으로는 주로 세 가지 관점으로 이해될 수 있습니다.
첫째로, 행복은 유틸리티주의 관점에서 이해될 수 있습니다.
이 관점에 따르면 행복은 쾌락과 만족으로 이루어진 상태를 의미합니다. 즉, 행복이란 개인이 쾌락을 느끼고 만족하는 상태를 말합니다.
둘째로, 신뢰주의 관점에서는 행복은 내적인 조화와 만족으로 이해됩니다.
이 관점은 내적인 성장, 자기 실현, 사회적 연결 등을 강조하며, 개인이 자기 자신과 주변 환경과 조화롭게 지내며 만족하는 상태를 행복으로 정의합니다.
셋째로, 가르침주의 관점에서는 행복은 지혜와 성공으로 이해됩니다.
이 관점은 지식과 인식력을 통해 성공적인 삶을 살아가는 것을 중요시하며, 지혜를 통해 더 나은 결정을 내리고 의미 있는 삶을 살아가는 것을 행복으로 여깁니다.
이렇게 다양한 관점을 통해 행복을 이해할 수 있지만, 결국에는 개인의 가치관, 신념, 환경, 문화 등에
따라서 각자가 행복을 찾아가는 과정이 중요하다고 할 수 있습니다.
각자가 자신의 가치관과 목표에 맞는 방식으로 행복을 추구하고 실현할 수 있도록 노력하는 것이 중요하다고 생각합니다.
이미지 생성
dall-e-3 생성형 모델
import openai # OpenAI API를 사용하기 위한 라이브러리 import
import os # 환경 변수에서 API 키를 가져오기 위해 os 모듈 import
# OpenAI API 키 설정 (환경 변수에서 'OPENAI_API_KEY' 값을 가져와 설정)
openai.api_key = os.environ.get("OPENAI_API_KEY")
# 이미지 생성 요청
response = openai.images.generate(
model="dall-e-3", # 이미지 생성에 사용할 모델: DALL·E 3
prompt="귀여운 고양이 사진", # 생성할 이미지의 설명 프롬프트
size="1024x1024", # 이미지 크기 (너비 x 높이)
n=1 # 생성할 이미지 수 (여기서는 1장)
)
# 생성된 이미지 URL 출력 (response 객체에는 이미지에 대한 정보가 포함되어 있음)
print(response)
프롬프트(Prompt)
정의
프롬프트는 언어 모델에게 작업을 지시하는 명령문 또는 입력 텍스트를 의미합니다. 프롬프트의 표현 방식이나 구성에 따라 모델의 응답 품질이 크게 달라질 수 있습니다.
사고 유도형 프롬프트 (Step-by-step prompting)
예시
Let's think step by step.
(우리 단계별로 생각해보자.)
설명
- 이 프롬프트는 모델이 정답을 곧바로 출력하지 않고, 중간 사고 과정을 먼저 기술하도록 유도합니다.
- 모델은 각 단계에서 어떤 판단을 하고 있는지 자기 설명(self-explanation) 방식으로 풀이하며, 결과적으로 더 정확하고 신뢰할 수 있는 답변을 도출하는 경향이 있습니다.
효과 및 사례
- 정확도 향상: 실제 논문에 따르면, 단순 지시 프롬프트에 비해 사고 유도형 프롬프트를 사용했을 때 정답률이 약 10%대에서 70%대까지 증가한 사례가 있습니다.
- 대표 논문: Chain of Thought Prompting Elicits Reasoning in Large Language Models (2022)
- 이 논문에서는 Let's think step by step.이라는 프롬프트를 통해 수학, 논리 문제 해결 능력이 크게 향상되었음을 실험적으로 보여줍니다.
보충 설명
- 사고 유도형 프롬프트는 일종의 Chain-of-Thought (CoT) prompting의 기초 형태입니다.
- CoT 프롬프트는 특히 수학 문제, 논리 퍼즐, 다단계 추론이 필요한 질문에서 매우 효과적입니다.
- 모델이 추론 단계를 글로 풀어내면서 실수 가능성이 줄고, 복잡한 문제도 구조적으로 해결하게 됩니다.
좋은 프롬프트 작성 요령
언어 모델에게 더 명확하고 원하는 출력을 유도하기 위해, 프롬프트에는 다음의 다섯 가지 요소를 포함시키는 것이 효과적입니다.
1. Instruction (목표 지시)
- 역할과 목표를 분명하게 지시합니다.
- 모델이 수행해야 할 **행동(action)**을 정확히 정의합니다.
예:
다음 문장을 정중한 비즈니스 이메일로 바꿔줘.
2. Context (맥락)
- 모델이 문제를 잘 이해할 수 있도록 상황적 배경이나 전제 조건을 제공합니다.
- *‘누가’, ‘언제’, ‘어디서’, ‘왜’**와 같은 정보가 포함될 수 있습니다.
예:
상대는 신규 거래처이며, 첫 만남 이후 팔로업 메일을 보내는 상황입니다.
3. Constraints (제약 조건)
- 출력에 적용할 제한사항이나 스타일적 요구사항을 명시합니다.
- 언어, 톤, 길이, 피해야 할 표현 등을 지정할 수 있습니다.
예:
정중하지만 딱딱하지 않게 작성해줘.,
200자 이내로 요약해줘.,
전문 용어는 사용하지 마.
4. Format (출력 형식)
- 출력이 어떤 형태나 구조로 제공되길 원하는지를 지정합니다.
- 목록, 표, JSON, 마크다운, 코드 블록 등 다양한 포맷을 사용할 수 있습니다.
예:
표 형식으로 정리해줘,
JSON 형식으로 출력해줘,
마크다운으로 작성해줘
5. Examples (예시 제공)
- 참고할 수 있는 입력-출력 쌍을 함께 제공하면 모델이 패턴을 학습하여 더 정확한 출력을 생성합니다.
- 이를 Few-shot prompting이라고 부릅니다.
예:
예시:
입력: 회의 일정을 전달해줘.
출력: 안녕하세요, 회의 일정은 다음과 같습니다. (중략)
입력: 출장 계획을 간단히 알려줘.
출력: 안녕하세요, 다음은 출장 계획입니다. (중략)
요약
구성 요소 | 역할 |
Instruction | 모델에게 해야 할 작업을 지시 |
Context | 작업에 필요한 배경 정보 제공 |
Constraints | 출력의 형식이나 스타일에 대한 제약 지정 |
Format | 출력 결과의 구조나 포맷 설정 |
Examples | 모델이 참고할 수 있는 입력-출력 예시 제공 |
Zero-shot Prompting
# OpenAI 라이브러리에서 클라이언트 객체 생성
client = openai.OpenAI()
# 사용자 입력 프롬프트 (Zero-shot 설정: 예시 없이 바로 질문만 입력)
prompt = "수도권 당일 여행 코스 추천해줘"
# 챗봇 응답 생성 요청
result = client.chat.completions.create(
model='gpt-3.5-turbo', # 사용할 언어 모델 지정
messages=[
{"role": "system", "content": "너는 여행 스케줄을 작성하는 전문가야."}, # 시스템 메시지: 모델에게 역할 부여
{"role": "user", "content": prompt} # 사용자 입력 메시지
]
)
# 모델의 응답 출력
print(result.choices[0].message.content)
코드 설명
1. Zero-shot Prompting 사용
- 이 예시는 Zero-shot prompting 방식입니다.
- 예시 없이 단순한 지시(prompt)만 주어지고, 모델이 바로 응답을 생성합니다.
- 추가적인 예시(예: few-shot) 없이도 모델이 문맥과 시스템 메시지를 기반으로 작업을 수행합니다.
2. 역할 부여 (system message)
- "role": "system" 메시지를 통해 모델에게 **“여행 스케줄 전문가”**라는 정체성을 부여합니다.
- 이는 모델의 응답 스타일과 내용에 직접적인 영향을 줍니다.
3. 모델 응답 요청
- openai.chat.completions.create() 메서드는 대화형 챗봇 API로, messages 리스트를 바탕으로 다음 응답을 생성합니다.
- 사용된 모델: gpt-3.5-turbo (빠르고 저렴하며 대부분의 작업에 충분히 강력함)
4. 응답 출력
- 모델은 choices 리스트 형태로 응답을 반환하며, 그 중 첫 번째 응답(choices[0])의 실제 텍스트는 message.content에 담겨 있습니다.
- 이를 출력하여 결과를 확인합니다.
-
수도권 당일 여행 코스를 추천해드릴게요. 1. 아침: 경복궁 - 서울의 가장 유명한 궁궐인 경복궁을 방문해 역사와 전통을 느껴보세요. 경복궁에서는 국립고궁박물관도 함께 구경할 수 있어요. 2. 점심: 인사동 - 경복궁에서 걸어서 인사동으로 이동해 전통 한옥 건물과 다양한 전통 시장을 즐기며 점심 식사를 즐겨보세요. 인사동의 다양한 음식점에서 한국 전통 요리를 맛볼 수 있어요. 3. 오후: 명동 쇼핑 거리 - 점심 후에는 명동으로 이동하여 쇼핑을 즐기세요. 유명한 브랜드 매장뿐만 아니라 한국의 유명한 화장품 브랜드 상점들도 많이 있어 쇼핑하기 좋은 장소에요. 4. 저녁: 남산 서울타워 - 낮에는 남산을 오르거나 케이블카를 타고 남산을 즐기고, 밤에는 서울타워에서 서울의 야경을 감상하세요. 남산 공원에서는 밤에 서울의 불빛과 함께 멋진 전망을 즐길 수 있어요. 이렇게 수도권에서 하루 동안 다양한 명소를 경험하며 여행을 즐길 수 있을 거예요. 어떠세요? 이 코스로 여행을 계획해보시겠어요?
One-shot Prompting
# OpenAI 클라이언트 인스턴스 생성
client = openai.OpenAI()
# 사용자 프롬프트 설정
prompt = (
"강남역에서 맛집 투어를 하고 시티 투어 버스를 타고 도시 야경을 보는 것처럼 "
"여행 스케줄 추천해줘"
)
# 챗 모델 응답 요청
result = client.chat.completions.create(
model='gpt-3.5-turbo', # 사용할 OpenAI 언어 모델
messages=[
{"role": "system", "content": "너는 여행 스케줄을 작성하는 전문가야."}, # 역할 부여
{"role": "user", "content": prompt} # 사용자 입력 (예시로 기능함)
]
)
# 응답 출력
print(result.choices[0].message.content)
강남역에서 시작해서 맛집 투어와 도시 야경 감상을 즐길 수 있는 여행 스케줄을 추천해드릴게요.
**여행 일정:**
**1. 아침:**
- 강남역 부근에서 유명한 맛집에서 한식 혹은 서양식 아침 식사를 즐기세요.
- 예를 들어, "선릉역 부근"에서 인기 있는 아침 메뉴를 제공하는 레스토랑을 추천해줄 수 있어요.
**2. 오전:**
- 신사동 가로수길이나 청담동 쇼핑가를 거닐며 쇼핑을 즐기세요. 각종 패션 아이템부터 미용 제품까지 다양한 상품을 즐길 수 있답니다.
**3. 점심:**
- 간단하거나 특색 있는 한끼 식사를 위해 "삼성동"이나 "압구정"에서 유명한 맛집을 선택해서 식사하세요.
**4. 오후:**
- 오후에는 시티 투어 버스를 타고 서울의 다양한 명소를 돌며 휴양 신라스테이 이발공사 비앤비크루 프리미어 호텔 호아빌리티수상옆에서 야경을 감상하세요.
**5. 저녁:**
- 저녁 식사는 "잠실"이나 "강남"에서 맛있는 음식을 즐기며 하루를 마무리하세요.
이렇게 하루 일정을 계획하고 즐겁게 여행을 즐기세요!
One-shot Prompting 설명
1. One-shot Prompting이란?
- 모델에게 예시 하나만 제공하고 유사한 작업을 요청하는 방식입니다.
- 이 예시에서는 "강남역에서 맛집 투어를 하고 시티 투어 버스를 타고 도시 야경을 보는 것처럼" 이라는 구체적인 요청 자체가 예시 역할을 합니다.
- 모델은 이 예시를 기반으로 비슷한 스타일의 여행 일정을 생성하려고 시도합니다.
2. 왜 이것이 One-shot인가?
- 명시적으로 "예시입니다:" 라고 하지 않아도, 충분히 구체적인 예시는 모델에게 입력 형식과 기대 출력의 방향을 학습하는 힌트가 됩니다.
- 따라서 이 프롬프트는 단순 질의가 아니라, 참고 예시로 활용 가능한 사용자 입력으로 구성되어 One-shot으로 볼 수 있습니다.
정리
구분 | 설명 |
방식 | One-shot Prompting |
예시 | 강남역 맛집 + 시티투어 + 야경 감상 (사용자 입력이 예시 기능 수행) |
기대 결과 | 비슷한 구성을 가진 다른 여행 루트 제안 |
장점 | 예시 하나만으로도 모델이 포맷과 톤을 파악할 수 있어 효율적 |
Few-shot prompting
# OpenAI 클라이언트 생성
client = openai.OpenAI()
# 사용자 프롬프트: 구체적인 예시가 2개 포함된 입력 (Few-shot 역할)
prompt = (
"강남역에서 맛집 투어를 하고 시티 투어 버스를 타고 도시 야경을 보는 코스, "
"부산에서 오뎅을 먹고 자갈치 시장에서 광어회를 먹는 것처럼 맛집 투어 만들어줘"
)
# 챗봇 응답 요청
result = client.chat.completions.create(
model='gpt-3.5-turbo', # 사용할 언어 모델 지정
messages=[
{"role": "system", "content": "너는 여행 스케줄을 작성하는 전문가야."}, # 역할 부여
{"role": "user", "content": prompt} # 사용자 입력 (예제 2개 포함 → Few-shot)
]
)
# 응답 출력
print(result.choices[0].message.content)
강남역 맛집투어 & 시티투어 코스:
1. 아침:
- 강남역 근처에서 유명한 빵집이나 커피숍에서 아침식사를 즐기세요.
- 인기있는 수제 아이스크림 가게에서 디저트를 맛보세요.
2. 점심:
- 강남역 주변에서 유명한 음식점에서 한끼 식사를 즐기세요. 예를 들어, 고기집, 해산물 요리 전문점, 또는 한정식 전문점 등.
3. 오후:
- 강남역 주변에서 쇼핑을 즐기세요. 유명 백화점이나 쇼핑몰을 방문해보세요.
- 시티투어 버스를 타고 서울의 유명 관광명소를 투어해보세요. 낮이면 남산타워, 밤이면 노량진 수산시장, 용산 각이 다양한 명소들을 즐길 수 있습니다.
부산 오뎅 & 광어회 맛집투어:
1. 아침:
- 부산의 인기있는 오뎅 전문점에서 오도독뎅을 맛보세요. 예를 들어, 깡통오뎅이나 부산맛집 등이 좋은 선택일 수 있습니다.
2. 점심:
- 자갈치시장에서 신선한 광어회를 맛볼 수 있는 맛집을 찾아보세요. 현지인들이 자주 찾는 맛집을 찾는 것이 좋습니다.
3. 오후:
- 부산의 다양한 관광 명소들을 방문해보세요. 해운대 해수욕장, 태종대, 이기대 등 다양한 명소들을 즐길 수 있습니다. 부산의 멋진 야경을 즐기기 좋은 곳들입니다.
Few-shot Prompting 설명
1. Few-shot Prompting이란?
- 모델에게 2개 이상의 예시를 주어, 어떤 형식과 내용으로 응답해야 하는지 학습하게 하는 방식입니다.
- 예제:
- 강남역에서 맛집 투어 → 시티투어버스 → 도시 야경
- 부산에서 오뎅 → 자갈치 시장 광어회
이 두 개가 명시적 예시는 아니지만, 프롬프트의 구성 방식으로 맛집 중심 + 지역 특화된 이동 코스를 보여주고 있어 모델이 이를 패턴으로 인식하게 됩니다.
이 프롬프트가 Few-shot인 이유
- 예시가 여러 개 존재 → 각각은 지역별 여행 일정의 예시 역할 수행
- 명확한 구조:
- 시작 장소 + 먹거리 + 지역 명소
- 모델은 이를 기반으로 유사한 여행 일정을 생성하게 됨
정리
항목 | 내용 |
방식 | Few-shot Prompting |
예시 개수 | 2개 (서울 강남, 부산 자갈치 시장) |
구조 인식 유도 | 지역 → 음식 → 이동 or 명소 형식의 반복 구조로 패턴 유도 |
기대 응답 | 제3의 도시에서 유사한 맛집 중심 투어 코스 생성 |
고급 프롬프트 기법 요약 및 설명
1. CoT (Chain of Thought)
- 개념: 모델이 문제 해결 시 사고 과정을 단계적으로 표현하게 유도하는 전략.
- 주요 문구 예시:
- "단계적으로 생각해줘."
- "왜 그런지 논리적으로 설명해줘."
- 보충 설명:
Chain of Thought 방식은 단답형 출력보다 모델이 중간 추론 과정을 말하게 하여, 복잡한 문제(수학 문제, 추론 문제 등)에서 정답률을 크게 향상시킴.
실제 연구에서는 단순 지시보다 “Let's think step by step” 같은 문장이 정확도를 10%대에서 70%대로 끌어올리는 결과도 있음.
2. ReAct (Reasoning + Action)
- 개념: 모델이 **생각(Reasoning)**과 **행동(Action)**을 번갈아 수행하게 유도.
- 주요 문구 예시:
- “왜 그런지 자세히 설명하면서 단계적으로 풀이해줘.”
- 보충 설명:
이 방식은 주로 도구 사용이 가능한 환경 (예: 검색, 계산 등)에 유용하며, 모델이 스스로 “생각 → 도구 사용 → 다시 생각”의 순서를 반복하며 더 정확한 결과를 도출하도록 유도한다.
특히 복합적인 문제를 다룰 때 모델이 혼자 사고하면서도 필요한 조치를 취하도록 설계된 전략이다.
3. Self-Ask
- 개념: 모델이 사용자의 질문을 더 작은 하위 질문으로 분해해서 처리하게 유도.
- 주요 문구 예시:
- “이게 왜 이렇게 되는지 단계적으로 설명해줘.”
- 보충 설명:
복잡한 질문일수록 질문을 세분화해서 각 질문에 대해 순차적으로 대답하는 것이 더 효과적이다.
Self-Ask 방식은 내부적으로 문제를 “나누고, 해결하고, 결합”하는 구조로 답변 정확도를 높임.
일반적인 질의 응답보다는 복합적이고 추론 중심의 질문에서 효과적이다.
4. Multi-turn Prompting
- 개념: 모델과의 다회차 대화를 통해 맥락을 쌓아가며 정교하게 답변을 유도하는 방식.
- 활용 방식:
- 처음에는 가벼운 질문 → 이어서 보충 질문
- 또는 역할을 명확히 나눠 시뮬레이션 구성 (예: 전문가 vs 일반인)
- 보충 설명:
Multi-turn 대화는 모델이 이전 대화 내용을 기억하고 맥락 기반 응답을 하기 때문에, 점진적이고 정교한 정보 생성이 가능하다.
특히 역할극 형태(system, user, assistant)로 구성하면 특정 시나리오에서 자연스럽고 깊이 있는 응답 생성이 가능해짐.
문구가 유사한 이유와 전략별 차이점
전략 겉보기 문구 목적 및 차별점
CoT (Chain of Thought) | "단계적으로 생각해줘", "왜 그런지 설명해줘" | 사고 흐름을 말로 유도. 정답 도출 이전에 모델이 중간 과정을 서술하게 만듦. 주로 수학 문제, 논리 문제 등에서 사용. |
ReAct | "자세히 설명하면서 단계적으로 풀이해줘" | 생각 + 행동 반복. 사고와 외부 도구(예: 계산, 검색 등)를 교차적으로 수행하게 함. CoT보다 행동 유도가 강조됨. |
Self-Ask | "단계적으로 설명해줘", "질문을 나눠서 답해줘" | 질문 분해에 초점. 복잡한 질문을 여러 하위 질문으로 나누는 사고 전략을 유도함. CoT보다 질문 구조화가 핵심. |
Multi-turn | (자연스러운 대화 속 질문들) | 대화의 흐름을 유지하며 점진적으로 사고를 유도. 직접적인 "단계적으로 생각해줘" 문구보다는 대화 맥락에 따른 사고 전개가 특징. |
결론
- 겉으로 보기엔 비슷하지만 내부 사고 방식과 응용 방식이 다름.
- 예시 문구가 겹치는 이유는 실제로 다단계 사고를 유도하는 문장이 전략 전체에서 효과적이기 때문임.
- 따라서 문장은 유사해도, 모델의 내부 처리 방식과 프롬프트 구조는 전략마다 차별화되어 있음.
파인튜닝 (Fine-tuning): 미세조정
정의
- GPT 모델은 원래 방대한 범용 텍스트(위키백과, 웹 문서 등)를 기반으로 사전학습(Pretraining) 되어 있음.
- 그러나 특정 목적(예: 의료, 법률, 고객센터 등)이나 도메인 특화 태스크에서는 일반적인 GPT 응답이 부족할 수 있음.
- 이럴 때 해당 도메인에 맞는 데이터를 사용해 GPT 모델을 재학습시키는 작업이 파인튜닝임.
목적
- 특정 도메인에 대한 이해도를 높임
- 일관된 어조, 전문적인 용어 사용, 맞춤형 스타일 반영 가능
- 적은 프롬프트로도 높은 품질의 응답 생성 가능
보충 설명
- 예를 들어, 고객 상담 데이터로 파인튜닝하면 모델이 "A/S 요청", "환불 문의" 등에 대해 실제 상담원처럼 응답할 수 있음.
- OpenAI에서는 GPT-3.5, GPT-4의 일부 버전에 대해 파인튜닝 기능을 제공하며, JSONL 형식의 데이터셋을 요구함.
프롬프트 체인 (Prompt Chaining)
정의
- 하나의 복잡한 작업을 한 번에 처리하지 않고, 여러 단계로 나누어 각각을 프롬프트로 해결하는 방법.
- 각 단계에서 출력된 결과를 다음 프롬프트의 입력으로 사용하여, 마치 파이프라인처럼 동작함.
목적
- 복잡하거나 다단계적인 문제를 더 안정적으로 해결
- 단계별로 제어 가능하여 디버깅이나 설명이 쉬움
예시
- 입력: "나만의 블로그 운영 계획을 세워줘"
- 1단계 프롬프트: 주제를 분류하고 카테고리 목록을 생성
- 2단계 프롬프트: 각 카테고리에 대한 콘텐츠 아이디어 생성
- 3단계 프롬프트: 콘텐츠별 초안 생성
보충 설명
- 프롬프트 체인은 단순 응답 생성에서 나아가 복잡한 시스템 구축에 활용될 수 있음 (예: 자동 보고서 작성기, 다단계 요약 시스템 등).
- LangChain 같은 프레임워크는 프롬프트 체인을 구조적으로 구성할 수 있게 지원함.
아래와 같은 형식으로 확장자를 filename.jsonl로 저장
import pandas as pd
import json
# 파인튜닝용 대화 데이터를 딕셔너리 형태로 정의
data = {
"system": ["너는 친절한 AI", "너는 친절한 AI"], # 시스템 역할(assistant 성격 설정)
"user": ["오늘 날씨 어때", "파이썬으로 크롤링 해줘"], # 사용자 질문
"assistant": ["오늘은 맑고 기온은 20도 입니다.", "BeautifulSoup을 사용할 수 있습니다."] # 모델 응답
}
# 데이터를 DataFrame으로 변환
df = pd.DataFrame(data)
# JSONL 형식으로 변환하여 파일로 저장
with open("mydata.jsonl", 'w', encoding='utf-8') as f:
for _, row in df.iterrows():
# OpenAI 파인튜닝에 적합한 구조로 메시지 구성
messages = [
{"role": "system", "content": row["system"]},
{"role": "user", "content": row["user"]},
{"role": "assistant", "content": row["assistant"]}
]
# 한 줄에 하나의 JSON 객체를 기록 (JSONL 형식)
json.dump({"messages": messages}, f, ensure_ascii=False)
f.write('\\n') # 줄바꿈
설명
목적
이 코드는 OpenAI의 파인튜닝용 입력 데이터를 만들기 위한 것으로, 각 대화를 JSON Lines (.jsonl) 형식으로 저장합니다.
JSONL 포맷
- .jsonl은 한 줄에 하나의 JSON 객체가 들어 있는 파일 형식.
- 파인튜닝 시 OpenAI는 아래와 같은 구조를 요구합니다:
{
"messages": [
{"role": "system", "content": "너는 친절한 AI"},
{"role": "user", "content": "오늘 날씨 어때"},
{"role": "assistant", "content": "오늘은 맑고 기온은 20도 입니다."}
]
}
주요 포인트
- iterrows()로 DataFrame의 각 행을 순회하며 대화 데이터를 생성.
- 각 대화는 messages 리스트로 구성되며, 역할(role)에 따라 나뉨.
- ensure_ascii=False를 지정해 한글이 깨지지 않도록 함.
fine tuning 불러오기
# 사용할 파인튜닝된 모델 이름 지정 (본인 계정에서 생성한 모델 ID)
model_name = "ft:gpt-3.5-turbo-0125:personal::BURVV38t"
# OpenAI API 클라이언트 객체 생성
client = openai.OpenAI()
# 사용자 질문
prompt = '대한민국의 현재 인구수를 알려주세요.'
# GPT 모델에게 질문을 보내고 응답 받기
result = client.chat.completions.create(
model=model_name, # 파인튜닝된 모델 사용
messages=[
{"role": "system", "content": "너는 QA 전문가야."}, # assistant의 역할 설정
{"role": "user", "content": prompt} # 사용자 질문
]
)
# 모델의 응답 출력
print(result.choices[0].message.content)
네, 대한민국의 현재 인구는 약 5천만명 정도입니다. 최신 인구 통계에 따라서는 차이가 있을 수 있습니다.
설명
주요 요소
- model_name: OpenAI에서 파인튜닝한 모델의 고유 식별자. ft:로 시작함.
- system role: 대화 시작 시 모델의 역할을 설정해주는 메시지. 응답의 스타일, 어조 등에 영향을 줌.
- user role: 실제 사용자 입력.
- assistant role: OpenAI가 반환하는 응답. (이 코드는 출력만 하고 직접 assistant 역할 메시지를 전달하지 않음.)
파인튜닝 모델 사용 시 유의사항
- ft:gpt-3.5-turbo-0125 형식은 OpenAI가 2024년 1월 25일 버전의 gpt-3.5-turbo 기반으로 파인튜닝했음을 의미함.
- 파인튜닝한 모델은 해당 사용자 계정에서만 접근 가능.
- 프롬프트에 포함된 표현이나 도메인에 따라 성능 차이가 날 수 있음.
import openai
# OpenAI API 클라이언트 생성
client = openai.OpenAI()
# 학습 데이터(.jsonl)를 열어서 업로드
with open("mydata.jsonl", "rb") as f:
file_response = client.files.create(file=f, purpose="fine-tune") # 파일 업로드 목적을 'fine-tune'으로 지정
# 업로드된 파일의 고유 ID 저장
file_id = file_response.id
# 파인튜닝 작업 생성
fine_tune_response = client.fine_tuning.jobs.create(
training_file=file_id, # 학습에 사용할 파일 ID 지정
model="gpt-3.5-turbo" # 베이스 모델: gpt-3.5-turbo
)
# 생성된 파인튜닝 작업의 고유 ID 저장
fine_tune_id = fine_tune_response.id
설명
1. openai.OpenAI()
- OpenAI의 Python SDK 클라이언트를 생성합니다. 기본적으로 환경 변수에 설정된 API 키를 사용합니다.
2. 파일 업로드
- mydata.jsonl: 파인튜닝에 사용할 JSONL 형식의 학습 데이터.
- purpose="fine-tune": 업로드 목적을 명시해야 파인튜닝에 사용할 수 있습니다.
- file_response.id: 나중에 파인튜닝 작업에 사용할 파일 ID를 저장합니다.
3. 파인튜닝 작업 생성
- fine_tuning.jobs.create(...): 업로드한 학습 데이터를 기반으로 GPT 모델을 파인튜닝하는 작업을 생성합니다.
- model="gpt-3.5-turbo": 사전학습된 베이스 모델. GPT-3.5 turbo 버전을 기준으로 파인튜닝됩니다.
- fine_tune_response.id: 생성된 작업의 ID로, 이후 작업 상태 확인 등에 사용됩니다.
# 파인튜닝 작업 상태 확인
status = client.fine_tuning.jobs.retrieve(fine_tune_id)
# 현재 파인튜닝 상태 출력
print(status.status) # 예: 'pending', 'running', 'succeeded', 'failed'
상태값 설명
상태 | 의미 |
pending | 대기 중 (다른 작업 순서를 기다리는 상태) |
running | 현재 파인튜닝이 진행 중 |
succeeded | 파인튜닝이 성공적으로 완료됨 |
failed | 오류 등으로 파인튜닝 작업이 실패함 |
cancelled | 사용자가 수동으로 작업을 중단한 경우 |
# 파인튜닝 작업의 상세 정보 가져오기
status = client.fine_tuning.jobs.retrieve(fine_tune_id)
# 전체 응답 객체 출력 (딕셔너리 형태로 다양한 정보 포함)
print(status)
# 주요 정보만 골라 출력해보기
# 파인튜닝 작업 ID
print("Job ID:", status.id)
# 사용된 원본 모델 (예: gpt-3.5-turbo)
print("Base model:", status.model)
# 파인튜닝으로 생성된 최종 모델 이름 (완료 후에만 존재)
print("Fine-tuned model:", status.fine_tuned_model)
# 작업 상태 (예: pending, running, succeeded, failed)
print("Status:", status.status)
# 생성 시각 (ISO 8601 형식, UTC 기준)
print("Created at:", status.created_at)
# 완료 시각 (작업이 끝난 경우에만 존재)
print("Finished at:", status.finished_at)
# 학습에 사용된 파일 ID
print("Training file ID:", status.training_file)
# 검증용 파일 ID (사용한 경우)
print("Validation file ID:", status.validation_file)
# Hyperparameters: 에폭 수 등 (필요시 참고)
print("Hyperparameters:", status.hyperparameters)
참고
- status 객체는 내부적으로 딕셔너리처럼 작동하며, 다양한 정보를 담고 있습니다.
- fine_tuned_model은 파인튜닝이 완료된 후에만 존재하며, 해당 값을 모델 호출 시 model="ft:..." 형식으로 사용합니다.
- 날짜 정보(created_at, finished_at)는 Unix timestamp가 아닌 ISO8601 문자열이거나 정수형 타임스탬프이므로 가공이 필요할 수 있습니다.
# 사용자가 입력한 프롬프트 (질문)
prompt = '대한민국의 현재 인구수 알려주세요'
# OpenAI Chat API를 사용하여 파인튜닝된 모델로 응답 생성 요청
result = client.chat.completions.create(
model=status.fine_tuned_model, # 파인튜닝된 모델 이름 사용 (예: ft:gpt-3.5-turbo-0125:your-id)
messages=[
{"role": "system", "content": "너는 QA 전문가"}, # 시스템 역할 지정 (모델의 행동 방식을 정의)
{"role": "user", "content": prompt} # 사용자 입력 메시지
]
)
# 생성된 응답 메시지 출력
print(result.choices[0].message.content)
2021년 9월 기준 대한민국의 인구수는 약 5천2백만 명입니다.
fine-tuning 데이터
- 데이터 업로드
- fine tuning 학습
- 학습된 모델을 로드해서 실행
파일 업로드
import openai
client = openai.OpenAI() # OpenAI API 클라이언트를 생성합니다.
# 데이터 업로드
with open("/content/npc_dialogues.jsonl", "rb") as f:
file_response = client.files.create(file=f, purpose="fine-tune") # 업로드할 데이터를 'fine-tune' 목적을 위해 업로드합니다.
# 업로드된 파일 ID 가져오기
file_id = file_response.id # 업로드한 파일의 ID를 가져옵니다.
print(f"업로드 파일 아이디: {file_response.id}") # 업로드된 파일의 ID를 출력합니다.
주요 기능:
- 파일 업로드: /content/npc_dialogues.jsonl 파일을 OpenAI에 업로드하고, purpose="fine-tune"을 설정하여 해당 파일을 fine-tuning 목적으로 사용하도록 지정합니다.
- 파일 ID 출력: 파일이 성공적으로 업로드되면 파일의 ID를 file_response.id를 통해 확인할 수 있습니다. 이 ID는 이후 fine-tuning 작업을 시작할 때 사용됩니다.
업로드된 파일을 파인튜닝
fine_tune_response = client.fine_tuning.jobs.create(
training_file=file_id, # 이전에 업로드한 fine-tuning 데이터의 파일 ID
model="gpt-3.5-turbo", # 사용할 기본 모델 (gpt-3.5-turbo 모델을 사용)
hyperparameters={ # 학습 하이퍼파라미터 설정
'n_epochs': 1, # 에폭 수: 학습 데이터를 몇 번 반복할지 설정 (여기서는 1번 학습)
'learning_rate_multiplier': 0.1, # 기본 학습률에 0.1을 곱하여 학습률을 설정 (기본 학습률 1e-3에 0.1을 곱하여 0.0001로 설정)
'batch_size': 1 # 배치 크기: 한 번에 처리할 샘플 수 (여기서는 1로 설정)
}
)
# fine-tune 작업의 ID를 가져옴
fine_tune_id = fine_tune_response.id
print(f"파인튜닝 아이디: {fine_tune_id}") # 학습 작업 ID 출력
주요 기능:
- fine-tuning 작업 시작: client.fine_tuning.jobs.create() 메서드를 호출하여 fine-tuning 작업을 시작합니다.
- training_file: 이전에 업로드한 file_id를 사용하여 학습할 데이터를 지정합니다.
- model: 기본 모델로 gpt-3.5-turbo를 사용합니다. fine-tuning을 원하는 모델을 지정합니다.
- hyperparameters: 학습 하이퍼파라미터를 설정합니다.
- n_epochs: 데이터를 몇 번 반복해서 학습할지 설정합니다. 여기서는 1번 학습하도록 설정합니다.
- learning_rate_multiplier: 기본 학습률에 곱할 배수입니다. 기본값은 1e-3 (0.001)이고, 여기에 0.1을 곱하여 0.0001로 설정합니다.
- batch_size: 한 번에 처리할 샘플의 수입니다. 여기서는 배치 크기를 1로 설정합니다.
- fine-tune ID 출력: fine_tune_response.id를 사용하여 시작된 fine-tuning 작업의 ID를 가져옵니다. 이 ID는 나중에 작업의 상태를 확인할 때 유용하게 사용됩니다.
상태확인
# 파인튜닝 작업 상태 확인
status = client.fine_tuning.jobs.retrieve(fine_tune_id)
print(f"파인튜닝 작업 상태: {status.status}") # 상태 출력 (예: pending, running, succeeded)
파인튜닝된 모델 확인 및 로드
print(f"파인튜닝된 모델: {status.fine_tuned_model}")
result = client.chat.completions.create(
model=status.fine_tuned_model, # 파인튜닝된 모델 사용 (fine_tuned_model은 이전에 fine-tuning 작업으로 얻은 모델 이름)
messages=[ # 모델에 전달할 대화 메시지 목록
# 시스템 역할: 모델에게 역할을 설정해줌
{"role": "system", "content": "당신은 NPC 대사를 창작하는 AI입니다."},
# 사용자 역할: 모델이 창작할 대사에 대한 조건을 제공
{"role": "user", "content": "캐릭터: 까칠한 마법사\\n상황: 주인공이 실수를 했다"}
]
)
# 모델의 응답에서 대사를 출력
print(result.choices[0].message.content) # 생성된 대사를 출력
주요 기능:
- fine-tuned 모델 사용: status.fine_tuned_model을 사용하여 fine-tuning된 모델을 호출합니다. 이 모델은 이전에 파인튜닝 작업을 통해 학습된 모델로, NPC 대사를 생성하는 데 특화되어 있습니다.
- 대화 설정: messages 파라미터를 통해 시스템 메시지와 사용자 메시지를 설정합니다.
- 시스템 메시지: 모델에게 특정 역할을 부여하는 메시지입니다. 여기서는 "당신은 NPC 대사를 창작하는 AI입니다."라는 역할을 설정해줍니다.
- 사용자 메시지: 모델에게 창작할 대사의 조건을 전달하는 메시지입니다. "캐릭터: 까칠한 마법사\n상황: 주인공이 실수를 했다"라는 조건을 제공하여, 이에 맞는 대사를 생성하도록 유도합니다.
- 응답 출력: 모델의 응답에서 첫 번째 선택지를 가져와 대사를 출력합니다. result.choices[0].message.content를 통해 생성된 대사를 가져옵니다.
예시 출력:
모델이 "까칠한 마법사" 캐릭터와 "주인공이 실수를 했다"는 상황에 맞는 대사를 생성하면, 다음과 같은 결과가 나올 수 있습니다:
- "이게 무슨 실수냐, 주인공! 내 마법이 없었으면 어쩔 뻔했나?"
csv 파일을 jsonl 파일로 변환하기
import pandas as pd
import json
path = "/content/npc_dialogues.csv"
df = pd.read_csv(path)
df
No. | 캐릭터 | 상황 | 대사 문장 |
0 | 겁 많은 마을 청년 | 낯선 사람이 마을에 들어왔다 | 으-으윽… 방금 지나간 그 사람, 뭔가 수상하지 않아? |
1 | 늙은 대장장이 | 주인공에게 검을 건넨다 | 이 검은 젊었을 적 마지막으로 만든 물건이야. 헛되이 쓰지 말거라. |
2 | 냉소적인 도적 | 플레이어에게 정보를 판다 | 돈이 먼저다. 정보는 그다음이지. 거래할 준비는 됐나? |
3 | 무뚝뚝한 경비병 | 야간 순찰 중 낌새를 느낀다 | …잠깐, 저기 뭔가 소리가 났다. 너 거기서 나와봐. |
4 | 상냥한 여관 주인 | 주인공이 피곤해 보인다 | 오늘 하루도 힘들었나 보군요. 따뜻한 스튜랑 침대 준비해둘게요. |
... | ... | ... | … |
305 | 수상한 노점상 | 이상한 물건을 판다 | 흐흐, 이 물건은 단 하나뿐이야. 사갈 생각 있어? |
306 | 과묵한 무도가 | 전투 후 말을 건넨다 | 말은 필요 없어. 실력으로 증명하는 거지. |
307 | 호기심 많은 학자 | 주인공의 장비에 관심을 가진다 | 이건… 이건 굉장한 유물이야! 어떻게 구한 거죠? |
308 | 사교적인 괴짜 마법사 | 파티에 불쑥 나타난다 | 짜잔~ 내가 빠지면 파티가 아니지! 오늘은 어떤 마법을 보여줄까? |
309 | 우울한 시인 | 달빛 아래서 시를 읊는다 | 달은 오늘도 슬픔을 품고 있네… 너도 느끼는가? |
# JSONL 파일로 변환
with open("npc_dialogues.jsonl", 'w', encoding='utf-8') as f:
for _, row in df.iterrows():
# messages 구조 생성: system, user, assistant 역할을 갖는 메시지 리스트
messages = [
{"role": "system", "content": "당신은 NPC 대사를 창작하는 AI입니다."}, # 모델의 역할 정의
{"role": "user", "content": f"캐릭터: {row['캐릭터']}\\n상황: {row['상황']}"}, # 사용자 프롬프트 정의
{"role": "assistant", "content": row["대사 문장"]} # 기대하는 정답(모델 출력) 정의
]
# JSONL 형식으로 한 줄씩 저장
json.dump({"messages": messages}, f, ensure_ascii=False)
f.write('\\n')
{"messages":
[
{"role": "system", "content": "당신은 NPC 대사를 창작하는 AI입니다."},
{"role": "user", "content": "캐릭터: 겁 많은 마을 청년\\n상황: 낯선 사람이 마을에 들어왔다"},
{"role": "assistant", "content": "으-으윽… 방금 지나간 그 사람, 뭔가 수상하지 않아?"}
]
}
포맷 요약 (fine-tuning용):
- system: AI의 역할 설정
- user: 프롬프트 입력
- assistant: 기대하는 출력 (정답)
파일 업로드
import openai # OpenAI 라이브러리 임포트
client = openai.OpenAI() # OpenAI 클라이언트 인스턴스 생성
# 데이터 업로드
with open("/content/npc_dialogues.jsonl", "rb") as f:
# 'fine-tune' 목적을 명시하고 파일 업로드
file_response = client.files.create(file=f, purpose="fine-tune")
# 업로드된 파일의 ID 추출
file_id = file_response.id
# 업로드 확인용 출력
print(f"업로드 파일 아이디: {file_response.id}")
출력 예시
업로드 파일 아이디: file-abc123def456ghi789
참고 사항
- purpose="fine-tune"을 지정해야 학습용으로 인식됩니다.
- 업로드한 파일은 OpenAI 계정의 파일 리스트에서 확인 가능하며, file_id는 fine-tuning 요청 시 training_file 인자로 사용됩니다.
업로드된 파일을 파인튜닝
# 파인튜닝 작업 시작
fine_tune_response = client.fine_tuning.jobs.create(
training_file=file_id, # 앞서 업로드한 학습용 데이터 파일 ID
model="gpt-3.5-turbo", # 파인튜닝할 기본 모델
hyperparameters={ # 하이퍼파라미터 설정
'n_epochs': 1, # 전체 데이터셋을 1회 학습
'learning_rate_multiplier': 0.1, # 기본 학습률(1e-3)에 대한 배수
'batch_size': 1 # 배치 크기(한 번에 학습할 샘플 수)
}
)
# 생성된 파인튜닝 작업의 ID 저장
fine_tune_id = fine_tune_response.id
# 파인튜닝 작업 ID 출력
print(f"파인튜닝 아이디: {fine_tune_id}")
파인튜닝 설정 요약
하이퍼파라미터 | 설명 |
n_epochs | 데이터 전체를 몇 번 반복할지 지정 |
learning_rate_multiplier | 기본 학습률의 배수. 값이 작을수록 학습이 더 안정적 |
batch_size | 한 번에 처리할 샘플 수. 데이터 수가 적을수록 작게 설정 |
상태확인
# 상태 확인
status = client.fine_tuning.jobs.retrieve(fine_tune_id)
print(status.status) # pendding, running, successed
파인튜닝된 모델 확인 및 로드
print(f"파인튜닝된 모델: {status.fine_tuned_model}")
# 파인튜닝된 모델을 사용해 NPC 대사를 생성
result = client.chat.completions.create(
model=status.fine_tuned_model, # 파인튜닝된 모델을 지정
messages=[
{"role": "system", "content": "당신은 NPC 대사를 창작하는 AI입니다."}, # 시스템 프롬프트로 역할 고정
{"role": "user", "content": "캐릭터: 상냥한 대장장이\\n상황: 꼬마가 대장간에 들어왔다"} # 사용자 입력
]
)
# 모델의 응답 출력
print(result.choices[0].message.content)
결과 예시
어서 오렴, 꼬마야! 쇠망치가 궁금하니? 다치지 않게 조심해야 해~