과적합: 에포크를 과도하게 늘리면 학습데이터셋에서는 높은 정확도를 보이지만 새로운 데이터셋에서 일반화 되지 못할 수 있음
Catastophic Forgetting: 특정한 작업을 위한 미세조정 과정에서 처음에 습득한 광범위한 지식을 잃을 위험
데이터 유출: 훈련 및 검증 데이터 세트가 중복됨
RAG
정의: 검색기반 모델과 생성 모델의 장점을 결합, 입력 쿼리를 기반으로 대규모 데이터베이스 또는 지식 기반을 검색하여 관련 정보를 검색
동적 지식 통합: 외부 소스의 실시간 정보를 통합하여 최신 지식이나 특정 지식이 필요한 작업에 적합
문맥적 연관성: 검색된 문서에서 추가적인 맥락을 제공하여 생성 모델의 응답을 향상
다재다능: 더 광범위한 쿼리를 처리할 수 있음
2. Langchain
LLM 기반 어플리케이션 개발을 간소화하고 유연하게 만드는 핵심적인 역할
2.1 Runnable
Chain을 구성하는 모든 구성요소를 연결하고 실행하기 위한 표준 인터페이스
표준화된 메소드: invoke, batch, stream 표준 호출 메소드를 제공
모든 구성요소가 공통된 메서드를 가지게 하는 것
2.2 LCEL
LangChainExpressionLanguage Runnable을 체인으로 구성하여 유닉스 파이프 연산자처럼 선언적인 방식 제공
Prompt | model | output_parser 형식으로 구성
프롬프트 엔지니어링 기법 지원
역할 기반 메시지: ChatPromptTemplate.from_messages 메소드를 사용하여 Human, AI, System 와 같은 역할 기반 메시지를 명시적으로 정의
퓨삿 프롬프팅: FewShotChatMessagePromptTemplate 모델 동작에 영향에 미치는 예시를 사전에 제공할 수 있음
출처: Prompt Engineering vs. RAG vs. Finetuning: What’s the Difference?
StringOutputParser
언어모델의 출력값을 다루기 쉬운 문자열로 변환하기 위해 사용함
LLM이나 챗봇 모델은 단순히 텍스트만 변환하는 것이 아니라 AIMessage, ChatMessage와 같은 복잡한 객체 형태로 출력하기 때문에 순수한 텍스트 내용을 추출하기 위한 방법
3. 기타
3.1. Pydantic 사용하는 이유
파이썬은 동적언어여서 자료형이 사전에 선언되지 않음
타입 힌트는 힌트일 뿐이며 데이터 유효성 검사를 위해 Pydantic를 사용하여 출력 자료형을 구체하하는것
3.2. RAG을 사용해야하는 이유
지식의 단절, 특정 시점까지만 LLM이 학습하기 때문
context window의 한계, 기억 메모리가 무한하지 않음
벡터 DB는 기존 DB가 정확히 요청한 단어만 찾는것과 달리, 유사한 단어를 찾아 응답결과를 좀더 풍성하게 해줌
벡터(색인)과 원본데이터(원자료)를 모두 저장하여 유사한 색인을 찾아 결과를 반환하는 형태로 구현됨
3.3. 메모리를 기억하기 위한 방법
이 부분 확실하지 않음. 애초에 LLM은 stateless 하기 떄문에 정보를 저장하는게 중요.chat_message 메소드에 이전 대화 기록을 AI message, Human Message등을 저장하고 멀티턴으로 구현하는 방법도 있으나 context limt 때문에 적절하지 않을 수 있음. 검색한 결과 다음 메서드가 있는 것을 확인
이번 글은 NVIDIA의 certificate 중 하나인 Prompt Engeering 자격증에 대한 취득 과정을 기술합니다. 또한, 학습과정에서 NotebookLM, GPTs, 노션AI를 활용해서 효과적으로 학습한 후기를 함께 남깁니다. 추후 다른 자격증을 공부하실 때 활용할 수 있는 좋은 레퍼런스가 될 수 있길 바랍니다.
인증 자격 대상이 된다면 다음 링크에 지원서를 작성합니다. Application 링크 저는 소속 기업이 있어서 스폰을 받아 지원했고, experience와 delivery plan을 집중적으로 적는게 권장됩니다. 내가 어떤 경험이 있고 이 자격을 획득하여 어떻게 사용할 것인지 기술하는 과정입니다. 정상적으로 접수되면 수 일 내 등록된 이메일로 연락이 오며, 보통 Monthly하게 학습 코호트가 시작되어 저는 바로 6월에 참여할 수 있었습니다. 해당 참여 코호트 안에 교육 이수와 최종 인터뷰까지 하는 것이 필수적으로 요구됩니다.
Student Assesment: 자체적으로 운영하는 Jupyter notebook 플랫폼에서 실습를 하는 과정입니다. 2주간 소요됩니다.
Review Instructor video: (선택사항) Assesment를 이수하면 제공되는 해설 강의입니다.
Certification Interview: 최종 통과를 위한 화상 면접(영어)이 진행됩니다.
2. 이수 진행
2.1. Student Assement 개요
Student Assessment가 가장 투자 시간을 많이 하는 부분입니다. 기본적인 프롬프트 엔지니어링 기술과 함께 LCEL, Pydantic, Gradio 와 같은 프레임 워크를 알려줍니다. 하지만 정작 평가는 간단히 자연어로 프롬프팅하면 통과가 되는 쉬운 문제로 구성되어 있습니다.
교안 자체는 Jupyter notebook으로 코드가 작성되어 실행만하면 대부분 원하는 결과를 얻을 수 있지만 이 학습 방식이 생각보다 굉장히 지루했습니다. 사실 영어라서 눈에 잘 안들어오기도 하고, 이미 작성된 코드 + 추상화된 Langchain 코드의 특성상 안에 들어가는 원리를 파악하는데는 큰 도움이 되지 않았습니다. 서버에서 이미 패키징된 NVIDIA api를 사용해서 실습하는 방식인데, 저는 로컬에서 직접하고 싶어서 Container에 가입하고 했는데, 세상에 NVIDIA에 한국 verification이 없습니다 :< 통신사 이슈인 것 같은데, 그래서 그냥 gemini로 변경해서 진행했습니다.
API key를 얻기 위해서 Verification 필요
그 과정에서 Langchain의 공식 Docs는 물론 Teddynote님이 작성하신 랭체인노트도 참고를 했습니다. 프롬프트 엔지니어링부분만 본다면 사실 많은 클래스와 메소드를 사용하지는 않지만, 워낙 Langchain이 클래스와 그 클래스를 상속한 다른 클래스가 많아서 가독성이 좀 좋진 않았습니다.
2.2. 학습 방법: NotebookLM
추가적으로 이번에 NotebookLM을 사용해봤는데, 학습에 필요한 링크나 자료(pdf)등을 업로드 하면 RAG를 자체적으로 구축하여 질의응답을 할 수 있는 시스템입니다. 다 넣어놓고 핵심 부분을 뽑아달라고 하거나 아니면 개인적으로 궁금한 것들을 대화형으로 공부하니까 훨씬 집중이 잘되었습니다. 개인적으로 진짜 학습하기 좋은 환경인 것 같네요.
자료가 올라간 NotebookLM
3. 면접
3.1. 영어 면접 준비 - GPTs
Assessment는 충분한 시간을 가지고 문제를 풀 수 있지만 문제는 인터뷰 입니다. 교육에 관련하여 일정이나 Timeline을 알려주는 DLI 담당자가 미국에 있어서 새벽에 볼 줄 알았는데 다행이 대만에 Principle Instructor가 있어서 주간 시간 내에 볼 수 있었습니다. 프롬프트 엔지니어링과 그 기반의 이론들은 한국어로 설명하려면 어렵진 않지만 영어로 표현이 잘 안되어서 GPTs에 자연어로 빌드해놓고 공부했습니다. 확실히 다른 LLM과 달리 ChatGPT에서 지원하는 GPTs 만큼은 음성으로 대화도 편리하게 잘되고 LLM에 대한 프로토 타이핑 관점에서 유용하게 쓸만한 것 같아서 여전히 ChatGPT가 매력적인 포지션을 가지고 있는 것 같습니다. 또 면접 시작 전 30분 정도는 ChatGPT 어플과 영어로 대화하면서 입을 풀었습니다.
3.2. 면접 과정
프롬프트 엔지니어링의 수행 방법은 간단하고 쉽지만 그 기반에 대한 질문들이 많이 나왔습니다. 처음부터 토크나이징, 벡터화, one-hot encoding 의 정의와 차이점을 기술하라 등 부터 시작하여, Runnable, Tempature와 같은 Langchain와 LLM에 관련된 핵심 개념들을 질의응답 했습니다. 생각보다 Langchain의 핵심 메소드나 클래스에 대한 질문은 덜 했고 이론을 위주로 티키타카하는 시간이였습니다. 30분간 진행해서 처음에는 집중력이 좋았지만, 후에 갈수록 질문을 잘 못듣고 놓치는 상황이 발생해서 조금 아쉬웠습니다.
3.3. 면접 후 정리: 노션 AI
요즘 Notion에서 노트AI라고 회의 내용을 저장하고 요약해주는 기능을 제공합니다. 면접과정에 이걸 켜놓고 복기하기 위한 수단으로 사용했습니다. 처음 당시는 무료로 시간제한도 없고 실시간 streaming하게 적어나가는 모습이 보였는데, 서버 부하 때문인지 녹음 시간이 제한이 되기 시작했습니다. 그래도 접근성도 좋고 편의성도 좋은 툴이라 복기할 때 잘 썼습니다.
4. 후기
미루고 미루던 Langchain을 접할 기회가 있어서 좋았습니다. 일과 병행하느라 처음에는 적잖이 집중을 못했는데 다양한 AI툴과 나의 학습방법을 갖춰나가니 조금 더 정리하는 시간이 되어서 매우 좋았습니다. 관련하여 더 괜찮은 자격증이 있으면 추후 학습 기회로 삼아볼 생각입니다. 프롬프트 엔지니어링에 대한 공부 내용과 레퍼런스는 다음 글에 작성해놓았으니 참고하시길 바랍니다!
이번 글에서는 NVIDA DLI Course에서 수행한 과정에서 LLMs 특성과 그를 보완하기 위한 방법에 대해서 작성합니다. 프롬프트엔지니어링이 무엇인지 그리고 Langchian으로 어떤 클래스와 메소드를 이용해서 구현하는지 알아보겠습니다.
1. LLM이 무엇인가?
LLM은 2017년 Google 발표한 Transformer를 기반으로하는 딥러닝 아키텍처. 핵심은 문맥을 이해하기 위해 단어 간의 관계를 계산하여 토크나이징과 벡터화를 이용하여 정보를 추상화
딥러닝은 행렬과 가중치로 데이터를 저장. 음악 믹서로 비교하자면, 보컬,드럼,베이스에 대한 소리를 조절하는 슬라이더가 있고, 그 슬라이더의 위치(가중치)를 바꾸면서 음악을 만들어내는 것과 같음. 수십개의 슬라이더의 조합이 행렬이라고 할 수 있음
이 가중치는 사전 학습(Pretrain)때 정해지므로 내부 규칙이자 고정된 노하우. 내가 프롬프트를 한다고 해서 이 고정된 규칙이 변하는게 아니라 context window가 계속 추가하고 변화되기 때문에 결과값이 변하는 것처럼 느껴지는 것
LLM의 특징
장점: 강력한 기능과 광범위한 활용성
단점: 할루시네이션에 대한 문제
2. LLM의 단점의 보완 대책
프롬프트 엔지니어링: 원하는 응답을 얻기 위해 효과적으로 소통하는 방식
Chain of Thought: LLM이 복잡한 문제를 중간 단계로 분해하여 생각하도록 유도하는 복잡한 추론 능력을 향상시킴. 명시적인 예시 / 단계별로 생각을 유도 / 작업 과정을 보여주게 하여 보완
검색 증강 생성(RAG): LLM의 지식 한계를 보완하기 위해 외부 지식과 LLM을 결합하는 기술, 문맥적으로 관련성 높은 응답을 제공. 이 때 코사인 유사도를 통해 의미 유사도를 벡터 검색함
가드레일: 신뢰있는 LLM을 구축하기 위한 제약조건과 규칙. 부적절한/유해한 응답을 방지
3. What is Langchain?
LangChain은 이러한 기반 어플리케이션 개발을 간소화하고 유연하게 만드는오픈소스 프레임워크. 상당한 추상화를 제공하여 초보자도 쉽게 접근할 수 있는 장점이 있으나, 지나친 추상화로 인한 디버깅이 힘든 단점이 존재하기도 함
핵심 개념
Runnable: LLM의 인스턴스로, 기본 작업 단위. RunnableLambda를 이용해 사용자정의함수를 Runnable로 변환 가능
LCEL: LangChainExpressionLanguage Runnable을 체인으로 구성하는 선언적인 방ㅇ식 제공
표준화된 메소드: invoke, batch, stream 표준 호출 메소드를 제공합니다.
프롬프트 엔지니어링 기법 지원
역할 기반 메시지: ChatPromptTemplate.from_messages 메소드를 사용하여 Human, AI, System 와 같은 역할 기반 메시지를 명시적으로 정의
퓨삿 프롬프팅: FewShotChatMessagePromptTemplate 모델 동작에 영향에 미치는 예시를 사전에 제공할 수 있음
프롬프트 엔지니어링 관련 Lanchain 디렉토리
#langchain_core
runnables.base # Runnable
├── Runnable : 기본 단위
├── RunnableLambda: 함수를 Runnable로 변환
├── RunnableParallel:
│
langchain_core.prompts.chat
├── ChatPromptTemplate
│ ├── from_messages(): reate a chat prompt template from a variety of message formats.
│ # 튜플 형식, "SystemMessage" 등의 키워드 사용 가능
├── few_shot.FewShotPromptTemplate: fewshot 제공
│
output_parsers.string
├──StrOutputParser: llm이 반환하는 결과를 문자형으로 변환
#llm api class
langchain_google_genai
├──ChatGoogleGenerativeAI
│ ├──invoke()
│ ├──stream()
│ ├──batch()
4. 용어집(Glossary)
대분류
소분류
설명
Prompt Engineering
Prompt Engineering
LLM의 가진 본질적인 특성 할루시네이션을 제어하고 원하는 결과를 도출하기 위한 방방법
Prompting
LLM에게 작업을 지시하는 행위 그 자체
Prompt Template
프롬프트의 구조를 미리 만들어 놓고 변수를 주입항여 재사용성을 높이는 도구
System Messages and System Context
모델의 역할, 성격, 행동 지침을 설정하는 시스템 레벨의 지시어
Chain-of-Thought
모델이 복잡한 문제를 풀 때, 생각 과정을 단계별로 서술하게 항여 정확도를 높이는 프롬프트 기법
Few-shot Classification
몇 가지 예시(few-shot)을 프롬프트에 포함하여 모델이 특정 패턴이나 분류 기준을 학습하게 하는 기법
Prompt Injection
악의적인 사용자가 프롬프트를 조작하여 개발자가 의도하지 않은 동작을 유도하는 보안 공격
개발 프레임워크 및 도구
LangChain
LLM을 외부 데이터 및 다른 서비스와 쉽게 연동하여 어플리케이션을 만들도록 돕는 개발 프레임워크
LCEL
Langchain의 여러 컴포넌트(Runnable)을 파이프라인으로 직관적으로 연결할 수 있게 하는 선언형 문법
Runnables
LCEL을 구성하는 기본 단위
Gradio and Chatbots
머신러닝 모델의 UI를 빠르게 만들어 프로토 타이핑하고 공유할 수 있는 도구
Pydantic
Python에서 데이터 유효성검사와 구조화를 쉽게 해주는 라이브러리
고급 어플리케이션 패턴
Agents
LLM과 RAG를 포함한 다양한 기술(플러그인, API)을 활용하여 사용자의 질문을 처리하고 실제 행동을 수행할 수 있는 인공지능 시스템
Retrieval Augmented Generation (RAG)
LLM의 추상화된 벡터에 의존하지 않고 외부 데이터베이스에서 정보를 검색하여 답변을 생성(Generation)하는 기술
Structured Data Generation
LLM이 단순 텍스트가 아닌 JSON/XML 등 정해진 형식의 구조화된 데이터를 생성하도록 하는 작업
LLM 모델 및 동작 제어
SOTA LLM models (ChatGPT, LlamaX, etc.)
현재 최고 성능을 보이는 모델들
Temperature
모델 답변 생성시 무작위성을 조절하는 파라미터, 높을수록 창의적
Instruction fine tuning
특정 작업이나 스타일에 맞게 응답하도록 사전 학습된 LLM을 명령어 데이터셋으로 학습시키는 과정. zero-shot에도 잘 작동할 수 있게됨
Hallucinations
다음 단어를 예측하는 LLM의 특징 때문에 일어나는 현상이며, 실제로 사실이 아닌데 사실 인 것처럼 말하는 현상
데이터 처리 및 인프라
JSON
JavaScript Object Notion.key-value 쌍으로 이루어진 데이터 교환 포맷.
Streaming vs. Batching
스트리밍은 결과가 생성되는 즉시 실시간으로 전송하는 방식, 배치는 한 번에 처리하는 방식
Nvidia NIM
NVIDIA Inference Microservice, 쿠버네틱스 기반 마이크로서비스 세트
from dotenv import load_dotenv
import getpass
import os
load_dotenv(verbose = True)
# os.getenv("GOOGLE_API_KEY")
if "GOOGLE_API_KEY" not in os.environ:
os.environ["GOOGLE_API_KEY"] = getpass.getpass("Enter your Google AI API key: ")
NVIDA에서 모델 불러올 수 있는데 황당한건 모델 컨테이너 사이트에서 한국인증이 아직 안됩니다.. 어째서..?
2. 본문 불러오기
from langchain_google_genai import ChatGoogleGenerativeAI
llm = ChatGoogleGenerativeAI(model="gemini-2.0-flash")
result = llm.invoke('What is OMSCS?')
print(result.content)
"""
OMSCS stands for **Online Master of Science in Computer Science** offered by the **Georgia Institute of Technology (Georgia Tech)**.
Here's a breakdown of what makes it significant:
* **Reputable Institution:** It's a fully online master's degree from a top-ranked computer science program. Georgia Tech is highly respected in the field.
* **Affordable:** Compared to traditional on-campus master's programs, OMSCS is significantly more affordable. This makes it accessible to a wider range of students.
* **Flexible:** The online format allows students to study at their own pace and on their own schedule, making it ideal for working professionals.
* **Rigorous Curriculum:** The program covers a wide range of computer science topics and maintains a high academic standard. It is not a "watered down" version of the on-campus program.
* **Diverse Specializations:** Students can choose to specialize in areas such as:
"""
3. 스트리밍과 배치
invoke와 대응되게 대답을 받는 방법이며, streaming은 동기적으로 batch는 비동기 형식으로 대답을 반환
# llm이 뱉어내는 결과를 스트리밍하게 밷어낼 수 있다.
# invoke는 동기식, stream은 비동기식으로 결과를 받아온다.
prompt = "What is OMSCS?"
for chunk in llm.stream(prompt):
print(chunk.content, end='')
#batch 식
prompts = [
'What is OMSCS?',
'What is the capital of France?',
'What is the largest mammal?'
]
results = llm.batch(prompts)
for result in results:
print(result.content)
4. 템플릿을 이용한 재사용
def translate_to_french(text):
prompt = f"Translate the following English text to French: '{text}'"
return llm.invoke(prompt).content
english_statsments = [
"Hello, how are you?",
"What is your name?",
"I love programming.",
"The weather is nice today."
]
prompts = [translate_to_french(statement) for statement in english_statsments]
prompts
"""
['Here are a few options for translating "Hello, how are you?" into French, with slightly different nuances:\n\n* **Bonjour, comment allez-vous ?** (Formal, polite. Use with people you don\'t know well, or in professional settings.)\n\n* **Salut, comment vas-tu ?** (Informal, friendly. Use with friends, family, and people you know well.)\n\n* **Bonjour, ça va ?** (Informal, but very common. A general greeting, like "Hi, how\'s it going?")\n\n* **Salut, ça va ?** (Even more informal, like "Hey, what\'s up?")\n\nThe best choice depends on the context and your relationship with the person you\'re speaking to.',
'The most common and polite translation of "What is your name?" in French is:\n\n**Comment vous appelez-vous ?**\n\nHere are a few other options, with slightly different connotations:\n\n* **Quel est votre nom ?** (More formal, literally "What is your name?")\n* **Tu t\'appelles comment ?** (Informal, used with people you know or are on familiar terms with)\n* **Comment tu t\'appelles ?** (Also informal, but slightly more direct than "Tu t\'appelles comment ?")\n\nThe best choice depends on the context and your relationship with the person you\'re asking. However, "Comment vous appelez-vous ?" is generally the safest and most appropriate option.',
'The most common and direct translation of "I love programming" in French is:\n\n**J\'adore la programmation.**\n\nHere are a few other options, with slightly different nuances:\n\n* **J\'aime la programmation.** (This is also very common and means "I like programming," but can also imply love in some contexts)\n\n* **J\'aime beaucoup la programmation.** (This emphasizes the liking, "I like programming a lot")\n\n* **Je suis passionné(e) par la programmation.** (This means "I am passionate about programming." Use "passionné" if you are male, and "passionnée" if you are female.)\n\n* **La programmation, c\'est ma passion.** (This means "Programming is my passion.")\n\nThe best choice depends on the specific context and the degree of enthusiasm you want to convey. However, **J\'adore la programmation** is generally the safest and most natural translation for "I love programming."',
'There are a few ways to translate "The weather is nice today" into French, depending on the nuance you want to convey:\n\n* **Il fait beau aujourd\'hui.** (This is the most common and straightforward translation. It means "The weather is good today.")\n\n* **Le temps est agréable aujourd\'hui.** (This is a slightly more formal way of saying it, and means "The weather is pleasant today.")\n\n* **On a du beau temps aujourd\'hui.** (This is a more colloquial way of saying it, and translates to "We have nice weather today.")\n\nSo, the best option depends on the context, but **Il fait beau aujourd\'hui** is generally the safest and most widely understood.']
"""
translations = llm.batch(prompts)
for translation in translations:
print('---')
print(translation.content)
"""
---
This is a great and accurate breakdown of the different ways to say "Hello, how are you?" in French! You've covered the key distinctions of formality and provided helpful context for each option.
Here are a few minor additions that could further enhance this explanation:
"""
#template 으로 프롬프트 엔지니어링 하기
from langchain_core.prompts import ChatPromptTemplate
#사전에 템플릿을 만들어 runnable을 만드는 방식
english_to_spanish_template = ChatPromptTemplate.from_template("""Translate the following English text to Spanish Provide only the translated text: {english_statement}""")
prompt = english_to_spanish_template.invoke('Hello, how are you?')
print(llm.invoke(prompt).content)
6. 예시
다음 문장들을 가지고 3가지(감성분석, 메인 토픽 추출, 다음에 올 질문 만들기)
statements = [
"I had a fantastic time hiking up the mountain yesterday.",
"The new restaurant downtwon serves delicious vegeterian dishes.",
"I am feeling quite stressed about the upcoming project deadline.",
"Watching the sunsset at the beach was a calming exmperience.",
"I recently started reading a fascinating book about space exploration.",
]
sentiment_template = ChatPromptTemplate.from_template("In a single word, either 'positive' or 'negative' provide the overall sentiment of " \
"following piece of text: {text}")
main_topic_template = ChatPromptTemplate.from_template("Identify main topic with one sentence about following piece of text: {text}")
followup_template = ChatPromptTemplate.from_template("what is followup just one question about following piece of text: {text}")
sentiment_prompts = [sentiment_template.invoke({"text":statement}) for statement in statements ]
main_prompts = [main_topic_template.invoke({"text":statement}) for statement in statements ]
followup_prompts = [followup_template.invoke({"text":statement}) for statement in statements ]
sentiments = llm.batch(sentiment_prompts)
main_topics = llm.batch(main_prompts)
followups = llm.batch(followup_prompts)
for statement, sentiment, main_topic, followup in zip(statements, sentiments, main_topics, followups):
print(
f"Statement : {statement}\n"
f"Overall sentiment : {sentiment.content}\n"
f"Main topic : {main_topic.content}\n"
f"Followup question : {followup.content}"
)