[LangChain for LLM Application Development] 랭체인 Chains

본 게시물은 Deeplearning.ai 코스를 수강 후 요약 및 정리한 내용입니다.


 

LangChain에서 지원하는 다양한 모듈 중 하나인 Chain

 

이 체인은 LLM과 프롬프트를 결합하며 다양한 요소를 한 번에 묶어 텍스트나 다른 데이터에 사용할 수 있다는 장점이 있다.

즉, 데이터를 기반으로 Prompt 와 LLM을 결합해서 Sequential 작업을 할 수 있도록 돕는것이 바로 Chain의 역할이다.

 

 

따라서, 

체인의 장점 중 하나는 바로 많은 입력을 동시에 실행할 수 있다는 것!

 

 

그래서 체인 기술을 이용하면 LLM을 단독으로 사용하는 것 보다 더 복잡한 응용 프로그램에 적용시킬 수 있다는 장점이 존재하는데, (그래서 이름이 랭체인인가?)

 

 

체인은 쉽게 말하자면

chain = prompt | model | output_parser

 

로 나타낼 수 있다. 

 

 

복잡하게 보면 더 다양한 체인들이 존재하지만, 먼저 기초적인 체인의 종류로는

  • LLM Chain
  • Router Chain
  • Sequential Chain
  • Transformation Chain

 

등이 있다.

 

이 중에 본 게시물에서는 LLM Chain, Sequential Chain, Router Chain을 다뤄보고자 한다.

 

 

앞서 말했듯, Chain을 이용해서 외부 데이터와 연결을 할 수 도 있다. (예를 들면 Pandas 라이브러리를 통해 csv 파일을 불러 올 수도 있음.)

 

Product 와 Review 에 대한 데이터프레임

 

따라서 우선 다음과 같은 데이터프레임을 불러 실습을 진행하였다!

 

 데이터 프레임은 Product, Review에 대한 Column으로 구성되어 있고, Product column에는 각 상품 정보가 담겨 있고, Review column에는 각 상품에 대한 리뷰 정보들이 Value 값으로 포함되어 있는 것을 확인할 수 있다.

 

 

LLM Chain

가장 기본이 되는 Chain을 말한다.

 

LLM Chain은 LLM 모델과 Prompt 로 구성되어 있으며 따라서 다음과 같이 모듈을 불러오면 된다.

from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.chains import LLMChain

 

그 다음으로는 초기 모델을 설정 해 준다.

llm = ChatOpenAI(temperature=0.9, model = llm_model)

prompt = ChatPromptTemplate.from_template(
	"What is the best name to describe \
    a company that makes {product}?"
)

chain = LLMChain(llm=llm, prompt=prompt)

product = "Queen Size Sheet Set"
chain.run(product)

 

LLM model은 ChatOpenAI로 설정해주었고, Temperature를 0.9 로 설정해주었다.

(Temperature가 0에 가까울 수록 정확한 정보만을 추출하고, 1에 가까울수록 보다 창의적인 정보를 추출하게 됨)

 

 

그리고 Chain에 LLM Chain을 등록하였으며 Prompt Template을 통해 정해놓은 prompt 와 model을 지정해주었다.

그리고 prompt에 해당하는 key값인 product를 입력해주었을 때 아래와 같이 실행결과가 나오는 것을 확인할 수 있다!

 

다음과 같이 창의적인 결과를 출력하는 것을 확인할 수 있다.

 

다음과 같이 체인을 이용하면 한번의 작동으로 프롬프트를 거쳐 LLM 까지 실행할 수가 있다!

 

(체인은 내부적으로 프롬프트를 형식화 하고 전체 프롬프트를 LLM에 전달하는 방식)

 

 

 

Sequential Chains

 Sequential Chain은 순차 체인이라고 부르는 유형의 Chain들을 의미한다. Sequential Chain은 하나의 체인의 출력이 다음 체인의 입력이 되도록 여러 체인을 결합하는 것을 말한다.

 

