🤖 AI Language Models & Prompt Engineering¶

⚙️ 1. Setup¶

It checks that the required packages are installed and connects to the AI server running on the Strix board.

  • The bootcamp_ai module handles all the network communication for us.
  • It exposes a simple launch_chat() function that opens an interactive chat panel
  • prompt() function for use directly in code.
In [ ]:
# Import our bootcamp AI helper
from bootcamp_ai import launch_chat, prompt, reset, list_models, use_model

# Check what models are available on the server
print("Models available on the Strix:", list_models())
print("\n✅ Setup complete. You are ready to go!")

Note: If you see an empty list or a connection error, the AI server on the Strix may not be running. Reach out to the instructor

🧠 2. What Is an LLM?¶

Large Language Model

A text prediction engine trained on billions of web pages, books, articles, and code.

🔁 One trick, repeated many times¶

The model does exactly one thing: predict the most likely next word, over and over, until the answer is complete.

🧠 Your brain does this too — without thinking
Finish this: "The sky is ___"
blue
89%
grey
7%
clear
3%
🔁 You knew it was "blue" instantly — because you've heard that phrase thousands of times. The LLM does the same thing, but it has read billions of sentences.
💡 The idea: an LLM isn't magic — it learned patterns the same way you did, just from a lot more reading. That's why it can finish sentences, answer questions, and write code.

🎯 What this means for you¶

  • Not a search engine — it generates from patterns, doesn't look things up
  • Different answer each time — there's built-in randomness, controlled by a setting called temperature
  • Can be confidently wrong — likely-sounding ≠ true

🎮 Try It — Think Like an AI!¶

Type the start of any sentence below and see what word the AI thinks comes next. Can you predict it before the AI does?

  1. the cat sat on the
  2. the kria kv260 is a powerful
  3. python is a
In [ ]:
# ===== GAME: Next-Word Predictor (run me, then click!) =====
import ipywidgets as widgets
from IPython.display import display, HTML, clear_output
import random

_DB = {
    "the cat sat on the": [("mat",61),("floor",18),("roof",9),("sofa",7),("bed",5)],
    "the kria kv260 is a powerful": [("FPGA",64),("board",21),("chip",9),("computer",4),("tool",2)],
    "python is a": [("programming",45),("popular",22),("high-level",18),("versatile",10),("great",5)],
}

def _bars(probs):
    cols = ["#4ade80","#38bdf8","#fbbf24","#a78bfa","#fb923c"]
    out = ""
    for i,(t,p) in enumerate(probs):
        out += (f"<div style='display:flex;align-items:center;gap:8px;margin:5px 0;'>"
                f"<div style='width:130px;text-align:right;font-family:monospace;font-size:13px;color:#e7edf5;'>{t}</div>"
                f"<div style='background:{cols[i%5]};height:20px;width:{max(8,int(p*2.6))}%;border-radius:4px;'></div>"
                f"<div style='color:{cols[i%5]};font-weight:700;font-size:12px;'>{p}%</div></div>")
    return out

def _lookup(text):
    t = text.strip().lower().rstrip(".!?,")
    for k in _DB:
        if t.endswith(k):
            return _DB[k]
    pcts = sorted([random.randint(5,50) for _ in range(5)], reverse=True)
    tot = sum(pcts)
    return list(zip(["the","is","a","and","to"], [round(p/tot*100) for p in pcts]))

_inp = widgets.Text(value="The Kria KV260 is a powerful",
                    layout=widgets.Layout(width="480px"))
_btn = widgets.Button(description="Predict next word!", button_style="primary",
                      layout=widgets.Layout(width="170px", height="36px"))
_out = widgets.Output()

def _go(_):
    probs = _lookup(_inp.value)
    with _out:
        clear_output(wait=True)
        display(HTML(
            f"<div style='font-family:sans-serif;background:#0f1419;border-radius:10px;padding:16px;margin-top:8px;'>"
            f"<div style='color:#8a97ab;font-size:12px;margin-bottom:8px;'>Your text: "
            f"<em style='color:#e7edf5;'>\"{_inp.value}\"</em></div>{_bars(probs)}"
            f"<div style='margin-top:10px;color:#4ade80;font-size:12px;'>The model picks "
            f"<b>{probs[0][0]}</b>, adds it, and predicts again!</div></div>"))

_btn.on_click(_go)
display(HTML("<div style='font-family:sans-serif;font-size:16px;font-weight:700;color:#1e2a4a;'>"
             "&#127918; GAME: Be the AI &mdash; Predict the Next Word</div>"
             "<div style='font-size:13px;color:#64748b;margin-bottom:8px;'>Type the start of a "
             "sentence and see the model's top 5 guesses. Try the examples in the boxes above!</div>"))
display(widgets.HBox([_inp, _btn]))
display(_out)
_go(None)

💬 Your turn — type these into the chat panel:¶

