카테고리 없음

스파르타 AI-8기 TIL(11/12) -> LLM 제작 및 사용

kimjunki-8 2024. 11. 12. 21:26
주의 사항
ChatGPTLLM(대규모 언어 모델)을 사용하기 전에 고려해야 할 중요한 사항들은 모델의 정확성과 안전성, 데이터 보호, 목적에 따른 최적화 등 여러 요소에 관한 것입니다. LLM은 강력한 도구이지만, 올바르게 사용하지 않으면 예기치 않은 문제나 비효율이 발생할 수 있으므로 주의가 필요합니다.
1. 출력 내용의 정확성과 신뢰성
한계 인식: LLM은 학습된 데이터에 기반해 예측을 수행하지만, 항상 정확한 정보를 제공하지는 않습니다. 가짜 정보나 신뢰성이 낮은 답변이 생성될 가능성이 있습니다.
검증 필요: 모델의 응답이 중요한 의사결정이나 민감한 주제에 활용된다면 반드시 검증 절차를 거쳐야 합니다. AI가 제공하는 정보는 참고용으로 사용하고, 필요한 경우 전문가의 검토를 받는 것이 좋습니다.

2. 데이터 프라이버시와 보안
민감 데이터 사용 금지: 고객 정보, 비밀번호, 금융 정보 등 민감한 데이터를 모델 입력값으로 전달하지 않도록 주의해야 합니다. 일부 LLM은 외부 서버에서 동작하며, 입력된 정보가 모델 학습에 사용될 가능성도 있습니다.
암호화와 익명화: 중요한 데이터는 익명화하거나 암호화하여 사용하고, 필요시 데이터 사용 동의를 받는 것이 바람직합니다.

3. 출력 조작 방지
프롬프트 주입 공격: LLM은 사용자 입력에 민감하여 프롬프트 주입과 같은 공격을 받을 수 있습니다. 악의적인 사용자가 모델을 조작하거나, 특정 입력으로 모델의 예측을 왜곡할 수 있으므로, 입력값을 사전 검토하거나 제한을 두는 등의 조치가 필요합니다.

4. 편향(Bias)과 공정성
편향된 학습 데이터: LLM은 학습 데이터에 포함된 사회적, 문화적 편견을 반영할 수 있습니다. 이러한 편향은 특정 그룹에 대한 부정확한 정보나 부정적인 관점을 생성하게 할 수 있습니다.
검토와 조정: 응답의 편향 가능성을 인지하고, 모델이 특정 편견 없이 공정하게 응답하도록 사후 검토, 응답 필터링 또는 후처리 작업이 필요할 수 있습니다.

5. 비용과 성능 최적화
모델 호출 비용: LLM 호출은 상당한 비용이 발생할 수 있습니다. 특히 고도화된 모델일수록 사용 빈도에 따른 비용이 높아질 수 있으므로, 최적화된 호출 전략을 설계해야 합니다.
효율적인 사용 전략: 모델 사용을 최소화할 수 있도록 캐싱 전략을 사용하거나, 특정 작업에 대해 더 적합한 작은 모델이나 규칙 기반 솔루션을 병행하여 비용을 절감할 수 있습니다.

6. 안전성 및 의도하지 않은 사용 방지
유해 콘텐츠 방지: 사용자가 부적절한 내용이나 유해한 질문을 입력했을 때 모델이 적절히 대응할 수 있도록 사전 필터링이 필요합니다. 일부 LLM은 안전하지 않은 콘텐츠를 생성할 수 있으므로 이를 방지할 필터링 또는 제한 설정이 필요합니다.
허위 정보 차단: LLM은 문장을 그럴듯하게 구성하는 능력이 뛰어나지만, 가짜 뉴스나 허위 정보를 제공할 가능성이 있습니다. 따라서 정보의 신뢰성을 확인할 수 있는 검증 시스템과 함께 사용해야 합니다.

7. 도메인 특화 모델 사용 고려
범용 모델의 한계: LLM은 범용적이지만, 특정 도메인에서는 적절한 응답을 하지 못할 수 있습니다. 의료, 법률, 금융과 같은 분야에서는 정확성이 매우 중요하기 때문에, 도메인 특화 모델을 병행 사용하거나 도메인 전문가의 검토가 필수적입니다.

8. 법적 규제와 윤리적 책임
법적 요구사항 준수: 특히 GDPR과 같은 데이터 보호 규정이 있는 지역에서는 개인 데이터를 다룰 때 해당 규정을 철저히 준수해야 합니다. 또한 AI 사용에 따른 법적 책임을 고려하여 사용 목적과 방식에 대한 법적 자문을 구하는 것이 좋습니다.
윤리적 기준: LLM의 사용 목적이 사회적, 윤리적 기준에 부합하는지 확인하는 것이 중요합니다. 잘못된 사용이 윤리적 문제로 이어질 수 있으며, 사용자의 신뢰를 잃을 위험이 있습니다.
LLM을 사용할 때 발생할 수 있는 각 문제에 대해 구체적인 해결 방법이 따로 있습니다.
1. 출력 내용의 정확성과 신뢰성
다중 검증: LLM의 출력을 직접 신뢰하지 않고, 외부 데이터 소스나 전문가의 검토 과정을 거치도록 합니다. 중요 정보나 의사결정에 사용될 답변은 적어도 한 번 이상 교차 검증하는 것을 추천합니다.
모델 튜닝: 자주 사용하는 질문이나 중요한 작업에 대해 정확성을 높이기 위해 모델을 추가로 튜닝합니다. 튜닝을 통해 특정 분야에 맞는 정보만을 우선적으로 출력하도록 조정할 수 있습니다.
후처리 필터: 모델의 응답에 대해 후처리 필터를 설정해, 답변 내용에서 허위 정보가 포함되지 않도록 하는 규칙을 적용합니다.

2. 데이터 프라이버시와 보안
익명화 및 민감 정보 필터링: 입력된 데이터에서 개인 식별 정보를 삭제하거나 익명화 처리해 민감한 데이터를 보호합니다. 예를 들어, 사용자 정보를 해싱 처리하거나, 입력 전에 중요한 정보를 자동 필터링하는 시스템을 도입합니다.
데이터 암호화: 데이터 전송 시 암호화를 통해 중간에 유출될 위험을 방지합니다. TLS(전송 계층 보안) 등의 프로토콜을 사용해 네트워크 전송을 안전하게 만듭니다.
로컬 모델 사용 고려: 민감한 정보 처리 시 오픈 소스 LLM을 로컬 환경에서 사용하여 데이터 유출 가능성을 차단할 수 있습니다.

