~/TechPurAI
~/tutorials/ai-projects-with-python/build-an-ai-chatbot-with-python
beginner·part 2 of 22·4 min read

Build an AI Chatbot with Python

Updated Aug 31, 2026Python · AI

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

python
# 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

text
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 uncertainty

Nothing 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

bash
python chatbot.py
text
You: 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.

Common mistake

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

text
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 use

This 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.

VK

Vijay Kumar

Founder of TechPurAI — writing hands-on tutorials and honest tool breakdowns.

LinkedIn ↗
← previous1. Setting Up a Real Python AI Projectnext →3. Adding a Simple Web UI to Your Python Chatbot