티스토리 뷰

728x90
반응형

이 글은 LangChain의 핵심 모듈을 개념 → 실습 예제 → 실무 팁 순서로 빠르게 익힐 수 있도록 구성했습니다. 예제 코드는 모두 최신 스타일(LCEL, | 파이프)과 분리 패키지(langchain-openai 등)를 사용합니다.


1) LLMs — 언어 모델 연결과 호출

핵심 개념 세 줄 요약

  • LangChain은 "모델"을 직접 제공하지 않고, 외부 LLM(예: OpenAI) 또는 오픈소스 LLM에 연결합니다.
  • 모든 모델·체인은 공통으로 invoke / stream / batch 같은 Runnable 인터페이스를 지원합니다.
  • OpenAI는 langchain-openai, Anthropic/Groq 등은 각 통합 패키지를 통해 연결합니다.

설치

pip install -U langchain langchain-openai pydantic python-dotenv

Hello, LLM (invoke)

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="gpt-4o-mini",  # 비용/속도 균형 모델 예시
    temperature=0.0,
)

res = llm.invoke("한 문장으로 자기소개를 해주세요.")
print(res.content)

스트리밍 출력 (stream)

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
for chunk in llm.stream("한국에서 가장 높은 산은?"):
    # chunk는 ChatMessageChunk. 토큰 단위로 출력됨
    print(chunk.content, end="", flush=True)

구조화된 출력 (with_structured_output)

from pydantic import BaseModel, Field
from langchain_openai import ChatOpenAI

class TravelPlan(BaseModel):
    city: str = Field(description="여행지")
    days: int = Field(description="여행 일수")
    must_eats: list[str] = Field(description="꼭 먹어야 할 음식")

llm = ChatOpenAI(model="gpt-4o-mini")
structured_llm = llm.with_structured_output(TravelPlan)

plan = structured_llm.invoke("부산 2박 3일 맛집 중심 일정 짜줘")
print(plan.dict())

실무 팁

  • 비용 관리: 개발/테스트는 경량 모델(gpt-4o-mini) → 운영은 고품질 모델 단계적 적용.
  • 스트리밍으로 체감 지연을 줄이고, 배치(batch) 로 대량 처리 성능을 확보하세요.
  • LangSmith로 토큰 사용량, 실패 사례를 추적하면 운영 품질이 급상승합니다.

2) Prompts — 대화 프롬프트 템플릿

핵심 개념 세 줄 요약

  • ChatPromptTemplate은 system/human/ai 등 메시지 역할별 템플릿을 구성합니다.
  • 템플릿은 변수 바인딩을 거쳐 메시지 리스트로 변환되고, LLM 입력으로 사용됩니다.
  • MessagesPlaceholder로 대화 히스토리를 자연스럽게 삽입할 수 있습니다.

기본 사용

from langchain_core.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate.from_messages([
    ("system", "너는 간결하고 정확한 한국어 글쓰기 도우미야."),
    ("human", "다음 문장을 더 자연스럽게 고쳐줘: {sentence}"),
])

msg = prompt.invoke({"sentence": "저는 오늘 회사에 갑니다 그리고 점심을 먹었습니다"})
print(msg.to_messages())  # LLM에 투입되는 메시지 목록 확인

대화 히스토리와 플레이스홀더

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt = ChatPromptTemplate.from_messages([
    ("system", "너는 기술 블로그 편집자다. 톤은 친절하고 실용적."),
    ("placeholder", "{history}"),  # 또는 MessagesPlaceholder("history")
    ("human", "이 주제에 대한 개요를 작성해줘: {topic}"),
])

history = [
    ("human", "LangChain 글 시리즈를 쓰고 싶어"),
    ("ai", "좋아요! 어떤 주제로 시작할까요?"),
]
msg = prompt.invoke({"history": history, "topic": "LCEL 소개"})

실무 팁

  • 톤·스타일을 system에 고정하고, human에는 가변 콘텐츠만 넣으면 유지보수가 쉽습니다.
  • 프롬프트는 버전 관리(Git)하고, A/B 실험으로 문구를 다듬으세요.

3) Chains — LCEL로 파이프라인 구성

핵심 개념 세 줄 요약

  • LCEL(LangChain Expression Language)은 | 파이프 연산으로 프롬프트 → 모델 → 파서를 연결합니다.
  • 모든 구성요소는 Runnable이므로 invoke/stream/batch를 동일하게 사용할 수 있습니다.
  • RunnableParallel, RunnablePassthrough 등으로 병렬 분기/머지가 가능합니다.

가장 기본적인 체인

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

prompt = ChatPromptTemplate.from_messages([
    ("system", "너는 한 문장 요약기다."),
    ("human", "다음 내용을 한 문장으로 요약: {text}"),
])
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
parser = StrOutputParser()

chain = prompt | llm | parser
print(chain.invoke({"text": "LangChain은 LLM 애플리케이션 개발을 단순화하는 프레임워크다."}))