1. Explain what an LLM is in two sentences, for a high school student.

2. Finish this sentence: If your Jupyter notebook kernel crashes, the first thing you should

3. Write one sentence about robots.

→ Now click ✦ New chat and type the exact same thing again.

→ Did you get the same words? That's not a bug — that's the AI being creative. 🎲

In [ ]:
# Each launch_chat() creates its own independent memory session.
launch_chat()

🧩 3. Tokens — How the Model Reads¶

The model doesn't read words — it reads tokens (word chunks).

  • "basketball" → "basket" + "ball" — two tokens!
  • Rule of thumb: 1 token ≈ ¾ of a word → 100 words ≈ 133 tokens

💰 Why it matters¶

What Unit
How much the model can remember tokens
How fast it responds tokens/second
How much it costs on paid APIs tokens

👀 Watch the "answered in X.Xs" line under each chat reply — that's token speed, live!

🧩 The AI reads TOKENS, not words
Even "ChatGPT" gets split into 3 tokens:
ChatGPT
Rule of thumb: 1 token ≈ three-quarters of a word  ·  100 words ≈ 133 tokens
🌐 Real life: Paid AI services (like the ChatGPT API) charge you per token. A long chatbot conversation literally costs more money because more tokens are processed.

🧩 Watch Words Break Apart — Live!¶

Type anything below and see it split into tokens as you type. Try your name, a long word, or even some code!

Try:

  1. I love building robots on kv260
  2. Today is day 1 of the pynq bootcamp
  3. I live in colorado
In [ ]:
# ===== GAME: Live Token Counter (type and watch!) =====
import ipywidgets as widgets
from IPython.display import display, HTML, clear_output
import re

def _tok(text):
    if not text: return []
    raw = re.findall(r"[A-Z][a-z]*|[a-z]+|[0-9]+|[^a-zA-Z0-9\s]", text)
    out = []
    for r in raw:
        if len(r) > 5:
            m = len(r)//2; out += [r[:m], r[m:]]
        else: out.append(r)
    return out or [text]

_cols = ["#3b5bdb","#db2777","#059688","#ea580c","#7c3aed","#16a34a","#0284c7"]
_ta = widgets.Textarea(value="I love building robots on the KV260!",
                       layout=widgets.Layout(width="600px", height="55px"))
_o = widgets.Output()

def _upd(_):
    toks = _tok(_ta.value)
    chips = "".join(
        f"<span style='display:inline-block;background:{_cols[i%7]};color:#fff;"
        f"padding:4px 10px;border-radius:14px;font-size:13px;font-weight:600;"
        f"margin:3px;font-family:monospace;'>{t}</span>" for i,t in enumerate(toks))
    with _o:
        clear_output(wait=True)
        display(HTML(
            f"<div style='font-family:sans-serif;margin-top:8px;'>"
            f"<div style='display:flex;gap:14px;margin-bottom:12px;'>"
            f"<div style='background:#eef1ff;border-radius:8px;padding:8px 16px;text-align:center;'>"
            f"<div style='font-size:24px;font-weight:700;color:#3b5bdb;'>{len(toks)}</div>"
            f"<div style='font-size:11px;color:#64748b;'>tokens</div></div>"
            f"<div style='background:#fce7f3;border-radius:8px;padding:8px 16px;text-align:center;'>"
            f"<div style='font-size:24px;font-weight:700;color:#db2777;'>{len(_ta.value)}</div>"
            f"<div style='font-size:11px;color:#64748b;'>characters</div></div>"
            f"<div style='background:#dcfce7;border-radius:8px;padding:8px 16px;text-align:center;'>"
            f"<div style='font-size:24px;font-weight:700;color:#16a34a;'>{len(_ta.value.split())}</div>"
            f"<div style='font-size:11px;color:#64748b;'>words</div></div></div>"
            f"<div>{chips}</div>"
            f"<div style='margin-top:8px;font-size:11px;color:#94a3b8;'>Each chip = 1 token. "
            f"Long words split into pieces!</div></div>"))

_ta.observe(_upd, names="value")
display(HTML("<div style='font-family:sans-serif;font-size:16px;font-weight:700;color:#1e2a4a;'>"
             "&#127918; GAME: Live Token Counter</div>"
             "<div style='font-size:13px;color:#64748b;margin-bottom:8px;'>Type anything and watch it "
             "break into tokens as you type. Try a really long word!</div>"))
display(_ta); display(_o); _upd(None)

💬 Try it yourself:¶

  1. Break the word 'basketball' into token-sized pieces and show each piece.
  2. Roughly how many tokens is the sentence "I love building robots with Python"?
  3. Ask for a 1-sentence answer on any topic, then ask for a 10-sentence answer on the same topic. Watch the timing line -> more tokens = more time.

💡 Switch between Quick Helper (8B) and Code Helper (30B) in the dropdown — bigger model, slower tok/s.

