AI Engineering Academy · 강의

LCEL로 체인 구축하기

파이프 연산자로 프롬프트 템플릿, LLM, 출력 파서를 Runnable 시퀀스로 연결하고, 이를 동기 및 비동기로 호출하며, 중간 출력을 확인합니다.

레슨 2/413개 단계

LCEL로 체인 구축하기은(는) CoddyKit의 무료 AI Engineering Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 AI Engineering Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. AI Engineering Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

LCEL이란 무엇인가요?

LCEL (LangChain Expression Language)은 LangChain 구성 요소를 파이프라인으로 선언적으로 조합하는 방법입니다. 장황한 Chain 클래스를 인스턴스화하는 대신 | 연산자로 Runnable을 연결합니다. LCEL 체인은 스트리밍, 비동기 처리, 일괄 처리, 대체 체인을 자동으로 지원하므로 파이프 구문을 사용하는 것만으로 이러한 기능을 모두 이용할 수 있습니다.

첫 번째 LCEL 체인

가장 간단한 LCEL 체인은 PromptTemplate, ChatModel, OutputParser를 조합합니다. 각 구성 요소는 Runnable이며, 파이프 연산자가 이들을 연결합니다. chain.invoke()를 호출하면 입력이 각 단계를 순서대로 통과하고, 각 단계의 출력이 다음 단계의 입력이 됩니다.

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

prompt = ChatPromptTemplate.from_template(
    'Write a product description for: {product}'
)
model = ChatOpenAI(model='gpt-4o-mini', temperature=0.7)
parser = StrOutputParser()

chain = prompt | model | parser

result = chain.invoke({'product': 'noise-cancelling headphones'})
print(result)

체인 내부 구조 살펴보기

LCEL 체인은 구조를 투명하게 보여줍니다. chain.steps에는 구성 요소가 순서대로 나열됩니다. chain.input_schema와 chain.output_schema를 호출하면 입력과 출력으로 전달되는 형식을 확인할 수 있습니다. 또한 invoke() 호출은 체인 정의를 변경하지 않고 단일 호출에 실행 이름, 태그, 콜백을 전달할 수 있는 config 매개변수를 받습니다.

# Inspect chain structure
print('Steps:', chain.steps)
print('Input schema:', chain.input_schema.schema())
print('Output schema:', chain.output_schema.schema())

# Named run for observability
result = chain.invoke(
    {'product': 'coffee maker'},
    config={'run_name': 'product-desc-run', 'tags': ['production']}
)

동기 호출과 비동기 호출 비교

LCEL 체인은 모든 메서드에 대해 동기 버전과 비동기 버전을 제공합니다. invoke()는 호출한 스레드를 차단합니다. ainvoke()는 비동기 방식에 해당하며 이벤트 루프를 차단하지 않도록 FastAPI 핸들러 및 기타 비동기 컨텍스트에서 사용해야 합니다. 비동기 버전의 의미는 동일하며, 인터페이스상의 차이는 await뿐입니다.

import asyncio
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

chain = ChatPromptTemplate.from_template('Explain {topic}') | ChatOpenAI() | StrOutputParser()

async def main():
    # Async invocation
    result = await chain.ainvoke({'topic': 'quantum computing'})
    print(result)

asyncio.run(main())

체인을 통한 토큰 스트리밍

LCEL 체인은 전체 과정에서 스트리밍을 전달합니다. chain.stream()을 호출하면 모델이 토큰을 생성하는 즉시 받을 수 있습니다. StrOutputParser는 스트리밍을 인식하므로 전체 응답을 기다리지 않고 개별 문자열 청크를 전달합니다. 따라서 사용자는 긴 대기 후 완성된 답변을 받는 대신 즉시 피드백을 받을 수 있습니다.

chain = (
    ChatPromptTemplate.from_template('Tell me about {topic} in detail.')
    | ChatOpenAI(model='gpt-4o-mini')
    | StrOutputParser()
)

# Print each token as it arrives
for chunk in chain.stream({'topic': 'neural networks'}):
    print(chunk, end='', flush=True)
