본문으로 건너뛰기
Kreath Archive
TechProjectsBooksAbout
TechProjectsBooksAbout

내비게이션

  • Tech
  • Projects
  • Books
  • About
  • Tags

카테고리

  • AI / ML
  • 웹 개발
  • 프로그래밍
  • 개발 도구

연결

  • GitHub
  • Email
  • RSS
© 2026 Kreath Archive. All rights reserved.Built with Next.js + MDX
홈TechProjectsBooksAbout
//
  1. 홈
  2. 테크
  3. 2장: LangChain 아키텍처와 LCEL 심층 분석
2026년 2월 4일·AI / ML·

2장: LangChain 아키텍처와 LCEL 심층 분석

LangChain 1.0의 아키텍처, LCEL 파이프 문법, 미들웨어, 콘텐츠 블록, OpenTelemetry 통합을 실전 예제와 함께 분석합니다.

14분678자9개 섹션
orchestrationai-frameworkaillm
공유
ai-orchestration2 / 11
1234567891011
이전1장: AI 오케스트레이션의 필요성과 프레임워크 생태계다음3장: LangGraph -- 그래프 기반 에이전트 오케스트레이션

이 장에서 배우는 것

  • LangChain 1.0의 패키지 구조와 아키텍처 설계 철학
  • LCEL(LangChain Expression Language)의 파이프 문법과 동작 원리
  • 미들웨어를 활용한 횡단 관심사 처리
  • 콘텐츠 블록을 통한 멀티모달 지원
  • OpenTelemetry 기반 관측성 통합

LangChain 1.0 아키텍처

LangChain은 2026년 1.0 릴리스를 통해 안정된 API를 확립했습니다. "2.0까지 브레이킹 체인지 없음"을 공약하며, 프로덕션 환경에서의 신뢰성을 보장합니다. 이전 버전들에서 비판받던 과도한 추상화를 줄이고, 명시적이고 예측 가능한 설계로 전환했습니다.

패키지 구조

LangChain 1.0의 패키지 구조는 세 계층으로 나뉩니다.

  • langchain-core: 인터페이스 정의, LCEL 런타임, 기본 타입. 의존성이 최소화된 핵심 패키지입니다.
  • langchain-[provider]: OpenAI, Anthropic 등 각 공급자별 통합 패키지. 필요한 것만 설치합니다.
  • langgraph / langsmith: 그래프 오케스트레이션과 관측성 도구. 별도 패키지로 분리되어 있습니다.
Info

LangChain 1.0에서는 더 이상 langchain 단일 패키지에 모든 것이 포함되지 않습니다. langchain-core를 중심으로 필요한 통합 패키지만 추가하는 방식으로 의존성을 관리합니다.

핵심 추상화

LangChain 1.0의 핵심 추상화는 Runnable입니다. 모든 컴포넌트가 Runnable 인터페이스를 구현하며, 이를 통해 일관된 방식으로 호출, 스트리밍, 배치 처리가 가능합니다.

runnable_interface.py
python
from langchain_core.runnables import Runnable
 
# 모든 Runnable이 공통으로 제공하는 메서드
# .invoke(input)      - 단일 입력 처리
# .stream(input)      - 스트리밍 출력
# .batch(inputs)      - 배치 처리
# .ainvoke(input)     - 비동기 호출
# .astream(input)     - 비동기 스트리밍
# .astream_events()   - 이벤트 스트리밍

LCEL: 선언적 체인 구성

LCEL은 LangChain 1.0의 핵심 혁신입니다. 파이프 연산자(|)를 사용하여 컴포넌트를 연결하는 선언적 문법으로, 체인의 구조를 코드에서 직관적으로 파악할 수 있습니다.

기본 파이프 문법

lcel_basic.py
python
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI
 
