1️⃣ 섹션 1. 교재 다운로드~섹션 4. Langchain 프레임워크 소개 수강
RAG201 의 개념과 필요성
개요
LLM이 거짓말을 하는 이유?
GAG란?
개요
RAG(Retrieval-Augmented Generation, 검색 증강 생성) 서비스는 대규모 언어 모델(LLM)의 hallucination(환각 현상)을 최소화하며 외부 지식 베이스를 실시간 검색해 컨텍스트를 증강하는 AI 아키텍처이다.
필요성
기본 나이브 서비스 방식으로는 충분하지 않기 때문에 다양한 방법으로 설계한다.
그럼 LLM 언어모델이 무엇인지 알아보자.
LLM의 이해
초기 인코더+디코더의 구조를 활용하여 번역소프트웨어엔진을 개발하던 중 디코더 부분 (다음 단어가 나올 수 있는 확률의 프로세싱)만가지고 여러 레이어를 쌓아 Text Prediction + Tack Classifier으로 GPT란 소프트웨어를 개발 하였음.
학습량을 늟리고 디코더의 새수를 개속적으로 늟기게 되면서 메모리의 증가로 GPT의 모델이 발전함.
초기에는 인코더–디코더 구조의 트랜스포머를 이용하여 기계번역 엔진을 개발했다. 인코더는 입력 문장을 의미 공간의 표현(continuous representation)으로 압축하고, 디코더는 이 표현을 참고하면서 번역 결과 문장을 한 토큰씩 생성한다.
이후 연구에서는 이 구조 중 디코더가 담당하던 “이전 단어들을 기반으로 다음 단어의 확률 분포를 예측하는” 언어 모델링 부분에 주목했다. 이 디코더만을 여러 층으로 깊게 쌓은 디코더 전용(Decoder-only) 트랜스포머 구조를 사용해, 텍스트 생성(Text Prediction)과 텍스트 분류(Task Classification)을 수행하는 GPT(Generative Pre-trained Transformer) 계열 모델이 개발되었다.
GPT는 대규모 코퍼스에 대해, 주어진 토큰 시퀀스가 올 때 다음 토큰의 조건부 확률을 최대화하도록 사전학습(pre-training)된 언어 모델이다. 이렇게 학습된 표현을 기반으로 프롬프트 설계나 간단한 미세조정(fine-tuning)만으로 번역·요약·질의응답·분류 등 다양한 다운스트림 태스크에 활용할 수 있다.
모델의 성능은 크게 두 방향으로 확장되었다. 하나는 학습 데이터의 양과 학습 스텝을 증가시키는 것이고, 다른 하나는 디코더 블록(레이어)의 개수, 임베딩 차원, 어텐션 헤드 수 등을 늘려 파라미터 수를 키우는 것이다. 이러한 스케일 업은 메모리 사용량과 연산량을 크게 증가시키지만, 손실 감소 및 다양한 벤치마크에서의 성능 향상으로 이어지며 GPT-1, GPT-2, GPT-3, GPT-4 등 대형 언어 모델로 발전하는 데 핵심적인 역할을 했다.
LLM의 한계
개요
GPT3의 버젼 업에서 GPT4로 넘어가지 않고 3.5의 이름으로 버젼 이름을 사용한 이유로 볼 수 있다.
GPT-3.5라는 이름은 GPT-3와 GPT-4 사이의 중간 세대(Intermediate iteration)를 나타내는 버전명이다.
GPT-3와 동일하게 디코더 전용 트랜스포머 구조와 다음 토큰 예측 목표를 유지한다.
다만 모델 크기, 학습 데이터, 미세 튜닝 방식(RLHF 기반 정렬 등)이 개선되면서 성능이 향상된 “개선형 GPT-3”에 가깝다.
“GPT-3에서 전혀 새로운 개념이 추가되지 않았다”라고 단정하기보다는, “기존 아키텍처와 학습 목표를 유지한 채, 사람 선호도에 맞게 정렬하고 성능을 튜닝한 강화 버전”이라고 표현하는 것이 더 정확하다.
GPT-3.5 계열(ChatGPT 초기 모델 포함)은 대규모 감독 학습 + 강화학습(RLHF)으로 인간 선호를 반영한 응답을 내도록 추가 학습된 것이 핵심 차별점이다.
여전히 모델의 내부는 “조건부 확률
P(next token ∣ previous tokens)을 최대화하도록 학습된 언어 모델”이라는 구조를 유지한다.
- 확각현상 : 학습이 없는 자료에도 강제 답변을 요구에 의해서 이전 대이터를 활용한 답변
- 기억불가: 사전학습에서 배운 것 외의 자료는 기억을 못함.
- 토큰제한: 입력값이 길어지면 계산량이 크게 증가하므로 모델별 토큰에 제한을 두게 됨.
RAG의 개념
LLM의 한계를 극복하기 위한 방법으로
RAG에서 증강(augmentation)은 검색된 정보를 AI에게 공부 자료처럼 제공하여 답변의 정확성을 높이는 단계이다.
간단한 비유
AI가 시험 문제에 책 지식만으로 대응할 때 잘못된 답을 만들어낼 수 있다. RAG는 그 순간 책에서 문제와 딱 맞는 페이지를 복사해 AI 책상에 놓아주는 과정이다. AI는 이 자료를 보고 정확한 답변을 생성한다.
설명
질문 → 책장 검색 → 관련 페이지 3장 추출(질문)
↓
AI 책상에 페이지 제공(증강) ← 증강 단계(힌트)
↓
AI가 자료 보고 답변 생성
RAG파이프라인 개요와 핵심 컴포턴트
데이터 인덱싱 과정
PDF, 워드, 파워포인트, 웹링크 같은 문서(Document) 를 먼저 작은 조각으로 나눈다(Chunk).
각 조각을 벡터 임베딩(Vector Embedding)으로 바꾼 뒤, 이 벡터들을 벡터 데이터베이스(Vector DB)에 저장해 둔다.
질의·검색·답변 생성 과정
사용자가 “현재 갤럭시 Z 시리즈의 최신 모델은 뭐야?” 같은 질문(Query) 을 입력한다.
이 질문도 벡터 임베딩으로 바꾼 뒤, 벡터 DB에서 비슷한 의미의 문서 조각들을 검색(Retrieval)하고 Top‑K 조각을 가져온다.
이렇게 찾은 관련 문서 조각들을 LLM에게 함께 넘겨, LLM이 이를 참고하여 최종 답변(Answer) 을 생성하는 흐름을 보여준다.
“자료 찾아서 똑똑하게 대답해 주는 챗봇(RAG)”만들기
RAG 기반 챗봇은 문서 내용을 미리 벡터로 인덱싱하여 벡터 DB에 저장해 두고, 질의 시 의미적으로 유사한 문서를 검색하여 이를 힌트로 포함한 프롬프트를 LLM에 제공함으로써 보다 정확한 답변을 생성하는 시스템이다.
1단계: 문서 불러오기 (Document Loader)
문서 로더는 PDF, 워드, PPT, 웹페이지 등 다양한 형태의 문서를 읽어 텍스트로 변환하는 역할을 한다.
- 오픈 소스
- LangChain Document Loaders: PDF, Word, HTML, Notion, Google Drive 등 수십 종의 로더 제공.
- Unstructured.io: PDF, 스캔 이미지, 슬라이드 등을 구조화된 텍스트로 변환하는 파이프라인.
- 상용/클라우드 API
- Microsoft Graph / Google Drive API: OneDrive, SharePoint, Google Drive에 저장된 문서를 불러올 때 사용.
- AWS Textract / Azure Form Recognizer: 스캔 문서·이미지(PDF, 스캔된 계약서 등)를 텍스트로 OCR 추출하는 서비스.
2단계: 문서 임베딩 (Embedding Model)
문서·질문을 의미 벡터로 바꾸는 단계이며, 검색 정확도에 직접적인 영향을 준다.
- 오픈 소스
-
Sentence Transformers (
all-MiniLM-L6-v2,all-mpnet-base-v2,paraphrase-multilingual-MiniLM-L12-v2등): 파이썬sentence-transformers라이브러리로 사용, 로컬 RAG에서 가장 널리 쓰이는 계열. - nomic-embed-text, gte-small/large 등: RAG 벤치마크에서 성능이 좋은 범용 임베딩 모델.
-
Sentence Transformers (
- 상용 API
-
OpenAI Embeddings (
text-embedding-3-small,text-embedding-3-large): 검색·클러스터링·추천 등 범용 용도로 가장 많이 사용되는 상용 임베딩 API. - Cohere Embed API: 의미 검색·추천 시스템에 최적화된 상용 임베딩 서비스.
- (참고) Google Gemini, Voyage AI, Mistral 등도 각각 임베딩 API를 제공하며, 비용·언어지원·성능 기준으로 선택한다.
-
OpenAI Embeddings (
3단계: 벡터 DB 저장 및 검색 (Vector DB)
생성된 임베딩 벡터를 저장하고, 질문 임베딩과의 유사도(코사인, 내적 등)를 기준으로 Top‑K 문서를 검색하는 역할이다.
- 오픈 소스
- FAISS (Meta): CPU/GPU에서 대규모 벡터 검색을 지원하는 라이브러리로, 로컬 RAG에서 표준처럼 사용된다.
- Qdrant, Milvus, Weaviate: gRPC/REST API를 제공하는 오픈 소스 벡터 데이터베이스.
- 상용/매니지드 서비스
- Pinecone: 완전 관리형 벡터 DB 서비스로, OpenAI·LangChain과 연동 예제가 매우 많다.
- Azure AI Search / Elasticsearch + vector: 기존 검색 인프라에 벡터 검색 기능을 추가한 형태로 엔터프라이즈에서 자주 사용된다.
4단계: LLM 프롬프트 구성 및 답변 생성
검색된 유사 문장(힌트 문장)을 사용자 질문과 함께 하나의 프롬프트로 구성하여 LLM에 전달하고, LLM이 이를 바탕으로 최종 답변을 생성한다.
- 오픈 소스 LLM
- Llama 3 / Llama 2: 메타의 오픈 소스 LLM으로, 8B·70B 등 다양한 크기와 Chat/Instruction 튜닝 버전이 있어 RAG 백엔드로 많이 사용된다.
- Mistral / Mixtral, Qwen, Gemma: 다국어 지원·긴 컨텍스트·경량성을 강점으로 갖는 최신 오픈 소스 LLM들로, 로컬·온프렘 RAG에서 인기 있다.
- OpenAI GPT 계열
- 대표 모델: GPT‑4.1, GPT‑4o, o3‑mini 등.
- 특징: 생태계·예제가 풍부하고, RAG용 프롬프트 패턴이 가장 많이 축적되어 있음.
- Anthropic Claude 계열
- 대표 모델: Claude 3.5 Sonnet, Claude 3 Opus, Claude 3 Haiku 등.
- 특징: 최대 200K 이상 컨텍스트 윈도우를 지원하여 긴 문서 기반 RAG에 유리하고, 안전성·환각 감소에 초점을 둔 설계가 강점.
- Google Gemini 계열
- 대표 모델: Gemini 1.5 Pro, Gemini 1.5 Flash 등.
- 특징: 텍스트·이미지·코드 등 멀티모달 입력을 지원하고, Vertex AI RAG Engine·File Search 도구를 통해 임베딩·벡터 검색·컨텍스트 주입까지 통합 제공.
전체 흐름 한 줄 정리
- 문서 로더·임베딩 모델·벡터 DB·LLM을 조합하여, 문서를 로드하고 → 임베딩으로 변환해 벡터 DB에 저장한 뒤 → 질문 임베딩으로 유사 문서를 검색하고 → 그 문맥을 포함한 프롬프트를 LLM에 전달하여 답변을 생성하는 구조가 RAG의 기본 파이프라인이며, 각 단계에서 위와 같은 오픈 소스 컴포넌트와 상용 API가 널리 활용된다.
RAG를 활용하는 기업과 이에 산악협력하는 벤쳐기업들
| 구분 | 이름 | 연구기관·Labs | 설명 (20자 내) |
|---|---|---|---|
| 금융 | KB국민카드 | 스켈터랩스 | 이벤트 Q&AI RAG 챗봇skelterlabs+1 |
| 금융 | 신한투자증권 | 스켈터랩스 | 사내 RAG 챗봇 ‘챗프로’skelterlabs+1 |
| 금융 | BC카드 | 내부 데이터팀 | 약관·리포트용 RAG 논의bcif.bccard |
| 금융 | 다수 금융사 | 올거나이즈 | 금융 RAG 리더보드·PoCblog-ko.allganize+1 |
| 법률 | 로톡(로앤컴퍼니) | 로앤굿·AI팀 | AI 변호사 추천·검색aidev+1 |
| 법률 | 로앤굿(로앤봇) | 내부 변호사·AI팀 | RAG 기반 법률상담 챗봇aidev |
| 법률 | 빅케이스GPT | 법무법인·데이터팀 | 판결문 요약·유사판례techsuda+1 |
| 법률 | 한국 법률 RAG 챗봇 예제 | GitHub law_chatbot | 한국어 법률 RAG 예제github |
| 공공 | 통계청 | 민간 AI 기업 | 통계 챗봇에 RAG 도입beyondpost |
| 공공 | 법제처 | 민간 AI 컨소시엄 | AI 법령 RAG 서비스lawtalknews+1 |
| 공공 | K-water | 그리드원 | K‑water GPT 공공 RAGnaver |
| 공공 | 국가기록원 | 솔트룩스 | 기록물 지능형 검색·RAGsaltlux |
| 공공 | 공공기관 다수 | 안랩클라우드메이트 | 규정 관리 RAG 어시스턴트techinterviewblog |
| 헬스케어 | 메이크봇H | 국내 대형병원 다수 | 병원 예약·문의 RAG 챗봇asiae+1 |
| 헬스케어 | 메이크봇 HybridRAG | 자체 연구랩 | HybridRAG 프레임워크makebot+1 |
| 헬스케어 | 의료 RAG PoC들 | 대학병원·연구소 | 진단 보조·문서 RAG 실험seo.goover |
| 범용 | AIFRICA Gazelle RAG | AIFRICA Lab | 폐쇄망용 Gazelle RAGaifrica |
| 범용 | Konan RAG‑X | Konan LLM Lab | 기업용 RAG‑X 패키지konantech |
| 범용 | WISE iRAG V2 | WISENUT R&D | 검색 기반 iRAG 솔루션wisenut+1 |
| 범용 | LUXIA A.RAG | 솔트룩스 연구소 | 공공·엔터프라이즈 RAGsaltlux |
Langchain 개념과 아키텍처
LangChain 개념
LangChain은 LLM을 단독으로 사용하는 대신, 여러 컴포넌트를 연결하여 실세계 애플리케이션을 구축한다. 핵심 아이디어는 '체인화'로, 입력에서 출력까지 순차적 또는 병렬적 처리를 지원한다. 예를 들어, 텍스트 입력 → 검색 → 요약 → 응답 과정을 자동화한다.
주요 아키텍처 컴포넌트
- Models: LLM(예: GPT 시리즈) 또는 임베딩 모델을 추상화한 인터페이스.
- Prompts: 입력 템플릿을 관리하며, 동적 변수 삽입을 지원.
- Chains: 컴포넌트를 순차 연결하는 기본 단위(예: LLMChain).
- Agents: 도구(검색, 계산기 등)를 동적으로 선택·실행하는 지능형 체인.
- Memory: 대화 히스토리나 벡터 저장소를 통해 상태 유지.
동작 원리
입력 데이터를 프롬프트로 변환한 후 체인 내 모델에 전달하고, 출력은 다음 컴포넌트로 전달된다. 예: RetrievalQA 체인은 벡터 DB에서 관련 문서를 검색·회수한 후 LLM으로 답변 생성. 이는 모듈러 설계로 확장성과 디버깅을 용이하게 한다.
실무 예시
질의응답 시스템에서 LangChain은 문서 로더 → 임베딩 → 벡터 저장소 → 리트리버 → LLM 체인을 구성한다. 이는 RAG(Retrieval-Augmented Generation) 패턴의 표준 구현으로, 환각(hallucination) 감소와 정확도 향상을 이룬다.
LLM의 발전과 함께 중요해진 프롬프트 엔지니어링을 보조할 수 있다.
프롬프트 엔지니어링이란?
AI의 언어와 인간의 언어사이에 인간이 편하게 이해 할 수 있도록 목적에 맞는 답변을 해주는 문장을 만들어 주는 역활을 한다.
Langchain을 사용한 RAG구현 워크플로우
RAG(Retrieval-Augmented Generation) 시스템의 단계별 공정
RAG 시스템은 데이터를 저장 가능한 형태로 가공하는 인덱싱(Indexing) 과정과 사용자의 질문에 맞춰 최적의 답변을 도출하는 검색 및 생성(Retrieval & Generation) 과정으로 나뉜다.
1. 문서 로드 및 수집 (Document Loading)
시스템 구축의 첫 단계는 PDF, 워드, 웹페이지 등 다양한 형식의 원천 데이터를 확보하는 것이다. 이 단계에서는 외부 소스로부터 데이터를 가져와 시스템이 처리할 수 있는 문서 객체로 변환한다.
2. 텍스트 분할 (Text Splitting)
불러온 방대한 양의 문서를 효율적으로 처리하기 위해 '청크(Chunk)'라고 불리는 작은 단위로 세분화한다. 이는 정보의 탐색 속도를 높이고 인공지능이 한 번에 이해할 수 있는 적절한 정보량을 유지하기 위함이다.
3. 벡터 임베딩 (Vector Embedding)
분할된 텍스트 데이터는 임베딩 모델을 거쳐 수치화된 데이터인 '벡터(Vector)'로 변환된다. 이는 컴퓨터가 텍스트의 의미적 유사성을 계산할 수 있도록 기계어로 바꾸는 핵심 공정이다.
4. 벡터 데이터베이스 저장 (Vector Store)
수치화된 데이터는 검색 최적화 과정을 거쳐 벡터 데이터베이스(Vector Database)에 저장된다. 이 저장소는 사용자의 질문이 입력되었을 때 가장 연관성이 높은 데이터를 신속하게 찾아낼 수 있는 역할을 수행한다.
5. 검색 및 유사 문장 추출 (Retrieval)
사용자가 질문(Query)을 입력하면 해당 질문 역시 수치(벡터)로 변환된다. 이후 시스템은 데이터베이스 내에서 질문의 수치와 가장 유사한 정보를 담은 문장들을 선별하여 추출한다.
6. 답변 생성 (Generation)
최종적으로 대형언어모델(LLM)은 사용자의 질문과 시스템이 찾아낸 관련 정보를 결합한다. 모델은 제공된 힌트 문장들을 바탕으로 근거에 기반한 정확한 답변을 생성하여 사용자에게 전달한다.
## **Langchain을 표현하는 언어, LCEL**
*[LCEL로 기본 체인 구성하기]*
import os
os.environ["OPENAI_API_KEY"] = "YOUR_API_KEY"
#필수 라이브러리 설치
!pip install --upgrade --quiet langchain openai langchain-core langchain-openai
rom langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
#프롬프트 템플릿 설정
prompt = ChatPromptTemplate.from_template("tell me a short joke about {topic}")
#LLM 호출
model = ChatOpenAI(model="gpt-4o-mini")
#출력 파서 설정
output_parser = StrOutputParser()
#LCEL로 프롬프트템플릿-LLM-출력 파서 연결하기
chain = prompt | model | output_parser
#invoke함수로 chain 실행하기
chain.invoke({"topic": "ice cream"})
*[Streaming 기능 추가를 더욱 쉽게, stream()]
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
#Chain 선언
model = ChatOpenAI(model="gpt-4o-mini")
prompt = ChatPromptTemplate.from_template("tell me a joke about {topic}")
chain = prompt | model
#Chain의 stream()함수를 통해 스트리밍 기능 추가
for s in chain.stream({"topic": "bears"}):
print(s.content, end="", flush=True)
*[한꺼번에 여러 개 API 요청하고 답변 받기, batch()]*
- 5개 문장 번역 batch 수행
%%time
model = ChatOpenAI(model="gpt-4o-mini")
prompt = ChatPromptTemplate.from_template("다음 한글 문장을 프랑스어로 번역해줘 {sentence}")
chain = prompt | model
chain.batch([
{"sentence": "그녀는 매일 아침 책을 읽습니다."},
{"sentence": "오늘 날씨가 참 좋네요."},
{"sentence": "저녁에 친구들과 영화를 볼 거예요."},
{"sentence": "그 학생은 매우 성실하게 공부합니다."},
{"sentence": "커피 한 잔이 지금 딱 필요해요."}
])
- 1개 문장 번역 invoke 수행
%%time
prompt = ChatPromptTemplate.from_template("다음 한글 문장을 프랑스어로 번역해줘 {sentence}")
chain = prompt | model
chain.invoke({"sentence": "그녀는 매일 아침 책을 읽습니다."})
## **RunnablePassthrough, RunnableLambda, RunnableParallel**
*[RunnablePassthrough]*
*RunnablePassthrough는 가장 단순한 Runnable 객체로, 들어온 입력을 그대로 전달합니다.*
pip install -q langchain langchain-core langchain-openai
import os
os.environ["OPENAI_API_KEY"] = "YOUR_API_KEY"
from langchain_core.runnables import RunnablePassthrough
RunnablePassthrough().invoke("안녕하세요")
Langchain을 표현하는 언어, LCEL
[LCEL로 기본 체인 구성하기]
import os
os.environ["OPENAI_API_KEY"] = "YOUR_API_KEY"
필수 라이브러리 설치
!pip install --upgrade --quiet langchain openai langchain-core langchain-openai
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
프롬프트 템플릿 설정
prompt = ChatPromptTemplate.from_template("tell me a short joke about {topic}")
LLM 호출
model = ChatOpenAI(model="gpt-4o-mini")
출력 파서 설정
output_parser = StrOutputParser()
LCEL로 프롬프트템플릿-LLM-출력 파서 연결하기
chain = prompt | model | output_parser
invoke함수로 chain 실행하기
chain.invoke({"topic": "ice cream"})
[Streaming 기능 추가를 더욱 쉽게, stream()]
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
Chain 선언
model = ChatOpenAI(model="gpt-4o-mini")
prompt = ChatPromptTemplate.from_template("tell me a joke about {topic}")
chain = prompt | model
Chain의 stream()함수를 통해 스트리밍 기능 추가
for s in chain.stream({"topic": "bears"}):
print(s.content, end="", flush=True)
[한꺼번에 여러 개 API 요청하고 답변 받기, batch()]
- 5개 문장 번역 batch 수행 %%time model = ChatOpenAI(model="gpt-4o-mini") prompt = ChatPromptTemplate.from_template("다음 한글 문장을 프랑스어로 번역해줘 {sentence}") chain = prompt | model
chain.batch([
{"sentence": "그녀는 매일 아침 책을 읽습니다."},
{"sentence": "오늘 날씨가 참 좋네요."},
{"sentence": "저녁에 친구들과 영화를 볼 거예요."},
{"sentence": "그 학생은 매우 성실하게 공부합니다."},
{"sentence": "커피 한 잔이 지금 딱 필요해요."}
])
- 1개 문장 번역 invoke 수행 %%time prompt = ChatPromptTemplate.from_template("다음 한글 문장을 프랑스어로 번역해줘 {sentence}") chain = prompt | model
chain.invoke({"sentence": "그녀는 매일 아침 책을 읽습니다."})
RunnablePassthrough, RunnableLambda, RunnableParallel
[RunnablePassthrough]RunnablePassthrough는 가장 단순한 Runnable 객체로, 들어온 입력을 그대로 전달합니다.
pip install -q langchain langchain-core langchain-openai
import os
os.environ["OPENAI_API_KEY"] = "YOUR_API_KEY"
from langchain_core.runnables import RunnablePassthrough
RunnablePassthrough().invoke("안녕하세요")
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
prompt = ChatPromptTemplate.from_template("다음 한글 문장을 프랑스어로 번역해줘 {sentence} \n French sentence: (print from here)")
model = ChatOpenAI(model="gpt-4o-mini")
output_parser = StrOutputParser()
runnable_chain = {"sentence": RunnablePassthrough()} | prompt | model | output_parser
runnable_chain.invoke({"sentence": "그녀는 매일 아침 책을 읽습니다."})
RunnablePassthrough는 assin 함수를 통해 새로운 변수에 계산된 값을 입력할 수 있습니다.
(RunnablePassthrough.assign(mult=lambda x: x["num"]*3)).invoke({"num":3})
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
runnable = RunnableParallel(
extra=RunnablePassthrough.assign(mult=lambda x: x["num"] * 3),
modified=lambda x: x["num"] + 1,
)
runnable.invoke({"num": 1})
[RunnableLambda]RunnableLambda는 임의의 함수를 Chain에 결합할 수 있게 Runnable 객체로 변환합니다..
def add_smile(x):
return x + ":)"
from langchain_core.runnables import RunnableLambda
add_smile = RunnableLambda(add_smile)
from langchain.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain.schema.output_parser import StrOutputParser
prompt_str = "{topic}의 역사에 대해 세문장으로 설명해주세요."
prompt = ChatPromptTemplate.from_template(prompt_str)
model = ChatOpenAI(model_name = 'gpt-4o-mini')
output_parser = StrOutputParser()
chain = prompt | model | output_parser
from langchain_core.runnables import RunnableLambda
def add_thank(x):
return x + " 들어주셔서 감사합니다 :)"
add_thank = RunnableLambda(add_thank)
chain = prompt | model | output_parser | add_thank
chain.invoke("반도체")
pip install -q grandalf
chain.get_graph().print_ascii()
[RunnableParallel]RunnableParallel은 여러 요소가 병렬 처리되도록 처리합니다.
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
runnable = RunnableParallel(
passed=RunnablePassthrough(),
modified=lambda x: x["num"] + 1,
)
runnable.invoke({"num": 1})
runnable = RunnableParallel(
passed=RunnablePassthrough(),
modified=add_thank,
)
runnable.invoke("안녕하세요")
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableParallel
from langchain_openai import ChatOpenAI
from langchain.schema.output_parser import StrOutputParser
model = ChatOpenAI(model = 'gpt-4o-mini', max_tokens = 128, temperature = 0)
history_prompt = ChatPromptTemplate.from_template("{topic}가 무엇의 약자인지 알려주세요.")
celeb_prompt = ChatPromptTemplate.from_template("{topic} 분야의 유명인사 3명의 이름만 알려주세요.")
output_parser = StrOutputParser()
history_chain = history_prompt | model | output_parser
celeb_chain = celeb_prompt | model | output_parser
map_chain = RunnableParallel(history=history_chain, celeb=celeb_chain)
result = map_chain.invoke({"topic": "AI"})
result
LCEL로 RAG 구축하기
[기본 RAG 구축]
pip install -q langchain_chroma langchain_community langchainhub
from langchain_openai import ChatOpenAI
import bs4
from langchain import hub
from langchain_chroma import Chroma
from langchain_community.document_loaders import WebBaseLoader
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
model = ChatOpenAI(model="gpt-4o-mini")
Load, chunk and index the contents of the blog.
loader = WebBaseLoader(
web_paths=("https://n.news.naver.com/mnews/article/366/0001007619",),
bs_kwargs=dict(
parse_only=bs4.SoupStrainer(
class_=("newsct_article _article_body")
)
),
)
docs = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=300, chunk_overlap=50)
splits = text_splitter.split_documents(docs)
vectorstore = Chroma.from_documents(documents=splits, embedding=OpenAIEmbeddings())
Retrieve and generate using the relevant snippets of the blog.
retriever = vectorstore.as_retriever()
prompt = hub.pull("rlm/rag-prompt")
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| model
| StrOutputParser()
)
rag_chain.invoke("아까 내가 했던 질문이 뭐야?")
메모리를 추가한 RAG 구축하기
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain.chains import create_history_aware_retriever
from langchain_core.prompts import MessagesPlaceholder
from langchain_core.messages import HumanMessage
loader = WebBaseLoader(
web_paths=("https://n.news.naver.com/mnews/article/366/0001007619",),
bs_kwargs=dict(
parse_only=bs4.SoupStrainer(
class_=("newsct_article _article_body")
)
),
)
docs = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splits = text_splitter.split_documents(docs)
vectorstore = Chroma.from_documents(documents=splits, embedding=OpenAIEmbeddings())
retriever = vectorstore.as_retriever()
contextualize_q_system_prompt = (
"Given a chat history and the latest user question "
"which might reference context in the chat history, "
"formulate a standalone question which can be understood "
"without the chat history. Do NOT answer the question, "
"just reformulate it if needed and otherwise return it as is."
)
contextualize_q_prompt = ChatPromptTemplate.from_messages(
[
("system", contextualize_q_system_prompt),
MessagesPlaceholder("chat_history"),
("human", "{input}"),
]
)
history_aware_retriever = create_history_aware_retriever(
model, retriever, contextualize_q_prompt
)
system_prompt = (
"You are an assistant for question-answering tasks. "
"Use the following pieces of retrieved context to answer "
"the question. If you don't know the answer, say that you "
"don't know. Use three sentences maximum and keep the "
"answer concise."
"\n\n"
"{context}"
)
qa_prompt = ChatPromptTemplate.from_messages(
[
("system", system_prompt),
MessagesPlaceholder("chat_history"),
("human", "{input}"),
]
)
question_answer_chain = create_stuff_documents_chain(model, qa_prompt)
rag_chain = create_retrieval_chain(history_aware_retriever, question_answer_chain)
chat_history = []
question = "오픈AI 근황은 어때?"
ai_msg_1 = rag_chain.invoke({"input": question, "chat_history": chat_history})
chat_history.extend([HumanMessage(content=question), ai_msg_1["answer"]])
ai_msg_1
chat_history
question = "다시 한번 설명해줄래?"
ai_msg_2 = rag_chain.invoke({"input": question, "chat_history": chat_history})
chat_history.extend([HumanMessage(content=question), ai_msg_2["answer"]])
ai_msg_2
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.chat_history import BaseChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
store = {}
def get_session_history(session_id: str) -> BaseChatMessageHistory:
if session_id not in store:
store[session_id] = ChatMessageHistory()
return store[session_id]
conversational_rag_chain = RunnableWithMessageHistory(
rag_chain,
get_session_history,
input_messages_key="input",
history_messages_key="chat_history",
output_messages_key="answer",
)
conversational_rag_chain.invoke(
{"input": "오픈AI의 근황이 어때?"},
config={
"configurable": {"session_id": "abc123"}
}, # constructs a key "abc123" in store.
)["answer"]
conversational_rag_chain.invoke(
{"input": "앞으로 어떻게 될까?"},
config={"configurable": {"session_id": "abc123"}},
)["answer"]
from langchain_core.messages import AIMessage
for message in store["abc123"].messages:
if isinstance(message, AIMessage):
prefix = "AI"
else:
prefix = "User"
print(f"{prefix}: {message.content}\\n")
Top comments (0)