회고기간 : 2025.04.21월~2025.04.25금
이번 주차는 langchain에 대해 배웠다
LangChain
LangChain 은 LLM의 기능을 확장하고 체계화하여 복잡한 애플리케이션을 구축할 수 있도록 지원하는 프레임워크다.
여러 프롬프트, 도구, 데이터 소스를 체인으로 연결해 효율적으로 작업을 수행할 수 있다.
1. Prompt Template
프롬프트 템플릿은 반복적인 작업에서 재사용 가능한 프롬프트를 설계하고, 동적 입력 변수를 통해 작업을 수행하는 구조
- 자동화된 입력 구성
- 대화형 응답
- 샘플 기반 학습
- 결과 파싱
키를 활용하기 전 환경변수를 로드하는 것은 필수!
from dotenv import load_dotenv
load_dotenv()
프롬프트 예시 (few shot)
from langchain.prompts import FewShotPromptTemplate
examples = [
{"question" : "2 + 2 는 무엇인가요?", "answer" : "2 + 2 = 4"},
{"question" : "3 + 4 는 무엇인가요?", "answer" : "3 + 4 = 7"}
]
example_prompt = PromptTemplate(
template="Q : {question} \nA : {answer}",
input_variables=['question', 'answer']
)
fewshot_prompt = FewShotPromptTemplate(
examples=examples,
example_prompt=example_prompt,
prefix="다음 계산 문제를 해결하세요",
suffix="Q : {question} 은 무엇인가요?\nA:",
input_variables=['question']
)
print(fewshot_prompt.format(question='34 + 78'))
<출력>
다음 계산 문제를 해결하세요
Q : 2 + 2 는 무엇인가요?
A : 2 + 2 = 4
Q : 3 + 4 는 무엇인가요?
A : 3 + 4 = 7
Q : 34 + 78 은 무엇인가요?
A:
2. Output Parser
Output Parsers 는 LLM이 생성한 텍스트 출력을 특정 형식으로 변환하거나 처리하는 데 사용된다.
이는 모델의 응답을 해석하고, 이를 구조화된 데이터로 바꿔 후속 작업에 활용하기 위해 설계된다.
ex ) LLM 응답이 name:John, Age:30 이라면 -> 딕셔너리 형태로 바꿔줌
[output parser의 주요 메서드]
- get_format_instructions()
- 언어 모델이 출력해야 할 정보의 형식을 정의하는 지침(instruction) 을 제공
- parser()
- 언어 모델의 출력(문자열로 가정)을 받아들여 이를 특정 구조로 분석하고 변환
[output parser의 종류]
- BaseOutputParser: Output Parsers의 기본 클래스, 커스텀 파서 구현 시 사용한다.
- CommaSeparatedListOutputParser: 콤마로 구분된 문자열을 리스트로 변환한다.
- RegexParser: 정규식을 사용해 특정 패턴을 추출하고 키-값 형태로 반환한다.
- StructuredOutputParser: 출력의 JSON 또는 구조화된 형식을 강제한다.
- PydanticOutputParser: Pydantic 모델을 기반으로 출력 검증 및 변환한다.
- MarkdownOutputParser: 마크다운 형식의 텍스트에서 데이터를 추출한다.
# OutputParser 인스턴트 및 PromptTemplate 인스턴스 생성
from langchain_openai import ChatOpenAI
from langchain.output_parsers import CommaSeparatedListOutputParser
output_parser = CommaSeparatedListOutputParser()
format_instructions = output_parser.get_format_instructions() # 파싱해주는 형식 정보
prompt_tpl = PromptTemplate(
template="{subject} 5개의 팀을 알려주세요. \n형식 지정 : {format}",
input_variables=['subject'], # 사용자 입력 변수
partial_variables={'format' : format_instructions} # 고정 설정 변수
)
# 프롬프트 생성
query = "한국의 프로야구팀"
prompt = prompt_tpl.format(subject=query)
print(prompt)
# open ai api를 사용하기 위한 인스턴스 생성 및 요청 처리
model = ChatOpenAI(
model_name="gpt-4o-mini",
temperature=0,
max_tokens=2048
)
response = model.invoke(prompt) # prompt에 질의 보냄
# content 출력하기
print(response.content)
print(type(response.content))
# 형식 변경해주기
print(output_parser.parse(response.content))
print(type(output_parser.parse(response.content)))
<출력>
['두산 베어스', 'LG 트윈스', '삼성 라이온즈', '키움 히어로즈', 'NC 다이노스']
<class 'list'>
3. Chain
체인은 여러 작업 단계를 순차적으로 연결해 작업을 수행하는 LangChain의 핵심 개념이다. 각 체인은 다양한 구성 요소를 단계별로 연결하여 더 복잡한 태스크를 처리할 수 있도록 한다.
[output parser의 종류]
- Simple Chains
- 하나의 입력과 출력으로 구성된 가장 단순한 체인
- 예: 입력 프롬프트를 생성하고, LLM의 응답을 출력
- Sequential Chains
- 여러 단계를 순차적으로 실행하는 체인
- 각 단계의 출력이 다음 단계의 입력으로 사용
- 예: 텍스트 요약 → 질문 생성
- Conditonal Chains
- 특정 조건에 따라 다른 체인을 실행한다
- 예: 입력 유형에 따라 다양한 프롬프트를 사용
- Memory Chains
- 대화형 응용 프로그램에 적합하며, 이전 데이터를 저장 및 참조한다
- 예: 챗봇 응용 프로그램
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
prompt = ChatPromptTemplate.from_messages([
('system', '너는 {skill}을 잘하는 AI 어시스턴스야.'),
MessagesPlaceholder(variable_name='history'), # 메세지 목록을 전달하는 데 사용
('human', '{query}')
])
model = ChatOpenAI(model_name='gpt-4o-mini', temperature=0.5)
chain = prompt | model ##### 프롬프트와 model을 순서대로 작동되도록 연결
4. Agent & Tool
에이전트(Agent) 는 LLM이 외부 도구와 상호작용하며 복잡한 작업을 처리하는 시스템이다.
계산, 데이터 검색, API 호출 등 여러 단계를 자동으로 실행할 수 있다.
도구(Tool) 는 에이전트가 외부 작업(계산, 데이터 검색, API 호출 등)을 수행할 수 있도록 돕는 기능이다.에이전트는 도구를 활용해 LLM의 한계를 보완하고 복잡한 작업을 처리한다.
from langchain.agents import AgentType, initialize_agent, load_tools
tools = load_tools(['wikipedia', 'llm-math'], llm=model) # load_tools : 툴 사용
# 위키피디아와 수학연산자(llm 기반)
agent = initialize_agent( # initialize_agent : agent 생성
tools,
model,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, # AgentType : 프롬프트 추론 방식
handle_parsing_error=True,
verbose=True
)
사용예시 : agent.invoke('3+4'는 ?)
5. Memory
메모리(Memory) 는 LLM이 대화나 작업의 문맥을 유지하도록 지원하는 기능으로, 이전 대화 내용이나 작업 결과를 기억해 일관성 있는 응답을 생성한다.
chain_with_history = RunnableWithMessageHistory(
chain,
get_session_history=get_by_session_id, # 세션 기록을 가져오는 함수
input_messages_key='query', # 입력 메시지의 키
history_messages_key='history' # 기록 메시지의 키
)
이러한 방식으로 session_id를 입력하면 이전 대화를 불러와 대화가 가능하다.
6. RAG ⭐⭐⭐⭐
RAG (Retrieval-Augmented Generation) 는 Vector Database 와 LLM을 결합하여 정보 검색과 생성을 통합하는 방법론
[ RAG 워크플로우 ] == 크게 두가지로 나눠 진행된다.
< Indexing Phase >
1. 도큐먼트 로드
from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader('./data/snow-white.pdf')
documents = loader.load()
# 개행문자 제거
for doc in documents:
doc.page_content = doc.page_content.replace('\n', ' ')
documents
2. 텍스트 분할
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=100, # 각 chunk의 최대 문자 수 (기본값: 1000)
chunk_overlap=20 # 인접한 텍스트 조각 간 겹치는 문자 수 (기본값: 200)
) # seperators: 텍스트 분할 구분자 우선순위 (기본값: ['\n\n', '\n', ' ', ''])
docs = splitter.split_documents(documents)
docs
3. 임베딩(벡터 스토어 저장)
# 임베딩 모델 생성
from langchain_openai.embeddings import OpenAIEmbeddings
embedding_model = OpenAIEmbeddings(model='text-embedding-3-small')
!pip install langchain-chroma
from langchain_chroma.vectorstores import Chroma
vector_store = Chroma.from_documents(docs, embedding_model)
# Retriever을 사용한 유사도 기반 검색
query = "백설공주와 왕비 중에 누가 더 아름답나요?"
# vector store 직접 조회
retrievals = vector_store.similarity_search_with_score(query)
retrievals
# Retriever를 사용한 검색
retriever = vector_store.as_retriever(
search_type='similarity',
search_kwargs={'k': 3}
)
retriever_result = retriever.batch([query])
retriever_result
< Retrieval and Generation Phase >
1. 프롬프트 생성
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate([
("system", "당신은 어린 아이에게 꿈과 희망을 심어주는 유치원 교사입니다. 질문하는 아이에게 최대한 호응하면서 context 기반으로만 답변해 주세요."),
("user", """
어린이의 질문에 context만을 이용해 답변하세요.
질문: {query}
context: {context}
""")
])
prompt.invoke({'query': query, 'context': retrievals})
2. LLM 모델 생성
from langchain_openai import ChatOpenAI
model = ChatOpenAI(
model_name='gpt-4o-mini',
temperature=0.5
)
3. 체인 생성
from langchain_core.output_parsers import StrOutputParser
# context 생성
query = "왕비가 백설공주에게 먹인 것은 무엇인가요?"
retrievals = retriever.batch([query])
context_text = "\n".join([doc.page_content for doc in retrievals[0]])
chain = prompt | model | StrOutputParser()
4. 사용
chain.invoke({'query': query, 'context': context_text})
<출력>
'왕비가 백설공주에게 먹인 것은 맛있어 보이는 사과였어요. 그런데 그 사과에는 독이 발라져 있었답니다. 왕비는 백설공주를 속이기 위해 과일 장수로 변장하고 사과를 가지고 갔어요. 정말 무서운 이야기지만, 백설공주와 난쟁이들이 결국에는 잘 이겨낼 거예요!'
7. CoT
Chain of Thought (CoT) 는 LLM이 복잡한 문제를 해결하기 위해 단계적 사고 과정을 명시적으로 전개하도록 설계된 프롬프트 전략이다.
이는 수학 문제, 논리 퍼즐, 과학적 추론 등 복잡한 작업에서 정확성을 향상시킨다.
💡 CoT의 핵심은 "단계적 사고 과정을 밟는 것" 이다. 따라서 프롬프팅을 다르게 적용해보도록 하자
# 일반 프롬프트
prompt = '125 x 31은 얼마인가요?'
# Few-shot COT 적용 프롬프트
few_shot_cot = """
Q: 123 x 31 은 얼마인가요?
A:
1. 123를 분해합니다: 123 = 100 + 20 + 3
2. 각 항을 31과 곱합니다:
- 100 x 31 = 3100
- 20 x 31 = 620
- 3 x 31 = 93
3. 이제 이 결과들을 더합니다:
- 3100 + 620 + 93
4. 계산을 진행하면:
- 3100 + 620 = 3720
- 3720 + 93 = 3813
따라서, 123 x 31 = 3813입니다.
Q : 789 x 56 은 얼마인가요?
A :
"""
# 일반 프롬프트 응답
res = client.chat.completions.create(
model = 'gpt-4',
messages=[{"role" : "user", "content":prompt}]
)
# 퓨샷 프롬프트 응답 (CoT)
cot_res = client.chat.completions.create(
model = 'gpt-4',
messages=[{"role" : "user", "content" : cot_prompt}]
)
# res로 응답 받아오기
print(res.choices[0].message.content)
# cot_res로 응답 받아오기
print(cot_res.choices[0].message.content)
<출력>
# 일반 프롬프트 응답 (res)
125 x 31 = 3875
# Few shot 프롬프트 응답(cot)
125 x 31을 계산하려면, 다음의 단계를 따릅니다.
1. 먼저, 1 x 125을 계산하면, 그 결과는 125입니다.
2. 다음으로, 3 x 125는 375이며, 이는 실제로는 30 x 125입니다.
3. 마지막으로, 이 두 결과를 더하면 답이 나옵니다: 125 (1 x 125의 결과) + 3750 (30 x 125의 결과) = 3875
따라서, 125 x 31은 3875입니다.
💡 Keep
교육을 듣기 전, 학교에서 langchain 관련 프로젝트를 했었기 때문인지 langchain이 조금은 익숙하게 다룰 수 있어 좋았다 (아직 덜 까먹은 것 같아 기분이 좋았다ㅋㅋ..)그치만 복습은 제때제때 해야함을 매번 깨닫는다. 이제는 한번 놓치면 돌아올 수 없는 강을 건너버리는...
⚠️ Problem
1. 개인 프로젝트에서 runpod으로 gpu 환경을 돌리는데 pod 관리를 잘 못하는 것 같다.
프로젝트 설계에서 뼈대를 잡고 로직을 구현한 후 기동을 시켜야하는데 계속 오류가 나니까 이도 저도 못하면서 gpu만 날린다
큰 그림을 그리고 프로세스를 잡아가면서 개발을 해야함을 느끼는 요즘이다.
2. langchain 내용만 익숙하다뿐이지 새로운 패키지나 모델이 있으면 바로바로 적용하는 데에 시간이 걸리는 것 같다
연습해야지 머
🔥 Try
복습과 운동 꾸준히!!
(진짜 심각한 문젠데 안그러다가 요즘 버스 탈때마저도 헉헉댄다,,, 체력관리가 시급하다)

'SKN > Remind' 카테고리의 다른 글
| sk네트웍스 family AI 캠프 11기 5월 1주차 회고록 (0) | 2025.05.12 |
|---|---|
| sk네트웍스 family AI 캠프 11기 4월 5주차 회고록 (1) | 2025.05.04 |
| sk네트웍스 family AI 캠프 11기 4월 3주차 회고록 (1) | 2025.04.20 |
| sk네트웍스 family AI 캠프 11기 4월 1주차 회고록 (0) | 2025.04.07 |
| sk네트웍스 family AI 캠프 11기 3월 3주차 회고록 (0) | 2025.03.24 |