LangChain Chat with Your Data - Harrison Chase
March 17, 2024
Overview #
LLM Application 을 구축하기 위한 오픈 소스 개발자 프레임 워크와 관련해서
Langchain CEO인 Harrison Chase가 https://www.deeplearning.ai/short-courses/
에서 발표한 내용입니다.
LangChain은 대규모 언어 모델(Large Language Model, LLM) 기반 애플리케이션을 구축하기 위한 오픈 소스 도구입니다.
Langchain 관련 관심이 있다면 해당 short course를 들어보시길 권장드립니다.
해당 수업을 들으면서 간략하게 정리했던 내용 공유합니다.
LangChain 프레임워크의 다양한 구성 요소들은 다음과 같습니다: #
- Prompts: 프롬프트 템플릿, 출력 파서, 재시도/수정 로직, 예시 선택기 등을 포함합니다.
- Models: LLM 통합 20개 이상, 채팅 모델, 텍스트 임베딩 모델 통합 10개 이상을 제공합니다.
- Indexes: 문서 로더, 텍스트 분할기, 벡터 저장소, 검색기 통합 10개 이상을 포함합니다.
- Chains: 다른 체인을 위한 빌딩 블록으로 사용할 수 있으며, 20개 이상의 다양한 애플리케이션 특정 체인이 있습니다.
- Agents: 5가지 이상의 에이전트 타입, LLM이 도구를 사용하도록 하는 알고리즘, 10개 이상의 에이전트 툴킷이 있으며, 특정 애플리케이션에 대한 특정 도구로 무장한 에이전트를 제공합니다.
이 프레임워크는 개발자가 LLM 기반의 애플리케이션을 쉽게 구축할 수 있도록 지원하며,
다양한 구성 요소와 도구를 통해 필요에 맞는 맞춤형 솔루션을 개발할 수 있게 합니다.
LangChain을 사용하여 데이터와 대화하는 방법 정리 #

1. Document Loading #

데이터와 대화할 수 있는 애플리케이션을 만들기 위해서는 먼저 작업할 수 있는 형식으로 데이터를 로드해야 합니다. 이때 LangChain 문서 로더가 중요한 역할을 합니다. (80가지 이상의 다양한 유형의 문서 로더를 지원)
문서 로더는 다양한 형식과 소스의 데이터를 접근하고 표준화된 형식으로 변환하는 구체적인 작업을 다룹니다. 데이터를 로드하고자 하는 곳은 웹사이트, 다양한 데이터베이스, YouTube와 같은 다른 장소가 될 수 있으며, 이 문서들은 PDF, HTML, JSON과 같은 다양한 데이터 유형으로 제공될 수 있습니다. 그래서 문서 로더의 전체 목적은 이러한 다양한 데이터 소스를 표준 문서 객체로 로드하는 것입니다. 이는 내용과 관련 메타데이터로 구성됩니다.
LangChain에는 많은 종류의 문서 로더가 있으며, 모두를 다룰 시간은 없지만 80개 이상이 있다는 대략적인 분류를 보여줍니다. 많은 것들이 YouTube, Twitter, Hacker News와 같은 공개 데이터 소스에서 텍스트 파일과 같은 비구조화된 데이터를 로드하는 데에 초점을 맞추고 있으며, Figma, Notion과 같이 비구조화된 데이터를 로드하는 데에도 쓰일 수 있음.
물론, 문서 로더는 구조화된 데이터를 로드하는 데에도 사용할 수 있습니다.
2. Document Splitting #

