LangChain (1)

chelseey·2025년 12월 30일

Runnable

LangChain에서 입력 → 출력 변환을
표준 인터페이스(invoke/ainvoke/stream/batch 등으로
실행 가능하게 만든 단위

특징

  • 표준 메서드 제공
메서드기능
invoke한 번에 하나 실행 (동기)
ainvoke한 번에 하나 실행 (비동기)
batch여러 입력 동시 실행 (병렬 처리 최적화)
stream결과 실시간 스트리밍 (타자기 효과)
astream비동기 스트리밍
  • 파이프 연산자(|) 지원 (LCEL)
    Runnable끼리는 파이프(|)로 연결 가능

  • 각 단계가 입력/출력 스키마를 노출

RunnablePassthrough

입력받은 데이터를 아무런 변경 없이 그대로 다음 단계로 전달

RunnableParallel

여러 작업을 병렬로 실행하고, 결과를 모아서 하나의 dict으로 반환

RunnableLambda

일반 python 함수를 Runnable으로 변환

Prompt

PromptTemplate

변수(사용자 입력)를 받아서 프롬프트를 생성하는 템플릿

ChatPromptTemplate

역할이 구분된 채팅 메시지 목록 형식으로 프롬프트를 생성하는 템플릿

FewShotPromptTemplate

예시(Example)를 프롬프트 안에 넣는 템플릿

ExampleSelector

사용자의 현재 질문과 가장 관련성이 높은 예제를 선택하는 클래스

FewShotChatMessagePromptTemplate

채팅 모델을 위해, 예제들을 '대화 기록(메시지 리스트)' 형태로 주입하는 템플릿

Output Parsers

LLM의 출력을 구조화된 형태로 변환하는 컴포넌트

PydanticOuputParser

텍스트 형태의 응답을 사용자가 정의한 Schema에 맞게 변환

  • 핵심 메서드
메서드역할설명
get_format_instructions()지침 제공LLM에게 "데이터를 어떤 모양(필드, 타입)으로 내뱉어야 하는지" 알려주는 안내문(문자열)을 생성.
parse()분석 및 변환LLM이 내뱉은 문자열을 받아서, 미리 정의된 Pydantic 스키마와 일치하는지 검증하고, Python 객체로 변환.

with_structured_output

모델 호출 단계에서 스키마를 강제하고, 결과를 Pydantic으로 돌려주는 래퍼
(모델이 텍스트를 생성하는 게 아니라,
API 레벨에서 정확한 데이터 구조를 출력하도록 강제됨)

CommaSeparatedListOutputParser

콤마로 이어진 긴 문장을, 리스트(List) 형태로 반환

StructuredOutputParser

로컬 모델은 PydanticOuputParser가 동작하지 않는 경우가 많으므로, 대안으로 StructuredOutputParser를 사용.

JsonOutputParser

High Param 모델에서, 주어진 JSON 스키마에 맞게 결과를 도출

PandasDataFrameOutputParser

Pandas DataFrame에서 요구하는 데이터를 추출하는 도구

DatetimeOutputParser

LLM의 출력을 datetime 형식으로 파싱

EnumOutputParser

LLM 출력이 정해진 보기(Enum 값) 중 하나인지 검증하고,
맞으면 해당 Enum 값으로 파싱

OutputFixingParser

LLM 출력이 파싱될 때 형식/스키마 오류가 나면, 그 오류를 수정하는 도구

Model

캐싱(Caching)

LangChain은 LLM을 위한 선택적 캐싱 레이어를 제공

  • 비용 절감 (API 호출 감소)
  • 응답 속도 향상

InMemoryCache

컴퓨터의 메모리(RAM)에 저장.

SQLiteCache

컴퓨터의 하드디스크에 저장.

직렬화(Serialization)

객체(모델/체인/프롬프트 설정 등)를 파일로 저장할 수 있는 형태(JSON 등)로 변환하는 과정

  • 두 가지 방법: dumpd vs dumps
메서드이름의 뜻결과물 형태
dumpdDump to DictionaryPython 딕셔너리 (dict)
dumpsDump to StringJSON 문자열 (str)

Pickle 파일

Python 객체를 이진 형태로 직렬화해서 저장하는 포맷
효율적이나, 보안 위험이 있음.

Huggingface Endpoints 사용

모델을 다운로드하는 대신, 허깅페이스 서버에서 돌아가는 모델에 API로 요청을 보내 생성 결과만 응답으로 받는 방식

Serverless Endpoints (Inference API)

항목Inference API (Serverless)Inference Endpoints (Dedicated)
목적빠른 프로토타입/실험/소규모 호출프로덕션/대용량/엔터프라이즈
인프라공유(다른 사용자 요청과 자원 공유)전용(내 엔드포인트에 리소스 할당)
성능/지연트래픽 상황에 따라 변동 가능, 대량 사용 시 제한 가능더 예측 가능(지연/처리량 튜닝 가능)
확장제한적/자동 관리지만 제어권 적음AutoScaling 등 확장 옵션 제공
안정성베스트에포트 성격(제한/변동 가능)가동 시간 보장/SLA, 운영 지원 포함 가능
설정 가능 범위적음(간편)많음(클라우드/리전/인스턴스/보안 등 선택)
비용무료(제한 있음) 또는 저비용 중심유료(전용 리소스 비용 발생)

Hugging Face Pipelines

Hugging Face 모델을 로컬에서 실행하는 LangChain의 도구

Ollama

오픈소스 LLM을 로컬에서 실행하게 해주는 도구
GPU 사용 등 실행 설정을 최적화함

  1. Ollama에서 제공하는 모델 사용

  2. Hugging Face에서 GGUF 모델을 받아서 사용
    Hugging Face에서 .gguf 형식의 모델 파일을 받음
    Modelfile 생성
    그 Modelfile을 이용해 커스텀 모델 생성

Ollama의 JSON 출력 모드

  • format="json" 파라미터 추가
  • 프롬프트에 "resonse in JSON format." 추가

Memory

ConversationBufferMemory

대화에서 오간 사용자 입력 + AI 응답을 순서대로 버퍼에 계속 저장해두는 메모리

ConversationBufferWindowMemory

최근 대화 k개만 기억하고,
오래된 대화는 잊어버리는 슬라이딩 윈도우 방식의 메모리

토큰 비용과 메모리 용량 관리

ConversationTokenBufferMemory

대화 턴 수가 아닌, 토큰 수 기준으로 얼마나 저장할지 결정하는 메모리

ConversationEntityMemory

대화 속 엔티티(사람/회사/제품/장소 등)별로 사실(facts)을 뽑아서 저장하는 메모리

ConversationKGMemory (대화 지식그래프 메모리)

대화에서 나온 정보를
[주어–관계–목적어] 형태의 관계로 뽑아 지식 그래프(KG)로 저장하고,
이후 질문에 맞는 관련 관계들을 검색해 다시 컨텍스트로 넣어주는 메모리

ConversationSummaryMemory

대화가 길어질수록 전체 기록을 그대로 넣지 않고,
지금까지의 대화를 요약(Summary)으로 압축해서 저장하는 메모리

대화가 한 턴 진행될 때마다(혹은 일정 시점마다)
LLM을 사용해 이전 요약 + 새 대화 내용을 합쳐 업데이트된 요약을 생성

ConversationSummaryBufferMemory

Buffer + Summary를 결합한 형태

최근 대화는 그대로(버퍼로) 유지하고,
오래된 대화는 삭제하지 않고 요약으로 압축해 남기는 메모리

  • 대화가 들어오면 먼저 [최신 대화 목록]에 저장
  • 설정해 둔 max_token_limit 을 넘어가면
    가장 오래된 대화부터 요약한 뒤 [요약본]에 합침
  • 결과적으로 프롬프트에는 "과거 요약 + 최신 대화"가 함께 들어감

VectorStoreRetrieverMemory (벡터저장소 검색 메모리)

대화를 Vector Store에 저장해두고,
메모리를 불러올 때마다 현재 질문과 의미적으로 가장 비슷한 상위 K개를 검색해서 가져오는 메모리

LCEL (대화내용 기억하기): 메모리 추가

체인에 메모리를 직접 연결해서 대화 기록을 넣고 저장

SQL (SQLAlchemy)

램(RAM)이 아닌, DB에 파일로 저장하는 방법

SQLChatMessageHistory

SQLAlchemy를 통해 대화 기록을 DB에 자동으로 저장하고 불러오는 LangChain의 기능

필수 요소

  • session_id
    대화 세션의 고유 ID (사용자 이름/이메일/채팅방 ID 등)
  • connection
    데이터베이스 파일 위치나 접속 주소

RunnableWithMessageHistory에 ChatMessageHistory추가

멀티턴 대화에서 이전 발화를 기억하기 위해,
일반 LCEL 체인(prompt | llm | parser)에 세션별 대화 기록을
자동으로 불러와 프롬프트에 주입

문서 로더(Document Loader)

Document

LangChain에서 텍스트 데이터를 다루는 기본적인 단위

구조

  • page_content
    실제 문서의 본문 (String)
  • metadata
    본문 외의 부가 정보 (Dictionary)

Document Loaders

파일을 읽어와서, Document 객체 리스트로 변환해주는 도구

WebBaseLoader

웹 URL을 입력받아 BeautifulSoup으로 본문을 추출해
LangChain 문서(Document)로 변환해 주는 웹 크롤러

프록시(Proxy) 사용

내 컴퓨터(클라이언트) → 프록시 서버 → 목적지 서버(웹사이트/API)

실제 IP 주소 대신 프록시 서버를 거쳐 웹사이트에 접속해 차단을 피함

텍스트 분할(Text Splitter)

필요성

  • 검색 품질 향상
  • 비용 절감, 할루시네이션 방지

분할 과정

  • 구조 파악
  • 단위 선정
  • 크기 설정 (Chunk Size)
  • 겹치기 (Chunk Overlap)

CharacterTextSplitter

\n\n 단위로 분할,
토큰(Token)이 아니라 문자 수(Character count)를 기준으로 청크 크기 측정

RecursiveCharacterTextSplitter

'문단 → 문장 → 단어' 순서로 텍스트를 분할

기본 구분자 목록: "\n\n", "\n", " ", ""

TokenTextSplitter

LLM의 토큰 제한을 지키기 위한 분할기
토큰 수를 기준으로 청크의 크기 측정

NLP 기반 분할기 (NLTK, spaCy)

문맥/문법을 고려한 문장 분리
문자 수를 기준으로 청크의 크기 측정

SentenceTransformers

베딩(벡터 변환) 모델의 윈도우 크기에 최적화된 크기로 분할
토큰 수를 기준으로 청크의 크기 측정

SemanticChunker

텍스트를 의미론적으로 유사한 청크로 분할

작동 원리

  • 문장 분리
    텍스트를 문장 단위로 분할

  • 임베딩 & 그룹화
    각 문장을 AI(임베딩 모델)를 통해 벡터로 변환

  • 유사도 비교 및 병합
    인접한 문장 그룹끼리 Cosine Similarity를 계산
    유사도가 높으면 → 병합(Merge)
    유사도가 낮으면 → 분할(Split)

Standard Deviation

인접한 텍스트 조각들 사이의 의미 변화량(semantic distance)을 계산,
변화량이 평균 대비 비정상적으로 큰 지점에서 청크를 분할

Interquartile

전체 문장 간의 변화량 중 상위 25%(Q3)를 기준으로,
이보다 더 크게 변화하는 지점(이상치)을 찾아내어 분할하는 방식

작동 원리

  • 문장 사이의 유사도 거리(Distance)를 계산
    Q1: 하위 25% 지점
    Q3: 상위 25% 지점 (변화가 큰 구간)

  • 기준점(Threshold)을 설정
    Q3+(amount×IQR)Q3+(amount×IQR)
    IQR(InterquartileRange):Q3Q1IQR (Interquartile Range): Q3−Q1

Split code

특정 프로그래밍 언어에 사용되는 구분자(separators)로 분할

MarkdownHeaderTextSplitter

마크다운 텍스트를 지정한 헤더 레벨(#, ##, ### 등)을 기준으로 분할,
각 헤더 아래 내용을 하나의 청크로 묶어 관리

HTMLHeaderTextSplitter

HTML의 <h1>, <h2> 같은 태그를 기준으로 문서를 나누고,
해당 텍스트의 상위 헤더가 무엇인지 metadata에 기록

사용 방법
① HTML 문자열 직접 분할
HTML 코드가 문자열로 있을 때 사용

② 파이프라인 연결 (URL 로드 + 추가 분할)
웹페이지를 긁어온 뒤 1차로 HTML 구조대로 분할, 2차로 글자 수로 조절

한계점
: 복잡한 구조에서는 제목(h1)과 본문(article)이 서로 다른 div 박스(하위 트리)에 담겨 있을 수 있음

RecursiveJsonSplitter

JSON 데이터를 깊이 우선 탐색(DFS)하여 더 작은 JSON 청크를 생성하는 분할기

작동 원리

  • JSON 값 기준 분할
    JSON 형태를 유지하도록 데이터를 괄호나 따옴표 짝이 맞게 분할

  • 문자 수 기준:
    글자 수를 기준으로 청크 크기를
    min_chunk_size ~ max_chunk_size 범위로 맞추기 위해 분할

주의점
: 내용물(Value) 자체가 너무 길 땐, 작업이 끝난 뒤에
텍스트 분할기(RecursiveCharacterTextSplitter) 추가를 고려

0개의 댓글