LangChain 입문 가이드 - 파이썬으로 AI 앱 만들기
2026년 4월 기준 | AI 개발 가이드 · LangChain 0.3+
요약: LangChain은 LLM 기반 애플리케이션을 만들 때 가장 많이 쓰이는 프레임워크입니다. 이 글에서는 설치부터 기본 체인 구성, RAG 파이프라인까지 실제 코드로 다룹니다. 직접 프로젝트에 적용하면서 겪은 삽질 포인트도 같이 정리했습니다.
LangChain이 뭔가
솔직히 처음 LangChain 문서를 열었을 때 감이 안 왔습니다. "LLM 애플리케이션 개발 프레임워크"라는 설명만으로는 왜 필요한지 와닿지 않았거든요.
OpenAI API를 직접 호출해서 챗봇을 만든 적이 있다면, 이런 경험이 있을 겁니다. 프롬프트 관리가 점점 복잡해지고, 외부 데이터를 붙이려면 코드가 기하급수적으로 늘어나고, 모델을 바꿀 때마다 코드를 뜯어고쳐야 하는 상황. LangChain은 이 문제를 해결합니다.
핵심 개념은 "체인(Chain)"입니다. LLM 호출, 프롬프트 구성, 데이터 검색, 후처리 같은 작업을 레고 블록처럼 연결하는 구조입니다. 각 블록을 독립적으로 테스트하고, 자유롭게 교체할 수 있다는 게 장점입니다.
LangChain 0.3부터는 LCEL(LangChain Expression Language)이 기본 패턴입니다. 이전의 LLMChain, SequentialChain 같은 레거시 클래스는 deprecated 됐고, 파이프(|) 연산자로 체인을 구성합니다. 이 글에서는 0.3+ 문법만 사용합니다.
LLM 프레임워크 비교
LangChain만 있는 건 아닙니다. 프로젝트 성격에 따라 다른 선택이 나을 수도 있어서, 제가 직접 써본 프레임워크를 비교해봤습니다.
| 항목 | LangChain | LlamaIndex | Haystack | 직접 구현 |
|---|---|---|---|---|
| 주요 용도 | 범용 LLM 앱 | RAG 특화 | 검색 파이프라인 | 단순 API 호출 |
| 학습 곡선 | 중간 | 낮음 | 높음 | 가장 낮음 |
| GitHub Stars | ~98K | ~38K | ~18K | - |
| 모델 지원 | OpenAI, Claude, Gemini 등 50+ | 주요 모델 지원 | 주요 모델 지원 | 선택한 1개 |
| 에이전트 기능 | 강력함 (LangGraph) | 기본 수준 | 파이프라인 기반 | 직접 구현 필요 |
| 추천 상황 | 복잡한 AI 앱, 에이전트 | 문서 QA 시스템 | 엔터프라이즈 검색 | MVP, 단순 챗봇 |
제 기준에서는 "단순 챗봇이면 직접 구현, RAG만 필요하면 LlamaIndex, 그 외 대부분의 경우 LangChain"으로 갈립니다. 특히 에이전트를 만들 계획이라면 LangChain + LangGraph 조합이 현시점에서 가장 생태계가 넓습니다.
설치 및 환경 세팅
LangChain 0.3부터 패키지 구조가 바뀌었습니다. 코어 패키지와 모델별 통합 패키지가 분리됐기 때문에, 사용할 LLM에 맞는 패키지를 함께 설치해야 합니다.
기본 설치
# 코어 + OpenAI 조합 (가장 흔한 세팅)
pip install langchain langchain-openai
# Claude를 쓰는 경우
pip install langchain langchain-anthropic
# RAG까지 할 거라면 커뮤니티 패키지도
pip install langchain-community langchain-chroma
한 가지 주의점. langchain만 설치하면 LLM을 호출할 수 없습니다. 반드시 langchain-openai나 langchain-anthropic 같은 통합 패키지가 있어야 합니다. 처음에 이걸 몰라서 ImportError를 한참 디버깅한 기억이 있습니다.
API 키 설정
# .env 파일 생성
OPENAI_API_KEY=sk-your-key-here
# 또는 Claude를 쓰는 경우
ANTHROPIC_API_KEY=sk-ant-your-key-here
# 파이썬에서 .env 로드
from dotenv import load_dotenv
load_dotenv()
# 설치 확인
import langchain
print(langchain.__version__) # 0.3.x 이상이면 OK
기본 체인 만들기
LangChain의 핵심은 LCEL입니다. 파이프(|) 연산자로 컴포넌트를 연결하는 방식인데, 처음엔 낯설어도 익숙해지면 꽤 직관적입니다.
가장 단순한 체인
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
# 1. 모델 초기화
model = ChatOpenAI(model="gpt-4o", temperature=0.7)
# 2. 프롬프트 템플릿
prompt = ChatPromptTemplate.from_messages([
("system", "당신은 파이썬 전문 개발자입니다. 간결하게 답변하세요."),
("user", "{question}")
])
# 3. 체인 구성 (LCEL)
chain = prompt | model | StrOutputParser()
# 4. 실행
result = chain.invoke({"question": "데코레이터가 뭔지 3줄로 설명해줘"})
print(result)
prompt | model | StrOutputParser() 이 한 줄이 LangChain의 핵심입니다. 프롬프트를 만들고, 모델에 넘기고, 응답에서 문자열만 추출하는 파이프라인입니다.
예전 방식인 LLMChain(llm=model, prompt=prompt)를 쓰면 deprecation 경고가 뜹니다. 0.3+에서는 반드시 LCEL을 사용하세요.
Claude로 바꾸려면?
모델 교체가 이렇게 간단한 게 LangChain의 장점입니다.
# OpenAI 대신 Claude 사용
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(model="claude-sonnet-4-20250514", temperature=0.7)
# 나머지 코드는 동일!
chain = prompt | model | StrOutputParser()
result = chain.invoke({"question": "데코레이터가 뭔지 3줄로 설명해줘"})
import 한 줄과 모델 초기화 한 줄만 바꾸면 됩니다. API 응답 형식 차이를 LangChain이 내부에서 처리해줍니다.
프롬프트 템플릿 활용
프롬프트를 하드코딩하면 유지보수가 힘들어집니다. LangChain의 프롬프트 템플릿은 변수 치환뿐 아니라, 조건부 메시지 구성까지 가능합니다.
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
# 대화 기록을 포함하는 프롬프트
prompt = ChatPromptTemplate.from_messages([
("system", """당신은 {role} 전문가입니다.
답변 시 다음 규칙을 따르세요:
- 핵심을 먼저 말할 것
- 코드 예제를 포함할 것
- 초보자도 이해할 수 있게 설명할 것"""),
MessagesPlaceholder(variable_name="chat_history", optional=True),
("user", "{question}")
])
# 대화 기록 없이 호출
chain = prompt | model | StrOutputParser()
result = chain.invoke({
"role": "파이썬",
"question": "리스트 컴프리헨션 예제 보여줘"
})
# 대화 기록 포함해서 호출
from langchain_core.messages import HumanMessage, AIMessage
result = chain.invoke({
"role": "파이썬",
"chat_history": [
HumanMessage(content="for문 설명해줘"),
AIMessage(content="for문은 반복 구조입니다..."),
],
"question": "그걸 while로 바꾸면?"
})
MessagesPlaceholder에 optional=True를 주면, 대화 기록이 없을 때도 에러 없이 동작합니다. 실무에서 자주 쓰는 패턴입니다.
출력 파서로 구조화된 응답 받기
LLM의 응답을 문자열이 아닌 구조화된 데이터로 받고 싶을 때가 많습니다. 예를 들어 코드 리뷰 결과를 JSON으로 받거나, 분석 결과를 파이썬 객체로 바로 쓰고 싶은 경우입니다.
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_core.output_parsers import JsonOutputParser
# 원하는 출력 구조 정의
class CodeReview(BaseModel):
summary: str = Field(description="코드 리뷰 요약")
issues: list[str] = Field(description="발견된 문제점 목록")
score: int = Field(description="1-10 점수")
suggestion: str = Field(description="개선 제안")
parser = JsonOutputParser(pydantic_object=CodeReview)
prompt = ChatPromptTemplate.from_messages([
("system", "당신은 시니어 파이썬 개발자입니다.\n{format_instructions}"),
("user", "다음 코드를 리뷰해주세요:\n```python\n{code}\n```")
])
chain = prompt | model | parser
review = chain.invoke({
"code": "def add(a,b): return a+b",
"format_instructions": parser.get_format_instructions()
})
# review는 딕셔너리로 반환됨
print(review["score"]) # 6
print(review["issues"]) # ["타입 힌트 없음", "docstring 없음"]
이 방식 덕분에 LLM 응답을 후속 로직에서 바로 활용할 수 있습니다. JSON 파싱 실패를 대비한 retry 로직도 나중에 추가하면 좋습니다.
RAG 파이프라인 구현
RAG(Retrieval-Augmented Generation)는 LangChain을 쓰는 가장 큰 이유 중 하나입니다. 내 문서를 기반으로 답변하는 AI를 만드는 패턴인데, 직접 구현하면 코드가 꽤 복잡해집니다. LangChain을 쓰면 상대적으로 깔끔합니다.
전체 흐름
문서 로드 → 텍스트 분할 → 임베딩 생성 → 벡터 DB 저장 → 질문 시 유사 문서 검색 → LLM에 컨텍스트와 함께 전달 → 답변
구현 코드
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_chroma import Chroma
# 1. 문서 로드
loader = TextLoader("./my_docs/guide.txt", encoding="utf-8")
docs = loader.load()
# 2. 텍스트 분할
splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
separators=["\n\n", "\n", ".", " "]
)
splits = splitter.split_documents(docs)
# 3. 벡터 DB에 저장
vectorstore = Chroma.from_documents(
documents=splits,
embedding=OpenAIEmbeddings(model="text-embedding-3-small"),
persist_directory="./chroma_db"
)
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
# 4. RAG 프롬프트
rag_prompt = ChatPromptTemplate.from_messages([
("system", """다음 컨텍스트를 참고하여 질문에 답변하세요.
컨텍스트에 없는 내용은 "해당 정보가 문서에 없습니다"라고 답하세요.
컨텍스트:
{context}"""),
("user", "{question}")
])
# 5. 문서 포맷 함수
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
# 6. RAG 체인 구성
model = ChatOpenAI(model="gpt-4o", temperature=0)
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| rag_prompt
| model
| StrOutputParser()
)
# 7. 실행
answer = rag_chain.invoke("배포 절차가 어떻게 되나요?")
print(answer)
코드가 좀 길어 보이지만, 핵심은 6번의 rag_chain 구성입니다. retriever가 관련 문서를 찾고, format_docs가 텍스트로 변환하고, 프롬프트에 컨텍스트로 주입한 뒤, 모델이 답변하는 흐름입니다.
chunk_size 선택 기준
텍스트 분할에서 chunk_size를 얼마로 잡느냐가 RAG 성능에 큰 영향을 줍니다. 제가 여러 프로젝트에서 테스트한 결과입니다.
| chunk_size | 검색 정확도 | 답변 품질 | 적합한 상황 |
|---|---|---|---|
| 200~300 | 높음 | 맥락 부족할 수 있음 | FAQ, 짧은 정의 |
| 500~800 | 균형 잡힘 | 대부분 양호 | 일반적인 문서 QA (추천) |
| 1000~1500 | 낮을 수 있음 | 맥락 풍부 | 기술 문서, 논문 |
| 2000+ | 낮음 | 노이즈 증가 | 비추천 |
대부분의 경우 500~800이 무난합니다. chunk_overlap은 chunk_size의 10% 정도로 잡으면 문장이 잘리는 문제를 줄일 수 있습니다.
실전에서 얻은 팁 7가지
몇 달간 LangChain으로 프로젝트를 진행하면서 배운 것들을 정리합니다. 공식 문서에 안 나오는 것들 위주입니다.
1. 스트리밍은 invoke 대신 stream 사용
# 한 번에 전체 응답을 기다리는 방식
result = chain.invoke({"question": "설명해줘"})
# 토큰 단위로 스트리밍 (UX가 훨씬 좋음)
for chunk in chain.stream({"question": "설명해줘"}):
print(chunk, end="", flush=True)
LCEL 체인은 .invoke(), .stream(), .batch(), .ainvoke()를 모두 지원합니다. 체인을 한 번 만들어두면 동기/비동기/스트리밍을 자유롭게 전환할 수 있다는 게 LCEL의 큰 장점입니다.
2. 디버깅할 때는 LangSmith 연결
# .env에 추가하면 자동으로 트레이싱 시작
LANGCHAIN_TRACING_V2=true
LANGCHAIN_API_KEY=lsv2_your_key_here
LANGCHAIN_PROJECT=my-project
LangSmith를 연결하면 체인의 각 단계에서 어떤 입력이 들어가고 어떤 출력이 나왔는지 전부 볼 수 있습니다. 프롬프트 디버깅 시간이 체감상 절반 이하로 줄었습니다. 무료 플랜에서도 월 5,000 트레이스까지 가능합니다.
3. RunnableParallel로 병렬 처리
from langchain_core.runnables import RunnableParallel
# 요약과 키워드 추출을 동시에 실행
parallel_chain = RunnableParallel(
summary=summary_chain,
keywords=keyword_chain
)
# 두 체인이 병렬로 실행됨
result = parallel_chain.invoke({"text": article_text})
print(result["summary"])
print(result["keywords"])
독립적인 LLM 호출이 여러 개일 때, 순차 실행 대신 병렬로 돌리면 응답 시간이 확 줄어듭니다.
4. 에러 핸들링은 with_fallbacks
# GPT-4o가 실패하면 GPT-4o-mini로 폴백
primary = ChatOpenAI(model="gpt-4o")
fallback = ChatOpenAI(model="gpt-4o-mini")
robust_model = primary.with_fallbacks([fallback])
chain = prompt | robust_model | StrOutputParser()
프로덕션에서 API 에러는 반드시 발생합니다. Rate limit, 타임아웃, 일시적 장애 등. with_fallbacks로 대체 모델을 지정해두면 서비스 안정성이 크게 올라갑니다.
5. 캐싱으로 비용 절감
from langchain_core.globals import set_llm_cache
from langchain_community.cache import SQLiteCache
# SQLite 기반 캐시 설정
set_llm_cache(SQLiteCache(database_path=".langchain_cache.db"))
# 같은 입력이면 API 호출 없이 캐시에서 반환
result1 = chain.invoke({"question": "파이썬이란?"}) # API 호출
result2 = chain.invoke({"question": "파이썬이란?"}) # 캐시에서 즉시 반환
개발/테스트 단계에서 같은 프롬프트를 반복 실행하는 경우가 많은데, 캐시 하나 설정해두면 API 비용을 상당히 아낄 수 있습니다.
6. 긴 문서는 map-reduce 패턴
토큰 한도를 초과하는 긴 문서를 처리할 때, 문서를 쪼개서 각각 처리한 뒤 결과를 합치는 패턴입니다.
# 각 청크를 요약하는 체인
map_chain = ChatPromptTemplate.from_messages([
("user", "다음 텍스트를 3줄로 요약하세요:\n{text}")
]) | model | StrOutputParser()
# 청크별로 배치 실행
summaries = map_chain.batch(
[{"text": chunk.page_content} for chunk in splits],
config={"max_concurrency": 5}
)
# 요약 결과를 합쳐서 최종 요약
reduce_chain = ChatPromptTemplate.from_messages([
("user", "다음 요약들을 하나의 종합 요약으로 만드세요:\n{summaries}")
]) | model | StrOutputParser()
final = reduce_chain.invoke({"summaries": "\n".join(summaries)})
7. temperature 설정 기준
용도에 따라 temperature를 다르게 설정하는 게 중요합니다.
| 용도 | temperature | 이유 |
|---|---|---|
| 코드 생성 | 0 | 정확성이 최우선 |
| RAG 답변 | 0~0.3 | 문서 기반이므로 창의성 불필요 |
| 일반 대화 | 0.5~0.7 | 자연스러운 응답 |
| 창작/브레인스토밍 | 0.8~1.0 | 다양한 아이디어 필요 |
마무리
LangChain은 진입 장벽이 좀 있습니다. 개념도 많고, 패키지도 나눠져 있고, 버전에 따라 문법이 달라서 혼란스러울 수 있습니다. 하지만 LCEL 패턴에 익숙해지면, AI 앱을 만드는 속도가 확실히 빨라집니다.
이 글에서 다룬 내용을 정리하면:
- 기본 체인:
prompt | model | output_parser패턴으로 시작 - 프롬프트 관리: ChatPromptTemplate으로 체계적으로 관리
- 구조화된 출력: JsonOutputParser로 LLM 응답을 데이터로 변환
- RAG: 문서 로드 → 분할 → 임베딩 → 벡터 DB → 검색 → 답변
- 실전 팁: 스트리밍, 캐싱, 폴백, 병렬 처리
다음 단계로는 LangGraph를 추천합니다. LangChain 팀에서 만든 에이전트 프레임워크인데, 조건 분기나 반복이 있는 복잡한 워크플로우를 구현할 때 유용합니다. LangChain의 기본기를 익힌 상태라면 LangGraph 진입이 훨씬 수월합니다.
참고 자료:
- LangChain 공식 문서 - 0.3+ 기준 문서
- LangSmith - 디버깅 및 모니터링 도구
- LangGraph 문서 - 에이전트 개발
'AI 개발 가이드' 카테고리의 다른 글
| Claude Code CLI로 프로젝트 자동화하기 - 실전 워크플로우 (0) | 2026.04.09 |
|---|---|
| AI 코드 리뷰 자동화 - GitHub Actions + Claude API로 PR 자동 리뷰 (0) | 2026.04.06 |
| AI로 웹 크롤러 만들기 - BeautifulSoup + Claude API 조합 (0) | 2026.04.04 |
| 프롬프트 엔지니어링 개발자용 실전 가이드 - 원하는 답을 뽑아내는 기술 (0) | 2026.04.04 |
| 파이썬으로 AI 챗봇 만들기 - 초보자도 30분이면 완성 (0) | 2026.04.04 |