3. 출력 조작 방지
입력 사전 검열: 악의적인 입력이나 비정상적인 요청 패턴을 감지하는 필터를 적용해 프롬프트 주입 공격을 방지합니다. 예를 들어, 입력에서 특정 금지 단어나 의도적인 조작 가능성이 있는 구문을 차단하는 방법입니다.
제한된 입력 형태: 필요한 정보만 입력하도록 입력 범위를 제한해, 입력을 통해 모델의 답변을 조작하려는 시도를 어렵게 만듭니다. 입력을 구체화하거나, 프롬프트의 자유도를 낮추는 방법이 포함됩니다.
프롬프트 검증 로직 추가: 입력 프롬프트가 모델의 의도와 일치하는지 확인하는 로직을 추가하여, 공격성 질문이나 조작 가능성이 있는 질문을 자동으로 필터링할 수 있습니다.

4. 편향(Bias)과 공정성
데이터 셋 필터링: 학습 데이터에 포함된 편향을 줄이기 위해 데이터를 수집하는 단계에서 특정 그룹이나 문화에 대한 편향을 제거하거나 중립적인 데이터로 보완합니다.
후처리 필터 적용: 모델 출력에서 편향적인 표현을 감지하여 수정하는 후처리 필터를 적용합니다. 예를 들어, 특정 단어나 표현이 포함될 경우 자동으로 중립적인 용어로 변환하도록 설정합니다.
주기적 평가와 조정: 모델을 주기적으로 평가해 편향을 최소화하고, 필요한 경우 모델의 가중치나 데이터셋을 조정해 공정성을 지속적으로 개선합니다.

5. 비용과 성능 최적화
캐싱 시스템 도입: 자주 사용하는 응답은 캐시를 통해 저장하여, 동일한 요청이 반복될 경우 모델 호출을 줄이고 비용을 절감합니다.
간단한 요청에 작은 모델 사용: 모든 작업에 대형 모델을 사용하기보다, 간단한 질의나 기본적인 질문에 대해서는 더 작은 모델을 사용해 효율성을 높입니다.
최적의 사용 전략 설계: 응답이 필요한 상황과 그렇지 않은 상황을 구분하여, 모델 호출 빈도와 기간을 설정합니다. 예를 들어, 특정 상황에서만 대형 모델을 호출하거나, 특정 조건에서만 모델을 사용하도록 로직을 최적화합니다.

6. 안전성 및 의도하지 않은 사용 방지
유해 콘텐츠 필터링: 유해하거나 부적절한 내용을 사전에 차단할 수 있는 필터를 설정합니다. 필터링된 단어나 주제에 대해서는 모델이 응답하지 않거나, 공손히 거절하도록 설계할 수 있습니다.
사용자 행동 모니터링: 모델을 사용하는 동안 사용자의 행동을 모니터링하고, 악의적인 사용 시 경고 메시지를 띄우거나 사용을 제한할 수 있는 시스템을 도입합니다.
안전 강화 모델 사용: LLM을 활용할 때 OpenAI의 'Moderation API'와 같은 안전 필터링 모델을 추가로 적용해 유해하거나 오해를 부를 수 있는 답변이 생성되지 않도록 제어합니다.

7. 도메인 특화 모델 사용 고려
도메인 별 모델 설정: 의료, 법률, 금융 등의 특정 분야에 대해서는 해당 분야의 특화 모델을 선택하거나, 해당 분야에 대해 추가 학습된 모델을 사용합니다. 예를 들어, 특정 업계의 문서를 바탕으로 추가 학습을 하거나, 해당 분야 전문가의 피드백을 반영합니다.
도메인 지식 전문가 검토 프로세스 도입: 중요한 의사결정이 필요한 응답의 경우 도메인 전문가의 검토를 거쳐, 모델의 답변이 정확한지 확인하는 절차를 추가합니다.

8. 법적 규제와 윤리적 책임
데이터 처리 절차 준수: 데이터 사용과 관련된 모든 법적 규정을 준수하며, 민감한 정보에 대한 명확한 처리 절차와 정책을 마련합니다. 예를 들어, 데이터 수집과 활용에 대한 동의를 사용자로부터 사전에 얻고, 사용 이후에는 정보를 파기하는 절차를 포함합니다.
윤리적 AI 지침 마련: AI 사용의 윤리적 기준을 마련해, 악의적이거나 불공정한 사용을 방지합니다. 예를 들어, LLM을 특정 집단이나 개인을 비방하거나 오용하는 사례가 없도록 모니터링하고, 이러한 사용을 방지하는 방침을 수립합니다.
투명성 확보: 사용자에게 모델의 한계나 작동 방식을 명확하게 설명하고, 모델이 생성한 결과가 참고 자료일 뿐임을 안내하여 사용자가 오해하지 않도록 투명성을 확보합니다.

Vector DB(Vector Database) 및 RAG(Retrieval-Augmented Generation)
Vector DB(Vector Database)는 데이터의 벡터 표현을 저장하고 효율적으로 검색할 수 있는 데이터베이스입니다. RAG(Retrieval-Augmented Generation)는 정보 검색과 생성형 AI 모델을 결합하여 답변의 정확성과 신뢰성을 높이는 기술입니다.
Vector DB는 RAG의 핵심 구성 요소 중 하나로, RAG가 작동하는 데 있어 중요한 역할을 합니다. 그러나 RAG 기법 그 자체라기보다는, RAG가 데이터를 효율적으로 검색하고 활용하기 위해 사용하는 도구에 더 가깝습니다.

다시 말해, Vector DB는 RAG의 구성 요소로 포함되지만, 독립적으로도 다양한 애플리케이션에서 사용할 수 있는 별도의 데이터베이스 유형입니다. RAG 외에도 정보 검색, 추천 시스템, 이미지 및 비디오 검색 등에서도 Vector DB가 활용될 수 있죠.

관계를 정리하자면:
RAG(기법): LLM의 답변 정확도를 높이기 위해 외부 데이터베이스를 참고하여 정보를 보완하는 기법입니다.
Vector DB(도구): RAG가 사용자가 요청한 정보를 빠르고 효율적으로 검색하기 위해 사용하는 데이터베이스입니다. 주로 문서나 텍스트 데이터를 벡터로 변환해 저장하고, 유사도 검색을 통해 관련 데이터를 찾는 데 사용됩니다.
따라서 Vector DB는 RAG의 기법 중 하나라기보다는, RAG가 의존하는 기술적인 데이터베이스 구성 요소라고 볼 수 있습니다.

그런데 여기서 임배딩이란 개념이 나옵니다. 임베딩은 간단히 말해, 단어를 벡터 차원으로 변형시켜 준다고 생각하면 됩니다. 그런데, 만약 문맥안에서 서로간의 관계가 거의 없는(예를 들어: 초콜렛과 자동차)는 어떻게 이해 할까요?
그 방법으로는 분포 가설이라는 개념이 있습니다.
분포 가설(Distributional Hypothesis)은 자연어 처리에서 매우 중요한 개념으로, 단어의 의미를 그 단어가 등장하는 문맥(context)에 기반하여 이해할 수 있다는 가설입니다. 이 가설은 “유사한 문맥에서 사용되는 단어들은 비슷한 의미를 가진다”는 아이디어를 중심으로 합니다. 이 가설은 단어 임베딩(Word Embedding) 같은 현대의 언어 모델이 발전하게 된 토대이기도 합니다.