print()  # newline at end

# Async streaming
async def stream_async():
    async for chunk in chain.astream({'topic': 'transformers'}):
        print(chunk, end='', flush=True)

여러 입력 일괄 처리

chain.batch()는 입력 사전 목록을 받아 설정 가능한 동시성으로 처리합니다. LangChain은 내부적으로 호출을 병렬 스레드에서 실행하므로 반복문에서 invoke()를 호출하는 것보다 일괄 처리가 훨씬 빠릅니다. max_concurrency 매개변수는 병렬 API 호출 수를 제한하여 요청률 제한을 초과하지 않도록 합니다. 결과는 입력과 같은 순서로 반환됩니다.

products = [
    {'product': 'laptop'},
    {'product': 'tablet'},
    {'product': 'smartwatch'},
    {'product': 'earbuds'},
]

# Process all 4 concurrently
results = chain.batch(products, config={'max_concurrency': 4})

for product, description in zip(products, results):
    print(f'{product["product"]}: {description[:80]}...')

RunnablePassthrough와 RunnableLambda

RunnablePassthrough는 입력을 변경하지 않고 그대로 전달하므로, 변환된 데이터와 함께 원래 컨텍스트를 전달할 때 유용합니다. RunnableLambda는 모든 Python 함수를 Runnable로 감싸 LCEL 체인에 임의의 로직을 삽입할 수 있게 합니다. 이 둘을 함께 사용하면 완전한 사용자 지정 Runnable 클래스를 작성하지 않고도 체인 단계 사이에서 데이터를 조작할 수 있습니다.

from langchain_core.runnables import RunnablePassthrough, RunnableLambda

def word_count(text: str) -> str:
    count = len(text.split())
    return f'{text}\n\n[Word count: {count}]'

chain = (
    ChatPromptTemplate.from_template('Write about {topic}')
    | ChatOpenAI(model='gpt-4o-mini')
    | StrOutputParser()
    | RunnableLambda(word_count)  # Add word count to output
)

result = chain.invoke({'topic': 'climate change'})
print(result)

RunnablePassthrough로 추가 컨텍스트 전달하기

RAG에서 흔히 사용하는 패턴은 검색된 문서와 사용자 질문을 모두 최종 프롬프트에 전달하는 것입니다. RunnablePassthrough.assign()을 사용하면 원래 키를 잃지 않고 입력 사전에 계산된 필드를 추가할 수 있습니다. 이렇게 하면 체인을 통과하는 동안 컨텍스트 객체가 확장되어 모든 데이터를 프롬프트 템플릿에서 사용할 수 있습니다.

from langchain_core.runnables import RunnablePassthrough

# Fake retriever for illustration
def retrieve_docs(question: str):
    return ['Doc 1 content', 'Doc 2 content']

retriever = RunnableLambda(retrieve_docs)

rag_chain = (
    RunnablePassthrough.assign(context=retriever)  # adds 'context' key
    | ChatPromptTemplate.from_template(
        'Context: {context}\n\nAnswer: {question}'
    )
    | ChatOpenAI()
    | StrOutputParser()
)

result = rag_chain.invoke({'question': 'What is machine learning?'})

체인에 대체 체인 추가하기

LCEL 체인은 기본 체인에서 예외가 발생할 때 시도할 대체 체인을 지원합니다. chain.with_fallbacks([backup_chain])을 호출하면 하나 이상의 대체 체인을 등록할 수 있습니다. LangChain은 먼저 기본 체인을 시도하고, 예외가 발생하면 이를 포착한 뒤 대체 체인을 순서대로 시도합니다. 이는 서비스 제공자 장애나 모델 오류를 안정적으로 처리하는 표준적인 방법입니다.

from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic

primary_chain = (
    ChatPromptTemplate.from_template('Answer: {question}')
    | ChatOpenAI(model='gpt-4o')
    | StrOutputParser()
)

fallback_chain = (
    ChatPromptTemplate.from_template('Answer: {question}')
    | ChatAnthropic(model='claude-3-haiku-20240307')
    | StrOutputParser()
)

