본문 바로가기
인공지능/생성형 AI

[생성형 AI] LangChain 기초: LLM과 프롬프트 엔지니어링 실습

by 클레어몬트 2025. 3. 11.

https://claremont.tistory.com/entry/%EC%83%9D%EC%84%B1%ED%98%95-AI-LangChain%EC%9D%B4%EB%9E%80

 

[생성형 AI] LangChain이란?

ㅁLangChain: LLM을 활용하여 응용 프로그램을 개발하는 프레임워크주로 OpenAI의 GPT, Google의 PaLM, Meta의 Llama 등 다양한 LLM과 통합하여 문서 검색, 데이터 분석, 자동화된 AI 응답 시스템 등을 구축하는

claremont.tistory.com

 

 

 

ㅁLangChain(랭체인): 대형 언어 모델(LLM) 기반 애플리케이션을 쉽게 개발할 수 있도록 도와주는 라이브러리

OpenAI의 GPT-4, Meta의 LLaMA, Google의 PaLM 같은 다양한 LLM과 연동할 수 있으며, 문서 검색, 데이터 분석, AI 응답 시스템 등 다양한 AI 기반 애플리케이션을 구축하는 데 활용된다

 

이번 실습을 통해 LangChain의 기본 개념을 익히고, 직접 코드를 실행해 보면서 어떤 가능성이 있는지 탐색했다. 코드를 따라가면서 LLM을 활용한 질의응답, 프롬프트 템플릿, 댓글 자동 분류, Few-Shot Prompting 등을 경험할 수 있었다. 여기에 내가 느낀 점과 직접 시도해 본 것들을 덧붙여 정리해 보았다.


1. LangChain 설치 및 환경 설정

LangChain을 사용하기 위해서는 먼저 필요한 패키지를 설치해야 한다.

pip install langchain_community openai langchain langchain_openai

 

설치 후, OpenAI API 키를 환경 변수에 설정한다.

 

이 부분에서 처음에는 API 키가 정상적으로 설정되지 않는 문제가 발생했는데, 환경 변수를 .zshrc에 추가하는 방법도 있지만, Jupyter Notebook 환경에서는 다음과 같이 직접 설정하는 것이 가장 간편했다. (macOS 기준)

import os
os.environ["OPENAI_API_KEY"] = "your_openai_api_key_here"

 

이제 LangChain을 활용하여 OpenAI의 LLM을 호출할 수 있다.

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model='gpt-4o-mini', temperature=0.5, max_tokens=1024)

 

여기서 temperature 값은 모델의 창의성을 조절하는 역할을 한다. 0에 가까울수록 일관된 답변을, 1에 가까울수록 창의적인 답변을 생성한다.

 

 

 

2. LLM을 이용한 간단한 질의응답

question = "전 세계적으로 흥행한 영화에 나오는 유명한 명대사를 하나 알려주세요. 대사가 나온 배경과 의미도 설명해 주세요."
response = llm.invoke(question)
print(response.content)

 

LangChain에서는 invoke() 메서드를 사용하여 모델과 상호작용한다.
이전에는 llm.predict() 같은 메서드를 사용했지만, 현재는 invoke() 방식이 표준이다.

 

(실제 실행결과 예시)

"May the Force be with you." (스타워즈 시리즈)

 

 

※ OpenAI 최신 모델 활용

이렇게 OpenAI의 o1 모델을 활용할 수도 있다

o1 = ChatOpenAI(model='o1-mini', temperature=1.0, model_kwargs={'max_completion_tokens':25000})
response = o1.invoke("BERT와 같은 인코더 기반 모델이 이후 어떻게 임베딩 모델로 진화했는지 알려주세요.")
print(response.content)
 
 

3. 프롬프트 템플릿 활용한 최적화

LLM을 직접 호출하는 것도 가능하지만, 프롬프트를 일정한 형식으로 정리해 두면 더 효율적이다.
LangChain에서는 PromptTemplate을 사용하여 프롬프트를 체계적으로 구성할 수 있다.

from langchain.prompts import PromptTemplate

explain_template = """
당신은 어려운 용어를 초등학생 수준으로 쉽게 설명하는 챗봇입니다.
{term}에 대해 설명해 주세요.
"""

explain_prompt = PromptTemplate.from_template(template=explain_template)
print(explain_prompt.format(term="트랜스포머 네트워크"))

 

