본문 바로가기

Review

[리뷰] Udemy - Langchain으로 LLM 기반 어플리케이션 개발하기

 

  들어가며

LLM을 애플리케이션에 적용하려면 개발자는 프롬프트를 보내고 기다리는 것 외에도 고려해야할 많은 작업이 있습니다. LLM이 이전의 대화 내용을 기억하게 하기 위해 기록을 유지해야하고, 토큰의 한도를 지키는 전략을 취하면서 프롬프트 및 응답의 적절성을 판단하고 조정하는 등 상당한 노력을 필요로 합니다.

랭체인은 이러한 수고를 덜어주며 언어 모델 기반의 애플리케이션을 개발하도록 돕는 SDK입니다. 이번 글에서는 글또 9기 활동 중 유데미로부터 강의 쿠폰을 지원받아 【한글자막】 랭체인 - LangChain 으로 LLM 기반 애플리케이션 개발하기 강좌를 수강하고 느낀 점과 새롭게 알게된 점에 대해 간단히 정리한 부분을 남겨보려합니다.

강의에 대한 간단한 개요와 장단점은 아래와 같습니다.

  • 목표:
    • 실제 LLM 기반의 생성 AI 애플리케이션을 빠르게 개발하면서 랭체인 배우기
  • 대상 독자:
    • 파이썬 문법에 익숙한 사람
    • LLM에 대한 기본 지식이 있는 사람
    • LLM을 기반으로 애플리케이션을 개발해보고 싶은 사람
  • 과정 개요:
    • Section 1~2: 랭체인 개념 설명 및 간단한 프로젝트 구현
    • Section 4: ReAct 에이전트를 집중적으로 설명 및 구현
    • Section 5~6: 벡터 스토어를 활용하여 챗봇 구현
    • Section 7: chatgpt의 파이썬 코드 실행기를 직접 구현
    • Section 8~9: 랭체인의 토큰 처리 전략, 메모리 전략, 프롬프트 엔지니어링 종류 및 팁 설명
    • Section 10~12: 강의 마무리 및 앱 개발시 유용한 툴 소개
  • 장점:
    • 한글 자막이 잘 제공되어있음
    • 광범위한 랭체인의 개념 중 가장 핵심적인 부분에 대해 전반적으로 짧은 시간 안에 훑어보기 좋음
    • 실습중심의 설명으로 실제 앱 구현을 따라해보기 좋음
    • 프롬프트 엔지니어링의 최신 트렌드와 팁에 대해 전반적으로 설명되어있어 좋음
  • 단점:
    • 실습 중 ProxyCurl 같은 유료 서비스를 이용해야하는 과정이 있음
    • 특정 기술을 소개할 때 이론부터 소개하지 않고 바로 코딩에 들어가는 부분이 있음
    • 코딩을 하는 동안에도 실시간 디버깅을 하는 부분이 간혹 있어 흐름에 방해가 될 수 있음

 

ℹ️ 아래는 강의 수강 후 제가 정리한 부분이며, 강의 내용이 자세히 요약되지는 않았습니다. 이 강의를 고려하고 있는 분들은 강의 각 섹션에서 어떤 개념을 배울 수 있는지 간단히 참고해주시면 좋을 것 같습니다. 😊

 

  Section 1~3: 랭체인 개념 설명 및 간단한 프로젝트 구현

  프로젝트명: Ice Breaker

출처: https://github.com/emarco177/ice_breaker

  • 특정 인물의 이름을 입력하면 해당 인물을 온라인에서 검색하여 트위터 계정과 링크드인 계정을 찾고 프로필 정보를 제공해서 해당 사람과의 대화의 물꼬를 틀 수 있도록 하는 앱
  • 체인, 에이전트, 사용자 지정 에이전트, 도구(Tool), 사용자 지정 도구, 아웃풋 파서 등을 학습할 수 있음
  • 백엔드부터 프론트까지 전체적으로 구현하는 예시를 보여줌

 

  Section 4: ReAct 에이전트에 대한 내부 구현 확인

출처:  https://python.langchain.com/docs/use_cases/tool_use/agents/

  • 텍스트를 입력으로 받아 정확한 Tool을 선택해 실행하고, 응답을 큐레이팅하고 구체화하기까지 하는 일련의 과정이 구체적으로 어떻게 동작하는지 Agent프레임워크의 내부를 살펴봄
  • 해당 과정에서 LLM은 어떤 도구를 쓸지, 응답이 있는지 없는지 여부를 결정하는 추론엔진으로서 작동함
  •  

 

  Section 5: 임베딩, 벡터 데이터베이스, VectorDBQA 체인 그리고 RetrievalQA의 핵심

