0. LangChain이란?
정의
LangChain은 대규모 언어 모델(LLM)을 외부 세계—데이터베이스, API, 파일 시스템, 웹—와 연결해 검색 → 추론 → 실행(행동) 이 한 흐름으로 돌아가게 해 주는 Python 기반 오픈소스 프레임워크이다.
즉, “프롬프트 한 번 호출”을 넘어 완전한 LLM 애플리케이션을 만들 때 필요한 연결·조립·관측·배포 기능을 통합 제공한다.
| 요소 | 핵심 기능 | 대표 모듈 |
|---|---|---|
| 연결(Connect) | 벡터 스토어·SQL·HTTP API·파일 시스템 등 다양한 외부 자원과 LLM을 표준 인터페이스로 연결 | langchain, langchain-community |
| 조립(Compose) | 체인(LCEL)·그래프(LangGraph)·에이전트로 복잡한 추론 루프를 선언형으로 조립 | langchain-core, langgraph |
| 관측(Observe) | 토큰·시간·비용·정확도를 실시간 트레이싱·평가 | LangSmith, Langfuse |
| 배포(Serve) | 작성한 체인을 FastAPI REST 또는 멀티-에이전트 서버로 바로 배포 | LangServe, LangGraph Server |
0-1. LangChain은 왜 필요한가?
- LLM 한계
- LLM은 본질적으로 “문자열을 생성”할 뿐,
· 긴 대화 앞부분을 잊는다.
· 실시간 DB·API·파일을 직접 조회하지 못한다.
· 코드 실행·파일 I/O 같은 행동을 수행하지 못한다.
- LangChain이 해결하는 것
1. 연결 (Connect) – 외부 자원과 LLM을 쉽게 묶는다.
2. 조립 (Compose) – 체인·그래프·에이전트로 복잡한 추론·행동 루프를 선언형으로 만든다.
3. 관측 (Observe) – 토큰·시간·비용·정확도를 대시보드로 실시간 추적·테스트·평가한다.
4. 배포 (Serve) – 코드 몇 줄로 REST 서비스·멀티-에이전트 서버로 곧바로 배포한다.
LangChain은 “LLM 애플리케이션의 엔드-투-엔드 런타임”이다.
단순 프롬프트 호출만으로는 해결할 수 없는 데이터 연결·상태 관리·품질 관측·운영 문제를 한 번에 해결한다.
0-2. 핵심 라이브러리 스펙
| 단계 | 라이브러리 | 한 줄 역할 |
|---|---|---|
| 개발 | langchain, langchain-core, langchain-community |
체인·프롬프트·모델 I/O로 비즈니스 로직 구축 |
| 배포 | LangGraph (상태 지닌 그래프), LangServe (REST API 래퍼) | 복잡한 체인을 서버로 곧바로 배포 |
| 관측 | LangSmith | 트레이싱·테스트·평가를 통합한 관측 플랫폼 |
1. 전체 워크플로 & 학습 로드맵
undefined
2. Model I/O
2-1. LLM & Chat Model
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
load_dotenv() # .env → OPENAI_API_KEY
llm = ChatOpenAI(
model="gpt-3.5-turbo", # 필수: OpenAI 모델명
temperature=0.2, # 창의성 (0.0~2.0)
max_tokens=512, # 응답 길이 제한
streaming=False # 실시간 스트림 출력 여부
)
print(llm.invoke("LangChain을 한 문장으로 설명해줘.").content)
| 파라미터 | 용도 | 기본값 |
|---|---|---|
model |
사용할 OpenAI Chat 모델 | – |
temperature |
창의성 / 무작위성 | 0.7 |
max_tokens |
최대 응답 토큰 수 | 모델 기본 |
streaming |
스트리밍 모드 on/off | False |
timeout |
요청 제한 시간(sec) | None |
모델 교체 팁
ChatOpenAI만 바꾸면 Anthropic Claude, Mistral, Ollama 등도 동일 인터페이스로 사용할 수 있다.
2-2. Prompt Template
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
("system",
"당신은 기술 문서 작성가이다. 짧고 명확하게 대답한다."),
("user",
"키워드 '{keyword}'를 JSON으로 요약해줘 "
"→ summary, features[3] 필드 필수")
])
| 메서드 | 설명 |
|---|---|
from_messages() |
(role, content) 튜플 리스트로 프롬프트 생성 |
format() |
{placeholder} 채워 단일 문자열 반환 |
format_messages() |
채워진 message 객체 리스트 반환 (체인 입력용) |
2-3. Output Parser
from langchain_core.output_parsers import JsonOutputParser
parser = JsonOutputParser() # {"answer": "..."} 기본 구조
raw = llm.invoke(prompt.format(keyword="LangChain")) # ① LLM 호출
result = parser.invoke(raw) # ② JSON → dict
print(result["summary"])
| Parser | 결과 | 용도 | 주요 메서드 |
|---|---|---|---|
StrOutputParser |
str |
자유 형식 답변·요약 | invoke() |
JsonOutputParser |
dict |
단순 JSON 응답 | get_format_instructions(), invoke() |
CommaSeparatedListOutputParser |
list[str] |
태그·키워드 등 CSV | invoke() |
PydanticOutputParser |
Pydantic 모델 | 타입 검증 필요 시 | get_format_instructions(), invoke() |
2-4. Mini Chain Example
from langchain.schema.runnable import RunnablePassthrough
chain = prompt | llm | parser
print(chain.invoke({"keyword": "LangChain"}))
3. LCEL — 파이프 한 줄로 체인 조립
LCEL(LangChain Expression Language)은 | 파이프로 Runnable을 연결해 선언형으로 로직을 표현한다 (LangChain).
3-1. 실행 인터페이스
| 작업 | 동기 | 비동기 |
|---|---|---|
| 단일 입력 | invoke() |
ainvoke() |
| 스트림 출력 | stream() |
astream() |
| 배치 처리 | batch() |
abatch() |
3-2. 병렬 실행
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
capital = PromptTemplate.from_template("{c} 수도?") | llm | parser
area = PromptTemplate.from_template("{c} 면적?") | llm | parser
info = RunnableParallel(capital=capital, area=area)
print(info.invoke({"c": "대한민국"}))
4. RAG 파이프라인
4-1. 문서 로드
from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader("./spri_ai_brief.pdf")
docs = loader.load() # 23 page
- PDF를 page 단위로 읽는다.
- 페이지가 많으면
loader.load_and_split()로 스트리밍 처리도 가능하다.
4-2. 텍스트 분할
from langchain_text_splitters import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=50
)
chunks = splitter.split_documents(docs)
- LLM 입력 한도를 넘지 않도록 청크로 나눈다.
- 오버랩으로 경계 정보 손실을 줄인다.
4-3. 임베딩
from langchain_openai import OpenAIEmbeddings
emb = OpenAIEmbeddings() # text-embedding-ada-002 등 명시 가능
- 각 chunk를 고차원 벡터로 변환한다.
4-4. 벡터 스토어
1) 로컬 FAISS
from langchain_community.vectorstores import FAISS
store = FAISS.from_documents(chunks, emb)
store.save_local("faiss_index")
store = FAISS.load_local("faiss_index", emb)
2) 실전용 DB (Pinecone)
import pinecone
from langchain_pinecone import PineconeVectorStore
pinecone.init(api_key="YOUR_KEY", environment="us-west1-gcp")
pc_store = PineconeVectorStore.from_documents(
documents=chunks,
embedding=emb,
index_name="my-index",
namespace="pdf-demo"
)
- FAISS: 서버 없이 빠르고 가볍다.
- Pinecone: 수백만~수억 벡터, 다중 서비스 공유에 적합하다.
4-5. Retriever
dense = store.as_retriever(search_kwargs={"k": 4})
- 역할: 쿼리를 임베딩하여 후보 문서를 빠르게 찾는다.
- 이 단계가 Recall(포괄적 검색)을 담당한다.
4-6. Reranker
from langchain_community.rerankers import CohereReranker
reranker = CohereReranker(model="baai/bge-reranker-large-ko")
- 역할: (쿼리, 문서) 쌍을 교차-인코딩해 정밀 점수 부여 → 최종 순위 결정
- 정확도는 ↑, 속도는 ↓. 한국어 모델을 쓰면 한글 표현에 더 강하다.
4-7. 프롬프트
from langchain_core.prompts import ChatPromptTemplate
rag_prompt = ChatPromptTemplate.from_messages([
("system", "검색된 문맥만 근거로 답하라. 모르면 모른다. 한국어."),
("user", "{question}\n\n# Context\n{context}")
])
| 구역 | 역할 | 기법 · 팁 |
|---|---|---|
| System | 대화 전체 규칙·페르소나·출력 형식 지정 | – 역할 부여: “법률 전문 챗봇”, “제품 매뉴얼 기반 챗봇” 등 – 강제 규칙: “제공된 문맥만 근거”, “한국어로 답변”, “모르면 모른다고 말함” |
| User | 실제 질문 + 컨텍스트 주입 | – 플레이스홀더: {question}, {context}처럼 런타임에 값 삽입 – 구분자: # Context·""" 등으로 LLM이 근거 범위를 분명히 알도록 표시 |
| Assistant (옵션) | 예시답변(Few-shot) · 출력 예시 | – Few-shot: 정답 예시 2~3개 넣으면 톤과 포맷이 안정됨 – 포맷 예시: json\n{"answer": "..."}\n 처럼 결과 형식 샘플 제공 |
1. 근거 강제(Grounded Answering)
"검색된 문맥만 근거로 답하라"
- 효과: 모델이 문맥 외 내용을 추론(환각)할 확률 ↓
- 팁: 모르면 “모른다”·“문맥에 없다”로 답하게 명시.
2. 역할(Role) 지정
- 시스템 메시지 첫 줄에 “너는 ~ 전문가” 식으로 정체성을 고정.
- 특정 톤(반말, 존댓말)·형식(~한다/~했다)도 같이 적는다.
3. 컨텍스트 경계 선언
# Context
{context}
################
- 구분선을 사용해 LLM이 어디부터 어디까지가 참고자료인지 명확히 인식.
4. 플레이스홀더 사용
{question}{context}{date}등 변수로 두고 체인에서.format()또는 LCEL 파이프에서 주입.- 코드 유지·재사용이 쉬워진다.
5. 출력 형식 고정
결과를 반드시 아래 JSON 형태로 반환:
{"answer": "...", "cite": "..."}
- 후처리(JSON 파싱, 테이블 파싱) 시 깨짐을 방지.
JsonOutputParser.get_format_instructions()로 자동 삽입도 가능
4-8. 체인 결합
from langchain.schema.runnable import RunnablePassthrough
chain = (
{"context": dense, "question": RunnablePassthrough()}
| rag_prompt
| llm
| parser
)
result = chain.invoke("IDC가 예측한 AI SW CAGR은?")
print(result["summary"])
모델 역할 한눈에
| 단계 | 컴포넌트 | 역할 | 핵심 포인트 |
|---|---|---|---|
| 임베딩 | OpenAIEmbeddings | 텍스트 → 벡터 | 의미 보존 |
| 리트리버 | Dense (FAISS/Pinecone) | 후보 문서 Recall | top-k |
| 리랭커 | bge-reranker-large-ko | 순위 재정렬 | 교차 인코딩 |
| LLM | GPT-4o 등 | 최종 답 생성 | 프롬프트 제약 |
5. 메모리 & 대화 컨텍스트
from langchain.memory import VectorStoreRetrieverMemory
memory = VectorStoreRetrieverMemory(
retriever=store.as_retriever(k=3))
memory.save_context(
inputs={"human": "자기소개 해줘"},
outputs={"ai": "저는 컴퓨터과학 전공 신입 개발자입니다."})
print(memory.load_memory_variables(
{"prompt": "전공이 뭐였지?"})["history"])
6. 에이전트 — 도구 Orchestrator
- Agent : 의사 결정
- Tools / Toolkits : 외부 액션(API, DB, 크롤러)
- AgentExecutor : 루프를 돌며 “계획 → 실행 → 관찰 → 수정”
from langchain.agents import load_tools, initialize_agent
tools = load_tools(["serpapi"], {"serpapi_api_key": "..."})
agent = initialize_agent(
tools, llm, agent="zero-shot-react-description")
agent.invoke("오늘 서울 날씨 알려주고, 내일 우산 필요할지 알려줘.")
7. 품질 관리 — LangSmith 평가
- Trace : 각 스텝 토큰·비용·시간 시각화
- Evaluate : BLEU/ROUGE + LLM-as-Judge 지원 (docs.smith.langchain.com)
- Monitor : 프로덕션 호출 실시간 대시보드
from langsmith import Client, RunEvaluator, Run
client = Client()
evaluator = client.create_evaluator(
"llm-judge",
model="gpt-4o-mini",
rubric="helpfulness"
)
run = Run(chain, inputs={"question": "..."})
client.evaluate_run(run.id, evaluator.id)
8. 배포 전략
| 시나리오 | 권장 |
|---|---|
| 단일 체인 → REST | LangServe – FastAPI 래퍼 한 줄 |
| 상태·분기·루프 | LangGraph – 멀티-에이전트 그래프 서버 |
| 사내 운영 + 관측 | LangServe + LangSmith |
9. 빠른 실습 — “PDF Q&A 서버” 50줄 완성
# app.py
from fastapi import FastAPI
from langserve import add_routes
from my_chain import chain # 위 4-8에서 만든 LCEL 체인
app = FastAPI()
add_routes(app, chain, path="/qa")
uvicorn app:app --reload # http://localhost:8000/qa
10. 결론
- 학습 순서 : Model I/O → LCEL → RAG → Agent → Evaluation
- 프로젝트 착수 전 : 요구사항에 맞는 리트리버·메모리·에이전트 토폴로지를 먼저 설계해 재작업을 최소화하자.
- 운영 : LangServe로 배포하고 LangSmith로 모니터링·회귀 테스트를 자동화한다.
참고 문헌
- LangChain 공식 문서 – https://python.langchain.com
- LCEL 소개 – https://python.langchain.com/docs/concepts/lcel/
- LangServe – https://python.langchain.com/docs/langserve/
- LangSmith Evaluation Quick-Start – https://docs.smith.langchain.com/evaluation
- LangSmith Evaluation Concepts – https://docs.smith.langchain.com/evaluation/concepts
- LangChain Changelog (2025-07) – https://changelog.langchain.com/?date=2025-07-01
- LangGraph Server Docs – https://langchain-ai.github.io/langgraph/concepts/langgraph_server/