# 프롬프트 -> 모델 -> 파서 체인
prompt = ChatPromptTemplate.from_template(
    "다음 주제에 대해 3문장으로 설명해주세요: {topic}"
)
model = ChatOpenAI(model="gpt-4o", temperature=0.7)
parser = StrOutputParser()
 
chain = prompt | model | parser
 
# 실행
result = chain.invoke({"topic": "마이크로서비스 아키텍처"})

파이프 연산자 |는 Python의 __or__ 매직 메서드를 활용합니다. 왼쪽 컴포넌트의 출력이 오른쪽 컴포넌트의 입력으로 자동 전달됩니다.

병렬 실행: RunnableParallel

여러 체인을 동시에 실행해야 할 때 RunnableParallel을 사용합니다.

lcel_parallel.py
python
from langchain_core.runnables import RunnableParallel
 
# 동일한 입력으로 여러 체인을 병렬 실행
analysis_chain = RunnableParallel(
    summary=prompt_summary | model | parser,
    keywords=prompt_keywords | model | parser,
    sentiment=prompt_sentiment | model | parser,
)
 
# 세 체인이 동시에 실행됨
results = analysis_chain.invoke({"text": "분석할 텍스트..."})
# results["summary"], results["keywords"], results["sentiment"]

조건부 분기: RunnableBranch

입력에 따라 다른 처리 경로를 선택할 수 있습니다.

lcel_branch.py
python
from langchain_core.runnables import RunnableBranch
 
# 조건에 따라 다른 체인 실행
route = RunnableBranch(
    (lambda x: "코드" in x["question"], code_chain),
    (lambda x: "데이터" in x["question"], data_chain),
    general_chain,  # 기본 경로
)
 
result = route.invoke({"question": "Python 코드를 리뷰해주세요"})

동적 변환: RunnableLambda

임의의 Python 함수를 체인에 포함시킬 수 있습니다.

lcel_lambda.py
python
from langchain_core.runnables import RunnableLambda
 
def preprocess(input_dict: dict) -> dict:
    """입력 전처리"""
    return {
        "question": input_dict["question"].strip().lower(),
        "context": input_dict.get("context", ""),
    }
 
chain = RunnableLambda(preprocess) | prompt | model | parser
Warning

RunnableLambda 내부에서 부수 효과(side effect)가 있는 작업(파일 쓰기, DB 업데이트 등)을 수행하는 것은 권장하지 않습니다. 체인이 재실행되거나 배치 처리될 때 예상치 못한 결과를 초래할 수 있습니다.


미들웨어: 횡단 관심사 처리

LangChain 1.0은 미들웨어(Middleware) 개념을 도입하여 로깅, 캐싱, 속도 제한 등의 횡단 관심사를 체인 코드와 분리할 수 있게 했습니다.

미들웨어 구조

미들웨어 적용 예제

middleware_example.py
python
from langchain_core.runnables import RunnableConfig
 
# 기본 체인 정의
chain = prompt | model | parser
 
# 재시도 미들웨어 적용
chain_with_retry = chain.with_retry(
    stop_after_attempt=3,
    wait_exponential_jitter=True,
)
 
# 폴백 미들웨어 적용
fallback_model = ChatOpenAI(model="gpt-4o-mini")
fallback_chain = prompt | fallback_model | parser
 
chain_with_fallback = chain_with_retry.with_fallbacks(
    [fallback_chain]
)
 
# 속도 제한
from langchain_core.rate_limiters import InMemoryRateLimiter
 
rate_limiter = InMemoryRateLimiter(
    requests_per_second=10,
    check_every_n_seconds=0.1,
)
 
model_with_rate_limit = ChatOpenAI(
    model="gpt-4o",
    rate_limiter=rate_limiter,
)

커스텀 미들웨어 작성

custom_middleware.py
python
from langchain_core.runnables import RunnableConfig
from langchain_core.callbacks import CallbackManagerForChainRun
import time
 