섹션5에서는 랭체인이 어떤식으로 다양한 형식의 문서를 저장하는 클래스를 구현하였는지 살펴보며, 섹션 6에서 실제 도큐멘테이션 어시스턴트를 구축하는 예제를 수행하게 됨

출처: https://python.langchain.com/docs/use_cases/question_answering/

Document Loaders

  • 다양한 형식의 문서들(ppt, pdf, docx..)을 저장할때 우리는 결론적으로는 텍스트를 저장하게 됨
  • 문서 로더 클래스는 문서의 형식에 관계없이 텍스트를 사용하도록 돕는 추상 클래스

Text Splitters

  • 긴 텍스트는 청크로 분할하여 처리해야함
  • 텍스트 스플리터는 텍스트의 의미가 모두 연관된 상태로 분할하고 재조립하도록 도움
  • 텍스트를 작은 부분으로 분할하여 토큰 제한 문제를 해결하도록 도움

Text Embedding Models

  • 랭체인 내의 텍스트 임베딩 모델은 유저에게 여러가지 임베딩에 대한 단일 인터페이스를 제공함
  • 어떤 임베딩 모델을 사용하는지에 상관없이 사용자는 매개변수만 바꾸면 동일한 형식의 아웃풋을 뽑아낼 수 있음
  • 즉, 임베딩 모델에 관계없이 임베딩 하도록 돕는 추상 클래스

 

  프로젝트명: Medium Analyzer

RAG - 검색 증강 생성

  • 응답에 필요한 관련 정보를 넣어 그 정보를 이용해서 답변해달라고 LLM에게 요청하는 방식
  • 그러한 정보는 vectorstore로부터 가져오게 됨
import os

from langchain.document_loaders import TextLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Pinecone
from langchain import VectorDBQA, OpenAI
import pinecone

pinecone.init(
    api_key="304950dd-a5e0-406a-9c7f-d47602abcfab",
    environment="northamerica-northeast1-gcp",
)

if __name__ == "__main__":
    print("Hello VectorStore!")
    loader = TextLoader(
        "/Users/edenmarco/Desktop/intro-to-vector-db/mediumblogs/mediumblog1.txt"
    )
    document = loader.load()

    text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
    texts = text_splitter.split_documents(document)
    print(len(texts))

    embeddings = OpenAIEmbeddings(openai_api_key=os.environ.get("OPENAI_API_KEY"))
    docsearch = Pinecone.from_documents(
        texts, embeddings, index_name="medium-blogs-embeddings-index"
    )

    qa = VectorDBQA.from_chain_type(
        llm=OpenAI(), chain_type="stuff", vectorstore=docsearch, return_source_documents=True
    )
    query = "What is a vector DB? Give me a 15 word answer for a begginner"
    result = qa({"query": query})
    print(result)

Q. 체인에 벡터스토어를 직접 전달하는 것이 아니라  as_retriever를 거치는 이유는?

  • 벡터 스토어에서 하는 검색은 시맨틱 검색을 사용하지만 다른 유형의 검색도 있음
  • 그 모든 검색 방법을 추상화할 수 있도록 하기 위해 as_retriever 를 사용하는것

 

  Section 7: 슬림한 버전의 ChatGPT 코드 인터프리터 구축하기

목표

  • OpenAI Code Interpreter의 백엔드를 직접 구현하기
  • OpenAI Code Interpreter는 GPT4를 바탕으로 만들어진 에이전트
  • 다양한 파일 형식을 지원하며 분리된 환경에서 파이썬 코드를 실행하고 결과를 반환할 수 있도록 해줌

 

작동 원리

  • 파이썬 인터프리터가 여기서는 “Tools” 에 해당
  • Tools에 대한 input이 파이썬 코드가 됨

 

Python 에이전트

  • 파이썬 코드를 input으로 받아 작업을 수행하는 PythonREPLTool 을 사용하여 파이썬 에이전트 생성
  • 주의) 에이전트가 추론 과정에서 올바른 도구를 선택하지 못하는 경우가 발생할 수 있음
    • GPT4 활용 및 프롬프트 엔지니어링으로 조정을 수행해야함

 

CSV 에이전트

  • pandas에이전트를 바탕으로 만들어짐
  • CSV데이터를 추출해서 기존의 프롬프트를 자체적으로 증강하여 llm이 더 잘 답변하도록 함
  • 주의) pandas 코드를 실행하더라도 답이 정확히 맞지 않을 때가 있음
    • 한두 줄을 빠뜨려 필요한 정보를 모두 전달하지 않았거나, 추론 과정이 올바르지 않을 수 있음
    • 이는 GPT-4를 사용하더라도 추론 과정에 일부 오류가 있을 수 있음

 