더 작은 조각으로 나누는 방법
문서 분할은 데이터를 문서 형식으로 로드한 후, 그것이 벡터 저장소로 가기 전에 일어납니다. 이것은 매우 단순해 보일 수 있습니다. 각 문자의 길이에 따라 조각을 나눌 수도 있겠죠. 하지만 까다로운 작업입니다. 어떻게 조각을 나누느냐에 따라서,
많은 뉘앙스와 중요성이 있어, 의미적으로 관련된 조각들이 함께 있도록 해야 합니다. Lang Chain의 모든 텍스트 분할자는 일정한 조각 크기와 일부 조각 중첩을 가지고 조각을 나누는 것을 기본으로 합니다. 우리는 조각의 크기를 측정하기 위해 길이 함수를 전달할 수 있게 합니다. 이것은 종종 문자나 토큰입니다.
조각 중첩은 일반적으로 두 조각 사이에 조금의 중첩을 유지하는 것으로, 우리가 하나에서 다른 하나로 이동할 때 슬라이딩 윈도우처럼 작동합니다. 이것은 같은 맥락의 일부가 한 조각의 끝과 다른 조각의 시작에 있게 하여 일관성의 느낌을 생성하는 데 도움이 됩니다. Lang Chain의 텍스트 분할자는 모두 문서 생성 및 문서 분할 방법을 가지고 있습니다. 이것은 내부적으로 같은 논리를 포함하지만, 약간 다른 인터페이스를 노출합니다. 하나는 텍스트 목록을 입력으로 받고 다른 하나는 문서 목록을 입력으로 받습니다. Lang Chain에는 많은 다른 유형의 분할자가 있습니다
3. Vectorstores and Embedding #

이제 문서를 의미론적으로 의미 있는 작은 조각으로 나누었고, 이제 이러한 조각들을 색인에 넣어 데이터의 이 코퍼스에 대한 질문에 답할 때 쉽게 검색할 수 있게 할 시간입니다. 이를 위해 임베딩과 벡터 저장소를 활용할 것입니다.
하지만 지금은 벡터 저장소와 임베딩에 대해 이야기해봅시다.
이것은 텍스트 분할 후, 문서를 쉽게 접근할 수 있는 형식으로 저장할 준비가 되었을 때 발생합니다.
임베딩이란? 텍스트 한 조각을 취하고 그 텍스트의 수치적 표현을 생성합니다.
유사한 내용의 텍스트는 이 수치 공간에서 유사한 벡터를 가질 것입니다.
이것이 의미하는 바는, 그 벡터들을 비교하고 유사한 텍스트 조각을 찾을 수 있다는 것입니다.
아래 예에서, 우리는 애완 동물에 관한 두 문장이 매우 유사하다는 것을 볼 수 있으며, 애완 동물에 관한 문장과 자동차에 관한 문장은 별로 유사하지 않다는 것을 볼 수 있습니다. 전체 end-to-end 워크플로우를 상기시키기 위해, 문서로 시작해서, 그 문서들의 더 작은 분할을 생성하고, 그 문서들의 임베딩을 생성한 다음, 모든 것을 벡터 저장소에 저장합니다. 벡터 저장소는 나중에 유사한 벡터를 쉽게 찾아볼 수 있는 데이터베이스입니다. 이것은 손에 있는 질문에 관련된 문서를 찾으려고 할 때 유용해질 것입니다. 그때 손에 있는 질문의 임베딩을 생성하고, 벡터 저장소의 모든 다른 벡터들과 비교를 수행한 다음, 가장 유사한 n개를 선택할 수 있습니다. 그런 다음 가장 유사한 n개의 조각들을 질문과 함께 LLM으로 전달하고 답변을 받아냅니다.
4. Retrieval #

