LangChain과 LangGraph는 대규모 언어 모델(LLM)을 활용한 애플리케이션 개발을 위한 강력한 프레임워크입니다. LangChain은 LLM 기반 애플리케이션 개발을 위한 기본 구성 요소를 제공하며, LangGraph는 복잡한 AI 에이전트와 워크플로우를 그래프 구조로 설계할 수 있게 해줍니다.
LangChain이란?
LangChain은 LLM을 활용한 애플리케이션을 쉽게 구축할 수 있도록 돕는 오픈소스 프레임워크입니다.
LangChain의 주요 특징
체인(Chain) 기반 구조: 여러 컴포넌트를 연결하여 복잡한 작업 수행
다양한 LLM 지원: OpenAI, Anthropic, HuggingFace 등 다양한 모델 지원
Memory 관리: 대화 히스토리 및 컨텍스트 유지
도구 통합: 외부 API, 데이터베이스, 검색 엔진 등과 연동
프롬프트 템플릿: 재사용 가능한 프롬프트 관리
LangGraph란?
LangGraph는 LangChain을 기반으로 상태를 가진(stateful) 멀티 액터 애플리케이션을 그래프로 구축할 수 있는 라이브러리입니다.
LangGraph의 주요 특징
그래프 기반 워크플로우: 복잡한 AI 워크플로우를 노드와 엣지로 표현
상태 관리: 애플리케이션 전체의 상태를 효과적으로 관리
순환 구조 지원: 반복적인 작업 및 피드백 루프 구현 가능
조건부 라우팅: 동적으로 실행 경로 결정
Human-in-the-loop: 사람의 개입이 필요한 지점 설정 가능
1. 설치 및 환경 설정
필수 패키지 설치
# LangChain 설치 pip install langchain langchain-openai
# 간단한 테스트 response = llm.invoke("Hello, LangChain!") print(response.content)
2. LangChain 기본 사용법
2.1 프롬프트 템플릿
from langchain.prompts import ChatPromptTemplate
# 프롬프트 템플릿 생성 prompt = ChatPromptTemplate.from_messages([ ("system", "You are a helpful assistant that translates {input_language} to {output_language}."), ("human", "{text}") ])
# 프롬프트 포맷팅 messages = prompt.format_messages( input_language="English", output_language="Korean", text="Hello, how are you?" )
# 테스트 result1 = app.invoke({"input": "hello there", "route": "", "output": ""}) print(result1["output"]) # "Hello! How can I help you?"
result2 = app.invoke({"input": "what's the weather", "route": "", "output": ""}) print(result2["output"]) # "I'll help you with that."
3.3 AI 에이전트 구현
from langchain_openai import ChatOpenAI from langchain.tools import tool from langgraph.graph import StateGraph, END from typing import TypedDict, Annotated import operator
# 도구 정의 @tool defcalculator(expression: str) -> str: """Calculate a mathematical expression.""" try: result = eval(expression) returnf"The result is {result}" except Exception as e: returnf"Error: {str(e)}"
@tool defget_weather(city: str) -> str: """Get the current weather for a city.""" # 실제로는 API 호출 returnf"The weather in {city} is sunny, 22°C"
# 상태 정의 classAgentState(TypedDict): messages: Annotated[list, operator.add] next_action: str
workflow.add_conditional_edges( "agent", should_continue, { "tools": "tools", END: END } )
workflow.add_edge("tools", "agent")
agent_app = workflow.compile()
# 실행 result = agent_app.invoke({ "messages": [("user", "What is 25 * 4?")] })
for msg in result["messages"]: print(msg)
4. 실전 예제: RAG 시스템 구축
4.1 문서 로딩 및 벡터 저장소 구성
from langchain_community.document_loaders import TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_openai import OpenAIEmbeddings from langchain_community.vectorstores import Chroma
# 문서 로드 loader = TextLoader("documents/sample.txt") documents = loader.load()
# 텍스트 분할 text_splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=200 ) splits = text_splitter.split_documents(documents)
# 임베딩 생성 embeddings = OpenAIEmbeddings()
# 벡터 저장소 생성 vectorstore = Chroma.from_documents( documents=splits, embedding=embeddings, persist_directory="./chroma_db" )
4.2 RAG 체인 구성
from langchain.chains import RetrievalQA from langchain.prompts import PromptTemplate
# 프롬프트 템플릿 template = """ Use the following pieces of context to answer the question at the end. If you don't know the answer, just say that you don't know, don't try to make up an answer. Context: {context} Question: {question} Answer: """
# 답변 품질 평가 eval_prompt = f""" Evaluate if this answer adequately addresses the question. Question: {question} Answer: {answer} Reply with just 'yes' or 'no'. """
context = "\n\n".join([doc.page_content for doc in docs])
refine_prompt = f""" The previous answer was not satisfactory. Context: {context} Question: {question} Previous Answer: {previous_answer} Provide a better, more detailed answer: """
# 계획 생성 노드 defcreate_plan(state: ApprovalState) -> ApprovalState: task = state["task"]
prompt = f"Create a detailed plan for: {task}" response = llm.invoke(prompt)
state["plan"] = response.content return state
# 승인 대기 노드 defwait_for_approval(state: ApprovalState) -> ApprovalState: print("\n=== Plan for Approval ===") print(state["plan"]) print("\n========================")
# 실제로는 여기서 중단되고 사용자 입력을 기다림 return state
# 실행 노드 defexecute_plan(state: ApprovalState) -> ApprovalState: plan = state["plan"]
prompt = f"Execute this plan and provide results:\n{plan}" response = llm.invoke(prompt)
state["result"] = response.content return state
# 승인 확인 함수 defcheck_approval(state: ApprovalState) -> str: if state.get("approved", False): return"execute" return END
# 체크포인트를 사용한 그래프 구성 memory = SqliteSaver.from_conn_string(":memory:")
# 실행 result = multi_agent_app.invoke({ "task": "The impact of AI on software development", "research_output": "", "writing_output": "", "review_output": "", "final_output": "", "current_step": "" })
print("=== Research ===") print(result["research_output"]) print("\n=== Writing ===") print(result["writing_output"]) print("\n=== Review ===") print(result["review_output"]) print("\n=== Final Output ===") print(result["final_output"])
7. 스트리밍과 비동기 처리
7.1 스트리밍
# LLM 스트리밍 for chunk in llm.stream("Tell me a long story"): print(chunk.content, end="", flush=True)
# LangGraph 스트리밍 for event in app.stream({"messages": [("user", "Hello")]}): print(event)
7.2 비동기 처리
import asyncio
asyncdefasync_agent_call(): result = await agent_app.ainvoke({ "messages": [("user", "What's the weather?")] }) return result
# 실행 result = asyncio.run(async_agent_call()) print(result)
# 콜백 사용 chain = LLMChain( llm=llm, prompt=prompt, callbacks=[ErrorHandler()] )
# try-except 패턴 defsafe_node(state): try: # 처리 로직 return state except Exception as e: state["error"] = str(e) return state
9.2 프롬프트 관리
# 프롬프트를 파일로 관리 from langchain.prompts import load_prompt
prompt = load_prompt("prompts/qa_prompt.yaml")
# 또는 프롬프트 허브 사용 from langchain import hub
prompt = hub.pull("rlm/rag-prompt")
9.3 캐싱
from langchain.cache import InMemoryCache from langchain.globalsimport set_llm_cache
# 캐시 활성화 set_llm_cache(InMemoryCache())
# 같은 질문에 대해 캐시된 응답 사용 result1 = llm.invoke("What is 2+2?") result2 = llm.invoke("What is 2+2?") # 캐시에서 가져옴
9.4 비용 최적화
from langchain.callbacks import get_openai_callback
# 비용 추적 with get_openai_callback() as cb: result = chain.invoke({"question": "Test"}) print(f"Total Tokens: {cb.total_tokens}") print(f"Total Cost: ${cb.total_cost}")
10. 프로덕션 배포
10.1 LangServe로 API 서버 구축
from fastapi import FastAPI from langserve import add_routes
# 사용 llm = ChatOpenAI( model=settings.model_name, temperature=settings.temperature, max_tokens=settings.max_tokens )
11. 고급 패턴
11.1 Self-RAG (자체 수정 RAG)
classSelfRAGState(TypedDict): question: str documents: list answer: str relevance_score: float iteration: int
defretrieve_with_grading(state: SelfRAGState) -> SelfRAGState: # 문서 검색 및 관련성 평가 docs = vectorstore.similarity_search(state["question"], k=5)
# 관련성 점수 계산 grader_prompt = f"Rate the relevance of these documents to the question: {state['question']}" # ... 평가 로직
state["documents"] = docs state["relevance_score"] = 0.8# 예시 return state
11.2 Plan-and-Execute
defplan(state): # 전체 계획 수립 prompt = f"Create a step-by-step plan to answer: {state['question']}" plan = llm.invoke(prompt) state["plan"] = plan.content return state
defexecute_step(state): # 각 단계 실행 current_step = state["current_step"] # ... 실행 로직 return state