Learn Python by Building a Chatbot
Hands-on lab · IDE in your browser

Learn Python by Building a Chatbot

Learn the Python you need for AI work by building a real chat assistant, one idea per step: variables and f-strings for its instructions, lists and dictionaries for its memory, a while loop that reads what you type, if/elif/else for commands and limits, and slicing to keep a long conversation from growing without end.

Time
50 min
Checked steps
5
Level
Beginner
Setup
None
Read step 1

Hands-on labs require Pro · $29.99/mo · cancel anytime

Lab cockpit50 min · 5 stepsSession running
4 / 5 steps passingSlicing: keep long chats fast and cheap · step 5 of 5
chatbot.py▶ Run✓ Check
# ---------- Step 5: slicing ----------def trim(history, max_messages):    """Keep the system message plus only the newest max_messages messages."""  
TerminalOutput

The job

Brightline Books wants a chat assistant it can try out in a terminal before anything goes on the website. You build it in chatbot.py, and each step adds one piece of Python: a function that writes the assistant's instructions, a list of messages that gives it a memory, the loop that reads what a customer types, commands and a length limit, and a trim that keeps long chats fast and cheap. By the end you can talk to it with python3 chatbot.py, and you will have used the Python that most AI code is written in.

5 steps, each checked when you finish it

A check runs your work at the end of every step. Hints and the full solution are there if you get stuck.

  1. 1

    Variables and strings: write the assistant's instructions

    Every assistant starts with a paragraph of instructions, the *system prompt*, telling the model who it is and how to answer.

    You writebuild_system_prompt()
  2. 2

    Lists and dictionaries: give the bot a memory

    A language model remembers nothing between calls.

    You writenew_history()add_message()
  3. 3

    The loop: keep the conversation going

    A conversation is the same four moves repeated: read what the customer typed, add it to the history, ask the model, show the answer.

  4. 4

    Decisions: commands and a length limit

    Not every line should go to the model.

    You writehandle()
  5. 5

    Slicing: keep long chats fast and cheap

    Every turn resends the whole history, so each call is bigger than the last.

    You writetrim()

Step 1 as it appears in the lab

The lab’s own text. The hint and the solution stay inside the lab.

Step 1: Variables and strings: write the assistant's instructions

Every assistant starts with a paragraph of instructions, the system prompt, telling the model who it is and how to answer. Brightline will want to change the tone and length without rewriting the sentence, so you write it once as a function that fills in the parts that change.

Three Python ideas do all the work:

  • A variable is a name for a value. SHOP = "Brightline Books" near the top of chatbot.py is one. Text in quotes is a string.
  • A function is a named recipe. def build_system_prompt(shop, tone, max_sentences): takes three values (its parameters) and return hands one value back.
  • An f-string puts values inside text: f"Hello {name}" becomes Hello Sam when name is "Sam". The f before the quote switches it on.
Do this

1. Write build_system_prompt(). Return this sentence, with the three parameters in the braces:

return (
    f"You are the assistant of {shop}, an independent bookshop. "
    f"Answer in a {tone} tone, in at most {max_sentences} sentences."
)

Two strings side by side inside brackets are joined into one, which lets a long sentence span two lines. Mind the space before the closing quote of the first line.

2. Run. It builds the prompt with a cheerful tone and a two-sentence limit, sends it with a question, and prints the answer. Change "cheerful" to "formal" in try_it.py and run again: one word changes the whole voice.

chatbot.py, the file you edit64 lines
"""Brightline Books' chat assistant, one Python idea per step.

Run it yourself in the terminal:   python3 chatbot.py
(type a message and press Enter; type quit to stop)
"""
from openai import OpenAI

CLIENT = OpenAI()
MODEL = "meta/llama-3.1-8b-instruct"

SHOP = "Brightline Books"
MAX_CHARS = 500


# ---------- Step 1: variables, strings and a function ----------
def build_system_prompt(shop, tone, max_sentences):
    """Return the assistant's standing instructions as one string."""
    # TODO (Step 1): return ONE string built with an f-string, exactly:
    #   You are the assistant of <shop>, an independent bookshop. Answer in a <tone> tone, in at most <max_sentences> sentences.
    # where <shop>, <tone> and <max_sentences> are the three parameters.
    raise NotImplementedError("Step 1: write build_system_prompt()")


# ---------- Step 2: lists and dictionaries ----------
def new_history(system_prompt):
    """A fresh conversation: a list holding only the system message."""
    raise NotImplementedError("new_history() arrives in Step 2")


def add_message(history, role, content):
    """Append one message to the conversation (changes the list in place)."""
    raise NotImplementedError("add_message() arrives in Step 2")


def reply(history, client=None):
    """Send the whole conversation, store the model's answer in it, return the answer."""
    client = client or CLIENT
    response = client.chat.completions.create(model=MODEL, messages=history, temperature=0.3)
    answer = response.choices[0].message.content
    add_message(history, "assistant", answer)
    return answer


# ---------- Step 4: decisions (if / elif / else) ----------
def handle(line, history, client=None):
    """Decide what to do with one line the user typed. Return the text to show."""
    raise NotImplementedError("handle() arrives in Step 4")


# ---------- Step 5: slicing ----------
def trim(history, max_messages):
    """Keep the system message plus only the newest max_messages messages."""
    raise NotImplementedError("trim() arrives in Step 5")


# ---------- Step 3: a loop that reads what the user types ----------
def chat(read=input, show=print, client=None, max_messages=None):
    """Run the conversation until the user types quit. Return the history."""
    history = new_history(build_system_prompt(SHOP, "warm", 3))
    raise NotImplementedError("chat() arrives in Step 3")


if __name__ == "__main__":
    chat(max_messages=20)
Provided for you:try_it.py

Frequently asked questions

Is this lab for complete beginners?

Yes. Every step explains the Python it uses, shows the lines to write, and the checker tells you what to change when something is off. You write around 50 lines.

Why does the chatbot forget things between calls?

A language model keeps nothing between requests. A chatbot looks like it remembers because the program resends the whole conversation, as a list of messages, on every turn. Step 2 shows both versions side by side.

Why trim the conversation?

Every turn resends all earlier messages, so the prompt, the cost and the wait grow with the chat. Keeping the system message plus the newest messages holds them flat. Step 5 prints the prompt size per turn with and without the trim.

Do I need an API key?

No. The lab environment is already connected to a hosted Llama 3.1 8B model.

Why build a chatbot to learn Python

Most beginner Python courses teach variables, lists, loops and conditions on toy examples, and the link to real work comes much later. A chatbot needs every one of those ideas at once, for a reason you can see: the assistant's instructions are a string built from variables, its memory is a list of dictionaries, the conversation is a loop, commands are conditions, and a long chat has to be sliced to stay within the model's limits. In this lab you write those pieces in order and talk to a hosted language model after every step. You see that a model has no memory of its own, since each call only knows the messages you send, and you watch the prompt size grow turn after turn until a slice keeps it flat. Each checker tests your function with a stand-in model that records what you sent and then runs it against the real one.