In [ ]:
# Open a chat panel for Part 3.
launch_chat()

💡 The chat panel shows "answered in X.Xs (first word Y.Ys)" under each reply. The "first word" time is how long until tokens started arriving.

Use the model dropdown to switch between Quick Helper (8B) and Code Helper (30B) and compare the tok/s — bigger model, slower speed.

💬 4. Context and Memory¶

🤯 Surprising fact: The AI has zero built-in memory. Every message starts completely fresh.

So how does it remember you? We keep a running list of the conversation and re-send it every single turn — that list is called the context.

Turn 1:  We send  → ["User: My name is Nikhitha."]
         We get   → "Nice to meet you, Nikhitha!"

Turn 2:  We send  → ["User: My name is Nikhitha.",
                      "AI: Nice to meet you, Nikhitha!",
                      "User: What is my name?"]   ← full history every time
         We get   → "Your name is Nikhitha!"

📝 Think of it like a whiteboard that runs out of space — old notes get erased to make room for new ones.

🧪 See It Yourself — Does the AI Remember You?¶

Enter your name and hit the button. The AI gets asked the same question twice — once with memory, once without. Watch what happens!

In [ ]:
# ===== GAME: Memory ON vs OFF (asks the real AI!) =====
import ipywidgets as widgets
from IPython.display import display, HTML, clear_output

_nm = widgets.Text(value="Maya", description="Your name:",
                   style={"description_width":"80px"}, layout=widgets.Layout(width="300px"))
_b = widgets.Button(description="Ask both: What is my name?", button_style="primary",
                    layout=widgets.Layout(width="250px", height="38px"))
_o = widgets.Output()

def _go(_):
    name = _nm.value.strip() or "Maya"
    with _o:
        clear_output(wait=True); print("Asking the AI both ways...")
    reset()
    prompt(f"My name is {name} and I'm at the PYNQ Bootcamp.", enforce_cooldown=False)
    on = prompt("What is my name?", enforce_cooldown=False)
    reset()
    off = prompt("What is my name?", enforce_cooldown=False)
    with _o:
        clear_output(wait=True)
        display(HTML(
            f"<div style='font-family:sans-serif;display:flex;gap:12px;margin-top:8px;'>"
            f"<div style='flex:1;background:#dcfce7;border:2px solid #22c55e;border-radius:10px;padding:12px;'>"
            f"<div style='font-weight:700;color:#15803d;font-size:12px;margin-bottom:6px;'>&#9989; MEMORY ON</div>"
            f"<div style='font-size:12px;color:#374151;'>{on[:180]}</div></div>"
            f"<div style='flex:1;background:#fee2e2;border:2px solid #ef4444;border-radius:10px;padding:12px;'>"
            f"<div style='font-weight:700;color:#b91c1c;font-size:12px;margin-bottom:6px;'>&#10060; MEMORY OFF</div>"
            f"<div style='font-size:12px;color:#374151;'>{off[:180]}</div></div></div>"
            f"<div style='font-family:sans-serif;margin-top:10px;background:#fef9c3;border:1px solid #fbbf24;"
            f"border-radius:8px;padding:10px;font-size:12px;color:#78350f;'>&#128161; Same question, same AI &mdash; "
            f"the only difference is whether we sent the history list. That list <b>is</b> the memory!</div>"))

_b.on_click(_go)
display(HTML("<div style='font-family:sans-serif;font-size:16px;font-weight:700;color:#1e2a4a;'>"
             "&#127918; GAME: Memory ON vs OFF</div>"
             "<div style='font-size:13px;color:#64748b;margin-bottom:8px;'>Enter your name, then watch the "
             "AI answer the SAME question two ways &mdash; with and without memory.</div>"))
display(widgets.HBox([_nm, _b])); display(_o)

💬 Now Try It in the Chat Panel¶

Step 1 - show that it remembers:

  1. My name is [your name] and my PYNQ project is about [your project].
  2. What is my name and what am I building? — it remembers, because both messages are in the context.

Step 2 - erase the memory:

  1. Click ✦ New chat at the top of the panel.

  2. What is my name? — it has no idea. The context list was emptied.

In [ ]:
# Open a chat panel for Part 4.
launch_chat()

Key takeaway: Memory in AI is not magic — it is a Python list that gets re-sent each turn. The "New chat" button deletes that list.

✍️ 5. Prompt Engineering¶

A prompt is the text you send to an AI model. Prompt engineering is the practice of crafting and refining prompts to elicit better, more accurate, and more useful responses from the model.

According to Google Cloud, prompt engineering is an iterative, test-driven process — you write a prompt, evaluate the output, refine the wording, and repeat. The structure of a prompt (ordering, labeling, use of delimiters) matters just as much as its content.

🧬 The anatomy of a strong prompt¶

A well-engineered prompt typically combines some of these ingredients:

Ingredient Purpose Example
Role Sets the model's persona, tone, and expertise You are an experienced hardware engineer.
Task States exactly what you want Explain how an FPGA differs from a CPU.
Format Specifies how the answer should be structured Give your answer in exactly 3 bullet points.
Audience Adjusts vocabulary and detail level Write for a high school student with no prior experience.
Constraints Sets limits or rules Keep your answer under 100 words.

You do not need all five every time, but more direction usually means a better answer.

✍ The 5 ingredients of a strong prompt
🎭
Role
who to be
📝
Task
what to do
📋
Format
how to lay out
👥
Audience
who it is for
⛓
Limits
rules
🌐 Real life: Prompt engineering is now a real job title — companies pay people to write prompts that get reliable answers from AI. The skill you learn here is genuinely used in industry.

⚔️ Weak vs Strong — Which Prompt Wins?¶

Edit both sides, click Run the Duel, and see the difference a well-engineered prompt makes!

In [ ]:
# ===== GAME: Prompt Duel (edit both, then RUN!) =====
import ipywidgets as widgets
from IPython.display import display, HTML, clear_output

_w = widgets.Textarea(value="Tell me about FPGAs.", description="Weak:",
    layout=widgets.Layout(width="48%", height="75px"), style={"description_width":"55px"})
_s = widgets.Textarea(
    value="You are a hardware engineer. Explain what an FPGA is and give 3 examples, for a high school student.",
    description="Strong:", layout=widgets.Layout(width="48%", height="75px"),
    style={"description_width":"55px"})
_b = widgets.Button(description="Run the Duel!", button_style="primary",
                    layout=widgets.Layout(width="160px", height="38px"))
_l = widgets.Output(layout=widgets.Layout(width="48%", border="2px solid #ef4444", padding="8px"))
_r = widgets.Output(layout=widgets.Layout(width="48%", border="2px solid #22c55e", padding="8px"))
_why = widgets.Output()

def _an(bef, aft):
    b, a = bef.lower(), aft.lower(); t = []
    if "you are" not in b and "you are" in a: t.append("&#127917; added a ROLE")
    if not any(w in b for w in ("bullet","step","example","point")) and any(w in a for w in ("bullet","step","example","point")): t.append("&#128203; added a FORMAT")
    if not any(w in b for w in ("grader","student","for a")) and any(w in a for w in ("grader","student","for a")): t.append("&#128101; named an AUDIENCE")
    if len(aft) > len(bef)*1.3: t.append("&#128269; more DETAIL")
    return t or ["&#128221; more specific"]

def _go(_):
    for o in (_l,_r,_why): o.clear_output()
    with _l: print("thinking...")
    with _r: print("thinking...")
    reset(); wa = prompt(_w.value, enforce_cooldown=False)
    reset(); sa = prompt(_s.value, enforce_cooldown=False)
    _l.clear_output(); _r.clear_output()
    with _l: print("WEAK ANSWER\n" + "-"*24 + "\n" + wa)
    with _r: print("STRONG ANSWER\n" + "-"*24 + "\n" + sa)
    with _why:
        clear_output(wait=True)
        display(HTML("<div style='font-family:sans-serif;background:#fffbf0;border:1.5px solid #f59f00;"
                     "border-radius:8px;padding:12px;margin-top:10px;'><b style='color:#6b4f00;'>"
                     "&#128161; What made the strong prompt win:</b>&nbsp;&nbsp;"
                     + "&nbsp;&bull;&nbsp;".join(_an(_w.value, _s.value)) + "</div>"))

_b.on_click(_go)
display(HTML("<div style='font-family:sans-serif;font-size:16px;font-weight:700;color:#1e2a4a;'>"
             "&#127918; GAME: Prompt Duel</div>"
             "<div style='font-size:13px;color:#64748b;margin-bottom:8px;'>Edit the weak and strong prompts, "
             "click Run, and see who wins!</div>"))
display(widgets.HBox([_w, _s])); display(_b); display(widgets.HBox([_l, _r])); display(_why)

🎯 5.1 Zero-Shot — Just Ask¶

No examples. The AI uses only what it already knows.

Best for: summarising, translating, brainstorming, general questions.

In [ ]:
# Zero-shot: just ask, no examples provided.
reset()


result = prompt(
    "Summarise what an FPGA is and give one real-world use case. Keep it under 60 words.",
    enforce_cooldown=False
)
print(result)

1️⃣ 5.2 One-Shot — Show One Example¶

Show the AI one example of what you want, and it follows the pattern.

# One-shot example
Convert a technical term into a simple one-sentence definition.

Term: FPGA
Definition: A chip you can reprogram to act as custom hardware for a specific task.

Term: Tensor
Definition:

The model sees the Term → Definition pattern from one example and continues it.

When to use it: When you need a specific output format and zero-shot gives inconsistent results, but you only have one good example to provide.