(그림은 “Maximum Marginal Relevance (MMR)“이라는 개념을 설명하고 있습니다. 이는 정보 검색시 가장 관련성 높은 결과물만을 선택하는 것이 아니라, 다양한 결과물을 제공하기 위한 방법을 말합니다. 그림의 상단에서 요리사가 생각하는 구름 안에 “Tell me about all-white mushrooms with large fruiting bodies"라는 텍스트가 보이는데, 이는 검색 쿼리의 예시를 나타냅니다.
그 아래에는 두 개의 응답 예시가 보입니다. 첫 번째 응답은 “The Amanita phalloides has a large and imposing epigeous (aboveground) fruiting body (basidiocarp).“라고 되어 있고, 이는 가장 관련성이 높은 응답입니다. 두 번째 응답은 “A mushroom with a large fruiting body is the Amanita phalloides. Some varieties are all-white.“라고 되어 있고, 이는 MMR을 사용하여 선택된 응답입니다. MMR을 통해 선택된 응답은 단순히 관련성이 높은 것뿐만 아니라, 제공된 정보의 다양성을 높이기 위해 선택된 것입니다.
마지막으로, “AA. phalloides, a.k.a Death Cap, is one of the most poisonous of all known mushrooms.“라는 텍스트는 다른 관점에서 관련 정보를 제공하여, 검색 결과의 다양성을 더욱 향상시키는 예시를 보여줍니다.)
이 그림은 사용자가 주어진 쿼리에 대해 가장 관련성이 높은 답변뿐만 아니라, 다양한 정보를 포함하는 답변을 받을 수 있도록 돕는 MMR의 개념을 시각적으로 설명하고 있습니다.
지난 수업에서 의미 검색의 기본 사항을 다루고 이것이 많은 사용 사례에서 상당히 잘 작동한다는 것을 보았습니다. 하지만 몇 가지 경계 사례도 보고, 일부 상황에서 문제가 발생할 수 있음을 보았습니다. 이번 수업에서는 검색에 대해 심층 탐구하고 이러한 경계 사례를 극복하기 위한 몇 가지 더 진보된 방법에 대해 다룰 것입니다. 이것이 매우 흥미롭다고 생각합니다. 왜냐하면 검색은 새로운 것이며 우리가 이야기하는 많은 기술들이 지난 몇 달 동안 나타났기 때문입니다.
“검색”
질문이 들어왔을 때 가장 관련성 높은 조각들을 검색하고 싶을 때 중요합니다. 첫 번째로 다룰 것은 최대한변응답률(MMR)입니다. 만약 항상 임베딩 공간에서 질문과 가장 유사한 문서들만을 선택한다면, 한 경계 사례에서 보았듯이, 다양한 정보를 놓칠 수 있습니다. 이 예에서, 모든 하얀 버섯에 대해 묻는 요리사를 가지고 있습니다. 가장 유사한 결과를 보면, 첫 번째 두 문서가 될 것이며, 여기에는 과일체에 대한 정보와 전부 하얀색이라는 질문과 유사한 많은 정보가 있습니다. 하지만 우리는 정말로 그것이 매우 독성이 있다는 다른 정보도 얻고 싶어 합니다. 이것이 MMR을 사용하는 것이 중요한 이유 입니다. 다양한 문서 세트를 선택할 수 있도록 하기 때문입니다.
MMR의 아이디어는 질문을 보내고, 그 다음에 “fetch_k"라는 우리가 제어할 수 있는 매개변수를 기반으로 얼마나 많은 응답을 받을지 결정하는 응답 세트를 초기에 받아옵니다. 이것은 오로지 의미론적 유사성에 기반합니다. 거기서부터, 그 더 작은 문서 세트와 함께 작업하여, 의미론적 유사성을 기반으로 한 가장 관련성 높은 문서뿐만 아니라 다양한 문서들도 최적화합니다. 그 문서 세트에서, 사용자에게 반환할 최종 “k"를 선택합니다.
또 다른 검색 유형은 자가 질문입니다. 이것은의미론적으로 찾아보고 싶은 내용뿐만 아니라 일부 메타데이터에 대한 필터를 하고 싶은 언급을 포함하는 질문을 받을 때 유용합니다. 예를 들어, 1980년에 만들어진 외계인에 관한 영화는 무엇인가?라는 질문을 봅시다. 이것은 정말로 두 부분을 가지고 있습니다. 의미론적 부분, 외계인 비트입니다. 영화 데이터베이스에서 외계인을 찾고 싶어합니다. 하지만 이것은 또한 각 영화에 대한 메타데이터, 즉 연도가 1980년이어야 한다는 사실을 실제로 언급하는 부분도 가지고 있습니다. 할 수 있는 것은 언어 모델 자체를 사용하여 원래 질문을 두 가지 별개의 것으로 나누는 것입니다, 필터와 검색 용어. 대부분의 벡터 저장소는 메타데이터 필터를 지원합니다. 그래서 연도가 1980년인 것과 같은 메타데이터를 기반으로 기록을 쉽게 필터링할 수 있습니다.
마지막으로, 압축. 검색된 구절들에서 가장 관련성 높은 부분들만 정말로 추출하는 데 유용. 예를 들어, 질문을 하고 저장된 전체 문서를 받아오더라도, 실제로 관련된 부분은 첫 번째 또는 두 번째 문장만일 수 있습니다. 압축을 사용하면, 그 모든 문서들을 언어 모델을 통해 실행하고 가장 관련성 높은 부분들을 추출한 다음, 가장 관련성 높은 부분들만 최종 언어 모델 호출에 전달할 수 있습니다. 언어 모델에 더 많은 호출을 하는 비용이 들지만, 최종 답변을 오로지 가장 중요한 것들에만 집중하는 데에 정말 좋습니다.
5. Question Answering #

