LangChain Complete Guide | LLM Apps, Chains, Agents, RAG

LangChain Complete Guide | LLM Apps, Chains, Agents, RAG

이 글의 핵심

LangChain is the go-to framework for building LLM applications. This guide covers everything from basic Chains to production-ready RAG pipelines and autonomous Agents.

What This Guide Covers

LangChain is the most popular framework for building LLM-powered applications. This guide walks through the core concepts — Chains, Agents, Memory, and RAG — with practical Python examples you can run today.

Real-world insight: Migrating from raw OpenAI API calls to LangChain reduced our boilerplate by 60% and made complex multi-step workflows dramatically easier to maintain.


Installation

pip install langchain langchain-openai langchain-community chromadb

Set your API key:

export OPENAI_API_KEY="sk-..."

1. Basic Chain

A Chain is the fundamental unit in LangChain — it connects a prompt template to an LLM.

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

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

prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant."),
    ("human", "{question}")
])

chain = prompt | llm | StrOutputParser()

response = chain.invoke({"question": "What is LangChain?"})
print(response)

The | operator is LangChain Expression Language (LCEL) — it composes components into a pipeline.


2. Memory

Memory lets your chain remember previous messages in a conversation.

from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory

store = {}

def get_session_history(session_id: str):
    if session_id not in store:
        store[session_id] = InMemoryChatMessageHistory()
    return store[session_id]

with_history = RunnableWithMessageHistory(
    chain,
    get_session_history,
    input_messages_key="question",
    history_messages_key="history",
)

config = {"configurable": {"session_id": "user-123"}}

with_history.invoke({"question": "My name is Alice."}, config=config)
response = with_history.invoke({"question": "What's my name?"}, config=config)
print(response)  # Alice

For production, replace InMemoryChatMessageHistory with a Redis or database-backed store.


3. RAG — Retrieval-Augmented Generation

RAG lets your LLM answer questions based on your own documents.

Step 1: Load and split documents

from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter

loader = TextLoader("docs/my_document.txt")
docs = loader.load()

splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_documents(docs)

Step 2: Embed and store in a vector DB

from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma

embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(chunks, embeddings, persist_directory="./chroma_db")
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})

Step 3: Build the RAG chain

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough

rag_prompt = ChatPromptTemplate.from_template("""
Answer the question based only on the following context:

{context}

Question: {question}
""")

def format_docs(docs):
    return "\n\n".join(doc.page_content for doc in docs)

rag_chain = (
    {"context": retriever | format_docs, "question": RunnablePassthrough()}
    | rag_prompt
    | llm
    | StrOutputParser()
)

response = rag_chain.invoke("What does the document say about X?")
print(response)

4. Agents

Agents can decide which tools to call based on user input — they enable autonomous, multi-step reasoning.

from langchain_community.tools.tavily_search import TavilySearchResults
from langchain.agents import create_tool_calling_agent, AgentExecutor

tools = [TavilySearchResults(max_results=3)]

agent_prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant. Use tools when needed."),
    ("human", "{input}"),
    ("placeholder", "{agent_scratchpad}"),
])

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

result = executor.invoke({"input": "What is the latest LangChain version?"})
print(result["output"])

5. Custom Tools

You can give agents access to any Python function.

from langchain_core.tools import tool

@tool
def get_weather(city: str) -> str:
    """Get the current weather for a city."""
    # Call a real weather API here
    return f"The weather in {city} is sunny, 22°C."

tools = [get_weather]
agent = create_tool_calling_agent(llm, tools, agent_prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

result = executor.invoke({"input": "What's the weather in Seoul?"})

The docstring becomes the tool description that the LLM uses to decide when to call it — write it clearly.


6. Streaming

For responsive UIs, stream tokens as they arrive:

for chunk in chain.stream({"question": "Explain RAG in simple terms"}):
    print(chunk, end="", flush=True)

Works with agents too:

for event in executor.stream({"input": "Search for LangChain news"}):
    print(event)

Production Patterns

Structured output

from pydantic import BaseModel

class ProductInfo(BaseModel):
    name: str
    price: float
    in_stock: bool

structured_llm = llm.with_structured_output(ProductInfo)
result = structured_llm.invoke("Extract product info: Widget Pro, $29.99, available")
print(result.name, result.price)

Parallel chains

from langchain_core.runnables import RunnableParallel

parallel = RunnableParallel(
    summary=chain,
    keywords=(prompt | llm | StrOutputParser()),
)
result = parallel.invoke({"question": "Describe LangChain"})

Error handling and retries

chain_with_retry = chain.with_retry(stop_after_attempt=3)

LangSmith Observability

LangSmith traces every chain and agent call — essential for debugging production issues.

export LANGCHAIN_TRACING_V2=true
export LANGCHAIN_API_KEY="ls__..."

That’s all you need. Every invoke is automatically traced.


Key Takeaways

ConceptUse when
ChainFixed sequence of steps
MemoryConversational context needed
RAGAnswer from your own documents
AgentDynamic tool selection at runtime
Structured outputNeed typed, validated responses

LangChain’s LCEL makes it easy to compose these building blocks. Start with a simple chain, add memory for conversations, layer in RAG for document Q&A, and graduate to agents when you need autonomous decision-making.