안녕하세요! 저는 온다에서 개발 전반의 업무를 맡고 있는 Elliot(엘리엇, 이은규)입니다.
최근 GPT-4나 바드, LLaMa를 위시한 빅테크 기업들의 대규모 언어 모델 (LLM) 경쟁이 시장의 뜨거운 화두입니다. 이런 패러다임 변화의 중심에서 오픈소스 주도의 소규모 언어 모델과 그 응용 프로젝트들이 괄목할 성장을 보여주는 등 생성 인공지능과 언어 모델의 활용 능력의 중요성에 대한 공감대 또한 빠르게 확장되고 있습니다.
LLM의 활용은 텍스트 데이터를 처리하기 위해 우리가 사용해 온 이전의 방식을 완전히 혁신하며 데이터를 분석, 생성, 응용하는 새로운 접근 방법을 제시합니다. 우리는 LLM을 사용하여 어떤 주제에 대한 줄글을 자동으로 생성·요약하거나, 질문에 능동적인 대답을 받을 수 있는데요. 비정형 데이터를 정형 데이터로 스마트하게 치환하는 기능을 구현하는 등 이전에 시도할 수 없거나 시도하기가 굉장히 난해했던 여러가지 발상들을 쉽게 구현할 수 있습니다.
특히 최근에는 이런 LLM을 활용한 흥미로운 구현이나 시도가 계속해서 이루어지고 있죠. 예를 들면, LLM을 사용해 서로 교류가 가능한 인공지능 캐릭터의 집단을 구성하여 가상 공간에서 시뮬레이션하는 연구 프로젝트나 주어진 명령을 수행하기 위해 스스로 능동적으로 사고, 계획, 행동하는 Auto-GPT 에이전트 프로젝트처럼 말입니다.
누구든 한 번쯤 상상해 보았을 아이디어가 실제로 구현된 것을 보면서, 이런 프로젝트들이 LLM을 어떻게 조작하고 구성하는지 궁금증이 있으실 텐데요.
왠지 모르게 굉장히 복잡한 공학적 디자인과 알아듣지 못할 수학적 난해함 위에 쌓아 올려진 것처럼 느껴지는 프로젝트들, 사실 이들을 구성하는 핵심 아이디어가 우리가 생각하는 것 보다 얼마나 간단한 것인지 알게 된다면 대부분 깜짝 놀라실 겁니다.
오늘 소개해 드릴 Langchain은 LLM의 복잡한 연쇄작용을 제어하기 쉽도록 구성하고 모듈화하여 언어 모델을 원동력으로 동작하는 어플리케이션을 간단히 만들 수 있도록 돕는 프레임워크입니다.
Langchain은 2022년 10월에 등장한 오픈 소스 프레임워크입니다. 2023년 6월 현재 깃허브에서 4만 4천개에 가까운 스타를 받으며, 자체 커뮤니티의 폭발적인 성장세와 더불어 프레임워크 위에 생태계를 구성해 나가는 중인 거대 프로젝트입니다.
Langchain의 핵심적인 개념은 이름에서도 알 수 있듯, LLM 프롬프트의 실행과 외부 소스의 실행(계산기, 구글 검색, 슬랙 메시지 전송이나 소스코드 실행 등)을 엮어 연쇄(Chaining)하는 것입니다.
입력과 출력을 가지는 매개체들을 줄줄이 엮어 하나의 플로우(Flow)로 만들고, 그러한 플로우들을 또 모듈화하고 엮어서 하나의 어플리케이션으로 만들 수 있게 해주는 프레임워크라고 생각하면 이해가 편하실 텐데요. 이는 Langchain 설계를 위한 GUI 프로젝트인 Langflow의 화면을 보면 더 직관적으로 이해할 수 있습니다.
Langchain에는 사전 설정된 모듈(Module)이 존재하고 사용자는 이 모듈을 적절히 혼합하여 여러 구성 요소(Component)로 엮어낸 뒤 각 구성 요소 간의 파이프라인을 설정할 수 있습니다.
모듈에는 다양한 종류가 있으며 프레임워크 생태계의 발전에 따라 계속해서 증가하고 있습니다. 여러 개의 모듈이 모여 하나의 구성 요소를 이루고, 또 이렇게 모인 구성 요소가 체인을 이루어 마치 레고 블록을 쌓아 올리듯이 하나의 완성된 어플리케이션을 빌드하는 역할을 합니다.
Langchain에는 많은 종류의 모듈이 있지만, 그 중 가장 핵심적인 역할을 하는 모듈은 다음과 같습니다.
이번 글에서는 각 모듈의 역할을 설명하고 간단한 예시를 들어 모듈이 어떻게 동작하는지 알아보려고 합니다. 유념해야 할 점은 Langchain의 모듈이란 모든 모듈이 같은 레벨에서 동작하지 않고 (어떤 모듈은 다른 종류의 모듈을 필수 구성 요소로 요구하기도 합니다) 같은 모듈이라도 예제의 성격에 따라 다른 용도로 사용될 수 있다는 것입니다. 사람에 빗대어 보자면, 같은 직무더라도 회사에 따라 R&R이 다른 경우를 생각해보면 이해하기 쉽겠네요.
이제 각 모듈에 대해 살펴보겠습니다. 이번 글의 예제에서는 Langchain의 공식 자바스크립트 포팅 버전인 langchain-js를 사용하겠습니다.
LLM 모듈은 Langchain의 엔진입니다. 각기 다른 언어 모델 혹은 언어 모델 제공 서비스가 가진 API를 Langchain의 다른 여러 모듈에서 사용할 수 있도록 정규화한 인터페이스로 제공하는 역할을 합니다.
모듈에 연결할 LLM은 어떤 종류의 모델이라도 상관없습니다. OpenAI의 GPT-4, GPT-3.5나 Davinci, Ada 모델일 수도 있고, Hugging Face의 Inference API를 통해 호스트하고 있는 모델일 수도 있으며, 로컬에서 실행중인 LLaMa 기반 모델일 수도 있습니다. 커뮤니티가 빠르게 발전하는 만큼 대부분의 엔드포인트를 지원하며 필요할 경우 인터페이스를 직접 구성하는 것도 별로 어렵지 않습니다.
또 하나의 어플리케이션에서 꼭 하나의 LLM을 사용할 필요도 없습니다. 어플리케이션을 만들 때 가벼운 추론 능력을 요구하는 간단한 프롬프트의 실행에는 Ada 모델을, 더 심화된 추론 능력을 요하는 작업에는 자체 호스팅중인 Vicuna 모델을, 복잡한 추론과 행동 계획 수립을 요구하는 Agent 모듈에는 GPT-4 모델을 사용하는 식으로 어플리케이션을 잘 구성하면 불필요한 리소스 낭비를 줄이고 비용을 절감할 수 있습니다.
LLM 모듈 인스턴스를 생성하는 일은 굉장히 간단합니다. 아래 예시는 GPT-4 모델을 사용한 LLM 모듈 인스턴스를 생성하는 예시입니다.
이와 같이 생성한 LLM 인스턴스는 다른 모듈을 생성할 때 전달되어 프롬프트의 실행을 수행하는 역할을 맡게 됩니다.
Prompt Template은 사전 설정된 Prompt에 지정된 변수를 쉽게 넣을 수 있도록 구성한 템플릿 모듈입니다.
예를 들어, 여러분이 아래와 같이 간단한 언어 감지 프롬프트를 디자인하여 사용한다고 생각해보겠습니다.
위 프롬프트를 재활용하여 [이 글의 언어를 감지하려고 합니다.] 부분에 동적인 입력 값을 전달하여 템플릿으로 만들고자 할 때 다음과 같은 코드를 작성할 수 있습니다.
LANG_DETECTION 문자열은 작성된 프롬프트에서 치환하기를 원하는 부분을 {변수명} 로 대치한 것입니다. 문자 자체로서의 중괄호를 사용할 때는 {{}} 의 형태로 중괄호를 두개 사용해야 합니다.
LanguageDetectionParser 는 프롬프트의 실행 결과를 파싱하여 필요한 결과물만을 추출하는 OutputParser입니다. 예제에서는 Detected: 뒤에 따라 붙는 문자열만을 파싱하도록 하고 있습니다. 만약 LLM 모델이 해당 프롬프트의 실행 결과값으로 Detected: korean 이라는 응답을 보냈다면, 파싱된 Output은 korean 이 될 것입니다.
languageDetectionPrompt는 완성된 PromptTemplate입니다. 위의 구성 요소와 더불어 inputVariables로 템플릿에 사용된 변수명인 input 을 전달하고 있습니다.
이렇게 선언한 Prompt Template는 LLMChain 모듈을 통해 LLM에 연결되어 직접 사용되거나, Agent에 전달되어 Agent에 의해서 실행되거나 하는 등 프롬프트 입력을 요구하는 여러 모듈들에서 입력으로 사용하게 됩니다.
Agent는 Langchain에서 가장 핵심적인 역할을 하는 모듈일 뿐 아니라, 가장 복잡하고 정교한 사고 작업의 실행을 담당하는 모듈입니다.
Agent의 개념은 몇가지 핵심적인 생성 인공지능 논문에 그 뿌리를 두고 있으며, 새로운 접근 방법이 제시될 때 마다 거기에 맞추어 계속해서 개선되고 있습니다. Agent의 개념을 더 완벽하게 이해하기 위한 몇몇 중요한 레퍼런스를 제시하자면 다음과 같습니다.
위의 자료를 모두 읽어볼 필요는 없지만, 읽어본다면 Agent의 개념과 그 동작 원리를 파악하는데 큰 도움이 됩니다.
간단하게 설명하자면, Agent는
1. 자신에게 주어진 Task를 수행하기 위해, 주어진 도구(Tools)와 현재 상황을 토대로 사고(Thought)하여 필요한 다음 행동을 설계합니다. (Action planning/Reasoning)
2. 설계가 끝났다면 현재 필요한 Action을 적절한 Input과 함께 수행합니다.
3. Action의 수행이 끝나면 그 수행 결과를 분석(Observation)하고, 분석한 결과와 현재까지 수행했던 Action의 결과들을 토대로 1~3의 작업을 반복합니다. (Chain of thought)
4. 결과를 분석하여 Task가 완료되었거나 완료 가능하다면 작업 수행을 완료하고 종료합니다.
이처럼 Agent는 주체적으로 주어진 자원을 활용하여 어떤 작업을 실행하는 역할을 합니다.
Agent는 맡은 역할이 복잡한 만큼 그 구현도 천편일률적이지 않습니다. 같은 Langchain을 사용하더라도 Agent를 구성하는 방법은 여러가지가 있으니, 사용하는 용도에 따라 필요한 모듈의 구성이나 프롬프트의 형태가 완전히 제각각이 됩니다. 따라서, 이번 글에서는 Langchain 공식 문서에서 안내하는 Agent의 기본 예제를 보고 사용된 각 요소에 대해서 설명하겠습니다.
LangchainJs의 공식 문서에서 참고한 MRKL(Modular Reasoning, Knowledge and Language; 미라클으로 읽습니다) Agent의 예시입니다.
위에서 얘기한 것과 달리 예시 코드가 굉장히 간단한데요. zero-shot-react-description으로 정의된 agentType이 일종의 사전 설정 프리셋으로 Agent 구성에 필요한 많은 요소들을 포함하고 있기 때문입니다.
해당 코드를 실행해 보면, Agent가 유저의 첫 질문 [Who is Olivia Wilde's boyfriend? What is his current age raised to the 0.23 power?]을 받고
1. SerpAPI를 사용해 구글에 Olivia Wilde의 남자친구가 누군지 검색
2. 위에서 Harry Styles가 Olivia Wildes의 남자친구임을 알아냈으니, 그의 나이를 검색
3. 그의 나이가 29살임을 알았으니, Calculator Tool을 사용해 29의 0.23 제곱을 계산
4. 계산 결과가 나왔으니, 유저의 질문에 최종 대답을 생성
위 과정을 스스로 판단하여 순차적으로 실행하는 것을 관찰할 수 있습니다.
Auto GPT를 사용해 보신 분들이라면 이러한 동작 과정이 꽤 익숙하실 겁니다. Auto GPT 또한 잘 오케스트레이션한 Agent의 체인 위에 사용 가능한 다양한 Tool을 제공하는 방식으로 설계된 거대한 Agent이므로, Auto GPT가 어떻게 동작하는 것인지 궁금하셨던 분들이라면 그 궁금증이 일부 해소되셨을 것이라 생각합니다.
Tool은 Agent가 각 Action을 수행할 때 사용할 수 있도록 추상화된 일종의 함수입니다.
Agent는 자신이 사용할 수 있는 Tool의 목록을 아래 값과 함께 프롬프트의 일부로 전달 받게 됩니다.
Langchain에 정의된 Tool의 Interface는 위와 같습니다. 간단하지만 유연하며, 문자열으로 결과 값을 반환하기만 한다면 call 내부에서 어떤 동작을 수행해도 좋습니다.
여러가지 다른 모듈로 구성된 복잡한 Agent마저도 다른 Agent에게 Tool의 형태로 제공될 수 있으며, 이 간단하지만 강력한 Interface가 Langchain의 활용 가능성을 무궁무진하게 끌어올리는 요소 중 하나입니다.
간단한 LLMChain을 사용한 아래의 예제는 Calculator에 입력된 수식 값을 전달하기 전에 Calculator가 알아들을 수 있는 형태로 수식 값이 입력됨을 보장하기 위해 입력 값을 정제하도록 설계된 Calculator 툴입니다.
위 예제에는 Agent를 제외한 이번 글에서 다룬 모든 모듈과 LLMChain이라는 체인 모듈을 함께 사용했습니다. 예제를 보고 LLMChain이 어떻게 동작하는지, PromptTemplate과 LLM 모델이 어떻게 연계되어 실행되는지를 한번 살펴보시기 바랍니다.
이번 글에서는 Langchain 및 Langchain의 핵심적인 몇가지 모듈과 함께 해당 프레임워크를 사용해 쉽게 LLM의 응용 프로그램을 개발하는 기초적인 아이디어를 소개드렸습니다.
Langchain은 지금도 아주 빠른 속도로 개발되고 있는 프로젝트입니다. 글에서 다루지 못한 응용 예시들과 더 다양한 모듈이 존재하며, 개중에는 VectorStore를 응용한 장기 기억 구현 등 아주 흥미로운 사용 예시들도 많이 존재합니다. 생성 인공지능을 응용하여 어플리케이션을 개발하려고 한다면 꼭 한번 참고해보시기 바랍니다. 감사합니다.