·9 min read·AlgoMindset Team

LangChain Tutorial: Building Your First AI Agent (Free, Step-by-Step)

AI EngineeringLangChainTutorialAI Agents

What LangChain actually is

Strip away the abstractions and LangChain is a library for composing four things: a prompt template, a model call, an output parser, and — optionally — tools and memory bolted onto that core loop. It is not a replacement for understanding how the underlying model works, and it will not make a badly-designed prompt good. What it gives you is a consistent interface across model providers and a set of prebuilt patterns (agents, retrieval chains, memory stores) so you are not rebuilding them from scratch on every project.

The best way to learn it is to build the same small thing four times, adding one capability at a time: a plain chain, a chain with a tool, a chain with memory, and a chain with retrieval.

1. The core building block: a chain

A chain is a prompt template piped into a model piped into an output parser. In LangChain's expression language, that pipe is literal — you compose these three pieces with the `|` operator, and the result is itself a runnable object you can call, stream, or batch.

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

prompt = ChatPromptTemplate.from_template(
    "Explain {topic} to a {audience} in three sentences."
)
model = ChatOpenAI(model="gpt-4o-mini")
parser = StrOutputParser()

chain = prompt | model | parser

result = chain.invoke({"topic": "hash maps", "audience": "beginner"})
print(result)

2. Giving it a tool

A tool is a plain function with a description the model can read, so it knows when to call it. Bind one or more tools to the model, and instead of always returning text, the model can return a structured request to call a tool — your code executes it and feeds the result back in.

python
from langchain_core.tools import tool

@tool
def get_stock_price(ticker: str) -> str:
    """Look up the current price for a given stock ticker."""
    price = fetch_price(ticker)  # your own implementation
    return f"{ticker} is trading at ${price}"

model_with_tools = model.bind_tools([get_stock_price])

response = model_with_tools.invoke("What's AAPL trading at?")
# response.tool_calls will contain the tool the model wants to run

3. Adding memory

Without memory, every call to a chain is stateless — the model has no idea what you asked five seconds ago. Memory is just a way of collecting prior messages and re-injecting them into the prompt on the next call. The simplest version keeps the full conversation history; production systems usually summarize or trim older turns once the conversation gets long, to control token cost and stay inside the context window.

The pattern to remember: memory is not magic state living inside the model — it is your code re-sending the relevant history on every single call. That fact is worth stating explicitly in an interview, because it is exactly the kind of detail that separates "I used LangChain memory" from actually understanding what memory costs in tokens and latency.

4. Retrieval: grounding answers in your own data

Retrieval-augmented generation swaps "hope the model already knows this" for "look it up first." You embed your documents into a vector store, retrieve the most relevant chunks for a given query, and stuff them into the prompt alongside the question so the model answers from the retrieved text instead of its training data.

python
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings

vectorstore = FAISS.from_texts(document_chunks, OpenAIEmbeddings())
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})

relevant_docs = retriever.invoke("What is our refund policy?")
context = "\n\n".join(doc.page_content for doc in relevant_docs)

rag_prompt = ChatPromptTemplate.from_template(
    "Answer using only this context:\n{context}\n\nQuestion: {question}"
)
rag_chain = rag_prompt | model | parser
answer = rag_chain.invoke({"context": context, "question": "What is our refund policy?"})

The pitfall almost everyone hits

The most common mistake is chaining too much "magic" together — high-level agent executors that hide exactly what prompt is being sent and when a tool is being called — and then being unable to debug why the agent did something unexpected. Start with the explicit, composable pieces shown above before reaching for the fully automatic agent executors. You will understand failures faster, and you will be able to explain your own system in an interview instead of gesturing at a black box.

Once a fixed sequence like this stops being enough — once you need looping, branching, or a pause for human approval — that is the point to move from a plain chain to LangGraph, which we cover in a companion tutorial. For coordinating multiple specialized agents built this way, our LangChain Agent Patterns premium lab and multi-agent orchestration system design lab go further into executor and memory-store patterns.