내가 생각하는 이 방식이 유용한 이유

  • 프롬프트를 사전에 정의하고, 여러 입력값을 받아 반복적으로 활용할 수 있다
  • 특정 역할이나 스타일을 부여하여 AI의 응답 일관성을 유지할 수 있다

📌 실제 실행 후 깨달은 점

  • "트랜스포머 네트워크"를 설명하는 방식이 처음에는 너무 기술적이었다
  • "너무 어려운 단어는 피하고, 예시를 들어 쉽게 설명해 주세요." 같은 추가 조건을 넣으면 훨씬 더 나은 결과를 얻을 수 있다
 
 

4. LangChain을 활용한 댓글 자동 분류

이번 실습에서 가장 흥미로웠던 부분은 LangChain을 이용한 댓글 감성 분석(긍정/부정 분류)이었다.

4-1. 데이터 불러오기

import pandas as pd
reviews = pd.read_csv('./1_1.data_reviews.csv')
print(reviews.shape)
print(reviews.head())

 

데이터는 Review(리뷰 내용), Label(긍정/부정)이 포함된 형태였다.

4-2. 기본적인 댓글 분류 프롬프트 설정

system_prompt='''
주어지는 입력이 긍정/부정 중 어떤 내용을 담고 있는지 분류하세요.
분류 결과: 부정, 혹은 분류 결과: 긍정 을 출력하면 됩니다.
위 형식을 지키고, 분류 결과 뒤에는 별도의 내용을 출력하지 마세요.
'''

prompt = ChatPromptTemplate.from_messages([
    ("system", system_prompt),
    ("user", '{review}')
])

4-3. 분류 성능 평가

correct = 0
incorrect = 0
for idx, review, label in zip(reviews['Num'], reviews['Review'], reviews['Label']):
    response = llm.invoke(prompt.format_messages(review=review)).content
    if (label == -1 and '분류 결과: 부정' in response) or (label == 1 and '분류 결과: 긍정' in response):
        correct += 1
    else:
        incorrect += 1

print(f'Accuracy: {correct / (correct + incorrect):.2f}')

 

📌 실행 결과 & 트러블슈팅

  • 처음 실행했을 때, 모델이 "분류 결과: 긍정." 같은 출력 포맷을 정확히 지키지 않았다
  • CoT(Chain of Thought) 방식을 추가하니 성능이 향상됐다
  • "리뷰 내용을 분석한 후, 생각을 정리한 뒤 답변하세요." 같은 추가적인 프롬프트 최적화가 중요했다

5. Few-Shot Prompting 활용

LLM이 단일 예제만 보고 응답하는 것이 아니라, 몇 개의 예시를 학습하도록 하면 더 나은 결과를 얻을 수 있다.
Few-Shot Prompting을 활용하면 적은 샘플을 제공하는 것만으로 모델의 성능을 향상시킬 수 있다.

from langchain.prompts.few_shot import FewShotPromptTemplate

examples = [
    {"question": "Who lived longer, Muhammad Ali or Alan Turing?", "answer": "Muhammad Ali"},
    {"question": "Are both the directors of Jaws and Casino Royale from the same country?", "answer": "No"}
]

example_prompt = PromptTemplate.from_template(template="Question: {question}\n{answer}")

prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_prompt,
    prefix="질문-답변 형식의 예시가 주어집니다. 같은 방식으로 답변하세요.",
    suffix="Question: {input}",
    input_variables=["input"]
)

 

📌 Few-Shot Prompting을 시도하면서 느낀 점

  • 모델이 한두 개의 예시를 보고 학습할 수 있다는 점이 신기했다 ㅎㅎ
  • 예제를 다양하게 제공하면 모델의 성능이 더욱 향상됨을 체감했다 :>
 

 

 

이번 실습을 통해 LangChain의 기본 개념을 익히고, 실제로 적용하면서 프롬프트 엔지니어링, 댓글 자동 분류, Few-Shot Prompting을 경험해 보았다.

 

💡 개인적으로 앞으로 도전해보고 싶은 것

  • 벡터 데이터베이스(Vector DB)와 결합하여 RAG(Retrieval-Augmented Generation) 모델을 직접 구축해 보기
  • 프롬프트 튜닝을 더 정교하게 해서 LLM의 성능을 극대화하기

LangChain의 가능성은 무궁무진하며, 앞으로도 더욱 심화된 연구와 실험을 해보고 싶다! 🚀