In [ ]:
# One-shot: one example to set the pattern, then the real question.
reset()
one_shot_prompt = """Convert a technical term into a simple one-sentence definition.

Term: FPGA
Definition: A chip you can reprogram to act as custom hardware for a specific task.

Term: Tensor
Definition:"""

print(prompt(one_shot_prompt, enforce_cooldown=False))

📚 5.3 Few-Shot Prompting¶

  • Few-shot prompting provides multiple examples (typically 2–5) of the pattern you want.

  • The model identifies the relationship between inputs and outputs from those examples and applies the same pattern to the new input.

# Few-shot example — classify sensor readings
Classify the sensor reading as NORMAL, WARNING, or CRITICAL.

Reading: Temperature 22°C  → NORMAL
Reading: Temperature 78°C  → WARNING
Reading: Temperature 105°C → CRITICAL
Reading: Temperature 91°C  →

When to use it: Custom classification, unusual output formats, consistent style enforcement, or any task where zero-shot gives variable results.

In [ ]:
# Few-shot: three examples teach the model the classification pattern.
reset()
few_shot_prompt = """Classify the sensor reading as NORMAL, WARNING, or CRITICAL.

Reading: Temperature 22°C  -> NORMAL
Reading: Temperature 78°C  -> WARNING
Reading: Temperature 105°C -> CRITICAL
Reading: Temperature 91°C  ->"""

print(prompt(few_shot_prompt, enforce_cooldown=False))

⚡ Zero-Shot vs Few-Shot — Spot the Difference¶

In [ ]:
reset()
zero = prompt("Is a CPU temperature of 91°C normal, a warning, or critical?", enforce_cooldown=False)
reset()
few = prompt(few_shot_prompt, enforce_cooldown=False)

print("=" * 60)
print("🔴 ZERO-SHOT  —  no examples given")
print("=" * 60)
print(zero)

print()
print("=" * 60)
print("🟢 FEW-SHOT  —  examples locked the format")
print("=" * 60)
print(few)

print()
print("💡 Notice: zero-shot writes a paragraph.")
print("   Few-shot gives exactly ONE word — the format was learned from examples!")

🔗 5.4 Chain-of-Thought — Show Your Work¶

Instead of jumping to an answer, ask the AI to think out loud.

Just add "Think step by step." to any prompt — that's it.

Variant How it works Example
Zero-Shot CoT Add "Think step by step" to any question "How long does a 500-loop take? Think step by step."
Standard CoT Show an example with steps, then ask your question Give a solved example first, then ask the real one

Best for: maths, debugging, logic puzzles — anything where the steps matter more than a quick answer.

In [ ]:
# Without Chain-of-Thought: the model may give a direct answer that skips reasoning.
reset()
without_cot = prompt(
    "A loop runs 500 times. Each iteration takes 3ms. How long does the loop take in total?",
    enforce_cooldown=False
)
print("WITHOUT CoT:")
print(without_cot)
In [ ]:
# WITH Chain-of-Thought: ask the model to show its work.
# "Think step by step" is the simplest CoT trigger — it works surprisingly well.
reset()
with_cot = prompt(
    "A loop runs 500 times. Each iteration takes 3ms. "
    "How long does the loop take in total? Think step by step.",
    enforce_cooldown=False
)
print("WITH CoT:")
print(with_cot)

🐛 Real Example — Debug with Chain-of-Thought¶

In [ ]:
# CoT is especially powerful for debugging.
# Ask the model to reason through the bug before suggesting a fix.
reset()
buggy_code = """
def average(numbers):
    total = 0
    for n in numbers:
        total += n
    return total / len(numbers)

print(average([]))  # crashes!
"""

debug_prompt = (
    f"Here is a Python function that crashes:\n{buggy_code}\n"
    "Explain step by step WHY it crashes, then suggest the fix."
)

print(prompt(debug_prompt, enforce_cooldown=False))

🎭 5.5 Role Prompting — Give the AI a Persona¶

Start your prompt with "You are a ___." and the AI changes its entire voice.

  • 🗣️ Tone — formal or casual
  • 📖 Vocabulary — jargon or plain language
  • 🎯 Behaviour — what it will and won't say

The role sticks for the whole conversation — because it lives in the context.

In [ ]:
# We have ONE question — but we'll ask it THREE times with a different role each time
question = "Explain what is python programming language."

# Each row is: (the role we give the AI,   the label we print)
roles = [
    ("a friendly teacher explaining to a 12-year-old",  "TEACHER"),
    ("an excited sports commentator",                    "SPORTS CASTER"),
    ("a YouTuber making a fun tech video for teens",     "YOUTUBER"),
]

for role_desc, label in roles:
    reset()  # wipe memory so each role starts fresh

    # ↓ THIS is where the role is added — right at the start of the prompt!
    # "You are a friendly teacher..." tells the AI WHO to be before answering.
    answer = prompt(f"You are {role_desc}. {question} Keep it to 2 sentences.",
                    enforce_cooldown=False)

    print(f"[{label}] {answer}")
    print("-" * 50)