분포 가설의 핵심 아이디어
유사 문맥 유사 의미: 비슷한 문맥에서 자주 나타나는 단어들은 유사한 의미를 가진다.
예를 들어, "강아지"와 "고양이"는 서로 다른 단어지만, 종종 비슷한 문장에서 등장하기 때문에 유사한 의미를 공유한다고 볼 수 있습니다.
“애완동물”, “동물”, “귀엽다”와 같은 문맥에서 이 단어들이 함께 사용될 가능성이 높기 때문입니다.
벡터 공간에서의 표현: 분포 가설을 바탕으로 단어를 벡터로 변환할 수 있습니다. 단어 임베딩 기법은 이 가설을 활용하여 비슷한 문맥을 가진 단어들을 벡터 공간에서 가깝게 배치합니다. 예를 들어, 강아지와 고양이는 벡터 공간에서도 가깝게 위치하게 됩니다.

분포 가설의 예시
문장에서 “나는 강아지를 좋아한다”라는 문장이 있고, 또 다른 문장에 “나는 고양이를 좋아한다”가 있다면, “강아지”와 “고양이”는 서로 다른 단어지만 유사한 문맥에 나타납니다.
이러한 문맥적 유사성은 임베딩 기법을 통해 두 단어가 벡터 공간에서 서로 가깝게 표현될 수 있도록 합니다.

분포 가설의 응용
분포 가설은 다음과 같은 자연어 처리 기법의 기반이 됩니다.
Word2Vec, GloVe: 단어를 벡터화하여 비슷한 단어를 가깝게 위치시키는 임베딩 기법.
BERT, GPT: 트랜스포머 기반 모델도 문맥을 분석하여 단어의 의미를 학습합니다.
결론적으로, 분포 가설은 자연어 처리에서 단어와 문장의 의미를 수학적 벡터로 표현하는 데 큰 기여를 했습니다. 이를 통해 텍스트 유사도, 감성 분석, 번역 등의 다양한 작업이 가능해졌습니다.
임베딩 간단한 실습 코드
from sentence_transformers import SentenceTransformer as ST
import numpy as np
import warnings
warnings.filterwarnings(action = 'ignore')

model = ST('intfloat/multilingual-e5-large')
sentences = [
    "참새는 짹짹하고 웁니다.",
    "LangChain과 Faiss를 활용한 예시입니다.",
    "자연어 처리를 위한 임베딩 모델 사용법을 배워봅시다.",
    "유사한 문장을 검색하는 방법을 살펴보겠습니다.",
    "강좌를 수강하시는 수강생 여러분 감사합니다!"
]
embeddings = model.encode(sentences)
print(embeddings.shape) #(5, 1024) 5개의 문장이 1024개의 차원의 백터로 변환됨

간단히 말해서 SentenceTransformer를 불러와서, 그것을 encode하면, 그것이 임베딩 되었다고 할 수 있습니다.

텍스트 처리
LLM에서 텍스트 처리는 LLM의 성능, 효율성, 자원 관리에 중요한 영향을 미치며, 더 나은 품질의 출력을 생성하는 데 중요한 역할을 합니다.
모델의 정확도 향상: 텍스트 처리를 통해 LLM이 더 정확하게 텍스트의 의미를 파악하고, 문맥을 잘 이해할 수 있습니다. 예를 들어, 불필요한 기호나 특수 문자를 제거하고, 문장을 표준화하면 모델이 중요한 정보에 집중할 수 있습니다.

데이터 노이즈 제거: 실생활 데이터에는 오타, 불필요한 공백, 특수 문자 등 다양한 노이즈가 포함되어 있습니다. 텍스트 처리를 통해 이러한 노이즈를 제거하거나 최소화하여 모델이 더 깨끗하고 유의미한 데이터로 학습하도록 할 수 있습니다.

단어 및 문장 정규화: 텍스트 데이터에는 같은 의미를 가지더라도 표현 방식이 다양한 경우가 많습니다. 이를 정규화(normalization)하면 일관성을 높여 모델이 동일한 의미를 가진 표현을 더 잘 이해할 수 있습니다.

메모리 효율성: 대형 언어 모델은 일반적으로 많은 메모리와 연산 자원을 필요로 하기 때문에, 텍스트 처리로 입력 데이터를 압축하거나 필터링하여 모델이 적절한 리소스를 사용하도록 돕습니다. 이를 통해 모델의 효율성이 향상됩니다.

다국어 및 특수 문자의 처리: LLM이 다국어 텍스트를 다룰 때는 언어별로 고유한 텍스트 처리가 필요합니다. 예를 들어, 한국어의 형태소 분석, 영어의 어간 추출 등 다양한 언어별 처리가 모델의 이해력을 높여 줍니다.

학습 및 추론 시간 단축: 불필요한 데이터가 제거되면 학습 및 추론 시간이 단축될 수 있습니다. 특히 대량의 데이터를 다루는 LLM에서는 텍스트 처리로 불필요한 정보를 줄여 모델의 처리 속도를 개선할 수 있습니다.
기법
텍스트 처리 기법은 자연어 처리(NLP)에서 중요한 역할을 하며, 주로 데이터 전처리, 특성 추출, 텍스트 정규화 등을 포함합니다.
먼저 텍스트 처리를 하는 이유를 알아봅시다
1. 노이즈 제거 : 텍스트 내 필요없는 정보나 오류를 제거해서, 정확한 분석 유도
2. 일관성 확보 : 문장의 구조나 형태를 정리하여 더 빠르게 패턴 학습 유도
3. 효율적인 처리 : 필요없는 단어나 특수 문자를 제거하여 더 빠른 계산을 유도
1. 토큰화(Tokenization)

토큰화는 문장을 더 작은 단위인 토큰(token)으로 분리하는 과정입니다. 토큰은 보통 단어, 문장 부호, 혹은 문자일 수 있습니다.
단어 토큰화 (Word Tokenization): 문장을 단어 단위로 분리합니다.
문장 토큰화 (Sentence Tokenization): 텍스트를 문장 단위로 분리합니다.
서브워드 토큰화(Subword Toeknization) : 단어를 더 작은 단위로 분리해서 새로운 단어를 처리할 수 있도록 하는 기법. BPE나 WordPiece 같은 기법을 사용.

2. 소문자화 (Lowercasing)
모든 텍스트를 소문자로 변환하여 대소문자 차이를 없애는 기법입니다. 이는 텍스트의 일관성을 유지하고, 모델이 동일한 단어를 다르게 인식하지 않도록 합니다.

