Build an AI Chatbot with Python
This is the first real, complete project in this series — a working, terminal-based chatbot for Bright Leaf Coffee, using part 1's shared setup. It's deliberately the same real project the AI Fundamentals series built conceptually, now as a single, complete, standalone script.
The real, complete chatbot script
# chatbot.py
from shared.ai_client import get_client
PLAN_DATA = """
- Gift Subscription: $18/mo, 1 bag, free shipping
- Monthly Subscription: $16/mo, 1 bag, free shipping
- Double Bag: $30/mo, 2 bags, free shipping
"""
SYSTEM_PROMPT = f"""You are a customer support assistant for Bright
Leaf Coffee, a small-batch coffee subscription business.
Real, current plan data:
{PLAN_DATA}
Only answer using this real data. If you don't have the information
needed to answer, say so directly rather than guessing. Keep
responses to 2-3 sentences."""
def run_chatbot():
client = get_client()
history = []
print("Bright Leaf Coffee support — type 'quit' to exit\n")
while True:
user_input = input("You: ").strip()
if user_input.lower() in ("quit", "exit"):
break
history.append({"role": "user", "content": user_input})
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
system=SYSTEM_PROMPT,
messages=history,
)
answer = response.content[0].text
print(f"\nAssistant: {answer}\n")
history.append({"role": "assistant", "content": answer})
if __name__ == "__main__":
run_chatbot()Why every real design decision here matches earlier guidance
Real product data in the system prompt → grounding, preventing
hallucination
history list, resent every request → real, multi-turn memory
"say so directly rather than guessing" → explicit permission to
admit uncertaintyNothing here is a new pattern — it's the exact, real combination from the AI Fundamentals series' own project, assembled into one complete, runnable file rather than split across explanatory parts.
Running it, and a real, sample conversation
python chatbot.pyYou: What subscriptions do you offer?
Assistant: We offer three plans: a Gift Subscription ($18/mo, 1 bag),
a Monthly Subscription ($16/mo, 1 bag), and a Double Bag option
($30/mo, 2 bags) — all with free shipping.
You: Which one is cheapest per bag?
Assistant: The Monthly Subscription is the cheapest per bag at $16,
compared to $18 for the Gift Subscription and $15 for the Double Bag.The second real answer correctly does actual math across the real data provided — a genuine, direct demonstration of the model reasoning over the grounded context, not just repeating it verbatim.
Forgetting to append the assistant's own response back into history after printing it. Without that line, every new message loses all real prior context — the chatbot would answer each question in isolation, unable to correctly resolve something like "which one is cheapest" without genuinely remembering what "one" refers to from the previous real exchange.
A real, honest limitation of this version
No error handling for a real, failed request
No limit on how large history can grow — the exact real context-
window problem covered in the AI Fundamentals series
Runs only in a terminal — not something a real website visitor
could actually useThis is deliberate — this part's real goal is a complete, correct, minimal chatbot. Part 3 adds a real, simple web interface; later parts in this series add production concerns like error handling (part 7), caching (part 18), and testing (part 19) as dedicated topics, rather than bundling everything into one overloaded first example.
FAQ
Does the conversation history persist after the script exits?
No — history is a plain Python list living only in the running process's memory. Closing the terminal or restarting the script loses it entirely; adding real persistence means writing history to a file or database, which this deliberately minimal version doesn't do.
Can I swap in a different model without changing anything else?
Yes — model="claude-sonnet-5" is the only line that names a specific model; everything else (the message loop, the system prompt, the history list) is model-agnostic and works the same way regardless of which model string is passed.
Why keep the plan data in a Python string instead of a database?
Because this part's focus is the chatbot pattern itself — grounding, history, uncertainty handling — not data storage. A real version would query PLAN_DATA from wherever pricing actually lives (a database, a CMS, a pricing API), with everything else in this file unchanged.
Next: adding a real, simple web UI to this chatbot with Flask, so it's something an actual visitor could use in a browser.