# The question never changes — only "You are ___." changes.
# That one phrase completely transforms the AI's tone, vocabulary, and style.

✅ 5.6 Prompt Engineering Best Practices¶

The following guidelines come from Google Cloud's prompt engineering research:

Practice Why it helps
Be specific Vague prompts produce vague answers. State exactly what you need.
Define the output format Tell the model how to structure the answer (bullet list, table, code block, etc.)
Use delimiters Separate instructions from content using ---, triple quotes, or XML-style tags
Label your sections Use headings like Input: and Output: to help the model parse complex prompts
Iterate Treat prompting as a test-driven loop — evaluate the output and refine the wording
Order matters The model pays more attention to content at the start and end of long prompts
Add constraints "Keep under 100 words" or "do not use jargon" prevents unwanted behaviours
Ask for self-critique "What might be wrong with the answer you just gave?" can catch errors

✅ Best Practices in Action — A Structured Prompt¶

In [ ]:
# Best practices in action: a well-structured prompt using delimiters and labels.

reset()
structured_prompt = """
You are a PYNQ board technical assistant.

Task: Review the code below and identify any bugs or improvements.

Output format:
- BUGS: list any errors that would cause a crash
- IMPROVEMENTS: list style or performance suggestions
- FIXED CODE: show the corrected version

---
Code to review:
```python
def read_sensor(pin):
    values = []
    for i in range(10):
        values.append(pin.read)
    return sum(values) / 10
```
---
"""

print(prompt(structured_prompt, enforce_cooldown=False))

💬 Your Turn — Try All 5 Techniques in the Chat Panel¶

Exercises — try each prompting technique in the chat panel:

Zero-shot: Summarise what a DPU does in one sentence.

One-shot:

Translate a Python concept into plain English.
Concept: list comprehension
Plain English: A shortcut for creating a list by applying a rule to each item.

Concept: dictionary
Plain English:

Few-shot:

Rate the code quality: GOOD, OKAY, or NEEDS WORK.
Code: x = 1 + 1        -> GOOD
Code: x=1+1            -> OKAY
Code: x=1+1;y=x*x;z=y  -> NEEDS WORK
Code: for i in range(n): total=total+i  ->

Chain-of-Thought: If I sample the camera at 30 fps and each frame takes 5ms to process on the DPU, can I keep up in real time? Think step by step.

Role + Format + Constraint (all together):

You are a code reviewer at a robotics company.
Review this Python snippet for a PYNQ project.
Format: 3 bullet points — one bug, one improvement, one compliment.
Keep each bullet to one sentence.

Code:
capture = cv2.VideoCapture(0)
frame = capture.read()
cv2.imshow('feed', frame)
In [ ]:
# Open a chat panel to try all the techniques interactively.
launch_chat()

⚠️ 6. Limits and Responsible Use¶

AI is powerful — but it's not perfect. Here's what every AI user needs to know:

🌀 6.1 Hallucinations — When AI Makes Stuff Up¶

The AI doesn't look things up. It predicts words that sound right — which means it can say something completely wrong with total confidence.

Think of it like a student who didn't study but still writes a very convincing answer on the test. Sounds real. Totally made up.

Watch out for: made-up facts, wrong numbers, fake book titles, events it wasn't trained on.

📅 6.2 Knowledge Cutoff — It's Stuck in the Past¶

The AI stopped learning at a certain date. Everything after that? It has no idea.

It's like asking someone who's been on a desert island for 2 years about the latest news — they genuinely don't know.