3. 불용어 제거 (Stopwords Removal)
불용어(stopwords)란 의미가 적거나 중요한 정보가 없는 단어들로, 예를 들어 영어의 "the", "is", "in" 등이 있습니다. 불용어를 제거하면 텍스트에서 중요한 단어들만 남기고, 처리 시간을 단축할 수 있습니다.

4. 어간 추출 (Stemming)
어간 추출은 단어의 어간(root)을 찾아 단어를 그 형태로 변환하는 기법입니다. 예를 들어 "running", "ran", "runner"를 "run"으로 변환하는 방식입니다. 어간 추출은 단어의 변형을 줄여 데이터의 크기를 줄이기 위해 사용됩니다.
알고리즘: Porter Stemmer, Snowball Stemmer 등

5. 형태소 분석 (Morphological Analysis)
형태소 분석은 언어의 단위인 형태소를 추출하는 과정입니다. 형태소는 의미를 가진 최소 단위로, 한국어와 같은 교착어에서 중요한 기법입니다. 예를 들어, 한국어에서 "먹었다"는 "먹"과 "었다"라는 형태소로 분리될 수 있습니다.
도구: KoNLPy, MeCab(일본어), NLTK(영어) 등

6. 표제어 추출 (Lemmatization)
어간 추출과 비슷하지만, 표제어 추출은 더 정교하게 단어의 기본 형태를 찾아냅니다. 예를 들어 "better"는 "good"으로, "running"은 "run"으로 변환됩니다. 표제어 추출은 언어의 의미를 고려하여 단어를 변환하는 기법입니다.
도구: WordNet Lemmatizer (NLTK), spaCy 등

7. 정규화 (Normalization)
정규화는 텍스트를 일관된 형태로 변환하는 기법입니다. 예를 들어, 숫자나 기호를 일정한 형식으로 바꾸거나, 대소문자나 단어의 철자를 통일하는 작업입니다. 이 기법은 텍스트에서 다양한 표현을 일관되게 처리하는 데 유용합니다.

8. 특수 문자 제거 (Removing Punctuation)
구두점(문장 부호)이나 특수 문자를 제거하여 텍스트의 복잡성을 줄이고, 모델이 더 중요한 단어에 집중할 수 있도록 도와줍니다.

9. N-그램 생성 (N-gram Generation)
N-그램은 연속된 N개의 단어(혹은 문자)를 의미합니다. 예를 들어, "I love programming"이라는 문장에서 2-그램(bigram)은 ("I", "love"), ("love", "programming")이 됩니다. N-그램은 텍스트의 문맥을 더 잘 이해할 수 있도록 도와주며, 문맥 기반 모델에서 자주 사용됩니다.

10. 단어 임베딩 (Word Embedding)
단어를 벡터 형태로 표현하여 단어 간의 의미적 유사성을 포착하는 기법입니다. Word2Vec, GloVe, FastText 등이 대표적인 임베딩 모델입니다. 단어 임베딩은 단어를 고차원 공간의 실수 벡터로 변환하여 기계가 의미를 이해할 수 있도록 돕습니다.

11. TF-IDF (Term Frequency - Inverse Document Frequency)
TF-IDF는 단어의 중요도를 계산하는 방법으로, 단어가 문서 내에서 얼마나 자주 등장하는지(TF)와 그 단어가 전체 문서에서 얼마나 드물게 등장하는지(IDF)를 결합하여 중요한 단어를 식별합니다. 문서 간의 중요 단어를 구별하는 데 유용합니다.

12. 의미론적 분석 (Semantic Analysis)
의미론적 분석은 문장의 의미를 추출하는 과정입니다. 여기에는 개체명 인식 (Named Entity Recognition, NER), 의미론적 역할 라벨링 (Semantic Role Labeling, SRL) 등이 포함됩니다. NER은 사람, 장소, 조직 등의 명사구를 인식하는 기법이고, SRL은 문장에서 각 단어의 의미적 역할을 파악하는 방법입니다.

13. 문장 벡터화 (Sentence Embedding)
문장의 의미를 벡터로 표현하는 기법으로, BERT, RoBERTa, GPT와 같은 대형 언어 모델을 사용하여 문장을 임베딩할 수 있습니다. 이를 통해 문장의 유사도 계산, 질문 응답, 텍스트 분류 등의 다양한 작업을 수행할 수 있습니다.

14. 언어 모델을 활용한 생성 (Generation with Pre-trained Models)
최근에는 BERT, GPT 등 대형 언어 모델을 사용하여 텍스트의 생성 및 이해를 수행합니다. 이러한 모델들은 기존 텍스트 데이터를 학습하여 문맥을 이해하고, 새로운 텍스트를 생성할 수 있습니다.

이 외에도 텍스트를 분석하고 이해하기 위한 다양한 기법들이 존재합니다. 이러한 기법들은 주로 모델 학습 전처리 과정에서 활용되며, 모델의 성능을 최적화하는 데 중요한 역할을 합니다.

LangChain
LangChain은 대형 언어 모델(LLM)을 활용하여 복잡한 작업을 수행하고, 여러 단계로 구성된 프로세스를 효과적으로 관리하는 Python 라이브러리입니다. 주로 언어 모델을 활용한 애플리케이션 개발을 단순화하고, 다양한 도구와의 연계를 돕는 기능을 제공합니다. LangChain은 다양한 시스템 구성 요소들이 상호작용하는 방식으로 애플리케이션을 개발할 수 있도록 설계되었습니다.
LangChain의 주요 목적
LangChain은 LLM을 단독으로 사용하는 것에서 벗어나, 다양한 도구와 외부 시스템을 연결하여 복잡한 작업을 처리하는 데 중점을 둡니다. 이 라이브러리는 LLM을 여러 가지 방식으로 활용할 수 있도록 지원하며, 특히 텍스트 생성, 정보 검색, 데이터베이스 질의 처리, API 호출 등을 연계하는 데 유용합니다.

LangChain의 주요 구성 요소
언어 모델 연동 (LLM Wrappers):
LangChain은 OpenAI, Hugging Face, Cohere, GPT-3, GPT-4 등 다양한 LLM 서비스와 쉽게 통합할 수 있는 방법을 제공합니다. 이를 통해 여러 LLM의 기능을 동일한 방식으로 활용할 수 있게 됩니다.

체인(Chains):
LangChain에서 "체인"은 여러 단계를 이어서 처리하는 구성 요소입니다. 예를 들어, LLM을 사용하여 생성한 결과를 다른 시스템(예: API 호출, 파일 읽기/쓰기 등)에 전달하거나, 여러 모델을 연계해 복잡한 태스크를 처리할 수 있습니다.
기본 체인: 입력을 받아 모델에서 처리하고 결과를 반환합니다.
복합 체인: 여러 단계를 이어서 처리할 수 있도록 설계된 체인으로, 하나의 작업을 여러 단계로 나누어 진행합니다. 예를 들어, 자연어 질의를 데이터베이스에 전달하거나, 다른 API를 호출한 후 그 결과를 다시 LLM으로 처리하는 식입니다.