def timing_middleware(chain):
    """실행 시간을 측정하는 미들웨어"""
    original_invoke = chain.invoke
 
    def timed_invoke(input, config=None, **kwargs):
        start = time.perf_counter()
        result = original_invoke(input, config=config, **kwargs)
        elapsed = time.perf_counter() - start
        print(f"Chain execution: {elapsed:.3f}s")
        return result
 
    chain.invoke = timed_invoke
    return chain

콘텐츠 블록: 멀티모달 지원

LangChain 1.0은 콘텐츠 블록(Content Blocks)을 통해 멀티모달 입출력을 체계적으로 처리합니다. 텍스트, 이미지, 오디오, 도구 호출 결과를 통합된 형식으로 다룰 수 있습니다.

content_blocks.py
python
from langchain_core.messages import HumanMessage
 
# 텍스트 + 이미지 멀티모달 메시지
message = HumanMessage(
    content=[
        {"type": "text", "text": "이 이미지에서 무엇이 보이나요?"},
        {
            "type": "image_url",
            "image_url": {"url": "https://example.com/image.png"},
        },
    ]
)
 
response = model.invoke([message])

콘텐츠 블록은 모델 간 호환성을 보장합니다. OpenAI, Anthropic, Google 등 서로 다른 공급자의 멀티모달 API 형식을 LangChain이 자동으로 변환합니다.


OpenTelemetry 통합

LangChain 1.0은 OpenTelemetry를 네이티브로 지원합니다. 별도의 설정 없이 모든 체인 실행이 자동으로 트레이싱됩니다.

기본 설정

otel_setup.py
python
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanExporter
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
    OTLPSpanExporter,
)
 
# OpenTelemetry 설정
provider = TracerProvider()
exporter = OTLPSpanExporter(endpoint="http://localhost:4317")
provider.add_span_processor(BatchSpanExporter(exporter))
trace.set_tracer_provider(provider)
 
# LangChain은 자동으로 OpenTelemetry 트레이스를 생성
chain = prompt | model | parser
result = chain.invoke({"topic": "AI"})
# -> 자동으로 span 생성: prompt -> model -> parser

트레이스 구조

각 컴포넌트의 실행 시간, 입출력, 토큰 사용량이 OpenTelemetry 스팬에 자동으로 기록됩니다. 이 데이터는 Jaeger, Grafana Tempo, LangSmith 등으로 전송하여 시각화할 수 있습니다.

Tip

LangSmith를 사용하면 OpenTelemetry 데이터에 더해 LLM 특화 분석 -- 프롬프트 버전 비교, 토큰 비용 추적, A/B 테스트 등 -- 을 활용할 수 있습니다. 프로덕션 환경에서는 LangSmith와의 연동을 권장합니다.


실전 예제: RAG 체인 구성

지금까지 배운 개념을 종합하여 실전 RAG 체인을 구성해보겠습니다.

rag_chain.py
python
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import (
    RunnablePassthrough,
    RunnableParallel,
)
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
 
# 1. 벡터 스토어 설정
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma(
    collection_name="docs",
    embedding_function=embeddings,
)
retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
 
# 2. 프롬프트 정의
rag_prompt = ChatPromptTemplate.from_template("""
다음 컨텍스트를 바탕으로 질문에 답변해주세요.
컨텍스트에 없는 내용은 "해당 정보를 찾을 수 없습니다"라고 답변해주세요.
 
컨텍스트:
{context}
 
질문: {question}
""")
 
# 3. 모델 설정 (속도 제한 + 폴백)
from langchain_core.rate_limiters import InMemoryRateLimiter
 
rate_limiter = InMemoryRateLimiter(requests_per_second=10)
 
primary_model = ChatOpenAI(
    model="gpt-4o",
    rate_limiter=rate_limiter,
)
fallback_model = ChatOpenAI(model="gpt-4o-mini")
 
# 4. 문서 포맷팅 함수
def format_docs(docs):
    return "\n\n".join(doc.page_content for doc in docs)
 
