17  Debugging

17.1 The Wall

You pasted an error message into AI and it gave you a “fix” that introduced a different error. You pasted that error in and got yet another fix. Three rounds later, the code was completely different from what you started with and you had no idea what changed or why.

The problem was not AI’s debugging ability. It was that you could not isolate the bug yourself. You gave AI the entire program and said “fix it” instead of identifying which specific part was failing. AI cannot debug effectively without precise context, and you could not provide that context.

This chapter fixes that.

17.2 Thinking Session

17.2.1 Getting Oriented

NoteThinking Session Prompt

What are the main debugging strategies in Python? I know I can paste errors into AI, but I want to understand how to narrow down where a bug is before I ask for help. What is print debugging, what is the Python debugger (pdb), and when would I use each?

Your AI should explain: print debugging (adding print() statements to trace values) is quick and works everywhere. pdb (Python debugger) lets you step through code line by line. The strategy matters more than the tool: isolate the bug first, then fix it.

17.2.2 Go Deeper

NoteThinking Session Prompt

When I have a bug, what is a systematic process for finding it? Not just “add print statements everywhere”, give me a step-by-step method. How do I narrow down which function, which line, which variable is causing the problem?

TipWhat to Look For

A good debugging process: (1) reproduce the bug reliably, (2) form a hypothesis about what is wrong, (3) test the hypothesis by checking values at specific points, (4) fix the smallest thing possible, (5) verify the fix did not break something else. This is scientific method applied to code.

NoteThinking Session Prompt

How should I use AI for debugging effectively? What information should I include when I ask AI to help me fix a bug? What is the difference between “fix my code” and a good debugging prompt?

17.2.3 Challenge It

NoteThinking Session Prompt

This code is supposed to count vowels in a string but returns the wrong number. Debug it, do not just fix it, explain how you would find the bug step by step.

def count_vowels(text):
    vowels = "aeiou"
    count = 0
    for char in text:
        if char in vowels:
            count += 1
    return count

result = count_vowels("Hello World")
print(f"Vowels: {result}")  # Expected: 3, Got: 3
TipWhat to Look For

Trick question. This code is actually correct for lowercase vowels. But it misses uppercase vowels. "Hello World" has 3 lowercase vowels (e, o, o) and 0 uppercase. If the expected count was 3, the code works. But if the user expected to count “E” too, the fix is text.lower() or vowels = "aeiouAEIOU". The lesson: always clarify what “correct” means.

17.2.4 What You Should Have Learned

  • Debugging is a process: reproduce, hypothesise, test, fix, verify
  • Print debugging: add print(f"DEBUG: {variable=}") at key points
  • pdb: breakpoint() in your code to pause and inspect
  • When asking AI for help: include the error, the relevant code, what you expected, and what you tried
  • Do not ask AI to “fix my code”, ask it to explain why a specific line produces a specific result

17.3 The Gap

You now have a debugging process that works with or without AI. When you encounter a bug, you can narrow it down to a specific function, a specific line, a specific variable. When you do ask AI for help, you can provide precise context instead of dumping the entire program.

In the Building Session, you will add a debug mode to your chatbot.

17.4 Building Session

17.4.1 The Spec

Add a debug mode to your chatbot:

  • A --debug flag or “debug” command that toggles verbose output
  • In debug mode, show: the raw input, the classified category, the selected response, and the current history length
  • Debug output should be visually distinct from normal output

17.4.2 Prompt It

NoteBuilding Session Prompt

Update my chatbot to v1.7. Add a debug mode:

  • Add a DEBUG constant (default False)
  • Add a “debug” command that toggles debug mode on/off
  • When debug mode is on, after each message print: [DEBUG] Raw input: “…” [DEBUG] Category: “greeting” [DEBUG] History length: 15
  • Use a debug_log() function that only prints when DEBUG is True
  • Debug output should use [DEBUG] prefix to distinguish from normal output

Keep existing features.

17.4.3 Read the Code

Your AI will produce something like this:

debug_mode = False


def debug_log(*args):
    """Print debug info only when debug mode is on."""
    if debug_mode:
        print("[DEBUG]", *args)


# In the main loop:
    if command == "debug":
        debug_mode = not debug_mode
        status = "ON" if debug_mode else "OFF"
        print(f"{BOT_NAME}: Debug mode {status}")
        continue

    category = classify_input(user_input)
    debug_log(f"Raw: '{user_input}'")
    debug_log(f"Category: {category}")
    debug_log(f"History: {len(history)} entries")

    response, should_exit = get_response(user_input)
    debug_log(f"Response: '{response}'")
TipWhat to Notice

debug_log() uses *args to accept any number of arguments, just like print(). The [DEBUG] prefix makes debug output instantly recognisable. The toggle uses not debug_mode to flip the boolean. This pattern. A function that conditionally prints, is how professional code handles debug output.

17.4.4 Stretch It

NoteBuilding Session Prompt

Add timing to the debug output. Use import time and time.time() to measure how long each response takes to generate. Show it as “[DEBUG] Response time: 0.002s”.

17.5 Your Chatbot So Far

  • Ch 1-15: Full features with file persistence
  • Ch 16: Error handling and logging
  • Ch 17: Debug mode with toggle and verbose output

17.6 Quick Reference

# Print debugging
print(f"DEBUG: {variable=}")        # Python 3.8+
print(f"DEBUG: x={x}, y={y}")

# Python debugger
breakpoint()  # pauses execution here
# Commands: n (next), s (step in), c (continue),
#           p variable (print), q (quit)

# Conditional debug output
def debug_log(*args, enabled=False):
    if enabled:
        print("[DEBUG]", *args)

# Assert (catches impossible states)
assert len(items) > 0, "List should not be empty"