robust_chain = primary_chain.with_fallbacks([fallback_chain])
# If OpenAI fails, automatically tries Anthropic

중간 단계로 디버깅하기

invoke()의 config와 verbose=True 옵션을 사용하면 LCEL 체인을 더 쉽게 디버깅할 수 있습니다. 또한 모든 체인에서 .with_config({'verbose': True})를 사용하여 각 단계의 입력과 출력을 기록할 수 있습니다. 구조화된 디버깅을 위해 전역에서 체인을 set_verbose(True)로 설정하거나 LangSmith 추적을 사용하면 시각적 추적 탐색기에서 모든 중간 값을 확인할 수 있습니다.

from langchain.globals import set_verbose, set_debug

# Verbose: logs LLM inputs/outputs
set_verbose(True)

# Debug: logs everything including prompts, parsers, and runnables
set_debug(True)

result = chain.invoke({'product': 'smart watch'})

# Or per-chain verbose config
chain_debug = chain.with_config({'verbose': True})
result = chain_debug.invoke({'product': 'laptop'})

실행 시점에 구성 가능한 체인

LCEL 체인은 ConfigurableField를 통해 실행 시점 구성을 지원합니다. 모델 매개변수인 temperature, model name, max_tokens를 코드에 고정하지 않고 구성 가능한 옵션으로 노출할 수 있습니다. 호출할 때 Configurable config를 전달하면 기본값을 재정의할 수 있습니다. 이를 통해 서로 다른 설정을 사용하는 여러 사용자에게 하나의 체인을 제공하거나 모델 구성을 A/B 테스트할 수 있습니다.

from langchain_core.runnables import ConfigurableField

llm = ChatOpenAI(model='gpt-4o-mini').configurable_fields(
    temperature=ConfigurableField(
        id='temperature',
        name='LLM Temperature',
        description='Controls output creativity'
    )
)

chain = ChatPromptTemplate.from_template('Write about {topic}') | llm | StrOutputParser()

# Low temperature for factual output
factual = chain.invoke(
    {'topic': 'history of Rome'},
    config={'configurable': {'temperature': 0.0}}
)

빠른 확인

LCEL을 사용한 체인 구축에 대한 이해도를 확인해 보세요.

레슨 요약

이 레슨에서는 다음을 배웠습니다. LCEL 파이프 조합은 |를 사용해 Runnable을 깔끔하고 읽기 쉬운 파이프라인으로 연결합니다. RunnablePassthrough와 RunnableLambda를 사용하면 LCEL 방식을 벗어나지 않고 데이터 조작 단계를 삽입할 수 있습니다. 또한 대체 체인은 오류 발생 시 백업 체인을 자동으로 시도하여 체인의 복원력을 높입니다. 다음으로 더 복잡한 라우팅 로직을 위한 분기 체인과 병렬 체인을 살펴보겠습니다.

무료로 시작

AI 튜터와 함께 Python을(를) 배우세요 — 무료

브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.

코스
30
레슨
120

자주 묻는 질문

“LCEL로 체인 구축하기” 강의는 무료인가요?

네 — “LCEL로 체인 구축하기” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 AI Engineering Academy 강의 전체를 잠금 해제할 수 있습니다. AI Engineering Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“LCEL로 체인 구축하기”에서 뭘 배우나요?

파이프 연산자로 프롬프트 템플릿, LLM, 출력 파서를 Runnable 시퀀스로 연결하고, 이를 동기 및 비동기로 호출하며, 중간 출력을 확인합니다. 브라우저에서 직접 실행하는 실습 코드로 AI Engineering Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

AI Engineering Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 AI Engineering Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“LCEL로 체인 구축하기” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 AI Engineering Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 AI Engineering Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. LangChain 아키텍처와 핵심 추상화
  2. LCEL로 체인 구축하기
  3. 분기 및 병렬 체인
  4. LangChain에서 출력 스트리밍하기
← AI Engineering Academy(으)로 돌아가기