그에 대해 미리 알아야 할 Sub Chain 이라는 것이 있는데, 이 서브체인은 단 하나의 입력과 출력을 반환하는 체인을 말한다.

 

  • Sub Chain : 단 하나의 입력과 출력을 반환하는 체인

 

바로 실습해보자.

llm = ChatOpenAI(temperature=0.9, model=llm_model)

# prompt template 1
first_prompt = ChatPromptTemplate.from_template(
    "What is the best name to describe \
    a company that makes {product}?"
)

# Chain 1
chain_one = LLMChain(llm=llm, prompt=first_prompt)

 

먼저 이렇게 첫 번째 프롬프트와 첫 번째 체인을 만든다.

 

# prompt template 2
second_prompt = ChatPromptTemplate.from_template(
    "Write a 20 words description for the following \
    company:{company_name}"
)
# chain 2
chain_two = LLMChain(llm=llm, prompt=second_prompt)

 

다음으로 두 번째 프롬프트와 두 번째 체인을 만든다.

 

overall_simple_chain = SimpleSequentialChain(chains=[chain_one, chain_two],
                                             verbose=True
                                            )

 

 

첫 번째 프롬프트로 "{Product} 를 만드는 회사 이름을 묘사해줘." 라고 작성했고,

첫 번 째 프롬프트의 출력으로 부터 회사 이름을 제공받아

 

두 번째 프롬프트로 "{compay_name}에 대한 회사 묘사를 20 words로 제한하여 작성해줘."

라고 프롬프트를 제공했다.

 

 

 

 

 

그럼 결과를 확인하기 위해서

 

 

체인들을 실행시키면

 

overall_simple_chain.run(product)

 

Sequential Chain

 

 

다음과 같이 verbose로 확인한 결과, 첫 번째 output과 두 번째 output이 나온 것을 확인할 수 있고 그 두 Output을 바탕으로 최종 결과물이 출력된 것을 확인할 수 있다. 

 

 

 

 

그렇다면 입력 값이나 출력 값이 여러 개일 때는 어떻게 하는 것이 좋을까?

 

이 때는 Regular Simple Chain을 사용한다!

 

llm = ChatOpenAI(temperature=0.9, model=llm_model)

# prompt template 1: translate to english
first_prompt = ChatPromptTemplate.from_template(
    "Translate the following review to english:"
    "\n\n{Review}"
)
# chain 1: input= Review and output= English_Review
chain_one = LLMChain(llm=llm, prompt=first_prompt, 
                     output_key="English_Review"
                    )
second_prompt = ChatPromptTemplate.from_template(
    "Can you summarize the following review in 1 sentence:"
    "\n\n{English_Review}"
)
# chain 2: input= English_Review and output= summary
chain_two = LLMChain(llm=llm, prompt=second_prompt, 
                     output_key="summary"
                    )
# prompt template 3: translate to english
third_prompt = ChatPromptTemplate.from_template(
    "What language is the following review:\n\n{Review}"
)
# chain 3: input= Review and output= language
chain_three = LLMChain(llm=llm, prompt=third_prompt,
                       output_key="language"
                      )

(여기서 세 번째 체인은 다른 체인이 아니라 데이터에서 output을 받고 있음)

 

 

이런식으로 3가지 프롬프트 템플릿을 제작하고, Chain 내용을 보면 각각의 Output_key 를 설정하여 다른 프롬프트의 입력으로 받을 수 있도록 설정하였다.

(여기서 주의할 점은 Chain에서 Input, Output은 하나씩만 출력하기 때문에 제대로 변수명을 입력해주어야 한다는 주의점이 있다)

 

 

Sequential Chain의 전체적인 구성을 그림으로 확인하면 다음과 같다.

 

Sequential Chain

 

 

 

 

 

 

 

 

Router Chain

 

 

 

마지막으로,

LLM Chain, Sequential Chain보다 더 복잡한 상황을 다루기 위해서는 Router Chain 을 이용하면 된다.

 

 

 

