1. langchain 구성 요소 및 사전 세팅
langchain에서는 전체적으로 Schema, Model, Prompt, Index, Memory, Chain, Agent 총 7가지의 컴포넌트를 제공합니다.
환경 설정
- 환경 세팅을 실시하기 위해 langchain과 openai의 SDK를 설치
pip install langchain
pip install openai
- 환경 변수 설정
2.2) 변수로 api 세팅export OPENAI_API_KEY = "SK-..."
2.3) Jupyter notebook 활용 시, 환경 변수 설정 - import os os.environ["OPENAI_API_KEY"] = "..."
- api_key = "sk-..." chat_model = ChatOpenAI(openai_api_key=api_key)
- 2.1) export를 활용한 api 세팅
2. Simple start
LangSmith
들어가기에 앞서 많은 어플리케이션은 Langchain을 여러번 호출 할 수 있기 때문에 상대적으로 복잡해 질 수 있습니다. 때문에 안의 chain과 agent의 상황을 관리 감독하는 것이 중요한데 이를 LangSmith로 가능하게 되었습니다.
export LANGCHAIN_TRACING_V2="true"
export LANGCHAIN_API_KEY=...
LangServe
추가적으로 Langchain을 REST API로 배포를 쉽게 하기 위해서 LangServe를 사용하면 가능합니다.
pip install "Langserve[all]"
LangChain 구축
LangChain은 LLM을 구축하는데 많은 모듈을 제공하는데 이는 독립 실행형으로 사용할 수 있으며 복잡한 사용 사례를 위해 구성이 될 수 있습니다. 이러한 다양한 모듈은 LangChain Expreesion Language Runnable(LCEL)에 의해 구동되므로 구성 요소를 원활하게 연결이 가능합니다.
여기서 가장 단순하고 가장 일반적인 체인에는 세 가지가 포함됩니다.
- LLM/Chat Model: 여기서 언어 모델은 핵심 추론 엔진입니다. LangChain을 사용하려면 다양한 유형의 언어 모델과 이를 사용하는 방법을 이해해야 합니다.
- Prompt Template: 언어 모델에 대한 지침을 제공합니다. 이는 언어 모델의 출력을 제어하므로 프롬프트와 다양한 프롬프트 전략을 구성하는 방법을 이해하는 것이 중요합니다.
- Output Parser: 언어 모델의 원시 응답을 보다 실행 가능한 형식으로 변환하여 출력 다운스트림을 쉽게 사용할 수 있도록 합니다.
LLM / Chat Model
여기에는 LLM과 ChatModel이라는 두 가지 언어 모델을 제공해줍니다.
- LLM : 문자열을 입력하고 문자열을 반환
- ChatModel: 메세지의 리스트를 입력하고 메세지로 반환
기본 메시지 인터페이스는 BaseMessage로 다음 두 가지 필수 속성에 의해 정의됩니다.
- content : 문자열로 구성된 메시지 내용
- role : BaseMessage가 나오는 entity
LangChain은 서로 다른 역할을 쉽게 구별할 수 있는 여러 개체를 제공합니다.
- HumanMessage : human/user에게 오는 BaseMessage
- AIMessage : AI/assiatant에게 오는 BaseMessage
- SystemMessage : system에게 오는 BaseMessage
- FunctionMessage / ToolMessage : 함수나 tool 호출을 출력을 포함하는 BaseMessage
이러한 역할 중 어느 것도 적절하지 않은 경우 ChatMessage역할을 수동으로 지정할 수 있는 클래스도 있습니다.
Langchain은 LLM과 ChatModel을 같이 제공하는 것이 가능하지만 효과적인 프롬프트 작성을 위해서는 두 가지의 차이점을 인지하는 것이 좋습니다.
LLM과 ChatModel을 호출할 때 가장 간단한 방법은 LangChain Expression Language (LCEL)의 동시성 호출 방법인 .invoke()를 호출하는 것입니다.
- LLM.invoke : 문자열로 입력 받아 문자열로 반환합니다.
- ChatModel.invoke : BaseMessage의 리스트를 입력하고 BaseMessage로 반환을 해줍니다.
from langchain.llms import OpenAI
from langchain.chat_models import ChatOpenAI
llm = OpenAI()
chat_model = ChatOpenAI()
from langchain.schema import HumanMessage
text = "What would be a good company name for a company that makes colorful socks?"
messages = [HumanMessage(content=text)]
llm.invoke(text)
# >> Feetful of Fun
chat_model.invoke(messages)
# >> AIMessage(content="Socks O'Color")
더 알아보면 LLM.invoke와 ChatModel.invoke는 둘 다 입력으로 Union[str, List[BaseMessage], PromptValue] 제공합니다. 따라서 LLM동일한 입력을 수용 한다는 사실은 ChatModel 대부분의 chain에서 아무것도 손상 하지 않고 서로 직접 교환할 수 있다는 것을 의미합니다. 다만, 입력이 강제되는 방식과 이것이 모델 성능에 어떤 영향을 미칠 수 있는지 생각하는 것이 중요합니다.
Prompt templates
대부분의 LLM 응용 프로그램은 사용자 입력을 LLM에 직접 전달하지 않습니다. 일반적으로 현재 특정 작업에 대한 추가 Context를 제공하는 Prompt templates이라는 더 큰 텍스트에 사용자 입력을 추가합니다.
LangChain에서는 Prompt template이 바로 이 작업에 도움이 되며 사용자 입력을 완전히 형식화된 Prompt로 전환하기 위한 모든 논리를 묶습니다.
from langchain.propts import PromptTemplate
prompt = PromptTemplate.from_template("What is a good name for a company that makes {product}?")
prompt.format(product="colorful socks")
What is a good name for a company that makes colorful socks?
위와 같이 raw string format으로 질문을 하면 장점은 부분적으로 출력이 가능합니다. 예를 들어 한 번만에 일부 변수를 형식화가 가능한데 이는 다른 프롬프트와 결합이 가능하게 됩니다.
PromptTemplate도 리스트의 메세지를 생성 할 수 있습니다. 이 경우 프롬프트에는 콘텐츠에 대한 정보뿐만 아니라 각 메시지(해당 역할, 목록에서의 위치 등)도 포함됩니다. 여기서 가장 자주 일어나는 일은 ChatMessageTemplates에서의 ChatPromptTemplate입니다. 각각의 ChatMessageTemplate에서는 어떻게 ChatMessageTemplate을 구성 할 지가 나와있습니다.
from langchain.prompts.chat import ChatPromptTemplate
template = "You are a helpful assistant that translate {input_language} to {output_language}."
human_template = "{text}"
chat_prompt = ChatPromptTemplate.from_messages([
("system", template),
("human",human_template),
])
chat_prompt.format_messages(input_language="English", output_language="Korean", text="I love programming.")
[SystemMessage(content='You are a helpful assistant that translate English to Korean.'),
HumanMessage(content='I love programming.')]
Output parsers
OutputParser는 원시적인 언어 출력을 downstream에 사용이 가능하도록 변환해 줍니다. 여기에 OutputParser의 몇 가지 중요한 타입이 있습니다.
- text를 JSON과 같은 구조화된 정보에서 온 LLM으로 변환
- ChatMessage를 단지 문자열로 변환
- 메시지(예: OpenAI 함수 호출) 외에 호출에서 반환된 추가 정보를 문자열로 변환
from langchain.schema import BaseOutputParser
class CommaSeparatedListOutputParser(BaseOutputParser):
"""Parse the output of an LLM call to a comma-separated list."""
def parse(self, text: str):
"""Parse the output of an LLM call."""
return text.strip().split(", ")
CommaSeparatedListOutputParser().parse("hi, bye")
# >> ['hi', 'bye']
Composing with LCEL
앞에 나온 모든 것들을 하나의 Chain으로 결합할 수 있습니다. 이 Chain은 입력 변수를 가져와 Prompt Template에 전달하여 Prompt 를 생성하고, Prompt 를 언어 모델에 전달한 다음, (선택 사항) output parser를 통해 출력을 전달합니다.
from typing import list
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema import BaseOutputParser
class CommaSeparatedListOutputParser(BaseOutputParser[List[str]]):
"""Parse the output of an LLM call to a comma-separated list."""
def parse(self, text:str) -> List[str]:
"""Parse the output of an LLM call."""
return text.strip().split(",")
template = """You are a helpful assistant who generates comma separated lists.
A user will pass in a category, and you should generate 5 objects in that category in a comma separated list.
ONLY return a comma separated list, and nothing more."""
human_template = "{text}"
chat_prompt = ChatPromptTemplate.from_messages([
("system", template),
("human", human_template),
])
chain = chat_prompt | ChatOpenAI() | CommaSeparatedListOutputParser()
chain.invoke({"text": "colors"})
['red', 'blue', 'green', 'yellow', 'orange']
Serving with LangServe
이제 애플리케이션을 구축했으므로 이를 제공해야 합니다. 이것이 바로 LangServe가 등장하는 이유입니다. LangServe는 개발자가 LCEL chain을 REST API로 배포하는 데 도움을 줍니다. 라이브러리는 FastAPI와 통합되어 있으며 데이터 검증을 위해 pydantic을 사용합니다.
Server
어플리케이션용 서버를 생성하기 위해 3개의 파일로 구성된 serve.py를 생성해 줍니다.
- 위와 동일한 우리의 chain의 정의
- FastAPI app
- langserve.add_routes이라는 chain에 대한 경로를 정의
#!/usr/bin/env python
from typing import List
from fastapi import FastAPI
from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatOpenAI
from langchain.schema import BaseOutputParser
from langserve import add_routes
# 1. Chain definition
class CommaSeparatedListOutputParser(BaseOutputParser[List[str]]):
"""Parse the output of an LLM call to a comma-separated list."""
def parse(self, text: str) -> List[str]:
"""Parse the output of an LLM call."""
return text.strip().split(", ")
template = """You are a helpful assistant who generates comma separated lists.
A user will pass in a category, and you should generate 5 objects in that category in a comma separated list.
ONLY return a comma separated list, and nothing more."""
human_template = "{text}"
chat_prompt = ChatPromptTemplate.from_messages([
("system", template),
("human", human_template),
])
category_chain = chat_prompt | ChatOpenAI() | CommaSeparatedListOutputParser()
# 2. App definition
app = FastAPI(
title="LangChain Server",
version="1.0",
description="A simple API server using LangChain's Runnable interfaces",
)
# 3. Adding chain route
add_routes(
app,
category_chain,
path="/category_chain",
)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="localhost", port=8000)
python serve.py
'머신러닝 & 딥러닝 > 딥러닝' 카테고리의 다른 글
Flux perfermence improved by Flash attention3 + Triton (2) | 2024.11.22 |
---|---|
Flux 모델 최적화를 위한 TorchAO 및 torch.compile() 활용 가이드 (1) | 2024.11.21 |
Flux.1-dev 모델 구조와 작동 원리 (0) | 2024.11.18 |
[AI 기초 다지기] Kolmogorov Complexity and Algorithmic Randomness (0) | 2024.11.17 |
[AI 기초 다지기] Transformer & The Annotated Transformer & Scaling Laws for Neural Language Models 논문 분석 및 코드 구현 (0) | 2024.11.16 |