종합: Router 에이전트

  • 라우터 에이전트: 사용자의 쿼리를 기준으로 해당 쿼리를 실행할 에이전트를 결정
    • PythonAgentCSVAgent 를 tools에 넣어주고 OPENAI_FUNCTIONS 를 agent_type으로 함
    • 즉, OpenAI 함수 호출 기능에 의존하도록

 

OpenAI Functions ?

  • 이전의 섹션4에서 다루었던 ReAct에이전트 외에도 다양한 에이전트 타입이 있음
  • 이전의 Python 에이전트 생성시에도 문제가 되었던 “에이전트가 추론 과정에서 올바른 도구를 선택하지 못하는 경우” 에 대한 OpenAI의 솔루션
  • 알맞은 도구를 선택하는 과제는 openai가 처리하는 대신 사용자는 제대로 된 정보와 특정 스키마 유형만 제공해주면 됨
    • 함수가 하는 일, 받아서 처리하는 인수, 반환할 내용 등

 

 

  Section 8: 랭체인 이론

섹션8에서는 랭체인이 토큰 한도를 처리하는 전략과 메모리를 저장하는 방식에 대한 기본적인 개념들을 소개함

 

  랭체인의 토큰 한도 처리 전략

  • 문서 요약작업을 예시로 들어 랭체인의 다양한 토큰 한도 처리 전략에 대해 확인

1. Stuff

출처:  https://github.com/ksm26/LangChain-Chat-with-Your-Data?tab=readme-ov-file

  • 가장 간단한 접근 방식
  • 봉제 인형에 솜과 섬유를 채워넣듯, 프롬프트에 컨텍스트 즉 문서를 모두 채우고 싶다고 말하는것
  • 단점:
    • 이 방식은 토큰 제한 문제를 해결하지 못함

 

2. Map Reduce

  • 각 문서별로 프롬프트를 생성해서 LLM 요청 후(map) 결과를 취합 (reduce)하는 방식
  • 문서가 서로 의존하지 않고 독립적으로 실행될 수 있기 때문에 병렬로 실행 가능
  • 단점:
    • API 호출을 수가 많아지므로 비용에 영향
    • 각 문서를 요약하는 매핑 과정에서 정보가 손실될 수 있음

 

3. Refine

  • 점진적으로 문서를 요약한 결과를 덧붙여가면서 누적해서 요약하는 방식
  • 1번 문서 요약
    • (1번 요약 + 2번 문서) 요약
      • (1+2번 요약 + 3번 문서) 요약 … 이런식으로 수행
  • 장점: 문서의 맥락을 유지하며 긴 문서를 요약
  • 단점:
    • 이 또한 API 호출 회수가 많음
    • LLM을 순차적으로 호출해야하므로 작업 시간이 길어짐

 

  랭체인 메모리 심층 분석

1. ConversationBufferMemory:

  • 대화는 기본적으로 “버퍼”에 저장한다.

2. ConversationBufferWindowMemory:

  • 대화가 길어질수록 버퍼는 계속 커지기 때문에 가장 최근의 K개의 대화를 메모리에 저장하는 방식을 취한다.
  • k=2이면 매번 두 개의 메시지만 기록에 유지한다는 뜻

3. ConversationTokenBufferMemory

  • 메시지의 수가 아니라 버퍼에 저장할 토큰 수를 제한하는 방식
  • 기본값은 2000 토큰

4. ConversationSummaryMemory

  • 모든 시점마다 대화의 요약을 가지고 있는 방식

5. Entity Memory

  • 특정 엔티티에 대한 정보를 기억하는 메모리

 

ℹ️ 이외의 메모리 타입을 확인하려면 공식 문서를 참고

 

 

  마무리

해당 강의를 마무리하면서 몇 가지 핵심 사항을 강조하고 싶습니다.

첫째, 이 강의는 Lang Chain에 대한 유용한 개요를 제공했지만 주제에 대해 더 깊이 파고들려면 공식 문서와 예제를 개인적으로 자세히 봐야할 것입니다.

둘째, 이번 세션에서 몇 가지 실용적인 애플리케이션 구현에 대해 다루었지만 Lang Chain을 사용하여 앱을 개발하는 기술을 익히려면 좀 더 큰 규모의 오픈 소스 프로젝트나 예제를 조사해보는 것이 좋을 것 같습니다.

LLM 앱개발 학습과정의 첫 단추로서 해당 강의는 필요한 기본 개념과 기술에 대해 쉽게 알려주기 때문에 매우 도움이 되었습니다. 그러나 이론적인 부분 이외에도 실제로 코드를 작성하고 실행하는 과정을 경험해보는 것이 중요하니, 강의를 수강하시는 동안 실습에 충분한 시간을 투자하시는 것이 좋겠습니다! 👀