LangChain은 언어 모델을 활용해 다양한 애플리케이션을 개발할 수 있는 프레임워크이다. 이 프레임워크를 통해 언어 모델은 다음과 같은 기능을 수행할 수 있게 된다.
LangChain을 활용하면 이전에 언급한 기능을 바탕으로 검색 증강 생성(RAG) 어플리케이션 제작, 구조화된 데이터 분석, 챗봇 등을 만들 수 있다.
더 많은 예제는 유튜브 채널 테디노트에서 확인할 수 있다.
권장하는 파이썬 버전은 3.11 버전이다.
pip를 이용한 설치:
pip install -r https://raw.githubusercontent.com/teddylee777/langchain-kr/main/requirements.txt
최소한의 기능만 설치하기 위한 mini 버전 (일부 패키지만 설치하는 경우):
pip install -r https://raw.githubusercontent.com/teddylee777/langchain-kr/main/requirements-mini.txt
이 프레임워크는 여러 부분으로 구성되어 있다.
컴포넌트의 조립 및 통합 🔧
LangChain은 언어 모델과의 작업을 위한 조립 가능한 도구 및 통합을 제공한다. 컴포넌트는 모듈식으로 설계되어 있어, 사용하기 쉽다. 이는 개발자가 LangChain 프레임워크를 자유롭게 활용할 수 있게 한다.
즉시 사용 가능한 체인 🚀
고수준 작업을 수행하기 위한 컴포넌트의 내장 조합을 제공한다. 이러한 체인은 개발 과정을 간소화하고 속도를 높여준다.
모델 I/O 📃
프롬프트 관리, 최적화 및 LLM과의 일반적인 인터페이스와 작업을 위한 유틸리티를 포함한다.
검색 📚
'데이터 강화 생성'에 초점을 맞춘 이 모듈은 생성 단계에서 필요한 데이터를 외부 데이터 소스에서 가져오는 작업을 담당한다.
에이전트 🤖
언어 모델이 어떤 조치를 취할지 결정하고, 해당 조치를 실행하며, 관찰하고, 필요한 경우 반복하는 과정을 포함한다.
LangChain을 활용하면, 언어 모델 기반 애플리케이션의 개발을 보다 쉽게 시작할 수 있으며, 필요에 맞게 기능을 맞춤 설정하고, 다양한 데이터 소스와 통합하여 복잡한 작업을 처리할 수 있다.
1) OpenAI API 키 발급
OpenAI API 웹사이트에 접속한다.
우측 상단 "Sign Up"을 눌러 회원가입을 진행한다. (이미 가입되어 있는 경우 "Log in" 버튼을 눌러 로그인한다.)
우측 상단 톱니바퀴(Setting)를 눌러 설정으로 이동한다.
왼쪽 "Billing" 메뉴에서 "Payment methods"를 클릭하여 신용카드를 등록한다.
신용카드를 등록했다면, 아래와 같이 등록된 신용카드가 목록에 나타난다.
"Add to credit balance" 버튼을 눌러 사용할 만큼의 미화(달러)를 입력한다.
금액을 입력한 후 "Continue"를 눌러 결제를 진행한다.
왼쪽의 "Limits" 탭에서 월간 사용 한도를 설정할 수 있다.
우측 프로필 이미지 클릭 후 "Your profile"을 선택한다.
API Key 관리 메뉴로 접속한다.
"Create new secret key"를 클릭한다.
Name과 프로젝트를 입력한다. (별도로 생성한 프로젝트가 없다면 Default project를 설정한다.)
우측 "Copy" 버튼을 눌러 키를 복사한다.
주의!!!
2) .env 파일 설정
.env
파일을 생성한다..env
파일에 OPENAI_API_KEY=방금 복사한 키
를 입력한 뒤 Ctrl + S를 눌러 저장하고 파일을 닫는다.# LangChain 업데이트
!pip install -r https://raw.githubusercontent.com/teddylee777/langchain-kr/main/requirements.txt
# API KEY를 환경변수로 관리하기 위한 설정 파일
# 설치: pip install python-dotenv
from dotenv import load_dotenv
# API KEY 정보 로드
load_dotenv()
True
import os
print(f"[API KEY]\n{os.environ['OPENAI_API_KEY']}")
LangSmith는 LLM 애플리케이션의 개발, 모니터링 및 테스트를 위한 플랫폼으로, LangChain 사용 여부와 관계없이 강력한 추적 기능을 제공합니다. LLM 애플리케이션을 개발하면서 발생할 수 있는 다양한 문제를 추적하고 해결하는 데 도움을 줄 수 있습니다.
추적 기능은 다음과 같은 문제를 파악하는 데 유용합니다:
LangSmith는 프로젝트 단위로 실행된 모든 작업을 추적할 수 있습니다. 이를 통해 실행 카운트, 에러 발생률, 토큰 사용량, 과금 정보 등을 한눈에 확인할 수 있습니다. 또한, 실행된 각 단계별로 세부적인 추적 정보를 제공하여, 검색된 문서의 정확성 및 GPT의 입출력 내용에 대한 분석이 가능합니다.
.env
파일에 LangSmith 키 설정발급받은 API 키를 안전하게 보관한 후, .env
파일에 다음과 같이 설정합니다:
LANGCHAIN_TRACING_V2=true
LANGCHAIN_ENDPOINT=https://api.smith.langchain.com
LANGCHAIN_API_KEY=발급받은_API_KEY
LANGCHAIN_PROJECT=프로젝트_명
환경 변수를 설정하여 LangSmith의 추적 기능을 활성화합니다. 아래 코드를 사용하여 .env
파일에 설정된 내용을 불러올 수 있습니다.
from dotenv import load_dotenv
load_dotenv()
이 설정이 완료되면 추적이 자동으로 활성화됩니다. 프로젝트 명을 변경하거나, 추적 설정을 변경하고 싶다면 다음 코드를 사용합니다:
import os
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com"
os.environ["LANGCHAIN_PROJECT"] = "변경할_프로젝트_명"
os.environ["LANGCHAIN_API_KEY"] = "변경할_API_KEY"
langchain-teddynote
패키지 설치 및 추적 설정langchain-teddynote
패키지를 설치하여 LangChain 관련 기능을 더 편리하게 사용할 수 있습니다.
pip install langchain-teddynote
설치 후, 다음 코드를 사용하여 LangSmith 추적을 설정할 수 있습니다:
from langchain_teddynote import logging
# 프로젝트 이름을 입력하여 추적 시작
logging.langsmith("원하는_프로젝트_명")
추적을 원하지 않을 때는 다음과 같이 추적을 비활성화할 수 있습니다:
from langchain_teddynote import logging
# set_enable=False로 지정하여 추적 비활성화
logging.langsmith("프로젝트_명", set_enable=False)
이렇게 LangSmith를 설정하면 LLM 애플리케이션의 개발 과정에서 발생할 수 있는 다양한 문제를 효과적으로 추적하고 해결할 수 있습니다. 추적 데이터를 바탕으로 검색 알고리즘이나 프롬프트를 개선하여 더욱 효율적이고 정확한 응답을 생성할 수 있습니다.
# API KEY를 환경변수로 관리하기 위한 설정 파일
from dotenv import load_dotenv
# API KEY 정보 로드
load_dotenv()
True
# LangSmith 추적을 설정합니다. https://smith.langchain.com
# .env 파일에 LANGCHAIN_API_KEY를 입력합니다.
# !pip install -qU langchain-teddynote
from langchain_teddynote import logging
# 프로젝트 이름을 입력합니다.
logging.langsmith("CH01-Basic")
LangSmith 추적을 시작합니다.
[프로젝트명]
CH01-Basic
OpenAI 사의 채팅 전용 Large Language Model(LLM)이다. 객체를 생성할 때 다양한 옵션 값을 지정할 수 있으며, 주요 옵션에 대한 설명은 다음과 같다.
from langchain_openai import ChatOpenAI
# 객체 생성
llm = ChatOpenAI(
temperature=0.1, # 창의성 (0.0 ~ 2.0)
model_name="gpt-4o", # 모델명
)
# 질의내용
question = "대한민국의 수도는 어디인가요?"
# 질의
print(f"[답변]: {llm.invoke(question)}")
[답변]: content='대한민국의 수도는 서울입니다. 서울은 대한민국의 정치, 경제, 문화의 중심지로서 많은 인구와 다양한 명소를 자랑하는 도시입니다.'
# 질의내용
question = "대한민국의 수도는 어디인가요?"
# 질의
response = llm.invoke(question)
response
AIMessage(content='대한민국의 수도는 서울입니다. 서울은 대한민국의 정치, 경제, 문화의 중심지로서 많은 인구와 다양한 명소를 자랑하는 도시입니다.', response_metadata={'token_usage': {'completion_tokens': 36, 'prompt_tokens': 16, 'total_tokens': 52}, 'model_name': 'gpt-4o', 'system_fingerprint': 'fp_aa87380ac5', 'finish_reason': 'stop', 'logprobs': None}, id='run-3296402a-f47b-4ace-88cd-b74efb7465fb-0', usage_metadata={'input_tokens': 16, 'output_tokens': 36, 'total_tokens': 52})
response.content
# '대한민국의 수도는 서울입니다. 서울은 대한민국의 정치, 경제, 문화의 중심지로서 많은 인구와 다양한 명소를 자랑하는 도시입니다.'
response.response_metadata
# {'token_usage': {'completion_tokens': 36, 'prompt_tokens': 16, 'total_tokens': 52}, 'model_name': 'gpt-4o', 'system_fingerprint': 'fp_aa87380ac5', 'finish_reason': 'stop', 'logprobs': None}
LogProb는 주어진 텍스트에 대한 모델의 토큰 확률의 로그 값을 의미한다. 이는 문장을 구성하는 개별 단어나 문자의 확률을 예측하는 데 사용된다.
# 객체 생성
llm_with_logprob = ChatOpenAI(
temperature=0.1, # 창의성 (0.0 ~ 2.0)
max_tokens=2048, # 최대 토큰수
model_name="gpt-3.5-turbo", # 모델명
).bind(logprobs=True)
# 질의내용
question = "대한민국의 수도는 어디인가요?"
# 질의
response = llm_with_logprob.invoke(question)
# 결과 출력
response.response_metadata
# {'token_usage': {'completion_tokens': 15, 'prompt_tokens': 24, 'total_tokens': 39}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': {'content': [{'token': '대', 'bytes': [235, 140, 128], 'logprob': -0.03859115, 'top_logprobs': []}, {'token': '한', 'bytes': [237, 149, 156], 'logprob': -5.5122365e-07, 'top_logprobs': []}, {'token': '\\xeb\\xaf', 'bytes': [235, 175], 'logprob': -2.8160932e-06, 'top_logprobs': []}, {'token': '\\xbc', 'bytes': [188], 'logprob': 0.0, 'top_logprobs': []}, {'token': '\\xea\\xb5', 'bytes': [234, 181], 'logprob': -6.704273e-07, 'top_logprobs': []}, {'token': '\\xad', 'bytes': [173], 'logprob': 0.0, 'top_logprobs': []}, {'token': '의', 'bytes': [236, 157, 152], 'logprob': -6.2729996e-06, 'top_logprobs': []}, {'token': ' 수', 'bytes': [32, 236, 136, 152], 'logprob': -5.5122365e-07, 'top_logprobs': []}, {'token': '도', 'bytes': [235, 143, 132], 'logprob': -5.5122365e-07, 'top_logprobs': []}, {'token': '는', 'bytes': [235, 138, 148], 'logprob': -1.9361265e-07, 'top_logprobs': []}, {'token': ' 서', 'bytes': [32, 236, 132, 156], 'logprob': -5.080963e-06, 'top_logprobs': []}, {'token': '\\xec\\x9a', 'bytes': [236, 154], 'logprob': 0.0, 'top_logprobs': []}, {'token': '\\xb8', 'bytes': [184], 'logprob': 0.0, 'top_logprobs': []}, {'token': '입니다', 'bytes': [236, 158, 133, 235, 139, 136, 235, 139, 164], 'logprob': -0.13815464, 'top_logprobs': []}, {'token': '.', 'bytes': [46], 'logprob': -9.0883464e-07, 'top_logprobs': []}]}}
스트리밍 옵션은 질의에 대한 답변을 실시간으로 받을 때 유용하다.
# 스트림 방식으로 질의
# answer에 스트리밍 답변의 결과를 받습니다.
answer = llm.stream("대한민국의 아름다운 관광지 10곳과 주소를 알려주세요!")
# 스트리밍 방식으로 각 토큰을 출력합니다. (실시간 출력)
for token in answer:
print(token.content, end="", flush=True)
예시 출력
물론입니다! 대한민국에는 아름다운 관광지가 많이 있습니다. 다음은 그 중 10곳과 그 주소입니다:
1. **경복궁**
- 주소: 서울특별시 종로구 사직로 161
2. **부산 해운대 해수욕장**
- 주소: 부산광역시 해운대구 우동
3. **제주도 한라산 국립공원**
- 주소: 제주특별자치도 제주시 1100로 2070-61
4. **경주 불국사**
- 주소: 경상북도 경주시 불국로 385
5. **설악산 국립공원**
- 주소: 강원도 속초시 설악산로 833
6. **남이섬**
- 주소: 강원도 춘천시 남산면 남이섬길 1
7. **안동 하회마을**
- 주소: 경상북도 안동시 풍천면 하회종가길 40
8. **전주 한옥마을**
- 주소: 전라북도 전주시 완산구 기린대로 99
9. **서울 남산타워 (N서울타워)**
- 주소: 서울특별시 용산구 남산공원길 105
10. **보성 녹차밭 대한다원**
- 주소: 전라남도 보성군 보성읍 녹차
가장 기본적이고 일반적인 사용 사례는 PromptTemplate
과 모델을 함께 연결하는 것입니다. 이번 예제에서는 각 나라별 수도를 물어보는 Chain을 생성해 보겠습니다.
# API KEY를 환경변수로 관리하기 위한 설정 파일
from dotenv import load_dotenv
# API KEY 정보 로드
load_dotenv()
True
# LangSmith 추적을 설정합니다. https://smith.langchain.com
# !pip install -qU langchain-teddynote
from langchain_teddynote import logging
# 프로젝트 이름을 입력합니다.
logging.langsmith("CH01-Basic")
LangSmith 추적을 시작합니다.
[프로젝트명]
CH01-Basic
PromptTemplate은 사용자의 입력 변수를 사용하여 완전한 프롬프트 문자열을 만드는 데 사용되는 템플릿입니다.
사용법:
{}
는 변수를 나타냅니다.from langchain_teddynote.messages import stream_response # 스트리밍 출력
from langchain_core.prompts import PromptTemplate
# template 정의
template = "{country}의 수도는 어디인가요?"
# from_template 메소드를 이용하여 PromptTemplate 객체 생성
prompt_template = PromptTemplate.from_template(template)
prompt_template
# PromptTemplate(input_variables=['country'], template='{country}의 수도는 어디인가요?')
프롬프트 생성 예시:
# prompt 생성
prompt = prompt_template.format(country="대한민국")
print(prompt)
# '대한민국의 수도는 어디인가요?'
# 다른 국가로 프롬프트 생성
prompt = prompt_template.format(country="미국")
print(prompt)
# '미국의 수도는 어디인가요?'
from langchain_openai import ChatOpenAI
model = ChatOpenAI(
model="gpt-3.5-turbo",
max_tokens=2048,
temperature=0.1,
)
LCEL(LangChain Expression Language)을 사용하여 다양한 구성 요소를 단일 체인으로 결합할 수 있습니다.
# prompt 를 PromptTemplate 객체로 생성합니다.
prompt = PromptTemplate.from_template("{topic} 에 대해 쉽게 설명해주세요.")
model = ChatOpenAI()
chain = prompt | model
invoke() 호출 예시:
# input 딕셔너리에 주제를 설정합니다.
input = {"topic": "인공지능 모델의 학습 원리"}
# 체인을 실행하여 AI 모델이 생성한 메시지를 반환합니다.
response = chain.invoke(input)
print(response)
# '인공지능 모델의 학습 원리는 데이터를 이용하여 패턴을 학습하는 것입니다...'
# 스트리밍 출력을 위한 요청
answer = chain.stream(input)
# 스트리밍 출력
stream_response(answer)
출력 예시:
인공지능 모델의 학습 원리는 데이터를 입력으로 받아서 패턴을 학습하고 이를 기반으로 예측이나 분류를 수행하는 과정입니다...
from langchain_core.output_parsers import StrOutputParser
output_parser = StrOutputParser()
Chain에 출력 파서 추가:
# 프롬프트, 모델, 출력 파서를 연결하여 처리 체인을 구성합니다.
chain = prompt | model | output_parser
# 체인을 실행하여 결과를 얻습니다.
response = chain.invoke(input)
print(response)
# '인공지능 모델의 학습 원리는 데이터를 입력으로 받아서 패턴을 학습하는 것입니다...'
아래의 프롬프트 내용을 변경하거나, 모델명을 변경하여 테스트할 수 있습니다.
template = """
당신은 영어를 가르치는 10년차 영어 선생님입니다. 상황에 [FORMAT]에 영어 회화를 작성해 주세요.
상황:
{question}
FORMAT:
- 영어 회화:
- 한글 해석:
"""
# 프롬프트 템플릿을 이용하여 프롬프트를 생성합니다.
prompt = PromptTemplate.from_template(template)
# ChatOpenAI 챗모델을 초기화합니다.
model = ChatOpenAI(model_name="gpt-4-turbo")
# 문자열 출력 파서를 초기화합니다.
output_parser = StrOutputParser()
# 체인을 구성합니다.
chain = prompt | model | output_parser
실행 예시:
# 스트리밍 출력을 위한 요청
answer = chain.stream({"question": "저는 식당에 가서 음식을 주문하고 싶어요"})
# 스트리밍 출력
stream_response(answer)
출력 예시:
영어 회화:
- Hello, could I see the menu, please?
- I'd like to order the grilled salmon and a side of mashed potatoes.
- Could I have a glass of water as well?
- Thank you!
한글 해석:
- 안녕하세요, 메뉴판 좀 볼 수 있을까요?
- 구운 연어와 매시드 포테이토를 주문하고 싶어요.
- 물 한 잔도 주실 수 있나요?
- 감사합니다!
또는 다른 시나리오를 설정하여 테스트할 수 있습니다.
# question을 '미국에서 피자 주문'으로 설정하여 실행합니다.
answer = chain.stream({"question": "미국에서 피자 주문"})
stream_response(answer)
출력 예시:
영어 회화:
- Employee: "Hello, Tony's Pizza. How can I help you?"
- Customer: "Hi, I'd like to place an order for delivery, please."
- Employee: "Sure thing! What would you like to order?"
- Customer: "I'll have a large pepperoni pizza with extra cheese and a side of garlic bread."
- Employee: "Anything to drink?"
- Customer: "Yes, a 2-liter bottle of Coke, please."
- Employee: "Alright, your total comes to $22.50. Can I have your delivery address?"
- Customer: "It's 742 Evergreen Terrace."
- Employee: "Thank you. Your order will be there in about 30-45 minutes. Is there anything else I can help you with?"
- Customer: "No, that's everything. Thank you!"
- Employee: "Thank you for choosing Tony's Pizza. Have a great day!"
한글 해석:
- 직원: "안녕하세요, 토니의 피자입니다. 어떻게 도와드릴까요?"
- 고객: "안녕하세요, 배달 주문하고 싶은데요."
- 직원: "네, 무엇을 주문하시겠어요?"
- 고객: "큰 사이즈의 페퍼로니 피자에 치즈 추가하고, 마늘빵 하나 주세요."
- 직원: "음료는 드릴까요?"
- 고객: "네, 콜라 2리터 한 병 주세요."
- 직원: "알겠습니다, 합계는 $22.50입니다. 배달 주소를 알려주시겠어요?"
- 고객: "742 에버그린 테라스입니다."
- 직원: "감사합니다. 주문하신 음식은 대략 30-45분 내에 도착할 예정입니다. 다른 도움이 필요하신가요?"
- 고객: "아니요, 이게 다예요. 감사합니다!"
- 직원: "토니의 피자를 선택해주셔서 감사합니다. 좋은 하루 되세요!"
LCEL(LangChain Expression Language)은 사용자 정의 체인을 쉽게 만들 수 있도록 돕는 Runnable
프로토콜을 구현하고 있습니다. 이 프로토콜은 다양한 컴포넌트에 적용되며, 표준화된 인터페이스로 체인을 정의하고 호출할 수 있게 해줍니다. 주요 메서드에는 다음이 포함됩니다:
# API KEY를 환경변수로 관리하기 위한 설정 파일
from dotenv import load_dotenv
# API KEY 정보 로드
load_dotenv()
True
# LangSmith 추적을 설정합니다. https://smith.langchain.com
from langchain_teddynote import logging
# 프로젝트 이름을 입력합니다.
logging.langsmith("CH01-Basic")
from langchain_openai import ChatOpenAI
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser
# ChatOpenAI 모델을 인스턴스화합니다.
model = ChatOpenAI()
# 주어진 토픽에 대한 설명을 요청하는 프롬프트 템플릿을 생성합니다.
prompt = PromptTemplate.from_template("{topic} 에 대하여 3문장으로 설명해줘.")
# 프롬프트와 모델을 연결하여 대화 체인을 생성합니다.
chain = prompt | model | StrOutputParser()
# chain.stream 메서드를 사용하여 '멀티모달' 토픽에 대한 스트림을 생성하고 반복합니다.
for token in chain.stream({"topic": "멀티모달"}):
print(token, end="", flush=True)
출력 예시:
멀티모달은 여러 가지 다른 형태의 커뮤니케이션 수단을 통해 정보를 전달하고 상호작용하는 기술을 의미합니다...
# chain 객체의 invoke 메서드를 호출하고, 'ChatGPT'라는 주제로 딕셔너리를 전달합니다.
response = chain.invoke({"topic": "ChatGPT"})
print(response)
출력 예시:
'ChatGPT는 OpenAI에서 개발한 대화형 인공지능 모델로, 다양한 주제에 대한 대화를 자연스럽게 이어나갈 수 있습니다...'
# 주어진 토픽 리스트를 batch 처리하는 함수 호출
responses = chain.batch([{"topic": "ChatGPT"}, {"topic": "Instagram"}])
print(responses)
출력 예시:
['ChatGPT는 인공지능 챗봇으로 자연어 처리 기술을 사용하여 대화를 수행합니다...', 'Instagram은 사진과 동영상을 공유하고 다른 사람들과 소통하는 소셜 미디어 플랫폼입니다...']
# 비동기 스트림을 사용하여 'YouTube' 토픽의 메시지를 처리합니다.
async for token in chain.astream({"topic": "YouTube"}):
print(token, end="", flush=True)
출력 예시:
YouTube는 동영상을 공유하고 시청할 수 있는 온라인 동영상 플랫폼이다...
# 비동기 체인 객체의 'ainvoke' 메서드를 호출하여 'NVDA' 토픽을 처리합니다.
response = await chain.ainvoke({"topic": "NVDA"})
print(response)
출력 예시:
'NVDA는 엔비디아의 주식 코드로, 미국의 반도체 기업인 엔비디아(NVIDIA)의 주식을 말합니다...'
# 주어진 토픽에 대해 비동기적으로 일괄 처리를 수행합니다.
responses = await chain.abatch(
[{"topic": "YouTube"}, {"topic": "Instagram"}, {"topic": "Facebook"}]
)
print(responses)
출력 예시:
['YouTube는 동영상 공유 플랫폼으로 사용자들이 영상을 업로드하고 시청할 수 있는 서비스입니다...', 'Instagram은 사진과 동영상을 공유하는 소셜 미디어 플랫폼입니다...', 'Facebook은 미국의 소셜 네트워크 서비스로, 사용자들이 커뮤니케이션하고 정보를 공유할 수 있는 플랫폼입니다...']
from langchain_core.runnables import RunnableParallel
# {country}의 수도를 물어보는 체인을 생성합니다.
chain1 = (
PromptTemplate.from_template("{country}의 수도는 어디야?")
| model
| StrOutputParser()
)
# {country}의 면적을 물어보는 체인을 생성합니다.
chain2 = (
PromptTemplate.from_template("{country}의 면적은 얼마야?")
| model
| StrOutputParser()
)
# 위의 2개 체인을 동시에 생성하는 병렬 실행 체인을 생성합니다.
combined = RunnableParallel(capital=chain1, area=chain2)
병렬 실행 예시:
response = combined.invoke({"country": "대한민국"})
print(response)
출력 예시:
{'capital': '대한민국의 수도는 서울입니다.', 'area': '대한민국의 면적은 약 100,363.4 제곱 킬로미터 입니다.'}
responses = combined.batch([{"country": "대한민국"}, {"country": "미국"}])
print(responses)
출력 예시:
[{'capital': '대한민국의 수도는 서울이다.', 'area': '대한민국의 면적은 약 100,363km² 입니다.'}, {'capital': '미국의 수도는 워싱턴 D.C.입니다.', 'area': '미국의 면적은 약 9,833,520 km² 입니다.'}]
Runnable은 LangChain에서 체인을 구성하고 실행할 수 있는 중요한 구성 요소입니다. 이 구성 요소는 다양한 형태로 입력을 처리하고, 이를 다른 컴포넌트로 전달하여 복잡한 작업을 수행할 수 있게 해줍니다.
# .env 파일을 읽어서 환경변수로 설정
from dotenv import load_dotenv
# 토큰 정보 로드
load_dotenv()
True
# LangSmith 추적을 설정합니다. https://smith.langchain.com
from langchain_teddynote import logging
# 프로젝트 이름을 입력합니다.
logging.langsmith("CH01-Basic")
LangSmith 추적을 시작합니다.
[프로젝트명]
CH01-Basic
RunnablePassthrough
는 입력을 변경하지 않거나 추가 키를 더하여 전달하는 방식으로 동작합니다. 단독 호출 시 입력을 그대로 전달하며, assign()
메서드를 사용하면 입력에 새로운 값을 추가할 수 있습니다.
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
# prompt 와 llm 을 생성합니다.
prompt = PromptTemplate.from_template("{num} 의 10배는?")
llm = ChatOpenAI(temperature=0)
# chain 을 생성합니다.
chain = prompt | llm
체인 실행 예시:
# 딕셔너리 타입으로 입력하여 실행
response = chain.invoke({"num": 5})
print(response)
# 값만 전달하여 실행 (1개의 변수만 템플릿에 포함된 경우)
response = chain.invoke(5)
print(response)
from langchain_core.runnables import RunnablePassthrough
# RunnablePassthrough 단독 실행
response = RunnablePassthrough().invoke({"num": 10})
print(response)
RunnablePassthrough를 체인에 적용:
runnable_chain = {"num": RunnablePassthrough()} | prompt | ChatOpenAI()
response = runnable_chain.invoke(10)
print(response)
response = RunnablePassthrough.assign(new_num=lambda x: x["num"] * 3).invoke({"num": 1})
print(response)
RunnableParallel
은 여러 Runnable
인스턴스를 병렬로 실행할 수 있는 기능을 제공합니다.
from langchain_core.runnables import RunnableParallel
runnable = RunnableParallel(
passed=RunnablePassthrough(),
extra=RunnablePassthrough.assign(mult=lambda x: x["num"] * 3),
modified=lambda x: x["num"] + 1,
)
response = runnable.invoke({"num": 1})
print(response)
RunnableLambda
는 사용자 정의 함수를 Runnable
객체로 맵핑하는 기능을 제공합니다.
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from datetime import datetime
def get_today(a):
return datetime.today().strftime("%b-%d")
# 오늘 날짜를 출력
print(get_today(None))
# prompt 와 llm 을 생성하고 chain 을 설정합니다.
prompt = PromptTemplate.from_template(
"{today} 가 생일인 유명인 {n} 명을 나열하세요. 생년월일을 표기해 주세요."
)
llm = ChatOpenAI(temperature=0, model_name="gpt-4o")
chain = (
{"today": RunnableLambda(get_today), "n": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
# 출력
print(chain.invoke(3))
from operator import itemgetter
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableLambda
from langchain_openai import ChatOpenAI
def length_function(text):
return len(text)
def _multiple_length_function(text1, text2):
return len(text1) * len(text2)
def multiple_length_function(_dict):
return _multiple_length_function(_dict["text1"], _dict["text2"])
prompt = ChatPromptTemplate.from_template("{a} + {b} 는 무엇인가요?")
model = ChatOpenAI()
chain = (
{
"a": itemgetter("word1") | RunnableLambda(length_function),
"b": {"text1": itemgetter("word1"), "text2": itemgetter("word2")}
| RunnableLambda(multiple_length_function),
}
| prompt
| model
)
response = chain.invoke({"word1": "hello", "word2": "world"})
print(response)
출력 예시:
AIMessage(content='5 + 25 = 30입니다.', response_metadata={'token_usage': {'completion_tokens': 9, 'prompt_tokens': 22, 'total_tokens': 31}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-5db9b475-09ee-4edb-af9d-b37b320bee1e-0', usage_metadata={'input_tokens': 22, 'output_tokens': 9, 'total_tokens': 31})
이 예제를 통해 LangChain에서 Runnable
을 활용하여 다양한 입력 데이터를 처리하고, 복잡한 체인을 구성하는 방법을 이해할 수 있습니다.