언어 모델 기반 애플리케이션 개발 프레임워크 LangChain
LangChain은 언어 모델을 기반으로 하는 애플리케이션을 개발하기 위한 프레임워크입니다.
이를 통해 다음과 같은 특징을 갖는 애플리케이션을 개발할 수 있습니다.
- 문맥 인식: 언어 모델을 문맥 소스에 연결하여 응답을 생성합니다. (프롬프트 지시사항, 몇 가지 예시, 응답을 기반으로 하는 콘텐츠 등)
- 추론: 주어진 문맥을 기반으로 답변 방법이나 취해야 할 조치 등을 추론하는 데 언어 모델을 활용합니다.
이 프레임워크는 여러 구성 요소로 구성되어 있으며 다음과 같은 상호 작용을 확인할 수 있습니다.
- LangChain 패키지: Python 및 JavaScript 패키지로, 다양한 구성 요소에 대한 인터페이스 및 통합, 이러한 구성 요소를 연결하여 체인과 에이전트로 결합하는 기본 실행 시간 및 고성능 작업을 위한 내장 구현을 포함합니다.
- LangChain 템플릿: 다양한 작업에 대한 쉽게 배포 가능한 참조 아키텍처 모음.
- LangServe: LangChain 체인을 REST API로 배포하는 데 사용되는 라이브러리.
- LangSmith: 어떤 LLM 프레임워크에서든 구축된 체인을 디버깅, 테스트, 평가 및 모니터링할 수 있는 개발자 플랫폼으로, LangChain과 원활하게 통합됩니다.
이러한 제품들은 전체 애플리케이션 라이프사이클을 간편화합니다.
- 개발: LangChain/LangChain.js로 애플리케이션 작성. 참조를 위한 템플릿을 사용하여 신속하게 시작하세요.
- 프로덕션 화: LangSmith를 사용하여 체인을 검사, 테스트 및 모니터링하여 지속적으로 개선하고 확신을 가지고 배포하세요.
- 배포: LangServe를 사용하여 어떤 체인이든 API로 전환하세요.
LangChain 패키지의 주요 가치 제안은 다음과 같습니다.
- 구성 요소: 언어 모델과 작업하는 데 사용되는 모듈식 및 사용하기 쉬운 툴 및 통합입니다.
- 내장 체인: 고수준 작업을 수행하기 위한 구성 요소의 내장 구성으로, 시작하기가 쉽습니다. 구성 요소를 사용하여 기존 체인을 사용자 정의하고 새로운 체인을 구축하기가 쉽습니다.
시작하는 방법은 LangChain을 설치하고 환경을 설정하며 개발을 시작하는 것입니다. 프레임워크에 익숙해지기 위해 Quickstart 가이드를 따르는 것이 좋습니다.
LangChain은 다음과 같은 모듈에 대한 표준 및 확장 가능한 인터페이스 및 통합을 제공합니다.
- 모델 I/O: 언어 모델과의 인터페이스
- 검색: 응용 프로그램별 데이터와의 인터페이스
- 체인: 호출의 시퀀스를 구성
- 에이전트: 고수준 지시에 따라 사용할 도구를 선택하도록 하는 체인
- 메모리: 체인의 실행 사이에 애플리케이션 상태를 지속
- 콜백: 어떤 체인의 중간 단계를 기록하고 스트리밍
또한 다양한 사용 사례, 가이드 및 생태계 관련 자원들이 제공되며, LangChain은 다양한 도구들과 통합되어 있는 풍부한 생태계의 일부입니다. 커뮤니티 섹션에서는 질문을 하고 피드백을 공유하며 다른 개발자들과 소통하고 LLM의 미래에 대한 꿈을 나눌 수 있는 장소를 찾을 수 있습니다. 또한 API 참조 섹션에서는 LangChain Python 패키지의 모든 클래스 및 메서드에 대한 완벽한 문서를 찾을 수 있습니다.
LangChain을 시작하는 방법에 대한 내용을 정리해보겠습니다.
설치
LangChain을 설치하려면 다음 명령어를 실행하세요.
pip install langchain
환경 설정
LangChain을 사용하려면 일반적으로 하나 이상의 모델 공급 업체, 데이터 저장소, API 등과 통합이 필요합니다. 이 예제에서는 OpenAI의 모델 API를 사용할 것입니다.
먼저 OpenAI의 Python 패키지를 설치해야 합니다.
pip install openai
API에 액세스하려면 API 키가 필요하며, API 키를 설정하려면 다음 명령어를 실행하세요.
export OPENAI_API_KEY="..."
환경 변수를 설정하지 않고 직접 openai_api_key라는 이름의 매개 변수를 사용하여 OpenAI LLM 클래스를 초기화할 수도 있습니다.
from langchain.llms import OpenAI
llm = OpenAI(openai_api_key="...")
LangSmith 설정
LangChain으로 빌드하는 애플리케이션 중에는 여러 단계와 여러 LLM 호출이 포함된 것이 많습니다. 이러한 애플리케이션이 더 복잡해지면 체인이나 에이전트 내부에서 정확히 무슨 일이 일어나고 있는지 검사할 수 있는 것이 중요해집니다. 이를 위해 LangSmith를 사용하는 것이 가장 좋습니다.
LangSmith가 필수는 아니지만 도움이 됩니다. LangSmith를 사용하려면 위의 링크에서 가입한 후에 환경 변수를 설정하여 추적을 시작하십시오.
export LANGCHAIN_TRACING_V2="true"
export LANGCHAIN_API_KEY=...
애플리케이션 빌드
이제 언어 모델 애플리케이션을 빌드해볼 수 있습니다. LangChain은 언어 모델 애플리케이션을 구축하는 데 사용할 수 있는 여러 모듈을 제공합니다. 모듈은 간단한 애플리케이션에서 스탠드얼론으로 사용될 수 있으며 더 복잡한 사용 사례를 위해 결합될 수도 있습니다.
LangChain이 도움을 주는 가장 일반적이고 중요한 체인은 세 가지를 포함합니다.
- LLM: 여기서 언어 모델은 핵심 추론 엔진입니다. LangChain과 함께 작업하려면 다양한 유형의 언어 모델과 그들과 어떻게 작업하는지를 이해해야 합니다.
- Prompt Templates: 이는 언어 모델에 지시를 제공하는 역할을 합니다. 이는 언어 모델이 출력하는 내용을 제어하므로 프롬프트를 구성하고 다양한 프롬프트 전략을 구성하는 방법을 이해하는 것이 중요합니다.
- Output Parsers: 이는 LLM에서 반환된 원시 응답을 더 작업 가능한 형식으로 변환하는 역할을 합니다. 이로써 하향 스트림에서 출력을 쉽게 사용할 수 있게 됩니다.
이러한 개념을 이해하면 LangChain 애플리케이션을 사용하고 사용자 정의하는 데 좋은 기반을 마련할 수 있습니다.
LLMs
LangChain에서는 두 가지 유형의 언어 모델이 있습니다.
- LLMs: 이는 문자열을 입력으로 받아 문자열을 반환하는 언어 모델입니다.
- ChatModels: 이는 메시지 목록을 입력으로 받아 메시지를 반환하는 언어 모델입니다.
LLMs의 입력/출력은 간단하고 이해하기 쉽습니다. 그냥 문자열입니다. 그러나 ChatModels의 경우 입력은 ChatMessages 목록이며 출력은 단일 ChatMessage입니다. ChatMessage에는 두 가지 필수 구성 요소가 있습니다.
- content: 이는 메시지의 내용입니다.
- role: 이는 ChatMessage가 어디서 왔는지에 대한 엔터티의 역할입니다.
LangChain은 다양한 역할을 쉽게 구분할 수 있는 객체를 제공합니다.
- HumanMessage: 사용자/인간에서 오는 ChatMessage입니다.
- AIMessage: AI/어시스턴트에서 오는 ChatMessage입니다.
- SystemMessage: 시스템에서 오는 ChatMessage입니다.
- FunctionMessage: 함수 호출에서 오는 ChatMessage입니다.
이외에도 적절한 역할이 없다면 수동으로 역할을 지정할 수 있는 ChatMessage 클래스도 있습니다. 이러한 다양한 메시지를 가장 효과적으로 사용하는 방법에 대한 자세한 내용은 프롬프트 가이드를 참고하세요.
LangChain은 LLMs 및 ChatModels 간에 공통 인터페이스를 제공하지만 특정 언어 모델에 대한 프롬프트를 구성할 때 이 차이를 이해하는 것이 유용합니다.
LangChain이 제공하는 표준 인터페이스에는 두 가지 메서드가 있습니다.
- predict: 문자열을 입력으로 받아 문자열을 반환합니다.
- predict_messages: 메시지 목록을 입력으로 받아 메시지를 반환합니다.
이러한 다양한 모델 및 입력 유형과 함께 작업하는 방법에 대해 알아보겠습니다.
먼저 LLM 및 ChatModel을 가져오겠습니다.
from langchain.llms import OpenAI
from langchain.chat_models import ChatOpenAI
llm = OpenAI()
chat_model = ChatOpenAI()
llm.predict("안녕!")
# >> "안녕"
chat_model.predict("안녕!")
# >> "안녕"
OpenAI 및 ChatOpenAI 객체는 기본적으로 구성 객체일 뿐입니다. temperature 및 기타 매개 변수와 함께 이들을 초기화하고 전달할 수 있습니다.
다음으로 predict 메서드를 사용하여 문자열 입력에 대해 실행해 보겠습니다.
text = "컬러풀한 양말을 만드는 회사에 어울리는 회사 이름은 무엇일까요?"
llm.predict(text)
# >> "신나는 발걸음"
chat_model.predict(text)
# >> "컬러풀한 양말"
마지막으로 predict_messages 메서드를 사용하여 메시지 목록에 대해 실행해 보겠습니다.
from langchain.schema import HumanMessage
text = "컬러풀한 양말을 만드는 회사에 어울리는 회사 이름은 무엇일까요?"
messages = [HumanMessage(content=text)]
llm.predict_messages(messages)
# >> "신나는 발걸음"
chat_model.predict_messages(messages)
# >> "컬러풀한 양말"
이러한 메서드에는 키워드 인수로 매개 변수를 전달할 수도 있습니다. 예를 들어, temperature=0을 전달하여 실행 중에 사용되는 온도를 조정할 수 있습니다. 실행 중에 전달된 값은 항상 객체가 구성된 값으로 대체됩니다.
프롬프트 템플릿
대부분의 LLM 애플리케이션에서는 사용자 입력을 직접 LLM에 전달하지 않습니다. 보통 사용자 입력을 설명서 템플릿이라는 더 큰 텍스트 조각에 추가하여 작업의 특정 작업에 대한 추가 컨텍스트를 제공합니다.
이전 예제에서 모델에 전달한 텍스트에는 회사 이름을 생성하는 지시가 포함되어 있었습니다. 애플리케이션의 경우 사용자가 모델에 지시를 제공하지 않고 회사/제품의 설명만 제공하면 좋을 것입니다. 이러한 경우 PromptTemplates가 큰 도움이 됩니다. 이들은 사용자 입력을 완전히 포맷된 프롬프트로 변환하는 모든 로직을 묶어냅니다.
아주 간단한 시작은 위의 문자열을 생성하는 지시를 포함하는 프롬프트 일 수 있습니다.
from langchain.prompts import PromptTemplate
prompt = PromptTemplate.from_template("컬러풀한 {product}를 만드는 회사에 어울리는 좋은 회사 이름은 무엇일까요?")
prompt.format(product="양말")
컬러풀한 양말을 만드는 회사에 어울리는 좋은 회사 이름은 무엇일까요?
그러나 이러한 프롬프트를 사용하는 이점은 여러 가지입니다. 변수를 "부분적으로" 나눌 수 있습니다. 예를 들어, 한 번에 변수의 일부만 형식화할 수 있습니다. 이를 함께 구성하여 여러 템플릿을 쉽게 단일 프롬프트로 결합할 수 있습니다.
PromptTemplates는 메시지 목록을 생성하는 데도 사용할 수 있습니다. 이 경우 프롬프트에는 콘텐츠에 대한 정보뿐만 아니라 각 메시지에 대한 정보(역할, 목록 내에서의 위치 등)가 포함됩니다. 여기서 가장 흔한 것은 ChatPromptTemplate이며 이는 ChatMessageTemplates의 목록입니다. 각 ChatMessageTemplate에는 해당 ChatMessage를 형식화하는 방법에 대한 지침이 포함되어 있습니다.
from langchain.prompts.chat import ChatPromptTemplate
template = "도움이 되는 어시스턴트로서 {input_language}에서 {output_language}로 번역해줍니다."
human_template = "{text}"
chat_prompt = ChatPromptTemplate.from_messages([
("system", template),
("human", human_template),
])
chat_prompt.format_messages(input_language="영어", output_language="프랑스어", text="프로그래밍을 좋아해요.")
[
SystemMessage(content="도움이 되는 어시스턴트로서 영어에서 프랑스어로 번역해줍니다.", additional_kwargs={}),
HumanMessage(content="프로그래밍을 좋아해요.")
]
ChatPromptTemplates는 다른 방식으로 구성할 수도 있습니다.
출력 파서
OutputParsers는 LLM 언어 모델의 원시 출력을 하향 스트림에서 사용할 수 있는 형식으로 변환하는 역할을 합니다. 여러 종류의 OutputParsers가 있으며, 주요 유형은 다음과 같습니다.
- LLM의 텍스트를 구조화된 정보로 변환 (예: JSON)
- ChatMessage를 문자열로만 변환
- 메시지 이외의 호출에서 반환된 추가 정보를 문자열로 변환 (예: OpenAI 함수 호출)
이 가이드에서는 쉼표로 구분된 목록을 목록으로 변환하는 OutputParser를 작성해보겠습니다.
from langchain.schema import BaseOutputParser
class CommaSeparatedListOutputParser(BaseOutputParser):
"""LLM 호출 결과를 쉼표로 구분된 목록으로 파싱합니다."""
def parse(self, text: str):
"""LLM 호출 결과를 파싱합니다."""
return text.strip().split(", ")
이제 이 OutputParser를 사용하여 입력 변수를 가져와 프롬프트 템플릿을 통해 프롬프트를 생성하고, 이를 언어 모델에 전달한 다음 (선택적으로) 출력 파서를 통해 결과를 처리하는 LangChain을 만들어보겠습니다. 이는 모듈식 논리를 편리하게 묶어 사용하는 방법입니다.
from langchain.chat_models import ChatOpenAI
from langchain.prompts.chat import ChatPromptTemplate
from langchain.schema import BaseOutputParser
class CommaSeparatedListOutputParser(BaseOutputParser):
"""LLM 호출 결과를 쉼표로 구분된 목록으로 파싱합니다."""
def parse(self, text: str):
"""LLM 호출 결과를 파싱합니다."""
return text.strip().split(", ")
template = """도움이 되는 어시스턴트로서 쉼표로 구분된 목록을 생성합니다.
사용자가 카테고리를 전달하면 해당 카테고리에서 5개의 객체를 쉼표로 구분된 목록으로 생성해야 합니다.
쉼표로 구분된 목록만 반환하고 그 이상은 아무 것도 하지 않습니다."""
human_template = "{text}"
chat_prompt = ChatPromptTemplate.from_messages([
("system", template),
("human", human_template),
])
chain = chat_prompt | ChatOpenAI() | CommaSeparatedListOutputParser()
chain.invoke({"text": "색상"})
# >> ['빨강', '파랑', '녹색', '노랑', '주황']
이때 사용된 |
구문은 LangChain 표현 언어로, 이러한 구성 요소를 함께 연결하는 데 사용됩니다.