Skip to content
LangChain: Building LLM-Powered Applications

LangChain: Building LLM-Powered Applications

DodaTech Updated Jun 20, 2026 9 min read

LangChain is a framework for building applications powered by large language models (LLMs). It provides abstractions for chains, agents, memory, retrieval-augmented generation (RAG), and tool use — turning LLMs from standalone chatbots into composable application components.

Learning Path

    flowchart LR
  A["Anthropic Claude API<br/>Basics"] --> B["LangChain<br/>LLM Applications"]
  B --> C["DeepSeek API<br/>Open-Source LLMs"]
  B --> D["Mistral AI<br/>Models & API"]
  style B fill:#f90,color:#fff,stroke-width:2px
  
What you’ll learn: LangChain core concepts — chains (LLMChain, SequentialChain, RouterChain), prompt templates, output parsers, memory systems, document loaders, vector stores, and agents. Why it matters: LangChain is the most popular framework for LLM applications, with 100K+ GitHub stars. It simplifies complex LLM workflows into composable building blocks. Real-world use: DodaZIP uses LangChain for intelligent file categorization. Durga Antivirus Pro uses LangChain agents to orchestrate multiple threat analysis tools in automated security pipelines.

Core Concepts

    flowchart TD
    subgraph "LangChain Architecture"
        A["Prompt Templates"] --> B["LLM (Model)"]
        B --> C["Output Parsers"]
        C --> D["Chains"]
        D --> E["Memory"]
        D --> F["Agents"]
        F --> G["Tools"]
        D --> H["Document Loaders"]
        H --> I["Text Splitters"]
        I --> J["Vector Stores"]
        J --> K["Retrievers"]
    end
    style D fill:#f90,color:#fff,stroke-width:2px
  

Installation

pip install langchain langchain-community langchain-openai langchain-anthropic

Prompt Templates

Prompt templates provide reusable, parameterized prompt structures:

from langchain_core.prompts import PromptTemplate, ChatPromptTemplate

# Basic prompt template
template = PromptTemplate.from_template(
    "You are a {role}. Answer the question: {question}"
)
prompt = template.invoke({"role": "cybersecurity expert", "question": "What is XSS?"})
print(prompt.text)

# Chat prompt template (with system message)
chat_template = ChatPromptTemplate.from_messages([
    ("system", "You are a {role} at DodaTech."),
    ("human", "{input}")
])
chat_prompt = chat_template.invoke({
    "role": "security analyst",
    "input": "Analyze this log entry: failed login from 192.168.1.100"
})
print(chat_prompt.messages)

Expected output:

You are a cybersecurity expert. Answer the question: What is XSS?
[SystemMessage(content="You are a security analyst at DodaTech."), 
 HumanMessage(content="Analyze this log entry: failed login from 192.168.1.100")]

LLMChain

The most basic chain — takes a prompt, sends it to an LLM, and parses the output:

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

# Create components
llm = ChatOpenAI(model="gpt-4", temperature=0)
prompt = PromptTemplate.from_template(
    "Explain {concept} like I'm 5 years old."
)
parser = StrOutputParser()

# Build chain
chain = prompt | llm | parser

# Run
result = chain.invoke({"concept": "API"})
print(result)

Expected output:

An API is like a restaurant menu. You tell the kitchen what you want from the menu, and they bring it to you. You don't need to know how they cook it—you just get what you ordered.

SequentialChain

Chains multiple steps together — output of one step feeds the next:

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

# Chain 1: Generate a product idea
prompt1 = ChatPromptTemplate.from_template(
    "Suggest a product name for a {industry} startup. Only return the name."
)
chain1 = prompt1 | llm | StrOutputParser()

# Chain 2: Write a tagline for the product
prompt2 = ChatPromptTemplate.from_template(
    "Write a one-line tagline for a product called {product_name} in the {industry} space."
)
chain2 = prompt2 | llm | StrOutputParser()

# Compose
full_chain = chain1 | (lambda name: {"product_name": name, "industry": "cybersecurity"}) | chain2
result = full_chain.invoke({"industry": "cybersecurity"})
print(f"Result: {result}")

Expected output:

Result: "SentinelShield: Your first line of defense in a digital battlefield."

RouterChain

Routes between different chains based on input classification:

from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser

# Define specialized chains
tech_chain = PromptTemplate.from_template(
    "Answer this tech question: {input}"
) | llm | StrOutputParser()

health_chain = PromptTemplate.from_template(
    "Answer this health question: {input}"
) | llm | StrOutputParser()

finance_chain = PromptTemplate.from_template(
    "Answer this finance question: {input}"
) | llm | StrOutputParser()

