LangChain Quick Start - 랭체인 튜토리얼 with OpenAI (CHAT-GPT)
ToDo
- LangChain, LangSmith 및 LangServe로 설정하기
- LangChain의 가장 기본적이고 일반적인 구성 요소인 프롬프트 템플릿, 모델 및 출력 파서를 사용해보기
- LangChain Expression Language를 사용해보기
- LangChain으로 간단한 애플리케이션 구축해보기
- LangSmith로 애플리케이션 추적해보기
- LangServe로 애플리케이션 제공해보기
LangChain 설치및 기본세팅
다음 명령으로 랭체인 패키지를 설치합니다.
# pip으로 설치
pip install langchain
# conda로 설치
conda install langchain -c conda-forge
우리는 OpenAI의 모델 API를 사용할것이므로, 이부분을 세팅해주어야합니다. openai 패키지를 설치합니다.
pip install openai
openai api를 발급받고 환경변수로 등록해줍니다. 변수등록을 원하지 않는경우 매개변수로 전달할 수 도 있으나, 앞으로 계속 사용할것이므로 변수로 등록하겠습니다.
export OPENAI_API_KEY="sk-xxxxx"
# 매개변수로 전달하는경우
from langchain.chat_models import ChatOpenAI
llm = ChatOpenAI(openai_api_key="...")
애플리케이션을 추적(Trace)하기 위한 LangSmith를 설정하겠습니다. 다음 링크를 사용하여 가입한 이후 API키를 등록합니다.
현재 LangSmith는 신규가입이 불가능하며, 베타신청 하실 수 있습니다. 해당부분은 넘어가도 됩니다.
export LANGCHAIN_TRACING_V2="true"
export LANGCHAIN_API_KEY=...
LangServe를 사용하여 API서버를 배포해보도록 하겠습니다. 굳이 랭서브를 사용할 필요는 없지만 랭체인을 REST API로 쉽게 배포할 수 있는 프레임워크입니다. 다음을 사용하여 설치합니다.
pip install "langserve[all]"
랭체인구축
일반적으로 랭체인은 다음과같은 세가지가 포함됩니다.
- LLM / Chat Model
- 핵심 인퍼런스 엔진입니다. 다양한 유형의 언어모델과 사용하는법을 알아야합니다.
- Prompt Template
- 언어모델에 대한 지침입니다. 언어모델의 출력을 제어하므로 다양한 프롬프트 전략을 구성하는 방법을 이해하는것이 중요합니다.
- 출력구문 분석기
- 언어모델의 RAW한 리스폰스를 실행 가능한 형식으로 변환하여 쉽게 사용할 수 있도록 합니다.
본 문서에는 세가지 구성요소를 개별적으로 다루고 이를 결합해보도록 하겠습니다.
LLM / Chat Model
언어모델에는 2가지 유형이 있습니다.
- LLM : 문자열을 입력으로 사용하고 문자열을 반환
- ChatModel : 메세지 목록을 입력으로 사용하고 메세지를 반환
위에서 말하는 메세지란 다음에 의해 정의됩니다.
- context : 메세지 내용입니다. 일반적으로 string입니다.
- role : BaseMessage가 나오는 엔터티입니다.
위에서 말하는 role은 서로 다른 역할을 구별하는 엔터티입니다. 랭체인은 다음과 같은 엔터티를 제공합니다.
- HumanMessage : 인간이나 사용자로부터 오는 메세지
- AIMessage : AI로부터 오는 메세지
- SystemMessage : 시스템으로부터 오는 메세지
- FuctionMessage / ToolMessage : 함수나 도구 호출의 출력으로 부터 오는 메세지
- 4개 유형으로 정의할 수 없는경우 수동으로 지정할수 있는 ChatMessage라는 클래스가 있습니다.
LangChain과 LLM은 모두가 공유하는 공통 인터페이스인 ChatModel을 제공합니다.
LLM을 호출하는 가장 간단한 방법은 LangChain Expression Language (LCEL) 객체 (ChatModel) invoke() 하는것입니다.
- LLM.invoke : 문자열을 받아서 문자열을 반환합니다.
- ChatModel.invoke : 메세지목록을 가져와서 메세지를 반환합니다.
이런 유형(패턴)은 실제로는 더 복잡하지만 해당 문서에서는 단순화를 위해 LLM은 문자열만 취급하고 Chat모델은 메세지 모델만 취급한다고 가정하도록 하겠습니다.
이제 위 유형과 입력을 사용하여 작업하는 방법을 살펴보도록 하겠습니다. LLM과 ChatModel을 가져옵니다.
from langchain.llms import OpenAI
from langchain.chat_models import ChatOpenAI
llm = OpenAI()
chat_model = ChatOpenAI()
llm과 chat_model은 구성개체입니다. temperature및 기타 매개변수를 사용하여 초기화 한 후 전달할 수 있습니다.
from langchain.schema import HumanMessage
text = "무지개의 색깔에 대해 알려줘"
messages = [HumanMessage(content=text)]
llm_invoke = llm.invoke(text)
chat_model_invoke = chat_model.invoke(messages)

프롬프트
대부분의 LLM 응용프로그램은 유저의 입력을 LLM에 직접적으로 전달하지 않습니다. 일반적으로 특정 작업에 대한 추가 컨텍스트를 제공하는 프롬프트 템플릿이라는 더 큰 텍스트에 사용자 입력을 추가하게 됩니다.
이전 예에서 모델에 전달한 텍스트에는 무지개의 색깔에 대해 알려달라는 지침이 포함되어있습니다. 우리 애플리케이션은 사용자가 모델지침을 제공하는것에 대해 걱정할필요없이 무지개의 색깔에 대한 설명한 제공하면 됩니다.
이럴때 PromptTemplate가 도움이 됩니다. 사용자 입력을 형식화된 프롬프트로 전환하기위해 모든 논리를 묶을수 있습니다. 예를들어 회사명을 생성하라는 프롬프트는 다음과 같습니다.
from langchain.prompts import PromptTemplate
prompt = PromptTemplate.from_template("{product}를 생산, 판매하는 회사에 대해 좋은 회사명을 알려줘")
prompt.format(product="전자기기")