주어진 질문에 대해 관련된 문서를 검색하는 방법을 살펴보았습니다. 다음 단계는 그 문서들과 원래의 질문을 언어 모델에 전달하고, 그것에게 질문에 대답하도록 요청하는 것입니다.
이번 수업에서는 방금 검색한 문서를 사용하여 질문에 답하는 방법을 다룰 것입니다. 이것은 전체 저장 및 수집 작업을 마친 후, 관련된 조각들을 검색한 후에 이루어집니다. 이제 그것을 언어 모델에 전달하여 답을 얻어야 합니다. 일반적인 흐름은, 질문이 들어오고, 관련 문서를 찾은 다음, 그 조각들을 시스템 프롬프트와 인간의 질문과 함께 언어 모델에 전달하고 답을 얻습니다.
기본적으로, 모든 조각들을 같은 컨텍스트 창, 같은 언어 모델 호출로 전달합니다. 하지만, 그것에 대한 장단점이 있는 몇 가지 다른 방법들을 사용할 수 있습니다. 대부분의 장점은 때때로 많은 문서가 있을 수 있고 단순히 모든 것을 같은 컨텍스트 창에 전달할 수 없는 경우에 옵니다. MapReduce, Refine, MapRerank은 짧은 컨텍스트 창의 이슈를 해결하기 위한 세 가지 방법입니다.
6. Chat #