프롬프트 템플릿(Prompt Templates):
LangChain은 프롬프트 템플릿을 사용하여 LLM에 제공하는 입력 텍스트를 동적으로 생성할 수 있게 해줍니다. 예를 들어, 특정 질문에 맞는 프롬프트를 생성하거나, 특정 데이터에 기반해 텍스트를 구성할 때 유용합니다. 템플릿을 사용하면 LLM이 원하는 방식으로 보다 구체적이고 정확한 응답을 제공할 수 있습니다.

추론 (Retrieval):
LangChain은 LLM을 텍스트 생성뿐만 아니라, 정보 검색(retrieval)에도 사용할 수 있도록 지원합니다. 외부 데이터베이스나 파일 시스템에서 정보를 검색하고, 해당 정보를 LLM에 전달하여 더 정확하고 신뢰성 높은 응답을 생성하는 데 활용됩니다. 이를 통해 문서 검색, 질의 응답 시스템 등을 구축할 수 있습니다.

도구(Tools):
LangChain은 다양한 외부 도구(예: SQL 데이터베이스, 웹 스크래핑, REST API 호출 등)를 LLM과 연계하여 사용할 수 있는 기능을 제공합니다. 예를 들어, LLM이 API를 호출하여 데이터를 가져오고, 그 데이터를 바탕으로 후속 작업을 처리할 수 있습니다.

에이전트 (Agents):
에이전트는 LLM이 외부 도구나 데이터베이스를 사용하여 스스로 작업을 수행할 수 있도록 하는 컴포넌트입니다. 예를 들어, 에이전트는 텍스트를 분석하고, 그에 맞는 작업을 자동으로 결정하여 여러 도구를 동적으로 호출할 수 있습니다. 이를 통해 복잡한 작업을 자동화할 수 있습니다.
Agent Executor: 에이전트가 작업을 진행할 때, 여러 단계를 자동으로 수행할 수 있도록 하는 핵심 구성 요소입니다.

리소스 관리(Memory) 
LangChain은 메모리 기능을 통해 LLM이 대화형으로 동작하는 동안 이전의 대화 내용을 기억하거나, 여러 번의 상호작용을 추적할 수 있게 합니다. 이를 활용하여 대화형 챗봇을 만들거나, 상태를 추적하는 응용 프로그램을 구현할 수 있습니다.

LangChain의 활용 예시
문서 검색 시스템
문서의 내용을 LLM이 분석하고, 그에 맞는 질의 응답을 처리하는 시스템을 구축할 수 있습니다. 예를 들어, 사용자가 문서의 내용을 묻는다면, LangChain은 LLM을 통해 문서를 검색하고 적합한 답변을 생성합니다.

자동화된 데이터 분석
데이터베이스나 CSV 파일과 같은 구조화된 데이터를 분석하고, 그 결과를 LLM을 이용해 자연어로 설명할 수 있습니다. 예를 들어, SQL 질의 결과를 바탕으로 LLM이 데이터를 해석해 분석 리포트를 생성하는 것입니다.

멀티-스텝 프로세스
여러 도구를 연계하여 복잡한 작업을 자동화할 수 있습니다. 예를 들어, LLM을 통해 입력을 받고, 그 결과를 다른 시스템에 전달한 후 다시 LLM을 통해 후속 작업을 처리하는 방식입니다.

챗봇 및 대화형 애플리케이션
LangChain은 대화형 애플리케이션에 필요한 대화 기억 및 상태 추적을 관리할 수 있는 기능을 제공하여, 사용자와의 상호작용을 더욱 원활하게 만듭니다.

LangChain의 장점
모듈화: 다양한 작업을 손쉽게 연결하여 복잡한 워크플로우를 처리할 수 있습니다.
유연성: LLM을 포함한 다양한 외부 도구와 쉽게 연계할 수 있어, 필요에 따라 시스템을 확장할 수 있습니다.
자동화: LLM이 스스로 결정하고 작업을 수행할 수 있도록 하는 에이전트 시스템을 활용하면 많은 작업을 자동화할 수 있습니다.
확장성: LangChain은 다양한 플랫폼과 API와 호환되며, 이를 통해 보다 강력하고 유연한 애플리케이션을 만들 수 있습니다.

실습
LangChain 기본 개념
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
model = ChatOpenAI(model = 'gpt-4o-mini')

response = model.invoke([HumanMessage(content = '안녕하세요, 무엇을 도와드릴까요?')])
print(response.content)

1. from langchain_openai import ChatOpenAI
langchain_openai는 LangChain 프레임워크의 OpenAI 모델을 사용하기 위한 라이브러리입니다. 여기서 ChatOpenAI 클래스는 OpenAI의 GPT 모델을 쉽게 사용할 수 있도록 도와주는 클래스입니다. ChatOpenAI는 LangChain에서 OpenAI의 대화형 모델을 다루기 위한 도구로 사용됩니다.

2. from langchain_core.messages import HumanMessage
HumanMessage 클래스는 사용자가 보내는 메시지를 나타냅니다. 이 클래스는 메시지의 내용과 메타데이터를 캡슐화하여 모델에 전달하는 역할을 합니다. HumanMessage를 사용하면 사용자의 입력을 명확히 표현할 수 있습니다.

3. model = ChatOpenAI(model = 'gpt-4o-mini')
이 줄에서 ChatOpenAI 클래스의 인스턴스를 생성하고, model = 'gpt-4o-mini'로 GPT 모델을 설정합니다. 여기서 'gpt-4o-mini'는 사용하려는 모델의 이름을 나타내며, GPT-4 계열의 미니 버전을 사용하고 있다는 의미입니다.
이 객체(model)는 이후에 사용자가 보낸 메시지에 대한 응답을 생성하는 역할을 합니다.

4. response = model.invoke([HumanMessage(content = '안녕하세요, 무엇을 도와드릴까요?')])
model.invoke()는 모델에 요청을 보내는 함수입니다. 이 함수는 메시지 목록을 인자로 받아, 해당 메시지들에 대한 모델의 응답을 생성합니다. 여기서 HumanMessage(content = '안녕하세요, 무엇을 도와드릴까요?')는 사용자가 보내는 메시지입니다.
이 메시지는 invoke 메서드에 전달되어 모델이 이를 처리하고, 그에 대한 응답을 response 변수에 저장하게 됩니다.

5. print(response.content)
response.content는 모델이 생성한 응답의 내용을 출력하는 부분입니다. response는 모델의 응답 객체이며, 그 안의 content 속성에 모델이 생성한 텍스트 응답이 포함됩니다.
이 코드는 모델이 '안녕하세요, 무엇을 도와드릴까요?'라는 질문에 어떻게 응답하는지 출력합니다.

굳이 안녕하세요, 무엇을 도와드릴까요?뿐만 아니라, 다른 것들도 넣을 수 있습니다.