# Router (simplified with conditional)
def route_query(query):
    """Route query to appropriate chain based on topic."""
    topics = {
        "tech": tech_chain,
        "health": health_chain,
        "finance": finance_chain,
    }
    
    query_lower = query.lower()
    if any(w in query_lower for w in ["code", "software", "computer", "api"]):
        return tech_chain.invoke({"input": query})
    elif any(w in query_lower for w in ["symptom", "disease", "doctor", "medicine"]):
        return health_chain.invoke({"input": query})
    elif any(w in query_lower for w in ["money", "stock", "invest", "bank"]):
        return finance_chain.invoke({"input": query})
    else:
        return "I can only answer tech, health, and finance questions."

print(route_query("What is an API?"))
print(route_query("What is a stock?"))

Output Parsers

Parse LLM responses into structured formats:

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

# JSON output parser
class ThreatReport(BaseModel):
    threat_name: str = Field(description="Name of the threat")
    severity: str = Field(description="Severity: low/medium/high/critical")
    affected_systems: list = Field(description="Affected systems")

parser = JsonOutputParser(pydantic_object=ThreatReport)

prompt = PromptTemplate.from_template(
    "Analyze this threat: {log_entry}\n{format_instructions}",
    partial_variables={"format_instructions": parser.get_format_instructions()}
)

chain = prompt | llm | parser
result = chain.invoke({"log_entry": "Multiple failed SSH attempts from IP 10.0.0.5 targeting root"})
print(result)

# List output parser
list_parser = CommaSeparatedListOutputParser()
list_prompt = PromptTemplate.from_template(
    "List 3 {topic} security tools.\n{format_instructions}",
    partial_variables={"format_instructions": list_parser.get_format_instructions()}
)
list_chain = list_prompt | llm | list_parser
print(list_chain.invoke({"topic": "open-source network monitoring"}))

Expected output:

{'threat_name': 'Brute Force SSH Attack', 'severity': 'medium', 'affected_systems': ['SSH server on 10.0.0.5']}
['Wireshark', 'Zeek', 'Prometheus']

Memory

LangChain provides several memory types for conversation history:

from langchain.memory import ConversationBufferMemory, ConversationSummaryMemory
from langchain.chains import ConversationChain

# Buffer memory (stores full history)
buffer_memory = ConversationBufferMemory()
conversation = ConversationChain(llm=llm, memory=buffer_memory)

print(conversation.predict(input="Hi, I'm working on a security project."))
print(conversation.predict(input="What was my project about?"))

# Summary memory (summarizes history)
summary_memory = ConversationSummaryMemory(llm=llm)
summary_conversation = ConversationChain(llm=llm, memory=summary_memory)

print(summary_conversation.predict(input="Tell me about Python generators."))
print(summary_conversation.predict(input="Give me an example."))

Document Loaders and Text Splitting

from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter

# Load a document
# loader = TextLoader("report.txt")
# documents = loader.load()

# Simulate a document
doc_text = """LangChain is a framework for LLM applications. It provides chains, agents, and memory. 
The framework supports multiple LLM providers including OpenAI and Anthropic. 
LangChain also integrates with vector stores like Pinecone and Chroma."""

from langchain_core.documents import Document
documents = [Document(page_content=doc_text)]

# Split text into chunks
splitter = RecursiveCharacterTextSplitter(
    chunk_size=100,
    chunk_overlap=20,
    separators=["\n\n", "\n", " ", ""]
)
chunks = splitter.split_documents(documents)
print(f"Split into {len(chunks)} chunks")
for i, chunk in enumerate(chunks):
    print(f"Chunk {i+1}: {chunk.page_content[:50]}...")

Expected output:

Split into 2 chunks
Chunk 1: LangChain is a framework for LLM applications. It provides...
Chunk 2: supports multiple LLM providers including OpenAI and...

Vector Stores and RAG

from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.chains import RetrievalQA

# Create embeddings and vector store
# embeddings = OpenAIEmbeddings()
# vectorstore = FAISS.from_documents(documents, embeddings)

# Simulated vector store
fake_docs = [
    Document(page_content="API stands for Application Programming Interface"),
    Document(page_content="LangChain supports OpenAI and Anthropic models"),
    Document(page_content="RAG stands for Retrieval Augmented Generation"),
]

# Build QA chain
# qa_chain = RetrievalQA.from_chain_type(
#     llm=llm,
#     retriever=vectorstore.as_retriever()
# )
# result = qa_chain.invoke({"query": "What is RAG?"})
# print(result)

Agents

Agents use LLMs to decide which tools to call and in what order:

from langchain.agents import create_react_agent, AgentExecutor
from langchain_core.tools import tool

@tool
def search_web(query: str) -> str:
    """Search the web for information."""
    return f"Results for '{query}': [simulated web search results]"

@tool
def calculate(expression: str) -> str:
    """Calculate a mathematical expression."""
    try:
        return str(eval(expression))
    except:
        return "Error in calculation"

tools = [search_web, calculate]

