HxHippy

LangChain: Building LLM Applications

Chain prompts, tools, and memory together with LangChain for powerful AI applications.

Last updated: 2024-12-18

LangChain is a framework for building applications powered by language models. It provides tools for chaining, memory, agents, and retrieval.

Core Concepts

Chains

Sequential operations that process input through multiple steps.

Agents

LLMs that can use tools to accomplish tasks.

Memory

Persistence for conversation history and context.

Retrievers

Fetch relevant documents for RAG applications.

Installation

pip install langchain langchain-openai langchain-community
# For specific providers:
pip install langchain-anthropic  # Claude
pip install langchain-ollama     # Local models

Basic Usage

Simple Chain

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

# Initialize model
llm = ChatOpenAI(model="gpt-4o")

# Create prompt template
prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant."),
    ("user", "{input}")
])

# Build chain
chain = prompt | llm | StrOutputParser()

# Run
result = chain.invoke({"input": "What is LangChain?"})
print(result)

With Anthropic Claude

from langchain_anthropic import ChatAnthropic

llm = ChatAnthropic(model="claude-sonnet-4-20250514")

chain = prompt | llm | StrOutputParser()
result = chain.invoke({"input": "Explain Docker."})

With Local Ollama

from langchain_ollama import OllamaLLM

llm = OllamaLLM(model="llama3.1:8b")

chain = prompt | llm | StrOutputParser()
result = chain.invoke({"input": "Hello!"})

Retrieval Augmented Generation (RAG)

Basic RAG Pipeline

from langchain_community.document_loaders import TextLoader
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.text_splitter import CharacterTextSplitter
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough

# Load documents
loader = TextLoader("./docs/README.md")
documents = loader.load()

# Split into chunks
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
docs = text_splitter.split_documents(documents)

# Create vector store
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(docs, embeddings)

# Create retriever
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})

# Build RAG chain
template = """Answer based on this context:
{context}

Question: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
llm = ChatOpenAI(model="gpt-4o")

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

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

# Query
result = rag_chain.invoke("What is this project about?")

Agents with Tools

Create Tool-Using Agent

from langchain_openai import ChatOpenAI
from langchain.agents import create_react_agent, AgentExecutor
from langchain_core.tools import tool
from langchain import hub

# Define custom tools
@tool
def search_database(query: str) -> str:
    """Search the database for information."""
    # Your search implementation
    return f"Results for: {query}"

@tool
def calculate(expression: str) -> str:
    """Evaluate a math expression."""
    try:
        return str(eval(expression))
    except:
        return "Invalid expression"

# Create agent
tools = [search_database, calculate]
llm = ChatOpenAI(model="gpt-4o", temperature=0)
prompt = hub.pull("hwchase17/react")

agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

# Run agent
result = agent_executor.invoke({
    "input": "What is 25 * 4, and then search for that number?"
})

Memory for Conversations

Conversation Buffer Memory

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory

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

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

chain = prompt | llm

# Store for session histories
store = {}

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

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

# Chat with memory
config = {"configurable": {"session_id": "user123"}}

response1 = with_history.invoke(
    {"input": "My name is Alice"},
    config=config
)

response2 = with_history.invoke(
    {"input": "What's my name?"},
    config=config
)
# Response will remember the name

Document Loaders

from langchain_community.document_loaders import (
    TextLoader,
    PyPDFLoader,
    CSVLoader,
    WebBaseLoader,
    GitHubIssuesLoader
)

# Load text file
docs = TextLoader("file.txt").load()

# Load PDF
docs = PyPDFLoader("document.pdf").load()

# Load CSV
docs = CSVLoader("data.csv").load()

# Load web page
docs = WebBaseLoader("https://example.com").load()

# Load GitHub issues
docs = GitHubIssuesLoader(
    repo="owner/repo",
    access_token="your-token"
).load()

Text Splitters

from langchain.text_splitter import (
    CharacterTextSplitter,
    RecursiveCharacterTextSplitter,
    TokenTextSplitter
)

# By characters
splitter = CharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=200
)

# Recursive (better for code)
splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=200,
    separators=["\n\n", "\n", " ", ""]
)

# By tokens
splitter = TokenTextSplitter(
    chunk_size=500,
    chunk_overlap=50
)

chunks = splitter.split_documents(documents)

Output Parsers

from langchain_core.output_parsers import JsonOutputParser
from langchain_core.pydantic_v1 import BaseModel, Field

# Define output structure
class CodeReview(BaseModel):
    issues: list[str] = Field(description="List of issues found")
    suggestions: list[str] = Field(description="Improvement suggestions")
    score: int = Field(description="Code quality score 1-10")

parser = JsonOutputParser(pydantic_object=CodeReview)

prompt = ChatPromptTemplate.from_messages([
    ("system", "Review the code and output JSON.\n{format_instructions}"),
    ("user", "{code}")
])

chain = prompt | llm | parser

result = chain.invoke({
    "code": "def add(a,b): return a+b",
    "format_instructions": parser.get_format_instructions()
})
# result is a CodeReview object

Best Practices

  1. Use typing: Define Pydantic models for structured output
  2. Stream responses: Use .stream() for long generations
  3. Handle errors: Wrap chains in try/except
  4. Cache embeddings: Reuse vector stores across sessions
  5. Batch operations: Use .batch() for multiple inputs
  6. Monitor costs: Track token usage with callbacks
advanced Tools & APIs Updated 2024-12-18
  • langchain
  • llm applications
  • ai agents
  • rag
  • ai chains