LangChain Guide — Building LLM Applications with Chains and Agents
LangChain is a framework for developing applications powered by large language models, providing modular components for chains, agents, memory, retrieval, and tool integration.
What You’ll Learn
- Building chains that combine LLM calls with other processing steps
- Creating agents that dynamically choose tools to accomplish tasks
- Implementing conversational memory and document retrieval (RAG)
- Using vector stores for semantic search and document QA
Why LangChain Matters
Raw LLM APIs are powerful but limited. LangChain provides the scaffolding to build multi-step applications: chatbots with memory, document QA systems, automated research agents, and more. DodaTech’s Durga Antivirus Pro uses LangChain chains to orchestrate multi-stage threat analysis — first classifying a file, then searching threat databases, then generating a report. Doda Browser uses LangChain agents with web search tools for smart research assistance.
flowchart LR
A["LLM\nOpenAI/Claude"] --> B["LangChain\nFramework"]
B --> C["Chains\nSequential Steps"]
B --> D["Agents\nDynamic Tools"]
B --> E["Memory\nConversation"]
B --> F["RAG\nRetrieval"]
F --> G["Vector Store\nChroma/Pinecone"]
F --> H["Document\nLoaders"]
style B fill:#dbeafe,stroke:#2563eb
Setting Up LangChain
Install LangChain with your chosen LLM provider.
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
llm = ChatOpenAI(model="gpt-4")
response = llm.invoke([HumanMessage(content="What is LangChain?")])
print(response.content)Expected output:
LangChain is a framework for developing applications powered by language models. It provides modular components for chains, agents, memory, and retrieval, allowing developers to build complex LLM workflows with minimal boilerplate.Building Chains
Chains let you combine multiple steps. A simple chain takes input, passes it through a prompt template, calls the LLM, and parses the output.
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
prompt = ChatPromptTemplate.from_template(
"Explain {concept} in simple terms with a real-world analogy."
)
chain = prompt | llm | StrOutputParser()
result = chain.invoke({"concept": "RAG (retrieval augmented generation)"})
print(result)Expected output:
RAG is like a student taking an open-book exam. Instead of relying only on what they remember (the LLM's training data), they can look up specific information in the textbook (your documents) to give more accurate, up-to-date answers. The LLM retrieves relevant passages from your knowledge base before generating each response.Chains use LangChain’s pipe (|) operator, similar to Unix pipes. Each component transforms data and passes it to the next. This pattern is used in Durga Antivirus Pro’s threat report pipeline: raw file -> classification chain -> database lookup -> formatted report.
Conversational Memory
Memory lets your LLM remember previous interactions. LangChain provides several memory types.
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationChain
memory = ConversationBufferMemory()
conversation = ConversationChain(llm=llm, memory=memory)
print(conversation.predict(input="Hi, I'm learning LangChain."))
print(conversation.predict(input="What was my name?"))Expected output:
Hello! Welcome to LangChain. I'd be happy to help you learn about building LLM applications. What would you like to know?
You mentioned you're learning LangChain, but you didn't share your name yet. What would you like me to call you?Agents and Tools
Agents decide which tools to use based on the task. Define tools and let the agent plan its approach.
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain.tools import tool
from langchain_core.prompts import ChatPromptTemplate
@tool
def search_knowledge_base(query: str) -> str:
"""Search the internal knowledge base for documentation."""
return f"Results for '{query}': LangChain supports Python and JavaScript."
tools = [search_knowledge_base]
prompt = ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant with access to tools."),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
])
agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
result = agent_executor.invoke({"input": "What languages does LangChain support?"})
print(result["output"])Expected output:
LangChain supports both Python and JavaScript. You can use it with various LLM providers including OpenAI, Anthropic, and open-source models.RAG — Retrieval Augmented Generation
RAG combines document retrieval with LLM generation. Load documents, split them, embed them into a vector store, then retrieve relevant chunks for each query.
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.chains import RetrievalQA
loader = TextLoader("threat_report.txt")
documents = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
docs = text_splitter.split_documents(documents)
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma.from_documents(docs, embeddings)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
retriever=vectorstore.as_retriever(search_kwargs={"k": 3})
)
result = qa_chain.invoke({"query": "What indicators of compromise were found?"})
print(result["result"])Expected output (varies based on document content):
Based on the threat report, three indicators of compromise were identified:
1. Suspicious outbound connection to 203.0.113.42 on port 4444
2. File hash a1b2c3d4e5f6 matching known Cobalt Strike beacon
3. Unusual registry modification at HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
Each indicator should be investigated using the incident response playbook.Durga Antivirus Pro uses this exact pattern: security reports are loaded into a vector store, and analysts query the system using natural language to find relevant threat intelligence.
Document Loaders and Splitters
LangChain supports 100+ document loaders for PDFs, web pages, databases, and more.
from langchain_community.document_loaders import WebBaseLoader
loader = WebBaseLoader("https://docs.anthropic.com/en/docs/intro-to-claude")
docs = loader.load()
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
chunks = splitter.split_documents(docs)
print(f"Loaded {len(docs)} document(s), split into {len(chunks)} chunks")Expected output:
Loaded 1 document(s), split into 24 chunksCommon Errors
1. OpenAI API Key Not Set
LangChain reads OPENAI_API_KEY from the environment. Missing it causes an AuthenticationError. Set it before initializing any ChatOpenAI instance.
2. Vector Store Persistence Issues
Chroma saves to disk by default. If the directory is not writable or you run multiple processes, you may get PermissionError. Use a unique persist directory per process.
3. Chain Input Mismatch
Prompt templates with specific variables (e.g., {concept}) must receive all required keys in the input dict. Missing keys silently produce empty substitutions.
4. Agent Loop Exceeding Max Iterations
Agents may get stuck in a reasoning loop. Set max_iterations and max_execution_time on AgentExecutor to prevent runaway costs.
5. Memory Bloating Long Conversations
ConversationBufferMemory grows indefinitely. Use ConversationSummaryMemory or ConversationTokenBufferMemory to manage context window limits.
6. Retriever Returning Irrelevant Documents
If your vector store returns unrelated chunks, adjust chunk_size, chunk_overlap, or increase k and add a re-ranker step.
7. Deprecation Warnings
LangChain evolves rapidly. Pin versions in requirements.txt and migrate incrementally. The langchain-community package contains integrations that may move to separate packages.
Practice Questions
- What does the pipe (
|) operator do in LangChain expression language? - How does an agent differ from a chain?
- What is RAG and why is it important for LLM applications?
- Which memory type should you use for long conversations?
- How do you control how many documents a retriever returns?
Answers:
- It composes components — the output of one component becomes the input to the next, creating a processing pipeline similar to Unix pipes.
- A chain follows a fixed sequence of steps. An agent dynamically decides which tools to call based on the input, allowing flexible multi-step reasoning.
- RAG (Retrieval Augmented Generation) retrieves relevant documents from a knowledge base and includes them in the LLM prompt. This grounds responses in factual data and reduces hallucination.
ConversationSummaryMemoryorConversationTokenBufferMemory— they summarize or truncate older messages to stay within context limits.- Set
search_kwargs={"k": N}on the retriever. Higher values provide more context but increase token usage and potential noise.
Challenge: DodaZIP needs a smart assistant that answers questions about compression formats. Build a RAG system that loads documentation from multiple formats (PDF, web pages, text files), chunks them, stores them in Chroma, and answers user questions with source citations.
Mini Project: Research Assistant Agent
Build an agent that researches topics using web search and knowledge base tools:
from langchain_openai import ChatOpenAI
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain.tools import tool
from langchain_core.prompts import ChatPromptTemplate
import json
@tool
def search_web(query: str) -> str:
"""Search the web for information."""
return f"Search results for '{query}': [simulated results]"
@tool
def calculate(expression: str) -> str:
"""Evaluate a mathematical expression."""
return str(eval(expression))
llm = ChatOpenAI(model="gpt-4", temperature=0)
tools = [search_web, calculate]
prompt = ChatPromptTemplate.from_messages([
("system", "You are a research assistant. Use tools to find information."),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
])
agent = create_tool_calling_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
query = "What is the current population of Python programming users worldwide? Also calculate 15% of that number."
result = executor.invoke({"input": query})
print(result["output"])Try it: Run the agent with different research queries. Add more tools like a code interpreter or a database connector to expand its capabilities.
FAQ
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro