RAG : Query Transformation/ Query Routing

|

Query Transformation

HyDE (Hypothetical Document Embedding)

HyDE는 LLM을 통해 query에 대한 가상 응답/가상 문서를 생성하는 방법이다. 생성된 가상 응답/문서는 chunk retrieval에 사용된다.

from langchain_core.pydantic_v1 import BaseModel, Field
from typing import Literal
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
 
def hyde(query):
    prompt = ChatPromptTemplate.from_template(
        """You're an AI language assistant. 
        Please write a passage to answer the question.
        By doing so, you're helping the user with more information.
        Don't explain the question. Only provide a more broader version of it.
        The output should be in Korean.
        
        Question: {question}
        Output:
        """
        )
    
    # Chain
    hyde_chain = prompt | llm | StrOutputParser()
    generation = hyde_chain.invoke({"question": query})
    return generation

query="2022년부터 2023년 사이에 가장 주목 받은 LLM 모델들에 대해 설명해주세요. "
hyde(query)
output:
'2022년부터 2023년 사이에 인공지능 분야에서는 대규모 언어 모델(LLM)의 급격한 발전이 있었습니다. 특히 주목받은 모델로는 OpenAI의 GPT-3.5와 GPT-4, Google의 PaLM과 LaMDA, Anthropic의 Claude, Meta의 LLaMA 등이 있습니다.\n\nGPT-3.5와 GPT-4는 ChatGPT를 통해 대중에게 널리 알려졌으며, 자연스러운 대화와 다양한 작업 수행 능력으로 주목받았습니다. Google의 PaLM은 540B 파라미터로 대규모 모델의 새로운 기준을 제시했고, LaMDA는 대화의 자연스러움을 크게 향상시켰습니다.\n\nClaude는 윤리적이고 안전한 AI를 목표로 개발되어 주목받았으며, Meta의 LLaMA는 오픈소스로 공개되어 연구자들과 개발자들에게 큰 관심을 받았습니다.\n\n이러한 모델들은 텍스트 생성, 번역, 요약, 코딩 지원 등 다양한 분야에서 혁신적인 성능을 보여주었고, AI 기술의 미래에 대한 기대를 한층 높였습니다. 동시에 AI 윤리, 편향성, 저작권 등의 이슈도 함께 부각되어 사회적 논의를 촉발시켰습니다.'

Multi/Sub query transformation

LLM을 통해 복잡한 query를 여러 개의 단순한 query로 생성하거나, query를 다양한 버전으로 생성하는 방법이다.

from langchain_core.pydantic_v1 import BaseModel, Field
from typing import Literal
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

def multi_query(query):
    prompt = ChatPromptTemplate.from_template(
        """You are an AI language model assistant. 
        Your task is to create five versions of the user's question to fetch documents from a vector database. 
        By offering multiple perspectives on the user's question, your goal is to assist the user in overcoming some of the restrictions of distance-based similarity search. 
        Give these alternative questions, each on a new line.
        The output should be in Korean.
        
        Question: {question}
        Output:
        """
        )
    
    # Chain
    multi_query_chain = prompt | llm | StrOutputParser() | (lambda x: x.split("\n"))
    generation = multi_query_chain.invoke({"question": query})
    return generation

query="2022년부터 2023년 사이에 가장 주목 받은 LLM 모델들에 대해 설명해주세요. "
multi_query(query)
output:
['2022년부터 2023년 사이에 주목받은 주요 LLM 모델들은 무엇인가요?',
 '최근 2년간 인공지능 언어 모델 분야에서 가장 혁신적인 발전은 어떤 것들이 있었나요?',
 'ChatGPT와 GPT-4 외에 주목할 만한 대규모 언어 모델은 어떤 것들이 있나요?',
 '2022-2023년 사이 출시된 LLM 모델들의 특징과 성능을 비교해주세요.',
 '최근 LLM 기술 발전 동향과 주요 기업들의 AI 언어 모델 개발 현황은 어떠한가요?']

Step-back prompting

LLM을 통해 Query가 보다 넓은 범위를 포함하도록 변경하는 방법이다. 이 방법을 통 query가 너무 구체적이고 세부적이어서 발생하는 문제를 완화할 수 있다.

from langchain_core.pydantic_v1 import BaseModel, Field
from typing import Literal
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

def step_back_prompting(query):
    prompt = ChatPromptTemplate.from_template(
        """You are an expert software engineer. 
        Your task is to rephrase the given question into a more general form that is easier to answer.
        The output should be in Korean.
        
        # Example 1
        Question: How to improve Django performance?
        Output: what factors impact web app performance?
        
        # Example 2
        Question: How to optimize browser cache in Django?
        Output: What are the different caching options?
        
        
        Question: {question}
        Output:
        """
        )
    
    # Chain
    step_back_prompt_chain = prompt | llm | StrOutputParser()
    generation = step_back_prompt_chain.invoke({"question": query})
    return generation

query="2022년부터 2023년 사이에 가장 주목 받은 LLM 모델들에 대해 설명해주세요. "
step_back_prompting(query)
output:
'최근 몇 년간 주목받은 대규모 언어 모델(LLM)들의 주요 특징과 발전 동향은 무엇인가요?'

Query Routing

LLM Completion Router

LLM 자체의 completion을 이용한 Routing 방식

from langchain_core.pydantic_v1 import BaseModel, Field
from typing import Literal
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

def completion_router(query):
    prompt = ChatPromptTemplate.from_template(
        """Given the user question below, classify it as either
        being about `AI`, `Law`, `Social`, or `Other`.
        
        Do not respond with more than one word.
        
        <question>
        {question}
        </question>
        
        Classification:
        """
        )
    
    # Chain
    completion_router_chain = prompt | llm | StrOutputParser()
    generation = completion_router_chain.invoke({"question": query})
    return generation

query="2022년부터 2023년 사이에 가장 주목 받은 LLM 모델들에 대해 설명해주세요. "
completion_router(query)
output:
'AI'

LLM Function Calling Router

pydantic Function call을 통한 query routing 방법

from langchain_core.pydantic_v1 import BaseModel, Field
from typing import Literal
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

class RouteQuery(BaseModel):
    """Route a user query to the most relevant datasource."""

    datasource: Literal["AI", "Law", "Social", "Other"] = Field(
        ...,
        description="Given a user question choose to route it to AI or Law or Social or other.",
    )

def query_router(query):
    structured_llm_router = llm.with_structured_output(RouteQuery)
    
    system = """You are an expert at routing a user question to a vectorstore or web search or casual conversation.
    The vectorstore contains documents related to language processing, and artificial intelligence.
    Use the vectorstore for questions on these topics. For all else, use web-search.
    If the question is a casual conversation use original knowledge"""
    route_prompt = ChatPromptTemplate.from_messages(
        [
            ("system", system),
            ("human", "{question}"),
        ]
    )
    
    question_router = route_prompt | structured_llm_router
    result=question_router.invoke({"question": query})

    return result

query="2022년부터 2023년 사이에 가장 주목 받은 LLM 모델들에 대해 설명해주세요. "
query_router(query)
output:
RouteQuery(datasource='AI')

Semantic Router

예시로 지정된 sample query list와의 similarity search를 통한 query routing 방법

from semantic_router import Route
from semantic_router.encoders import CohereEncoder, OpenAIEncoder
from semantic_router.layer import RouteLayer

ai = Route(
    name="ai",
    utterances=[
        "LLaMa 3 모델 구조에 대해 알려줘",
        "2022년부터 2023년 사이 주목 받은 LLM모델들 알려줘",
        "LLM이 뭐야?",
        "OCR에 필요한 기술들 알려줘",
        "RAG이 뭐야?",
    ],
)

chitchat = Route(
    name="chitchat",
    utterances=[
        "안녕!",
        "오늘 기분이 좋아.",
        "저녁 메뉴 추천해줘",
        "주말에 볼 넷플릭스 영화 추천해줘",
        "평화롭고 좋다",
    ],
)

routes = [ai, chitchat]


os.environ["OPENAI_API_KEY"] =  Openai_API_KEY
encoder = OpenAIEncoder()

route_layer = RouteLayer(encoder=encoder, routes=routes)

print(f"{route_layer('mistral 모델 구조 알려줘').name}, {route_layer('오늘 조금 피곤한데 피로 해소 방법 알려줘').name}")
output:
ai, chitchat