문서를 불러오기로 시작했고, 그 다음에는 그것들을 분할했으며, 벡터 저장소를 만들었습니다.
다양한 종류의 검색에 대해 이야기했고, 질문에 답할 수 있다는 것을 보여주었지만, 후속 질문을 처리할 수 없으며, 실제 대화를 가질 수 없습니다. 질문 답변 챗봇을 만들기 위해 마무리 작업 -> 채팅 이력이라는 개념을 추가할 것입니다. 이는 체인과 교환한 이전의 대화나 메시지를 의미합니다.
이챗봇이 질문에 답변을 시도할 때 그 채팅 이력을 맥락으로 취할 수 있게 해줍니다. 그래서 만약 후속 질문을 한다면, 챗봇은 여러분이 무엇에 대해 이야기하는지 알 수 있을 것입니다.
여기서 중요한 것은, 지금까지 이야기한 모든 멋진 검색 유형들, 자가 질의나 압축 같은 것들을 여기서도 확실히 사용할 수 있다는 것입니다. 이야기한 모든 구성 요소들은 매우 모듈화되어 있고 잘 맞춰질 수 있습니다. 여기에 단지 채팅 이력이라는 개념을 추가하는 것뿐입니다.
제공된 그림은 대화형 검색 챗봇을 만드는 두 가지 접근 방식을 보여주고 있습니다. 이들은 대화형 인공지능 시스템을 구축하는 데 사용되는 아키텍처와 알고리즘을 설명합니다.
ConversationalRetrievalChain (왼쪽 그림)
- 이 구조에서는 채팅 이력을 통해 사용자가 이전에 한 질문을 기반으로 새로운 질문을 할 때, 이를 고려하여 더욱 정확한 답변을 할 수 있도록 합니다.
- ‘Chat History’는 사용자와 시스템 간의 이전 대화를 기록합니다.
- ‘Condense LLM’은 채팅 이력을 요약하고, ‘Retriever’는 관련 데이터를 검색하여 사용자의 질문에 가장 적합한 정보를 찾아냅니다.
- ‘Relevant splits’는 검색 결과 중에서 사용자의 질문에 가장 적합한 부분을 선택합니다.
- 마지막으로 ‘LLM’ (Large Language Model)은 선택된 정보를 바탕으로 사용자의 질문에 답변을 합니다.
Modular Components (오른쪽 그림)
- 이 접근 방식은 더욱 모듈화되어 있으며, 필요에 따라 추가적인 ‘Retriever’와 압축 기능을 추가할 수 있습니다.
- ‘Self-query’는 시스템이 스스로 질문을 생성하여 자신의 지식을 확장하는 방식입니다.
- ‘Map-reduce’는 대규모 데이터를 처리할 때 사용되는 프로그래밍 모델로, 데이터를 매핑(mapping) 단계에서 처리한 후 리듀스(reducing) 단계에서 결과를 합치는 작업을 수행합니다.
- 이 시스템도 마찬가지로 ‘LLM’을 사용하여 최종적인 답변을 생성합니다.
두 시스템 모두 대화형 질의응답 시스템에서 중요한 개념인 채팅 이력을 활용하여, 사용자의 질문에 대한 맥락을 이해하고 더욱 연관성 있는 답변을 제공하도록 설계되었습니다. 추가적인 구성 요소를 통해 시스템의 유연성과 기능을 확장할 수 있는 가능성을 보여줍니다.
“Stand-alone question"이라는 용어는 독립적인 질문을 의미합니다. 즉, 이 질문은 이전의 대화나 맥락에 의존하지 않고 혼자서도 충분히 이해하고 답변할 수 있는 질문입니다. 대화형 시스템에서는 이전 대화의 맥락에 의존하는 질문(예: “그는 어떻게 그렇게 했나요?” 또는 “그 다음에 무슨 일이 일어났나요?")과 달리, stand-alone 질문은 대화의 이전 부분을 참조하지 않아도 명확하고 완전한 정보를 제공합니다(예: “뉴욕의 인구는 얼마입니까?” 또는 “Amanita phalloides 버섯은 독성이 있나요?”).
Conclusion #
해당 강좌에서는, LangChain을 사용하여 80가지 이상의 다양한 문서 로더를 사용해 다양한 문서 소스에서 데이터를 로드하는 방법이 나옵니다.
문서를 조각으로 나누고, 이 작업을 수행할 때 발생하는 많은 미묘한 점들에 대해 이야기했습니다. 그 후, 그 조각들을 위해 임베딩을 생성하고, 그것들을 벡터 저장소에 넣어, 의미론적 검색을 쉽게 가능하게 하는 방법을 보여줍니다.
하지만 의미론적 검색의 단점과, 특정 경계 사례에서 실패할 수 있는 지점에 대해서도 이야기합니다. 다음으로 다룬 것은 검색. 가장 흥미로운 부분이죠….
여기서 그 경계 사례들을 극복하기 위한 많은 새롭고 진보된, 정말 재미있는 검색 알고리즘에 대해 이야기합니다.
그 다음 세션에서는 LLM과 결합하여, 검색된 문서들과 사용자의 질문을 LLM에 전달하고, 원래 질문에 대한 답변을 생성합니다. 그리고 검색 기록을 통해 이전 이력들. 채팅 이력이 추가 되어 end-to-end ChatBot이 완성됩니다.
강좌에는 코드도 함께 있는데 코드는 심플해서 읽기 편합니다.
CEO가 설명하면서 몹시 재밌고 흥미로워하는 게 해당 영상의 포인트입니다.
끝.