# 5. RAG 체인 조합
rag_chain = (
    RunnableParallel(
        context=retriever | format_docs,
        question=RunnablePassthrough(),
    )
    | rag_prompt
    | primary_model.with_fallbacks([fallback_model])
    | StrOutputParser()
).with_retry(stop_after_attempt=3)
 
# 6. 실행
result = rag_chain.invoke("LangChain의 LCEL이란 무엇인가요?")

이 예제에서는 검색과 질문 전달을 병렬로 처리하고, 모델에 폴백과 재시도를 적용하여 프로덕션 수준의 안정성을 확보했습니다.


핵심 요약

  • LangChain 1.0은 langchain-core 중심의 모듈화된 패키지 구조를 채택했습니다.
  • LCEL 파이프 문법(|)으로 체인을 선언적으로 구성하며, 모든 컴포넌트가 Runnable 인터페이스를 구현합니다.
  • 미들웨어로 재시도, 폴백, 속도 제한 등의 횡단 관심사를 체인 코드와 분리할 수 있습니다.
  • 콘텐츠 블록을 통해 텍스트, 이미지 등 멀티모달 데이터를 통합 처리합니다.
  • OpenTelemetry 네이티브 지원으로 별도 설정 없이 자동 트레이싱이 가능합니다.
  • 프레임워크 오버헤드는 약 10ms로, 프로덕션 사용에 충분히 낮은 수준입니다.

다음 장 예고

3장에서는 LangChain 생태계의 에이전트 오케스트레이션 프레임워크인 LangGraph를 심층 분석합니다. StateGraph와 MessageGraph의 차이, 듀러블 상태와 체크포인팅, 조건부 엣지와 사이클, 그리고 휴먼인더루프 패턴까지 실전 예제와 함께 다루겠습니다.

이 글이 도움이 되셨나요?

관련 주제 더 보기

#orchestration#ai-framework#ai#llm

관련 글

AI / ML

3장: LangGraph -- 그래프 기반 에이전트 오케스트레이션

LangGraph 1.0/1.1의 StateGraph, 듀러블 상태, 조건부 엣지, 휴먼인더루프, type-safe 스트리밍을 실전 예제와 함께 분석합니다.

2026년 2월 6일·14분
AI / ML

1장: AI 오케스트레이션의 필요성과 프레임워크 생태계

LLM 애플리케이션이 복잡해지는 이유를 분석하고, 오케스트레이션의 정의와 역할, 2026년 주요 프레임워크 생태계를 조망합니다.

2026년 2월 2일·17분
AI / ML

4장: LlamaIndex -- 데이터 프레임워크와 워크플로우

LlamaIndex의 데이터 커넥터, 인덱스 유형, 쿼리 엔진, 그리고 이벤트 드리븐 Workflows 1.0을 실전 예제와 함께 분석합니다.

2026년 2월 8일·15분
이전 글1장: AI 오케스트레이션의 필요성과 프레임워크 생태계
다음 글3장: LangGraph -- 그래프 기반 에이전트 오케스트레이션

댓글

목차

약 14분 남음
  • 이 장에서 배우는 것
  • LangChain 1.0 아키텍처
    • 패키지 구조
    • 핵심 추상화
  • LCEL: 선언적 체인 구성
    • 기본 파이프 문법
    • 병렬 실행: RunnableParallel
    • 조건부 분기: RunnableBranch
    • 동적 변환: RunnableLambda
  • 미들웨어: 횡단 관심사 처리
    • 미들웨어 구조
    • 미들웨어 적용 예제
    • 커스텀 미들웨어 작성
  • 콘텐츠 블록: 멀티모달 지원
  • OpenTelemetry 통합
    • 기본 설정
    • 트레이스 구조
  • 실전 예제: RAG 체인 구성
  • 핵심 요약
  • 다음 장 예고