response = model.invoke([HumanMessage(content = '사과가 뭔지 알려줘')])
print(response.content)

출력 예시:
사과는 쭉쭉 뻗은 나무에서 자라는 과일로, 주로 가을에 수확됩니다. 사과는 둥글고 단단하며, 
다양한 색상(빨간색, 녹색, 노란색 등)과 맛(달콤하거나 시큼함)을 가지고 있습니다. 
비타민 C와 식이섬유가 풍부하여 건강에 좋은 과일로 알려져 있습니다. 
생으로 먹거나, 주스, 잼, 파이 등 다양한 요리에 활용됩니다. 
사과는 또한 여러 문화에서 상징적인 의미를 갖고 있으며, 전 세계적으로 인기 있는 과일 중 하나입니다.

혹은

response = model.invoke([
    HumanMessage(content = '안녕하세요'),
    HumanMessage(content = '오늘 기분 어때요?')
])
print(response.content)

 

invoke는 모델에 메시지를 전달하고 그에 대한 응답을 받는 핵심적인 역할을 하는 함수입니다. invoke를 통해 모델에게 입력 데이터를 보내고 결과를 받아올 수 있습니다. LangChain에서 ChatOpenAI 클래스는 이와 같은 인터페이스를 제공합니다. 다른 함수들도 몇 가지 있을 수 있는데, 주로 모델을 다루는 데 사용되는 여러 기능이 있습니다.
1. invoke
역할: 모델에 사용자 메시지를 전달하고 그에 대한 응답을 받습니다.
예시:
response = model.invoke([HumanMessage(content = '안녕하세요')])

출력 예시:
안녕하세요! 무엇을 도와드릴까요?
invoke는 리스트 형태로 여러 메시지를 받을 수 있으며, 그에 대한 응답을 반환합니다. 이 응답은 response.content에서 확인할 수 있습니다.

2. acall
역할: invoke와 유사하지만, 비동기 방식으로 호출할 수 있는 함수입니다. acall은 비동기 처리를 지원하기 때문에, 대규모 작업이나 병렬 처리가 필요할 때 유용합니다.
예시:
import asyncio

async def async_example():
    response = await model.acall([HumanMessage(content = '안녕하세요')])
    print(response.content)

asyncio.run(async_example())

출력 예시:
안녕하세요! 무엇을 도와드릴까요?

3. predict
역할: predict는 invoke와 유사하지만, 모델의 응답을 바로 예측할 때 사용되는 메서드입니다. 주로 간단한 모델 호출을 할 때 사용될 수 있습니다.
예시:
response = model.predict('안녕하세요, 무엇을 도와드릴까요?')
print(response)

출력 예시:
안녕하세요! 무엇을 도와드릴까요?

 

predict는 일반적으로 하나의 메시지를 빠르게 처리할 때 유용합니다.

4. stream
역할: stream은 모델의 응답을 스트리밍 방식으로 받아오는 함수입니다. 큰 응답을 실시간으로 받을 수 있게 해주며, 긴 대화나 대규모 데이터를 처리할 때 유용합니다.
예시:
response = model.stream([HumanMessage(content = '안녕하세요')])
for chunk in response:
    print(chunk)
    
출력 예시:
안녕하세요!
무엇을
도와드릴까요?

5. complete
역할: complete는 모델이 하나의 완전한 응답을 반환할 때까지 기다리는 함수입니다. 주로 길고 복잡한 텍스트 생성을 요청할 때 사용됩니다.
예시:
response = model.complete([HumanMessage(content = '긴 대답을 부탁드려요')])
print(response.content)

출력 예시:
물론입니다. 긴 대답을 드리기 위해 여러 가지 사항을 고려할 수 있습니다. 우선, 대답의 내용에 따라...

6. chain
역할: 여러 모델을 연결하여 순차적으로 처리하는 방식으로, 복잡한 파이프라인을 구축할 때 사용됩니다.
예시:
response = model.chain([
    HumanMessage(content = '첫 번째 메시지'),
    HumanMessage(content = '두 번째 메시지')
])
print(response.content)

출력 예시:
첫 번째 메시지에 대한 응답입니다. 두 번째 메시지에 대한 응답은 다음과 같습니다: ...

7. reset
역할: 모델의 상태를 초기화하거나 리셋할 때 사용됩니다. 주로 대화 상태를 초기화하거나 모델을 처음 상태로 되돌리려고 할 때 유용합니다.
예시:
model.reset()

(이 메서드는 출력값을 반환하지 않음. 대신 모델의 상태를 초기화합니다.)


8. call (동기적 호출)
call은 모델에 메시지를 보내고 응답을 받는 또 다른 방법입니다. invoke와 비슷하지만, call은 주로 단일 메시지나 짧은 대화에 적합합니다.
예시:

response = model.call('안녕하세요, 무엇을 도와드릴까요?')
print(response)

출력 예시:
안녕하세요! 무엇을 도와드릴까요?


9. message (메시지 반환)
이 함수는 입력된 메시지를 처리하여 모델로 전달하기 전에 사전 처리 또는 포맷팅을 할 때 사용할 수 있습니다. message 함수는 모델의 응답뿐 아니라 특정 형식으로 메시지를 보내기 전에 수정할 수 있습니다.
예시:

formatted_message = model.message('안녕하세요!')
print(formatted_message)

{ 'content': '안녕하세요!', 'role': 'user' }


10. set_temperature
set_temperature는 모델의 생성에 영향을 미치는 파라미터인 temperature를 설정하는 함수입니다. temperature는 생성된 텍스트의 창의성이나 다양성을 조정하는 파라미터로, 값을 높이면 더 창의적인 결과가 나오고, 낮추면 더 결정적인 답변을 생성합니다.
예시:

model.set_temperature(0.7)

temperature 값이 높을수록 생성되는 응답이 더 다양하고 창의적입니다.
낮을수록 예측 가능한 정형화된 응답을 생성합니다.


11. set_max_tokens
set_max_tokens는 응답에서 사용할 최대 토큰 수를 설정하는 함수입니다. 이는 모델이 생성하는 텍스트의 길이를 제한할 때 유용합니다.
예시:

model.set_max_tokens(150)

 

max_tokens는 모델이 생성할 수 있는 최대 토큰 수를 설정하며, 1 토큰은 약 4개의 영어 문자에 해당합니다.
이 값을 설정하면 너무 긴 답변을 방지할 수 있습니다.

12. add_message
add_message는 대화의 맥락을 계속해서 추가할 수 있는 함수입니다. 이 함수를 사용하면 대화가 이어지면서 모델에 계속해서 새로운 메시지를 보낼 수 있습니다. 모델이 이전 대화의 문맥을 파악할 수 있도록 메시지를 추가하는 데 유용합니다.
예시:

model.add_message('첫 번째 메시지')
model.add_message('두 번째 메시지')
response = model.invoke([HumanMessage(content='세 번째 메시지')])
print(response.content)