보통의 체인들은 입력 값에 따라 다른 Chain의 Output이 정확하게 어떤 Chain에 들어가야 하는지 명확하게 지정해줘야 한다.

 

예시를 들자면, 입력 값이 특정 되어 있는 여러 서브체인들이 있는 경우 먼저 라우터 체인을 통해 특정 입력 값이 필요한 서브 체인들을 지정하고 변수를 보낼 수 있다. 

 

따라서 라우터 체인은 여기서 어떤 서브체인에게 특정 변수를 전달해야 하는가를 결정한다! (따라서 이 전에 준비했던 모든 프롬프트들의 이름과 설명이 여기서 사용된다.)

 

 

Multi-Prompt Chain을 이용하면 여러 프롬프트 템플릿에 정보가 오가게 할 수 있다.

 

 

또한 Router Output Parser를 이용하면 LLM 출력 값을 딕셔너리로 분해하여 이후에 어떤 출력 값을 어떤 서브체인으로 전달하는지 정하는데 사용할 수 있다.

 

 

예시로 확인해보자!

 

Multi-prompt Router Template

 

 

이렇게 Mulit-prompt Router Template을 만들어놓고 이를 LLM 이 다른 체인들 사이를 라우팅 하는데 사용할 템플릿으로 지정한다. (이 템플릿에는 작업의 지시사항과 출력 값이 어떤 형식으로 되어야 하는지 포함되어 있음)

 

그리고 이렇게 각 관련된 템플릿을 작성한다. (Chain이 될 템플릿들)

 

physics_template = """You are a very smart physics professor. \
You are great at answering questions about physics in a concise\
and easy to understand manner. \
When you don't know the answer to a question you admit\
that you don't know.

Here is a question:
{input}"""


math_template = """You are a very good mathematician. \
You are great at answering math questions. \
You are so good because you are able to break down \
hard problems into their component parts, 
answer the component parts, and then put them together\
to answer the broader question.

Here is a question:
{input}"""

history_template = """You are a very good historian. \
You have an excellent knowledge of and understanding of people,\
events and contexts from a range of historical periods. \
You have the ability to think, reflect, debate, discuss and \
evaluate the past. You have a respect for historical evidence\
and the ability to make use of it to support your explanations \
and judgements.

Here is a question:
{input}"""


computerscience_template = """ You are a successful computer scientist.\
You have a passion for creativity, collaboration,\
forward-thinking, confidence, strong problem-solving capabilities,\
understanding of theories and algorithms, and excellent communication \
skills. You are great at answering coding questions. \
You are so good because you know how to solve a problem by \
describing the solution in imperative steps \
that a machine can easily interpret and you know how to \
choose a solution that has a good balance between \
time complexity and space complexity. 

Here is a question:
{input}"""

 

이를 바탕으로 Chain에 관련한 질문을 던지면

 

특정 체인 템플릿을 포착하는 모습

 

질문에 따라 Chain이 자동으로 설정되는 것을 확인할 수 있다.

 

 

또 Chain에 관련 없는 질문을 던지면

 

Chain 과 관련 없는 질문을 했을 때

 

Chain : None으로 지정되며 답변이 저렇게 출력되는 것을 확인할 수 있다.

 

이렇게 되면 Chain이 기본 Chain으로 넘어가는 것을 의미하며 이는 평상시의 언어 모델을 호출하게 된다. 

(하지만 위처럼 다행히도 언어 모델이 해당 내용에 대해 잘 알고 있으면 제대로 답변할 수 있음!)

 

 

 

 

체인은 이 전 강의들보다 많이 복잡하고 어려운 것 같다.

하지만, 잘 이용하면 정말 복잡한 질문을 대답하는 용도로 LLM 모델을 이용 해 볼 수 있지 않을까..!

 

역시나 부족한 부분은 공식문서 참조하기

⬇⬇⬇⬇⬇⬇⬇⬇⬇

 

https://python.langchain.com/docs/modules/chains/

 

Chains | 🦜️🔗 Langchain

Using an LLM in isolation is fine for simple applications, but more

python.langchain.com