병렬 실행으로 콘텐츠 기획 파이프라인 만들기

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.3)

# 1) 주제 → 블로그 제목 5개
title_prompt = ChatPromptTemplate.from_template(
    "주제: {topic}\n블로그 제목 5개를 제안해줘(간결, 매력적)"
)
make_titles = title_prompt | llm | StrOutputParser()

# 2) 주제 → 소개문 1단락
intro_prompt = ChatPromptTemplate.from_template(
    "주제: {topic}\n개요 1단락을 작성해줘(200자 내외)"
)
make_intro = intro_prompt | llm | StrOutputParser()

# 3) 병렬 실행 → titles, intro 동시 생성
plan = RunnableParallel(
    titles=make_titles,
    intro=make_intro,
    topic=RunnablePassthrough(),  # 입력 그대로 전달
)

result = plan.invoke({"topic": "LangChain LCEL 실무 가이드"})
print(result["titles"])
print(result["intro"])

배치 처리 (여러 입력 한 번에)

inputs = [
    {"text": "Kafka는 대규모 스트리밍 데이터 플랫폼이다."},
    {"text": "Redis는 인메모리 키-값 데이터 저장소다."},
]

chain.batch(inputs)  # 결과 리스트 반환

실무 팁

  • 체인이 복잡해지면 LangGraph로 상태 관리/분기/루프를 명시적으로 표현하는 것을 고려하세요.
  • 체인 단위로 with_retry / with_config(tags, metadata) 를 지정하면 관측·제한·재시도 제어가 편해집니다.

4) Agents — 도구를 쓰는 모델(툴 콜링)

핵심 개념 세 줄 요약

  • 에이전트는 모델이 도구(tool) 를 선택·호출하여 목표를 달성하는 실행 루프입니다.
  • LangChain에서는 @tool 데코레이터로 손쉽게 커스텀 도구를 만들고, 툴 콜링 지원 모델에 바인딩합니다.
  • 간단한 용도는 LangChain의 create_tool_calling_agent + AgentExecutor로 충분하고, 복잡한 워크플로는 LangGraph 권장.

4-1. 간단한 커스텀 도구 정의

from langchain_core.tools import tool

@tool
def fx_krw(amount_usd: float) -> str:
    """미국 달러를 한국 원화로 단순 환산한다(예시, 고정 환율)."""
    rate = 1350  # 데모용 고정값
    return f"{amount_usd} USD ≈ {int(amount_usd * rate):,} KRW"

@tool
def topn(items: list[str], n: int = 3) -> list[str]:
    """리스트에서 상위 n개를 간단히 반환한다."""
    return items[:n]

TOOLS = [fx_krw, topn]

4-2. 툴 콜링 에이전트 구성

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.agents import AgentExecutor, create_tool_calling_agent

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

prompt = ChatPromptTemplate.from_messages([
    ("system", "너는 합리적으로 사고하는 비서야. 가능하면 도구를 활용해 정확히 답해."),
    ("placeholder", "{chat_history}"),
    ("human", "{input}"),
    ("placeholder", "{agent_scratchpad}"),  # 도구 호출/결과가 여기에 누적됨
])

agent = create_tool_calling_agent(llm, TOOLS, prompt)
executor = AgentExecutor(agent=agent, tools=TOOLS, verbose=True)

res = executor.invoke({
    "input": "미국달러 25달러를 원화로 바꿔줘. 그리고 ['a','b','c','d']에서 2개만 골라", 
    "chat_history": []
})
print(res["output"])  # 최종 답변

4-3. Agent 없이 간단히 "툴 바인딩"만으로 사용

from langchain_openai import ChatOpenAI
from langchain_core.tools import tool

@tool
def calc_square(x: int) -> int:
    """정수 제곱을 반환한다."""
    return x * x

model = ChatOpenAI(model="gpt-4o-mini", temperature=0)
model_with_tools = model.bind_tools([calc_square])

print(model_with_tools.invoke("5의 제곱은?"))

실무 팁

  • 도구 스키마(이름/설명/파라미터) 를 명확히 작성할수록 모델의 호출 정확도가 상승합니다.
  • 반복 루프·분기·메모리·장기 작업이 필요한 복잡한 에이전트는 LangGraph 에이전트로 설계하세요.
  • 운영 환경에선 max_iterations/max_execution_time 등을 제한하고, 모든 중간 단계를 로깅하세요.

마무리

  • LLMs: 표준 Runnable 인터페이스(invoke/stream/batch)로 쉽게 호출.
  • Prompts: 메시지 기반 템플릿으로 히스토리·변수를 체계적으로 관리.
  • Chains: LCEL 파이프라인으로 프롬프트→모델→파서를 연결하고, 병렬/배치 처리까지 확장.
  • Agents: 도구를 호출하는 모델. 단순 예제는 LangChain, 서비스급 복잡도는 LangGraph로.
728x90
반응형