⚖️ 6.3 Bias — It Learned from Humans (and Humans Aren't Perfect)¶

The AI learned from text written by people — and people have biases. So the AI can repeat those biases without realising it.

It doesn't mean the AI is bad. It just means you should think critically about what it says.

✨ The golden rule¶

Use AI as a smart first draft and thinking partner, not a source of truth. Always verify important information yourself.

⚠ AI can be confidently WRONG
🌀
Hallucination
Makes up facts that
sound totally believable
📅
Knowledge Cutoff
Knows nothing after
its training date
⚖
Bias
Repeats biases from
the text it learned from
🌐 Real life: Lawyers have been fined for submitting AI-written legal briefs that cited court cases that never existed — the AI invented them. Always verify what AI tells you!

🕵️ Can You Catch the AI Lying?¶

In [ ]:
# ===== GAME: Fact or Fiction? (spot the hallucination) =====
import ipywidgets as widgets
from IPython.display import display, HTML, clear_output
import random, threading, time

_Q = [
 {"c":"The PYNQ KV260 uses a Xilinx Zynq UltraScale+ MPSoC chip.","a":"fact",
  "e":"Correct! The KV260 is built on the Zynq UltraScale+ platform."},
 {"c":"Python was created by James Gosling in 1991.","a":"fiction",
  "e":"Gosling created Java. Python was made by Guido van Rossum. The AI mixed up two real facts!"},
 {"c":"GPT-4 has exactly 1.7 trillion parameters.","a":"fiction",
  "e":"OpenAI never confirmed this number. A classic hallucination: a precise-sounding but made-up stat."},
 {"c":"An FPGA can be reprogrammed after manufacturing, unlike an ASIC.","a":"fact",
  "e":"Correct! FPGAs are reconfigurable; ASICs are fixed once made."},
 {"c":"The DPU overlay runs at exactly 333 MHz with 4096 cores.","a":"fiction",
  "e":"Sounds technical, but these exact numbers are invented. That is how hallucinations trick you."},
 {"c":"The famous Battle of Cheeseburg in 1823 changed European trade.","a":"fiction",
  "e":"There was no Battle of Cheeseburg! But notice how believable it sounds."},
]
_qs = random.sample(_Q, len(_Q))
_i = [0]; _sc = [0,0]
_claim = widgets.HTML()
_bf = widgets.Button(description="Fact", button_style="success", layout=widgets.Layout(width="110px", height="40px"))
_bx = widgets.Button(description="Fiction", button_style="danger", layout=widgets.Layout(width="110px", height="40px"))
_res = widgets.Output(); _score = widgets.HTML()

def _show():
    i = _i[0]
    if i >= len(_qs):
        _claim.value = ("<div style='font-family:sans-serif;font-size:15px;color:#1e2a4a;padding:12px;'>"
                        f"&#127881; Done! Final score: {_sc[0]}/{_sc[1]}</div>")
        _bf.disabled = _bx.disabled = True; return
    q = _qs[i]
    _claim.value = (f"<div style='font-family:sans-serif;background:#f8faff;border:1px solid #e2e8f0;"
                    f"border-radius:10px;padding:16px;margin:8px 0;'>"
                    f"<div style='font-size:11px;color:#64748b;margin-bottom:6px;'>Claim {i+1} of {len(_qs)} "
                    f"&mdash; did the AI make this up?</div>"
                    f"<div style='font-size:15px;color:#1e2a4a;font-style:italic;'>\"{q['c']}\"</div></div>")
    _res.clear_output(); _bf.disabled = _bx.disabled = False

def _ans(choice):
    i = _i[0]
    if i >= len(_qs): return
    q = _qs[i]; ok = (choice == q["a"]); _sc[1]+=1
    if ok: _sc[0]+=1
    ic = "&#9989;" if ok else "&#10060;"; col = "#15803d" if ok else "#b91c1c"; bg = "#dcfce7" if ok else "#fee2e2"
    lbl = "Correct!" if ok else f"Nope &mdash; it was {q['a'].upper()}"
    with _res:
        clear_output(wait=True)
        display(HTML(f"<div style='font-family:sans-serif;background:{bg};border-radius:8px;padding:12px;'>"
                     f"<div style='font-weight:700;color:{col};font-size:14px;'>{ic} {lbl}</div>"
                     f"<div style='font-size:12px;color:#374151;margin-top:4px;'>{q['e']}</div></div>"))
    _score.value = f"<div style='font-family:sans-serif;font-size:12px;color:#64748b;'>Score: {_sc[0]}/{_sc[1]}</div>"
    _bf.disabled = _bx.disabled = True; _i[0]+=1
    def _nxt(): time.sleep(2.5); _show()
    threading.Thread(target=_nxt, daemon=True).start()

_bf.on_click(lambda _: _ans("fact")); _bx.on_click(lambda _: _ans("fiction"))
display(HTML("<div style='font-family:sans-serif;font-size:16px;font-weight:700;color:#1e2a4a;'>"
             "&#127918; GAME: Fact or Fiction?</div>"
             "<div style='font-size:13px;color:#64748b;margin-bottom:8px;'>Each claim was written by an AI. "
             "Can you spot the hallucinations?</div>"))
display(_claim); display(widgets.HBox([_bf, _bx])); display(_res); display(_score); _show()

🔀 7. Switching Models¶

Not all AI models are the same — bigger = smarter but slower. It's like picking the right tool for the job.

Model Size Good at
⚡ Quick Helper 8B Fast answers, everyday questions
💻 Code Helper 30B Python, debugging, technical stuff
🧠 Smart Helper 27B Hard problems, deep reasoning

Think of it like cars — a sports car is fast, an SUV carries more, a truck handles heavy loads. Pick the right one!

🔀 Pick the right model for the job
⚡ Quick Helper (8B)
Fast replies
Great for everyday questions
💻 Code Helper (30B)
Slower but sharper
Best for Python & debugging
Your coding buddy
🧠 Smart Helper (27B)
Slowest but deepest
Hard reasoning & analysis
When you need the best answer
💡 Think of it like this: A calculator is fast but basic. A laptop is slower but smarter. A supercomputer takes time but handles anything. Same idea — pick the model that fits the task!

Try it: Use the dropdown in the chat panel to switch models and run this:

Write a Python function that reverses a string. Include a docstring and a test.

Did the answers differ? Which model did better?

Bonus — upload a photo! 📷

Models can actually see images. Try uploading any picture and asking:

What do you see in this image?

In [ ]:
# launch chat 
launch_chat()

🎓 8. You Made It!¶

Nice work!!

you just learned how AI actually works under the hood! 🎉

Most people just use AI like a magic box. You now know what's inside it.

📋 Quick Recap¶

What you learned The big idea
🧠 LLM A prediction engine — guesses the next word, over and over
⚙️ Parameters Billions of tuned numbers that store everything it learned
🧩 Tokens Word chunks — the AI's alphabet
💬 Context A running list of messages — the AI's only memory
🎯 Zero-Shot Just ask — no examples needed
1️⃣ One-Shot Show one example to set the style
📚 Few-Shot Show a few examples to lock in the format
🔗 Chain-of-Thought Add "think step by step" for harder problems
🎭 Role Prompting "You are a ___." — changes the whole voice
🌀 Hallucination AI can be confidently wrong — always double-check!

💡 Remember: A good prompt = better answers. You now have the skills to get the most out of any AI tool — in this bootcamp and beyond!

🏁 Final Challenge: The Silent Bug¶

The function above runs without any error but it gives the wrong answer. It returns 20.0 when it should return 40.0.

This is the hardest kind of bug: the code doesn't crash, so the AI can't rely on an error message. Your job is to write a prompt good enough to catch it.

⚡ The Rule: only 3 messages¶

You may send the AI a maximum of 3 messages in the chat panel below. Make them count!

🎯 Your goal¶

Get the AI to:

  1. Find the logic bug
  2. Explain WHY it produces 20.0 instead of 40.0
  3. Show the fixed code

💡 Why this is tricky¶

If you just paste the code and ask "what's wrong?", the AI often says "looks correct!" — because it doesn't crash. You have to give the AI something to work with.

Hint: tell the AI the expected vs. actual result, and ask it to "think step by step: trace which values the loop actually reads."

🏆 Scoring¶

Points Achievement
🥉 1 pt AI finds that the loop reads the wrong values
🥈 2 pts AI explains it reads the FIRST 3 (10,20,30), not the LAST 3
🥇 3 pts AI gives a correct fix AND explains why
🌟 BONUS You solved it in just 1 message
In [ ]:
# ===== THE BROKEN CODE — run me first and watch it crash! =====
def moving_average(readings, window):
    """Return the average of the last `window` readings."""
    total = 0
    for i in range(window):
        total += readings[i]          
    return total / window

data = [10, 20, 30, 40, 50]
print(moving_average(data, 3))  

🧪 Try It Out!¶

Now it's your turn. Open the chat panel below and experiment with everything you learned today:

  • 🎭 Give the AI a role and watch its personality change
  • 📋 Ask for a specific format (bullet points, a table, one word only)
  • 🔗 Add "think step by step" to a tricky question
  • 💬 Test its memory — tell it something, then ask about it later
  • 🕵️ Try to catch a hallucination — ask it something it can't know

There are no wrong answers here — the best way to learn prompting is to play with it. Type a prompt, read the reply, tweak it, and try again!

In [ ]:
# launch chat()
launch_chat()

🚀 If you finish early¶

Write your own function with a silent bug (wrong output, no crash) and challenge a partner to catch it in 3 messages.

In [ ]:
# Stop the chat server to free up the port for other sessions.
from bootcamp_ai import stop_chat
stop_chat()

📖 Quick Reference - How to Talk to the AI¶


💬 Option 1 — Chat Panel (easiest)¶

Run this in any cell to open an interactive chat box:

launch_chat()

Type your prompt, hit Send. No code needed!


🐍 Option 2 — Through Code¶

from bootcamp_ai import prompt, reset

# 1. Simple question
reset()
answer = prompt("What is an FPGA?", enforce_cooldown=False)
print(answer)

# 2. With a role
reset()
answer = prompt("You are a friendly teacher. Explain what a token is.", enforce_cooldown=False)
print(answer)

# 3. Think step by step
reset()
answer = prompt("How long does a 500-loop take at 3ms each? Think step by step.", enforce_cooldown=False)
print(answer)

# 4. Few-shot (teach the format first)
reset()
answer = prompt("""Temperature 22C  -> NORMAL
Temperature 78C  -> WARNING
Temperature 105C -> CRITICAL
Temperature 91C  ->""", enforce_cooldown=False)
print(answer)

💡 Always call reset() before a new question to clear the AI's memory.

💡 Use launch_chat() when you want to have a conversation. Use ask() when you want a quick answer in your code output.