from langchain_core.prompts import PromptTemplate

agent_prompt = PromptTemplate.from_template(
    "You are a helpful assistant. Use tools to answer questions.\n\n"
    "Tools: {tools}\n"
    "Tool names: {tool_names}\n"
    "Input: {input}\n"
    "Agent scratchpad: {agent_scratchpad}"
)

# agent = create_react_agent(llm, tools, agent_prompt)
# agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# result = agent_executor.invoke({"input": "What is 25 * 4 + 10?"})
# print(result)

Common LangChain Errors

  1. API key not set — Missing OPENAI_API_KEY or ANTHROPIC_API_KEY environment variable. Always check before initializing LLM instances.
  2. Model not available from provider — Some models require specific API tiers. gpt-4 may not be available on free OpenAI accounts. Use gpt-3.5-turbo as fallback.
  3. Chain composition type mismatch — The output of one chain must match the expected input of the next. Use RunnablePassthrough or lambda functions to transform data between steps.
  4. Memory size growing unboundedConversationBufferMemory stores the full conversation. For long sessions, use ConversationSummaryMemory or ConversationBufferWindowMemory.
  5. Vector store indexing without embeddings — FAISS/Pinecone require embedding vectors. Forgetting to generate embeddings before indexing causes empty queries.
  6. Agent recursion limit exceeded — Agents can loop when deciding between tools. Set max_iterations (default 15) and early_stopping_method="generate" to prevent infinite loops.
  7. Output parser schema mismatch — JSON output parsers require the LLM output to match the Pydantic schema exactly. Use with_structured_output() when available for better reliability.

Practice Questions

1. What is the difference between an LLMChain and a SequentialChain? LLMChain runs a single prompt through one LLM call. SequentialChain chains multiple steps where each step’s output feeds the next step’s input.

2. When would you use RouterChain? When different types of inputs need different processing — routing tech questions to a tech chain and health questions to a health chain.

3. What’s the purpose of output parsers in LangChain? Output parsers convert LLM text responses into structured formats like JSON, lists, or Pydantic objects — making LLM outputs programmatically usable.

4. How does LangChain memory work? Memory stores conversation history and injects it into subsequent prompts. Different memory types (buffer, summary, buffer window) trade off between completeness and token usage.

5. Challenge: Build a RAG chat system Build a LangChain application that loads a document, splits it, creates a vector store, and answers questions about the document using retrieval-augmented generation.

Mini Project: Multi-Chain Document Analyzer

from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser, JsonOutputParser
from langchain_core.pydantic_v1 import BaseModel, Field

class DocAnalysis(BaseModel):
    summary: str = Field(description="One-sentence document summary")
    key_topics: list = Field(description="3-5 key topics")
    sentiment: str = Field(description="positive/negative/neutral")
    risk_level: str = Field(description="low/medium/high")

def analyze_document(text):
    """Multi-chain document analyzer."""
    # Chain 1: Summarize
    summarize = PromptTemplate.from_template(
        "Summarize this in one sentence: {text}"
    ) | llm | StrOutputParser()
    
    # Chain 2: Extract topics
    extract_topics = PromptTemplate.from_template(
        "List 3-5 key topics from: {text}"
    ) | llm | StrOutputParser()
    
    # Chain 3: Analyze risk
    analyze = PromptTemplate.from_template(
        "Analyze the sentiment and risk level (low/medium/high) of: {text}"
    ) | llm | StrOutputParser()
    
    summary = summarize.invoke({"text": text})
    topics = extract_topics.invoke({"text": text})
    risk = analyze.invoke({"text": text})
    
    return {
        "summary": summary,
        "topics": topics,
        "risk_analysis": risk
    }

doc = "Our system detected 47 failed login attempts from 3 different IPs in the last hour."
print(analyze_document(doc))

FAQ

What’s the difference between LangChain and Mastra?
LangChain is the more mature framework with broader community support, more integrations, and extensive documentation. Mastra is newer, TypeScript-first, and focuses on developer experience with a cleaner API.
Do I need LangChain to use LLMs?
No. You can call LLM APIs directly. LangChain adds value when you need chains, agents, memory, RAG, or tool use — complex workflows that benefit from framework abstractions.
What’s the best vector store to use with LangChain?
FAISS for development/prototyping (local, fast), Pinecone or Weaviate for production (managed, scalable), Chroma for simple local use. Choose based on scale and deployment needs.
Is LangChain production-ready?
Yes, but with caveats. LangChain’s rapid API evolution means code breaks between versions. Pin dependencies strictly and test upgrades thoroughly before deploying.
How do I handle rate limits with LangChain?
Use LangChain’s rate limiting support: configure max_retries on the LLM, implement exponential backoff with tenacity, or use the built-in rate limiter from langchain-core.

Related Tutorials


Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro. Updated 2026-06-20.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro