Build a LangChain AI Agent in 20 Minutes: Step‑by‑Step Guide

This tutorial walks through creating a LangChain‑based AI agent by covering model integration, tool definition with @tool, short‑ and long‑term memory handling via checkpointers and vector stores, and assembling everything with create_agent, middleware, and code examples for a functional travel assistant.

SpringMeng
SpringMeng
SpringMeng
Build a LangChain AI Agent in 20 Minutes: Step‑by‑Step Guide

LangChain and LangGraph version shift

Since LangChain 1.0, LangGraph is the low‑level orchestration engine for stateful, multi‑turn agents, while LangChain provides higher‑level abstractions, tool integration and convenient agent building.

Model invocation

LangChain supplies integration packages for many providers. Example using DeepSeek:

from langchain_deepseek import ChatDeepSeek
model = ChatDeepSeek(
    model="...",
    temperature=0,
    max_tokens=None,
    timeout=None,
    max_retries=2,
    api_key=os.getenv("DEEPSEEK_API_KEY")
)

Standard OpenAI‑compatible call:

from langchain_openai import ChatOpenAI
model = ChatOpenAI(
    model="deepseek-chat",
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    base_url="https://api.deepseek.com",
    temperature=0.7
)

Invoke with invoke or stream to get responses.

Tool definition

Use the @tool decorator with explicit name, description and parameter metadata ( Annotated, Field) so the model can select the correct tool.

from langchain_core.tools import tool
from typing import Annotated
from pydantic import Field

@tool(name_or_callable="get_weather", description="Get weather for a city on a specific date")
def get_weather(
    destination: Annotated[str, Field(description="City name, e.g., 'Xi'an'")],
    date: Annotated[str, Field(description="Date in YYYY‑MM‑DD format")]
) -> str:
    return f"{destination} {date} weather is sunny"

@tool(name_or_callable="get_attractions", description="Get popular attractions for a city")
def get_attractions(
    destination: Annotated[str, Field(description="City name, e.g., 'Beijing'")]
) -> str:
    return f"{destination} popular attractions are: Forbidden City, Summer Palace, Temple of Heaven."

Agent creation

Create an agent with create_agent (ReAct mode). Provide the model and the list of tools.

from langchain.agents import create_react_agent
tools = [get_weather, get_attractions]
agent = create_agent(model=model, tools=tools)
messages = {
    "messages": [
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "I want to travel to Beijing. Can you check the weather and attractions?"}
    ]
}
result = agent.invoke(messages)
print(result["messages"][-1].content)

ReAct workflow:

Model receives user messages, performs reasoning, decides whether a tool is needed.

If a tool is required, the model outputs a tool‑call command; the framework executes the tool and appends the result as a new message.

The updated message list is fed back to the model until a final answer is produced.

Short‑term memory

Persisted via the Checkpointer mechanism. Providing a consistent thread_id (or configurable dict) enables the agent to recall previous turns.

from langgraph.checkpoint.memory import InMemorySaver
agent = create_agent(..., checkpointer=InMemorySaver())
config = {"configurable": {"thread_id": "1"}}
result = agent.invoke(input=messages, config=config)

In production replace InMemorySaver with PostgresSaver or SqliteSaver for persistence.

Long‑term memory (vector store)

Use a vector database (e.g., Chroma) with an embedding model (e.g., DashScope) to store and retrieve conversation history.

from langchain_community.embeddings import DashScopeEmbeddings
from langchain_chroma import Chroma
from langchain_core.documents import Document

embeddings = DashScopeEmbeddings(
    model="text-embedding-v4",
    dashscope_api_key=os.getenv("DASHSCOPE_API_KEY")
)

vectorstore = Chroma(
    embedding_function=embeddings,
    persist_directory="./chroma_db",
    collection_name="chat_history"
)

Save a turn:

def save_messages(messages: str, user_id: int, session_id: int):
    doc = Document(page_content=messages, metadata={"user_id": user_id, "session_id": session_id})
    vectorstore.add_documents([doc])

Load relevant history for a new query (optional user_id and session_id filters):

def load_messages(query: str, user_id: int = None, session_id: int = None):
    filters = []
    if user_id:
        filters.append({"user_id": user_id})
    if session_id:
        filters.append({"session_id": session_id})
    if len(filters) > 1:
        filter_dict = {"$and": filters}
    elif filters:
        filter_dict = filters[0]
    else:
        filter_dict = None
    if filter_dict:
        docs = vectorstore.similarity_search(query=query, k=3, filter=filter_dict)
    else:
        docs = vectorstore.similarity_search(query=query, k=3)
    return docs

Middleware for long‑term memory

Define a middleware that fetches relevant documents and appends them to the prompt before each model call.

@wrap_model_call
def add_long_memory(request: ModelRequest, handler: Callable[[ModelRequest], ModelResponse]) -> ModelResponse:
    message = request.messages[-1]
    if message.type == "human":
        docs = load_messages(
            message.content,
            config["configurable"]["user_id"],
            config["configurable"]["session_id"]
        )
        extra = "
".join([doc.page_content for doc in docs])
        request.messages.append(ChatMessage(content=extra, role="system"))
    return handler(request)

Attach the middleware when creating the agent:

agent = create_agent(
    llm,
    tools=tools,
    middleware=[add_long_memory()],
    checkpointer=InMemorySaver()
)

Full example

config = {
    "configurable": {"thread_id": "1", "user_id": 1, "session_id": 1}
}
llm = ChatOpenAI(
    model="deepseek-chat",
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    base_url="https://api.deepseek.com",
    temperature=0.7
)
messages = {
    "messages": [
        {"role": "system", "content": "You are a travel planning assistant."},
        {"role": "user", "content": user_message}
    ]
}
tools = [get_weather, get_attractions]
agent = create_agent(
    llm,
    tools=tools,
    middleware=[add_long_memory()],
    checkpointer=InMemorySaver()
)
result = agent.invoke(input=messages, config=config)
ai_message = result["messages"][-1].content
save_messages(messages=user_message + ai_message, user_id=config["configurable"]["user_id"], session_id=config["configurable"]["session_id"])

Conclusion

The essential components of a LangChain agent are model, tools and memory. LangChain abstracts model differences, exposes functionality as tools with rich metadata, and provides both short‑term (checkpointer) and long‑term (vector store + middleware) memory mechanisms. Combining these enables a stateful AI assistant with minimal boilerplate.

memory managementPythonReActTool IntegrationLangChainAI AgentLangGraph
SpringMeng
Written by

SpringMeng

Focused on software development, sharing source code and tutorials for various systems.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.