PromptTemplate는 메세지 목록을 생성하는데 사용할 수 있습니다. 이런경우 프롬프트에는 컨텐츠에 대한 정보 뿐 아니라 각 메세지(역할, 목록에서의 위치) 등이 포함됩니다.
from langchain.prompts.chat import ChatPromptTemplate
template = "You are a helpful assistant that translates {input_language} to {output_language}."
human_template = "{text}"
chat_prompt = ChatPromptTemplate.from_messages([
("system", template),
("human", human_template),
])
chat_prompt.format_messages(input_language="English", output_language="Korean", text="I love programming.")

출력
OutputPaser를 사용하여 언어모델의 Raw 출력을 다운스트림에서 사용할 수 있도록 변환합니다.
- LLM 텍스트를 구조화된 정보(json 등)로 변환
- ChatMessage를 문자열로 변환
- 메세지(예를들어 OpenAI 함수 호출) 외에 호출에서 반환된 추가정보를 문자열로 변환
예를들어 쉼표로 구분된 목록을 목록으로 변환하는 출력구문 분석기를 작성해보겠습니다.
from langchain.schema import BaseOutputParser
class CommaSeparatedListOutputParser(BaseOutputParser):
"""Parse the output of an LLM call to a comma-separated list."""
def parse(self, text: str):
"""Parse the output of an LLM call."""
return text.strip().split(", ")
CommaSeparatedListOutputParser().parse("hi, bye")
# >> ['hi', 'bye']

LangChain 을 사용한 통합
이제 앞서 소개했던 3가지 요소를 하나의 체인으로 결합해보도록 하겠습니다. 입력변수를 가져와 템플릿에 전달하여 프롬프트를 생성하고, 프롬프트를 언어모델에 전달한 다음, 출력구문 분석기를 통해 출력을 전달합니다.
from typing import List
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema import BaseOutputParser
class CommaSeparatedListOutputParser(BaseOutputParser[List[str]]):
"""Parse the output of an LLM call to a comma-separated list."""
def parse(self, text: str) -> List[str]:
"""Parse the output of an LLM call."""
return text.strip().split(", ")
template = """You are a helpful assistant who generates comma separated lists.
A user will pass in a category, and you should generate 5 objects in that category in a comma separated list.
ONLY return a comma separated list, and nothing more."""
human_template = "{text}"
chat_prompt = ChatPromptTemplate.from_messages([
("system", template),
("human", human_template),
])
chain = chat_prompt | ChatOpenAI() | CommaSeparatedListOutputParser()
chain.invoke({"text": "colors"})
# >> ['red', 'blue', 'green', 'yellow', 'orange']

| 구문을 사용한다는 점의 유의해야합니다. 해당 구문은 LCEL에 의해 구동됩니다.
LangServe로 서비스하기
LanbServe를 사용하여 이제 이 LCEL체인을 RESTful API로 제공해보도록 하겠습니다.
라이브러리는 FastAPI와 통합되어있고 데이터 검증을 위해 pydantic을 사용하도록 하겠습니다.
fastapi와 uvicorn을 설치합니다.
pip install fastapi uvicorn
serve.py를 작성하고 실행합니다.
from typing import List
from fastapi import FastAPI
from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatOpenAI
from langchain.schema import BaseOutputParser
from langserve import add_routes
# 1. Chain definition
class CommaSeparatedListOutputParser(BaseOutputParser[List[str]]):
"""Parse the output of an LLM call to a comma-separated list."""
def parse(self, text: str) -> List[str]:
"""Parse the output of an LLM call."""
return text.strip().split(", ")
template = """You are a helpful assistant who generates comma separated lists.
A user will pass in a category, and you should generate 5 objects in that category in a comma separated list.
ONLY return a comma separated list, and nothing more."""
human_template = "{text}"
chat_prompt = ChatPromptTemplate.from_messages([
("system", template),
("human", human_template),
])
category_chain = chat_prompt | ChatOpenAI() | CommaSeparatedListOutputParser()
# 2. App definition
app = FastAPI(
title="LangChain Server",
version="1.0",
description="A simple api server using Langchain's Runnable interfaces",
)
# 3. Adding chain route
add_routes(
app,
category_chain,
path="/category_chain",
)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="localhost", port=8000)
이제 저희가 작성한 체인은 localhost:8000에서 확인해 볼 수 있습니다. 또한 모든 LangServe 서비스에서는 스트리밍 출력과 중간단계에 대한 가시성을 위한 내장 UI가 함께 제공됩니다. 라우팅경로에 playground로 이동하면 사용해볼 수 있습니다.


Remote Runnable
이제 서비스와 프로그래밍 방식으로 상호작용하기 위한 클라이언트를 설정해보도록 하겠습니다.
langserve.RemoteRunnable을 사용하면 쉽게 설정할 수 있습니다.
이를 사용하면 마치 클라이언트측에서 실행되는것처럼 제공되는 체인과 상호작용이 가능합니다.
from langserve import RemoteRunnable
remote_chain = RemoteRunnable("http://localhost:8000/category_chain/")
remote_chain.invoke({"text": "점심메뉴추천"})