출력 예시:
첫 번째 메시지, 두 번째 메시지, 세 번째 메시지에 대한 답변입니다.


13. get_model_name
이 함수는 사용 중인 모델의 이름을 반환합니다. 현재 어떤 모델을 사용하고 있는지 확인할 수 있습니다.

model_name = model.get_model_name()
print(model_name)

출력 예시:
gpt-4o-mini


14. get_messages
get_messages는 모델과의 대화에서 지금까지 주고받은 메시지들을 가져오는 함수입니다. 이 기능은 대화형 응답 시스템을 구축할 때 유용하게 사용할 수 있습니다.
예시:

messages = model.get_messages()
for message in messages:
    print(message.content)

출력 예시:
안녕하세요!
무엇을 도와드릴까요?


15. set_stop_sequences
set_stop_sequences는 응답을 생성할 때 중단되는 토큰 시퀀스를 설정하는 함수입니다. 이 기능은 특정 키워드나 구문에서 모델이 생성하는 텍스트를 중단하게 할 때 유용합니다.
예시:

model.set_stop_sequences(["END"])

stop_sequences는 텍스트 생성이 특정 단어나 구문에서 중지되도록 할 수 있는 방법입니다. 예를 들어, END라는 단어가 나오면 모델이 더 이상 텍스트를 생성하지 않게 할 수 있습니다.

요약하면,
invoke: 모델에 메시지를 보내고 응답을 받습니다. 동기적으로 처리됩니다.
acall: 비동기 방식으로 처리되며, 대규모 작업에 적합합니다.
predict: 단일 메시지에 대한 빠른 예측을 수행합니다.
stream: 응답을 실시간으로 스트리밍 방식으로 처리합니다.
complete: 긴 텍스트 생성을 기다리는 방식으로 사용됩니다.
chain: 여러 모델을 순차적으로 처리하는 데 유용합니다.
reset: 모델 상태를 초기화할 때 사용됩니다.
call: 모델에 동기적으로 메시지를 보내고 응답을 받는 함수.
message: 메시지를 처리하여 포맷을 설정하는 함수.
set_temperature: 생성되는 텍스트의 창의성을 조정하는 temperature 값 설정.
set_max_tokens: 모델이 생성할 최대 토큰 수 설정.
add_message: 대화의 맥락을 추가하는 함수.
get_model_name: 사용 중인 모델의 이름을 확인하는 함수.
get_messages: 대화 내역을 가져오는 함수.
set_stop_sequences: 텍스트 생성 중단 시퀀스를 설정하는 함수.


프롬프트 템플릿 사용하기
from langchain_core.prompts import ChatPromptTemplate

# 시스템 메시지 설정
system_template = "Translate the following sentence from English to {language}:"

# 사용자 텍스트 입력
prompt_template = ChatPromptTemplate.from_messages([
    ("system", system_template),
    ("user", "{text}")
])

# 프롬프트 생성
result = prompt_template.invoke({"language": "French", "text": "How are you?"})
print(result.to_messages())

출력 예시:
[
    {"role": "system", "content": "Translate the following sentence from English to French:"},
    {"role": "user", "content": "How are you?"}
]

1. from langchain_core.prompts import ChatPromptTemplate
ChatPromptTemplate는 LangChain에서 프롬프트 템플릿을 구성하고 메시지를 생성할 수 있게 해주는 클래스입니다.
템플릿 내에서 system 메시지(명령 메시지)와 user 메시지(사용자 입력 메시지) 같은 대화 요소를 설정할 수 있습니다.

2. system_template = "Translate the following sentence from English to {language}:"
시스템 메시지를 설정하는 부분입니다. 이 템플릿은 사용자의 입력을 받아 언어 변환을 수행할 때 사용할 메시지를 정의합니다.
{language} 부분은 변수로 설정되어 있으며(LangChain의 템플릿 시스템에서는 중괄호 {}를 사용하여 변수를 지정할 수 있습니다.), 이후에 전달된 값에 따라 실제 언어가 여기에 채워집니다.
예를 들어, "language": "French"라는 값을 입력하면 템플릿 내 {language} 부분이 "French"로 치환됩니다.

3. prompt_template = ChatPromptTemplate.from_messages([("system", system_template), ("user", "{text}")])
ChatPromptTemplate.from_messages()는 system과 user 메시지를 설정하여 프롬프트 템플릿을 만듭니다.
("system", system_template): 시스템 메시지를 설정합니다. system_template의 내용이 system 메시지에 들어가며, {language} 변수에 사용자가 지정한 값이 채워집니다.
("user", "{text}"): 사용자가 번역할 실제 문장인 {text} 변수를 설정합니다. 이후에 입력된 값에 따라 {text}가 채워지게 됩니다.

여기서 from_messages는 LangChain의 ChatPromptTemplate 클래스에서 프롬프트 템플릿을 여러 메시지로 구성할 수 있도록 도와주는 클래스 메서드입니다. 즉, 대화형 프롬프트를 만들 때, 여러 개의 메시지를 한 번에 정의하고 설정할 수 있게 해주는 도구입니다.

from_messages의 역할
from_messages는 다음과 같은 역할을 수행합니다:
여러 메시지의 구조화: 대화형 프롬프트에서 다양한 역할(예: system, user, assistant)과 내용을 순서대로 지정할 수 있습니다.
템플릿 생성: from_messages를 사용하면 각 메시지에 변수를 포함하여 템플릿을 쉽게 구성할 수 있습니다.

사용법
from_messages는 (role, content) 형태의 튜플을 포함한 리스트를 인수로 받아들입니다. 이 리스트에서 role은 메시지의 역할(system, user, assistant 등)을, content는 메시지 내용을 나타내며, 변수는 {}로 감싸서 사용하면 됩니다.

from_messages의 주요 장점
구조적인 대화 설정: 여러 메시지를 미리 구성하여 대화의 구조를 체계적으로 설정할 수 있습니다.
동적 프롬프트 구성: {}를 사용해 변수를 포함시킴으로써, 다양한 입력을 손쉽게 반영할 수 있습니다.

참고로, {text}와 같은 변수는 ChatPromptTemplate에서 미리 선언하지 않아도 invoke() 같은 메서드를 호출할 때 딕셔너리 형태로 값을 전달하면, 템플릿에서 자동으로 인식하고 치환합니다.

즉, LangChain의 템플릿 시스템에서는 {} 안에 들어가는 텍스트가 변수를 암시적으로 정의하며, 그 변수의 값은 invoke() 호출 시 제공된 딕셔너리에서 찾아 자동으로 치환됩니다.


4. result = prompt_template.invoke({"language": "French", "text": "How are you?"})
invoke()는 실제 프롬프트 템플릿을 생성할 때 사용하는 메서드입니다.
{"language": "French", "text": "How are you?"}라는 딕셔너리를 통해 {language}와 {text} 변수에 값을 할당합니다.
이 경우, {language}는 "French", {text}는 "How are you?"로 치환됩니다.

