langchain 기반의 LLM 애플리케이션 개발을 위해 chain 및 agent 모듈 사용을 위한 단계적 가이드 – 3부) RouterChain

개요

1부 글, 2부 글에 이어서 가장 복잡한 RouterChain에 대해서 설명한다.

RouterChain

RouterChain은 복잡한 작업에 사용됩니다. 예를 들어, 매우 일반적이지만 기본적인 작업은 해당 입력이 정확히 무엇인지에 따라 입력을 체인으로 라우팅하는 것입니다. 각각 특정 유형의 입력에 특화된 여러 하위 체인이 있는 경우 입력을 전달할 하위 체인을 결정하는 라우터 체인을 가질 수 있습니다. 예를 들어, 특정 유형의 입력에 대해 특화된 각각에 따라 여러 하위 체인 간에 라우팅할 수 있습니다.

예를 들어 수학, 물리학 등과 같은 주제를 기반으로 다양한 유형의 체인 간에 라우팅할 수 있습니다. 따라서 주제 유형에 따라 다양한 프롬프트를 가질 수 있습니다. 따라서 물리학 질문에 답하기 위한 프롬프트 하나, 수학 질문에 답하기 위한 두 번째 프롬프트, 역사 질문에 답하기 위한 세 번째 프롬프트, 컴퓨터 공학 질문에 답하기 위한 네 번째 프롬프트를 가질 수 있습니다.

이러한 주제에 대한 프롬프트 템플릿을 정의할 수 있습니다. 이러한 프롬프트 템플릿에 대한 추가 정보도 제공할 수 있습니다. 예를 들어 각 템플릿에 이름과 설명을 지정할 수 있습니다. 이제 이 정보를 라우터 체인에 전달할 수 있으며 라우터 체인은 언제 어떤 서브체인을 사용할지 결정할 수 있습니다.

physics_template = """당신은 매우 유능한 물리학 교수입니다.
당신은 물리학에 관한 질문에 간결하고 이해하기 쉬운 방식으로 대답하는 데 능숙합니다.
당신이 받은 질문에 대한 답을 모를 때 '잘 모르겠습니다.'라고 답하면 됩니다.

아래 질문에 대한 답변을 해주세요:
{input}"""


math_template = """당신은 매우 유능한 수학자입니다.
당신은 수학 질문에 답하는 데 능숙합니다.
당신은 어려운 문제를 여러 개의 단순한 문제로 분해하는 것이 가능한데,
먼저 분해된 문제에 대해서 개별적으로 답변을 하고, 그 다음에 그것들을 종합하여 최종적으로 답변을 할 수 있습니다.

아래 질문에 대한 답변을 해주세요:
{input}"""

history_template = """당신은 매우 훌륭한 역사가입니다.
당신은 다양한 역사적 시대의 사람, 사건 및 맥락에 대한 탁월한 지식과 이해를 가지고 있습니다 .
당신은 생각하고, 반성하고, 토론하고, 평가할 수 있는 능력을 가지고 있습니다.
당신은 역사적 증거에 대한 존경심을 가지고 있으며 당신의 설명과 판단을 뒷받침하기 위해 그것을 활용할 수 있는 능력이 있습니다 .

아래 질문에 대한 답변을 해주세요:
{input}"""


computerscience_template = """당신은 성공적인 컴퓨터 과학자입니다. 
당신은 창의성, 협업, 미래 지향적 사고, 자신감, 강력한 문제 해결 능력, 이론 및 알고리즘에 대한 이해, 그리고 훌륭한 의사소통 역량을 가지고 있으며 코딩 질문에도 훌륭하게 대답할 수 있습니다.
당신은 기계가 쉽게 해석할 수 있는 필수 단계로 솔루션을 설명하여 문제를 해결하는 방법을 알고 있고, 시간 복잡도와 공간 복잡도 사이의 균형이 잘 맞는 솔루션을 선택하는 방법을 알고 있기 때문에 정말 훌륭합니다.

아래 질문에 대한 답변을 해주세요:
{input}"""
prompt_infos = [
    {
        "name": "physics", 
        "description": "Good for answering questions about physics", 
        "prompt_template": physics_template
    },
    {
        "name": "math", 
        "description": "Good for answering math questions", 
        "prompt_template": math_template
    },
    {
        "name": "History", 
        "description": "Good for answering history questions", 
        "prompt_template": history_template
    },
    {
        "name": "computer science", 
        "description": "Good for answering computer science questions", 
        "prompt_template": computerscience_template
    }
]

이제 여러 개의 서로 다른 프롬프트 템플릿 간에 라우팅할 때 사용되는 특정 유형의 체인인 다중 프롬프트 체인이 필요합니다. 또한 언어 모델을 사용하여 서로 다른 하위 체인 간에 라우팅하는 LLMRouterChain도 필요합니다. Prompt_infos에서 제공한 설명과 이름을 사용합니다. 또한 LLM 출력을 다운스트림에서 사용할 수 있는 사전으로 구문 분석하여 사용할 체인과 해당 체인에 대한 입력이 무엇인지 결정하는 라우터 출력 파서를 가져옵니다.

import os
# 환경변수에 OPENAI_API_KEY를 설정합니다.
os.environ["OPENAI_API_KEY"] = "sk-XXXXXXXXXXXXXXXXXXXXXXX" 

from langchain.chat_models import ChatOpenAI
from langchain.chains.router import MultiPromptChain
from langchain.chains.router.llm_router import LLMRouterChain,RouterOutputParser
from langchain.prompts import PromptTemplate, ChatPromptTemplate
from langchain.chains import LLMChain

# Define the language model that we will use. 
llm = ChatOpenAI(temperature=0)

이제 대상 체인을 생성해야 합니다. 대상 체인은 RouterChain에 의해 호출되는 체인입니다. 각 대상 체인 자체는 언어 모델 체인, 즉 LLM 체인입니다. 또한 라우터가 사용할 하위 체인을 결정할 수 없을 때 호출되는 기본 체인을 정의합니다.

# Create destination chains
destination_chains = {}
for p_info in prompt_infos:
    name = p_info["name"]
    prompt_template = p_info["prompt_template"]
    prompt = ChatPromptTemplate.from_template(template=prompt_template)
    chain = LLMChain(llm=llm, prompt=prompt)
    destination_chains[name] = chain  
    
destinations = [f"{p['name']}: {p['description']}" for p in prompt_infos]
destinations_str = "\n".join(destinations)

이제 LLM이 서로 다른 체인 간을 라우팅하는 데 사용하는 템플릿을 정의합니다. 여기에는 수행할 작업에 대한 지침과 출력에 포함되어야 하는 특정 형식이 포함되어 있습니다.

default_prompt = ChatPromptTemplate.from_template("{input}")
default_chain = LLMChain(llm=llm, prompt=default_prompt)

아래는 라우팅 처리를 위한 프롬프트를 영어로 작성했는데, 이렇게 기능적인 동작을 위한 프롬프트의 경우 번역기를 쓰서라도 영어로 하는게 유리하다. 왜냐하면 ChatGPT는 영어를 더 잘 이해하고, 영어로 처리할때 더 적은 token을 이용하기 때문에 속도에 유리하다. (같은 동작을 한글로 하면 영어에 비해 2~3배 정도 느림)

MULTI_PROMPT_ROUTER_TEMPLATE = """Given a raw text input to a \
language model select the model prompt best suited for the input. \
You will be given the names of the available prompts and a \
description of what the prompt is best suited for. \
You may also revise the original input if you think that revising\
it will ultimately lead to a better response from the language model.

<< FORMATTING >>
Return a markdown code snippet with a JSON object formatted to look like:
```json
{{{{
    "destination": string \ name of the prompt to use or "DEFAULT"
    "next_inputs": string \ a potentially modified version of the original input
}}}}
```

REMEMBER: "destination" MUST be one of the candidate prompt \
names specified below OR it can be "DEFAULT" if the input is not\
well suited for any of the candidate prompts.
REMEMBER: "next_inputs" can just be the original input \
if you don't think any modifications are needed.

<< CANDIDATE PROMPTS >>
{destinations}

<< INPUT >>
{{input}}

<< OUTPUT (remember to include the ```json)>>"""

이제 위에서 정의한 대상으로 형식을 지정하여 전체 라우터 템플릿을 만듭니다. 이 템플릿은 다양한 유형의 대상에 유연하게 적용됩니다. 위에 정의된 물리학, 수학, 역사 또는 컴퓨터 과학 외에 영어/라틴어와 같은 다양한 유형의 대상을 추가할 수 있습니다.

또한 이 템플릿에서 프롬프트 템플릿을 생성하고 LLM 및 전체 라우터 프롬프트를 전달하여 라우터 체인을 생성합니다. 우리는 라우터 체인이 어느 하위 체인 사이에 라우팅할지 결정하는 데 도움이 되는 라우터 출력 파서도 사용했습니다. 마지막으로 라우터 체인, 대상 체인 및 기본 체인이 있는 전체 체인을 생성합니다.

router_template = MULTI_PROMPT_ROUTER_TEMPLATE.format(
    destinations=destinations_str
)
router_prompt = PromptTemplate(
    template=router_template,
    input_variables=["input"],
    output_parser=RouterOutputParser(),
)

router_chain = LLMRouterChain.from_llm(llm, router_prompt)

chain = MultiPromptChain(router_chain=router_chain, 
                         destination_chains=destination_chains, 
                         default_chain=default_chain, verbose=True
                        )
# Ask some questions to RouterChain
ret = chain.run("초전도체란 물질은 어떤 특성을 가지고 있습니까?")
print(ret)

아래와 같이 답변을 잘해준다

초전도체는 매우 낮은 온도에서 전기 저항이 없는 물질입니다. 이는 전기 전류가 자유롭게 흐를 수 있음을 의미합니다. 또한, 초전도체는 자기장을 효과적으로 배제할 수 있는 특성을 가지고 있습니다. 이러한 특성은 초전도체가 전력 손실 없이 전기를 전달하는 데 매우 유용하며, 자기 공명 이미징(MRI)과 같은 응용 분야에서도 중요한 역할을 합니다.

Leave a Comment