AI/LLM

[LLM] LangChain (prompttemplate 과 LCEL)

죵욜이 2025. 2. 19. 01:16

LangChain 이란?

랭체인(LangChain)대형 언어 모델(LLM)을 더 효과적으로 활용할 수 있도록 도와주는 프레임워크 이다

단순히 LLM에 프롬프트를 입력하고 답변을 받는 방식에서 벗어나, 데이터 검색, 메모리 저장, API 연동, 체인(Chain) 구성 등을 가능하게 해 준다.


랭체인의 기본요소

  • 프롬프트
  • LLM

랭체인의 기본은 LLM 에 프롬프트를 넣어주는 것이다

써보면서 익히는게 빠르니 바로해보자

 

먼저 라이브러리 설치와 환경설정부터 한다

pip install langchain-openai
import os
import getpass
os.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI API Key:")
from langchain_openai import ChatOpenAI

# model 생성
model = ChatOpenAI(model="gpt-4o-mini")

# prompt
prompt = "안녕"

# chain 실행
answer = model.invoke(prompt)
print(answer)
  • invoke : LangChain 에서 Chain 또는 Agent 를 실행 하는 함수

이러면 이제 llm 모델을 불러와서 쓸 수 있는것이다.


프롬프트의 정형화 - ChatPromptTemplate

  • ChatPromptTemplate 은 랭체인에서 프롬프트템플릿을 정형화 하고 동적으로 데이터를 삽입하는데 사용하는 클래스
  • 챗봇과 같은 대화형 모델에서 사용되는 프롬프트를 관리하고 쉽게 구성할 수 있게 해주는 클래스 이다.

ChatPromptTemplate의 역할

  • 프롬프트 템플릿화: 여러 프롬프트에 대해 반복적인 부분을 정형화하고, 필요한 변수나 값을 동적으로 삽입할 수 있게 해줍니다.
  • 동적 입력값 처리: 프롬프트에 들어갈 변수를 동적으로 할당할 수 있어서 더 효율적으로 프롬프트를 생성하고 관리할 수 있습니다.
더보기
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI

# LLM model 생성
model = ChatOpenAI(model="gpt-4o-mini")

# prompt 템플릿 생성
# prompt = "말티즈의 고향은?"
prompt = ChatPromptTemplate.from_template("{dog_breeds_input}들의 고향은 어디야?") # 틀

# chain 생성
chain = prompt | model

# chain 실행
answer = chain.invoke({"dog_breeds_input": "말티즈"}) # 변수 안에 들어갈것만 그때그때 설정해주면, 템플릿이 자동으로 프롬프트를 완성해준다!
print(answer)

answer = chain.invoke({"dog_breeds_input": "골든리트리버"}) # 붕어빵
print(answer)

answer = chain.invoke({"dog_breeds_input": "시츄"})
print(answer)

 

또한 템플릿을 사용하면 

프롬프트 = 개발자의 템플릿 + 사용자의 입력

이 될 수 있다.

더보기
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI

# LLM model 생성
model = ChatOpenAI(model="gpt-4o-mini")

# prompt 템플릿 생성
prompt = ChatPromptTemplate.from_template("너는 흉악한 조폭 만득이야. 그리고 나는 너의 보스야. \
무조건 말을 할때 앞에 '네 햄!!!!' 을 붙여야해. 너는 나를 '햄님'이라고 불러.\
내가 무슨 말을 하던, 너는 무조건 과장되게 맞장구를 쳐야해. \
너는 나와의 의리를 가장 중요하게 여겨. \
나의 말에 대답하도록 해.\
나의 말 : {input}") # 프롬프트에 독을탑니다..쿡쿡..

# chain 생성
chain = prompt | model

# 입력받기
user_input = input("입력: ")

# chain 실행
answer = chain.invoke({"input": user_input})
print(answer)

 

또한 페르소나를 부여해 특정 컨셉의 챗봇을 만들 수도 있다.

보통 너는 ㅇㅇㅇ야. 너는 ㅇㅇㅇ해야해. ㅇㅇㅇ로만 대답해. 너는 ㅇㅇㅇ한 성격이야

라고하면 된다

더보기
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI

# LLM model 생성
model = ChatOpenAI(model="gpt-4o-mini")

# prompt 템플릿 생성
prompt = ChatPromptTemplate.from_template("너는 {personality}한 성격의 조폭 만득이야. 그리고 나는 너의 보스야. \
무조건 말을 할때 앞에 '네 햄!!!!' 을 붙여야해. 너는 나를 '햄님'이라고 불러.\
내가 무슨 말을 하던, 너는 무조건 과장되게 맞장구를 쳐야해. \
너는 나와의 의리를 가장 중요하게 여겨. \
나의 말에 대답하도록 해.\
나의 말 : {input}") # 프롬프트에 독을탑니다..쿡쿡..

# chain 생성
chain = prompt | model

# 입력받기
user_input = input("입력: ")

# chain 실행
personality = "의외로 수줍" # 각 챗봇에 맞는 성격을 변수로 정의하기
answer = chain.invoke({"input": user_input, "personality" : personality})
print(answer)

LCEL (LangChain Expression Language) ->  

위 예시코드를 보면 처음보는게 나왔다.

chain = prompt | model
answer = chain.invoke({"input": user_input})

바로  이것인데 체인 안에 요소들을 연결해 주는것이다.

이  사이사이 있는 것들은 컴포넌트 이며 각 컴포넌트는 자신의 결과를 다음 컴포넌트로 넘겨준다

  • 이전 컴포넌트의 결과값 -> 다음 컴포넌트의 입력값

이러한 모습이 마치 체인과 같아서 LangChain 이라는 이름이 붙은 것이다


그렇다면 이  파이프 속에 아무거나 들어갈 수 있을까?

 

 |  파이프 사이에 연결될 수 있는 컴포넌트

  • Runnable 인터페이스
  • '조건'을 만족하는 함수

위에 prompt 나 model 은 랭체인 안에 있는

ChatpromptTemplateChatOpenAI 로 만든것인데

랭체인이 처음부터 Runnable 인터페이스로 만든것이라  파이프 속에 들어갈 수 있는 것이다.

 

 

그렇다면 '조건'  을 만족하는 함수는 무엇인가?

  1. 입력을 받고 출력을 반환하는 형태의 함수
  2. 이전 체인의 출력과 데이터 타입이 호환되어야 함
  3. 다음 체인의 입력돠 데이터 타입이 호환되어야 함
더보기
'''올바른 예시'''
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI

# LLM model 생성
model = ChatOpenAI(model="gpt-4o-mini")

# prompt 템플릿 생성
prompt = ChatPromptTemplate.from_template("{dog_breeds_input}들의 고향은 어디야?")

def my_print(string) :
  return string.content

# chain 생성
chain = prompt | model | my_print

# chain 실행
answer = chain.invoke({"dog_breeds_input": "말티즈"})
print(answer)

자주 쓰이는 runnable component: StrOutputParser()

  • 간단한 모델 출력에서 content 만 그대로 출력할 때
더보기
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser


# LLM model 생성
model = ChatOpenAI(model="gpt-4o-mini")

# prompt 템플릿 생성
prompt = ChatPromptTemplate.from_template("{dog_breeds_input}들의 고향은 어디야?")

# chain 생성
chain = prompt | model | StrOutputParser() # 깔끔하게 출력된다.

# chain 실행
answer = chain.invoke({"dog_breeds_input": "말티즈"})
print(answer)

자주 쓰이는 runnable component: RunnablePassthrough()

  • 입력을 변환하지 않음 : 입력 데이터를 그대로 반환
  • 데이터 검증 또는 테스트용 : 파이프라인에서 데이터 흐름을 확인하거나 테스트할 때 유용
  • 복잡한 체인에서 간단한 연결 구성 : 변환이 필요 없는 경우 체인의 일부로 사용된다.
더보기
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from langchain.schema.runnable import RunnablePassthrough

# LLM model 생성
model = ChatOpenAI(model="gpt-4o-mini")

# prompt 템플릿 생성
prompt = ChatPromptTemplate.from_template("{dog_breeds_input}들의 고향은 어디야?")

# RunnablePassthrough 객체 생성
passthrough = RunnablePassthrough()

# chain 생성
#chain = prompt | model | StrOutputParser() # 깔끔하게 출력된다.
chain = prompt | model | passthrough | passthrough  | StrOutputParser()

# chain 실행
answer = chain.invoke({"dog_breeds_input": "말티즈"})
print(answer)

 

이 RunnablePassthrough 를 상속받아 커스텀 컴포넌트를 만들 수  있다.

더보기
import time
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from langchain.schema.runnable import RunnablePassthrough

# LLM model 생성
model = ChatOpenAI(model="gpt-4o-mini")

# prompt 템플릿 생성
prompt = ChatPromptTemplate.from_template("{dog_breeds_input}들의 고향은 어디야?")

# 처리 시간을 기록하는 Custom RunnablePassthrough
class TimingRunnablePassthrough(RunnablePassthrough):
    def invoke(self, input, *arg):
        start_time = time.time()  # 시작 시간 기록
        output = super().invoke(input)  # 기존 Passthrough 동작 수행
        end_time = time.time()  # 종료 시간 기록

        # 처리 시간 출력
        processing_time = end_time - start_time
        print(f"Processing time: {processing_time:.6f} seconds")

        return output

# Custom RunnablePassthrough 객체 생성
timed_passthrough = TimingRunnablePassthrough()

# chain 생성
chain = prompt | timed_passthrough | model | timed_passthrough | StrOutputParser() | timed_passthrough

# chain 실행
answer = chain.invoke({"dog_breeds_input": "말티즈"})
print(answer)

'AI > LLM' 카테고리의 다른 글

[LangGraph] LangGraph 란 무엇인가?  (0) 2025.03.19
[LLM] LangChain 의 유용한 기능들  (0) 2025.02.28
[LLM] RAG  (0) 2025.02.27