5. print(result.to_messages())
result.to_messages()는 생성된 프롬프트를 메시지 형태로 반환합니다.
이 코드에서는 시스템 메시지와 사용자 메시지로 구성된 최종 프롬프트를 출력합니다.

그리고,
이 코드 예시는 프롬프트를 생성하기 위해 템플릿을 사용하는 것이지, 실제로 번역 작업을 수행하지는 않습니다. ChatPromptTemplate은 단순히 프롬프트 메시지를 구성하는 도구로, 모델에게 전달할 형식을 만드는 역할만 합니다.

따라서 이 예제는 번역 작업을 수행하는 모델에게 적절한 지시사항(prompt)을 전달하는 템플릿을 준비하는 것일 뿐, How are you?를 실제로 번역하는 것은 아닙니다. 프롬프트 자체를 만든 뒤, 이 메시지를 언어 모델에 전달하여 번역 작업을 수행하도록 해야 번역 결과가 나옵니다.
만약 번역 작업을 하고 싶으면,

result = prompt_template.invoke({'language' : 'Korean', 'text' : 'How are you?'}).to_messages()
# 모델 초기화 (GPT-4 API 호출)
model = ChatOpenAI(model="gpt-4")

# 생성된 프롬프트를 모델에 전달
response = model.invoke(prompt_content)
print(response.content)

을 밑에 추가하면 됩니다.

여기서 .to_messages()는, ChatPromptTemplate에서 생성한 프롬프트 템플릿을 LangChain 메시지 형식으로 변환해주는 메서드입니다. 이 형식은 LangChain에서 모델에게 전달할 때 사용하는 표준 메시지 구조로, 메시지의 종류와 내용을 명확히 구분하여 모델에 전달할 수 있게 해줍니다.

LangChain의 메시지 형식은 보통 다음과 같은 구조를 따릅니다:
role: 메시지의 역할 (system, user, assistant 등)입니다. 각 역할에 따라 대화의 목적이나 맥락이 달라지므로 이를 지정해 줍니다.
content: 실제 메시지 내용입니다.

그런데 .invoke는 여기서 쓰인것은 두번인데 역할이 각각 다릅니다.
.invoke()는 LangChain에서 템플릿에 전달된 변수 값을 채워서 최종 프롬프트를 생성하는 역할을 합니다. 다시 말해, .invoke()는 템플릿에 정의된 {} 변수를 실제 값으로 대체하여 준비된 프롬프트를 완성해 주기도 합니다.

.invoke()의 역할
.invoke() 메서드는 다음과 같은 상황에서 유용합니다:
변수 치환: 템플릿에 {}로 표시된 변수를 실제 값으로 채웁니다. 예를 들어, 템플릿에 {language}, {text}와 같은 변수가 있으면 .invoke() 호출 시 딕셔너리 형태로 값을 전달하여 이를 채웁니다.
템플릿 결과 반환: .invoke()는 프롬프트의 최종 결과를 LangChain에서 사용할 수 있는 형태로 반환합니다. 이 반환값은 to_messages() 메서드를 통해 LangChain의 표준 메시지 형식으로 변환할 수 있습니다.


LangChain Expression Language(LCEL)로 체인 연결
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

system_template = 'Translate the following sentence from English to {language}.'

prompt_template = ChatPromptTemplate.from_messages([
    ('system', system_template), ('user', '{text}')
])

parser = StrOutputParser()
chain = prompt_template|model|parser

result = chain.invoke({'language' : 'Korean', 'text' : 'Where is the library?'})
print(result)

StrOutputParser는 LangChain 라이브러리에서 제공되는 출력 파서 클래스 중 하나입니다. 파서는 모델이 생성한 결과를 특정 형식으로 변환하거나 처리하는 역할을 합니다. 이 경우 StrOutputParser는 모델의 출력(즉, 번역된 문장)을 단순한 문자열 형태로 반환합니다.

먼저, Parsar가 뭔지 보겠습니다.
Parser(파서)는 일반적으로 데이터를 읽거나 처리하는 도구로, 주어진 입력을 분석하여 원하는 형태로 변환하거나 처리하는 역할을 합니다. StrOutputParser는 LangChain의 경우 모델의 출력을 string(문자열) 형태로 처리하는 파서입니다. 예를 들어, model이 번역 결과를 반환하면, StrOutputParser는 이를 문자열로 변환하여 후속 단계에서 사용할 수 있도록 합니다.

그런데 |이라는 새로운 녀석이 나왔습니다

chain = prompt_template | model | parser에서 |은 Python에서 새로운 연산자(|, 파이프 연산자)이며,
이 구문에서 |를 사용했습니다. 이 구문은 LangChain에서 제공하는 기능으로, 각 구성 요소(예: prompt_template, model, parser)를 파이프라인 형태로 연결하여 순차적으로 처리할 수 있게 해줍니다.

이 구문에서 각 요소는 특정 작업을 담당하고, 파이프라인을 통해 결과를 처리합니다. 이를 좀 더 구체적으로 설명하면:
prompt_template: 사용자 입력과 시스템 템플릿을 결합한 프롬프트를 생성합니다. 이 부분은 모델에 전달될 입력을 준비하는 역할을 합니다.
model: 모델을 실행하여 입력된 프롬프트에 대해 실제 응답을 생성합니다. 예를 들어, 번역 모델이라면 주어진 텍스트를 번역하는 작업을 수행합니다.
parser: 모델의 출력을 받아서 원하는 형식(여기서는 문자열)으로 변환하는 작업을 합니다. 이 경우 StrOutputParser는 결과를 문자열로 반환합니다.

파이프라인의 흐름
첫 번째 prompt_template이 입력 데이터를 포맷팅하여 모델에 전달할 준비를 합니다.
그 다음, model이 해당 입력을 받아 실행되고, 번역된 문장 등의 결과를 생성합니다.
마지막으로, parser가 모델의 출력을 받아서 지정된 형식(여기서는 문자열)으로 변환하여 최종 결과를 반환합니다.

따라서 이 파이프라인 방식은 각 구성 요소가 서로 연결되어 작업을 순차적으로 처리하는 방식입니다. 이와 같은 방식은 모듈화된 코드로 각 단계를 쉽게 테스트하고 교체할 수 있게 해줍니다.

코드로 해석하면,
prompt_template이 텍스트 "Where is the library?"와 language='Korean'을 받아서 Translate the following sentence from English to Korean: Where is the library?라는 프롬프트를 생성합니다.

model은 이 프롬프트를 입력받아 번역된 결과(예: "도서관은 어디에 있나요?")를 생성합니다.

parser는 모델의 출력을 문자열 형식으로 처리하여 최종적으로 "도서관은 어디에 있나요?"를 반환합니다.

하지만 여기서는 model이 설정되어 있지 않기 때문에, 따로 설정하면 됩니다.

여기까지...