Building Your First AI Chatbot with Python and LangChain
If you have been following the rapid evolution of large language models, you have probably wondered how to move beyond simple prompt-and-response scripts and build something that actually feels like a conversation. That is exactly what LangChain helps you do. We will walk through building a chatbot from scratch using LangChain v0.1 and the OpenAI API, with proper conversational memory so the bot remembers what you talked about.
What is LangChain?
LangChain is a Python framework designed to simplify the development of applications powered by large language models. Rather than writing raw API calls and managing prompt templates by hand, LangChain gives you composable abstractions like chains, agents, and memory modules. Version 0.1, released in early January 2024, marked the framework's first stable release and introduced a cleaner package structure with langchain-core, langchain-community, and partner packages like langchain-openai.
Prerequisites
Before we start, make sure you have the following:
- Python 3.10 or later
- An OpenAI API key
- A virtual environment (recommended)
Install the required packages:
pip install langchain langchain-openai python-dotenv
Create a .env file in your project root to store your API key:
OPENAI_API_KEY=sk-your-api-key-here
Setting up the language model
The first step is to configure the language model. LangChain v0.1 introduced dedicated partner packages, so we import the chat model from langchain-openai rather than the old monolithic import.
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
load_dotenv()
llm = ChatOpenAI(
model="gpt-3.5-turbo",
temperature=0.7,
openai_api_key=os.getenv("OPENAI_API_KEY"),
)
The temperature parameter controls how creative the responses are. A value of 0.7 strikes a good balance between coherence and variety for a chatbot.
Building a simple chain
A chain in LangChain connects a prompt template to a model. Let us start with a basic example before adding memory.
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant named Aria. You answer questions concisely and clearly."),
("human", "{input}"),
])
chain = prompt | llm
response = chain.invoke({"input": "What is the capital of France?"})
print(response.content)
The pipe operator (|) is part of the LangChain Expression Language (LCEL) introduced in v0.1. It lets you compose runnables in a clean, readable way. This chain takes user input, formats it into a prompt, and sends it to the model.
Adding conversational memory
The chain above works, but it has no memory. Each call is independent, so the bot cannot refer back to previous messages. To fix this, we use ConversationBufferMemory along with a prompt that includes a placeholder for chat history.
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationChain
memory = ConversationBufferMemory(return_messages=True)
prompt = ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant named Aria. You remember previous messages and provide context-aware responses."),
MessagesPlaceholder(variable_name="history"),
("human", "{input}"),
])
conversation = ConversationChain(
llm=llm,
memory=memory,
prompt=prompt,
verbose=True,
)
Now let us test the memory by having a multi-turn conversation:
print(conversation.predict(input="My name is Khaled."))
# Output: "Hello Khaled! Nice to meet you. How can I help you today?"
print(conversation.predict(input="What's my name?"))
# Output: "Your name is Khaled!"
The ConversationBufferMemory stores every message in the conversation. This is straightforward but can get expensive with very long conversations since all messages are sent to the API each time.
Using window memory for longer conversations
For production chatbots, you often want to limit how much history is sent to the model. ConversationBufferWindowMemory keeps only the last k exchanges:
from langchain.memory import ConversationBufferWindowMemory
window_memory = ConversationBufferWindowMemory(
k=5,
return_messages=True,
)
conversation_with_window = ConversationChain(
llm=llm,
memory=window_memory,
prompt=prompt,
verbose=False,
)
This keeps the context window manageable while still giving the bot enough history to maintain a coherent conversation.
Building a terminal chat loop
Let us put everything together into an interactive terminal chatbot:
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.memory import ConversationBufferWindowMemory
from langchain.chains import ConversationChain
load_dotenv()
llm = ChatOpenAI(
model="gpt-3.5-turbo",
temperature=0.7,
openai_api_key=os.getenv("OPENAI_API_KEY"),
)
memory = ConversationBufferWindowMemory(k=10, return_messages=True)
prompt = ChatPromptTemplate.from_messages([
("system", "You are Aria, a friendly and knowledgeable AI assistant. Be concise but thorough."),
MessagesPlaceholder(variable_name="history"),
("human", "{input}"),
])
conversation = ConversationChain(
llm=llm,
memory=memory,
prompt=prompt,
verbose=False,
)
print("Aria Chatbot (type 'quit' to exit)")
print("-" * 40)
while True:
user_input = input("\nYou: ").strip()
if user_input.lower() in ("quit", "exit"):
print("Goodbye!")
break
if not user_input:
continue
response = conversation.predict(input=user_input)
print(f"\nAria: {response}")
Streaming responses
Nobody likes staring at a blank screen while the model generates a long response. LangChain v0.1 makes streaming straightforward:
from langchain_core.callbacks import StreamingStdOutCallbackHandler
streaming_llm = ChatOpenAI(
model="gpt-3.5-turbo",
temperature=0.7,
streaming=True,
callbacks=[StreamingStdOutCallbackHandler()],
)
Replace the llm in your conversation chain with streaming_llm, and you will see tokens appear in real time as the model generates them.
Where to go from here
This chatbot is a solid starting point, but there is a lot more you can build on top of it. Here are a few directions to explore:
- Retrieval-Augmented Generation (RAG): Connect your chatbot to a knowledge base so it can answer questions from your own documents.
- Agents and Tools: Give your chatbot the ability to call external APIs, run calculations, or search the web using LangChain agents.
- Persistent Memory: Store conversation history in a database like Redis or PostgreSQL so memory survives across sessions.
- Deployment: Wrap your chatbot in a FastAPI server or deploy it as a Slack or Discord bot.
LangChain v0.1 brought stability and a cleaner architecture to the framework. If you have been hesitant to adopt LangChain because of its rapid pace of breaking changes, this is a good version to start with. The conversational primitives are solid, the LCEL syntax is intuitive, and the ecosystem of integrations continues to grow.
Start with the simple chain, add memory, and iterate from there. The best chatbot is one you actually ship.