ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • LLM 기법(2) - Langchain
    Internship_LLM 2024. 2. 5. 15:45
    728x90

    지난 포스팅에서 소개했던 RAG 기법을 사용하기 위한 프레임워크를 소개하고자 한다.

     

    ※ LangChain

    - LangChain은 언어 모델을 이용한 개발을 촉진하고 간소화하는 목적으로 만들어진 프레임워크이다.

    - 언어 모델과 상호작용하는 애플리케이션을 빠르고 쉽게 구축할 수 있도록 설계되었다.

    - 주요 목적 : 언어 모델을 활용하여 다양한 도메인과 상황에서의 문제를 해결할 수 있도록 지원하는 것.

     

    주요 기능

    1. 언어 모델 통합 : 여러 언어 모델을 쉽게 통합하고 사용할 수 있도록 해서 다양한 소스의 언어모델을 쉽게 실험하고 최적의 결과를 얻을 수 있다.

    2. toolchain & 유틸리티 : 텍스트 생성, 요약, 질문 답변 등과 같은 언어 모델을 활용한 작업 도구와 유틸리티를 제공한다.

    3. 확장성 : 개발자가 필요에 따라 자신만의 기능을 추가하거나 기존 기능을 수정해서 사용할 수 있어, 프레임워크를 다양한 애플리케이션과 쉽게 통합할 수 있도록 해준다.

     

    이러한 프레임워크도 전문적인 지식이 필요한 task에 대해서 유의미한 답변 제공이 힘들 수 있다. 이러한 한계를 극복하기 위해 지난 시간 소개했던 RAG 기법을 사용하게 되는데, 이 과정에서 관련 문서를 chunk 단위로 쪼개거나, 임베딩 하고, 질문에 대해 유사한 chunk를 검색해서 활용하는 방식을 선택한다.

     

    LangChain 모듈

    1. Model I/O

    - 언어 모델과의 직접적인 input과 output을 관리한다.

    - 특정 언어 모델에 요청을 보내고, 모델의 예측 또는 응답을 받아 처리하는 역할을 한다.

    사용 방식 : 이 모듈을 통해 언어 모델을 선택, 모델에 전송할 텍스트 정의, 모델의 응답을 애플리케이션 내에서 사용할 수 있도록 한다.

    2. Data Connection

    - 애플리케이션에 필요한 특정 데이터 소스와의 연결을 관리한다.

    - 외부 API, 데이터베이스, 파일 시스템 등의 다양한 데이터 소스를 포함한다.

    사용 방식 : 이 모듈을 통해 애플리케이션에 필요한 데이터를 검색, 저장 또는 업데이트할 수 있다.

    3. Chains - Call 시퀀스 구성

    - 여러 단계 또는 작업을 연속적으로 실행하는 로직 정의

    - 복잡한 작업을 단순화하고, 재사용 가능한 프로세스 체인을 만드는 데 유용하다.

    사용방식 : 특정 작업을 위해 필요한 단계들을 체인으로 구성하여 체인 실행을 통해 작업을 자동화할 수 있다.

    4. Agents

    - 체인이 high-level 지침에 따라 사용할 도구를 선택하도록 한다.

    5. Memory

    - 애플리케이션의 상태 또는 컨텍스트를 저장하고, 체인 실행 사이에 정보를 유지한다.

    사용 방식 : 메모리 모듈을 통해서 사용자 세션, 대화 기록, 사용자 선호도 등의 정보를 저장하고 접근할 수 있다.

    6. Callbacks

    - 체인의 중간 단계를 기록하거나 스트리밍 하는 역할.

    사용 방식 : 중간 단계에서 로그를 기록하거나, 조건부 로직을 실행시킬 수 있다.

    7. UI/UX Components

    - 사용자의 입력을 받아 처리하고, 결과를 사용자에게 표시하는 데 사용된다.

    8. Security & Authentication

    - 보안 및 인증 모듈. 사용자의 신원 확인, 데이터 접근 제어

    9. Integration Tools 

    - 외부 서비스나 애플리케이션과의 통합을 용이하게 하는 도구. API 연동, 웹훅 설정 지원

     

    LLM Chain 활용하기

    LLM Chain을 활용해서 openAI API를 통해 쉽게 애플리케이션에 LLM 서비스를 제공할 수 있다.

    1. PromptTemplate

    prompt = ChatPromptTemplate.from_messages(
        [
            (
                "system",
                """
                You are a helpful assistant. 
                Answer questions using only the following context. 
                If you don't know the answer just say you don't know, don't make it up:
                \n\n
                {context}",
                """
            ),
            ("human", "{question}"),
        ]
    )

     

    이렇게 Prompt의 Template을 제시해서, 이 형식에 맞게 ChatGPT가 대답할 수 있도록 만들어 낼 수 있다.

     

    2. ChatOpenAI

    from langchain.chat_models import ChatOpenAI
    
    api_key = "..."
    
    llm = ChatOpenAI(openai_api_key=api_key, temperatrue=0.1)
    llm.predict("instruction~~~")

     

    이 기능을 사용하면, openAI API를 효율적으로 가져올 수 있다.

     

    3. OutputParser

    from langchain_core.output_parsers import StrOutputParser
    
    rag_chain = (
        {"context": retriever | format_docs, "question": RunnablePassthrough()}
        | prompt
        | llm
        | StrOutputParser()
    )

     

    이 기능을 사용하면, 결과물을 효율적으로 parsing 할 수 있다.

     

     

    ※ LangChain를 이용하여 RAG 구현

    위 LangChain을 설명하면서 LangChain의 주요 기능 아래에 한계점에 대해서 언급했다. 이러한 전문적인 도메인에서 가지는 한계점을 극복하기 위해 RAG 기법을 사용한다고 언급했는데, 그렇다면 RAG를 어떻게 LangChain으로 구현할 수 있는지 살펴보자.

     

    RAG는 전문적인 도메인과 아직 학습하지 않은 데이터에 대해 LLM이 가지는 hallucination을 막기 위해 외부에서 검색한 정보를 활용해서 정확하고 사실적인 응답을 생성할 수 있도록 LLM의 능력을 보완하고 강화하는 기법이다.

     

    1. 로컬 문서 기반 RAG 구현

    from langchain.chat_models import ChatOpenAI
    from langchain.document_loaders import UnstructuredFileLoader
    from langchain.text_splitter import CharacterTextSplitter
    
    llm = ChatOpenAI(temperatrue=0.1)
    
    cache_dir = LocalFileStore("로컬 문서 경로")
    
    splitter = CharacterTextSplitter.from_tiktoken_encoder(
        separator='\n',         
        chunk_size=600,        
        chunk_overlap=100,      
    )
    
    loader = UnstructuredFileLoader("txt 문서 경로")
    
    docs = loader.load_and_split(text_splitter=splitter)

     

    문서 제공 시 문서를 분할해서 필요한 부분만 전달하게 되면, 정확도 감소와 비용 소모를 줄일 수 있다.

    문맥의 의미를 손상시키지 않는 선에서 적절한 크기로 분할 하는 것이 중요하다.

     

    - CharacterTextSplitter : 사용자가 지정한 문자를 기준으로 문서를 분할한다.

    - UnstructuredFileLoader : text files, powerpoints, html, pdfs, images 등 여러 가지 형식의 파일 지원에 편리하다.

    - load_and_split : 파일 로딩과 동시에 분할 진행. splitter 파라미터로 전달하고, 분할된 문서를 반환한다.

     

     

    2. 웹 기반 문서 RAG 구현

    from langchain import hub
    from langchain.text_splitter import RecursiveCharacterTextSplitter
    from langchain_community.document_loaders import WebBaseLoader
    
    loader = WebBaseLoader(
        web_paths=("웹 문서 경로",),
        bs_kwargs=dict(
            parse_only=bs4.SoupStrainer(
                class_=("post-content", "post-title", "post-header")
            )
        ),
    )
    docs = loader.load()
    
    text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
    splits = text_splitter.split_documents(docs)

     

    - WebBaseLoader : Web에서 문서 경로를 받아오는 역할

    - RecursiveCharacterTextSplitter : 공통적인 구분 기호를 사용하여 문서를 재귀적으로 분할한다.

     

     

    위 두 작업은 초반부에 문서를 load 하는 과정에 차이가 있다.

    하지만, 결국 문서를 load하고 splitter를 사용하여 문서를 분할하고 나면, 그다음 작업은 동일하다.

    1. 임베딩을 통해 vectorstore에 저장.(이 때, cache Memory를 사용하여 효율적으로 임베딩 처리를 할 수도 있다.)

    2. retriever를 사용해서 검색.

    3. prompt template을 만들어주거나 chain을 구성.

    4. invoke나 predict 하면 모든 작업이 완료된다.(invoke : 전달된 쿼리를 retriever에 전달하고, 반환된 문서를 context에 담아준다.)

     

    이 과정을 통해서 RAG 방식을 구성해서 api를 적절하게 변형시킬 수 있다.

    728x90

    'Internship_LLM' 카테고리의 다른 글

    Langchain vs Llama-index  (2) 2024.02.06
    LLM 기법(3) - Llama-index  (2) 2024.02.06
    LLM 기법 (1)  (0) 2024.02.01
    LLaMA 논문 리뷰  (2) 2024.01.31
    LLM Parameters  (0) 2024.01.26
Designed by Tistory.