Your First AI Project

Lesson 5 of 14

Prompts in code

In a chat window you write a prompt once and correct it as you go. In code the prompt is a template that will run against inputs you have not seen, with nobody watching. That difference changes how you write it, and it is the main reason a prompt that works beautifully in a chat can fail in a script.

The system message

The messages list takes user turns. There is a separate slot for standing instructions, and it is worth using.

python
response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=500,
    system="You extract action items from meeting notes. You never invent an owner or a date that is not stated in the notes.",
    messages=[{"role": "user", "content": notes}],
)

The system parameter holds the role and the rules. The user message holds the thing to process.

Separating them is not cosmetic. It keeps your instructions in one place rather than glued to the front of every input, it makes them easy to change without touching the input-handling code, and — the practical part — it means a document containing instruction-shaped text is at least positioned as content rather than sitting in the same slot as your rules. That does not make it immune (lesson 10 returns to this), but the structure is right.

The template and the variable

python
SYSTEM = """You extract action items from meeting notes for an operations team.
Rules:
- Only list actions that are explicitly stated or clearly implied.
- Never invent an owner. If no owner is named, write UNKNOWN.
- Never invent a date. If no date is stated, write UNKNOWN.
- If the notes contain no actions, say exactly: NO ACTIONS FOUND."""

def extract(notes):
    response = client.messages.create(
        model="claude-sonnet-5",
        max_tokens=800,
        system=SYSTEM,
        messages=[{"role": "user", "content": f"Meeting notes:\n\n{notes}"}],
    )
    return response.content[0].text

SYSTEM is a triple-quoted string, so it can span lines. extract is a function — a named piece of code you can call repeatedly with different input. It is the unit that turns one call into a tool, and it is most of what "writing software" means at this scale.

Now extract(any_notes) works on anything.

The four rules that make a template survive

Never invent. The highest-value line in almost every production prompt. Models complete patterns, and a form with an empty owner field is a pattern begging to be completed. Say UNKNOWN explicitly and you get a gap you can see instead of a plausible name you cannot check.

Say what to do with nothing. NO ACTIONS FOUND, exactly. Without it you get a different apologetic sentence each time, and your parser has to cope with infinite variety where a fixed string would do.

Constrain the output shape absolutely. In a chat you can accept a friendly preamble. In code the next line of your program is going to try to read this, and "Sure! Here are the action items:" is the single most common cause of a broken pipeline.

Anticipate the ugly input. Your test file is clean. Real meeting notes are fragments, three people's shorthand, a paste of a WhatsApp thread, and sometimes an empty file. Every one of those will hit your template, and each needs a defined behaviour.

Temperature, briefly

Most APIs expose a temperature setting between 0 and 1. Lower means the model picks the most likely next token more often; higher means more variety.

For extraction, classification, and anything feeding a spreadsheet, set it low:

python
temperature=0,

For drafting and ideation, leave it at the default. The important caveat: temperature 0 is not determinism. It reduces variation substantially; it does not guarantee identical output across runs, and anything in your design that requires byte-identical replies is built on sand.

Test the template on the ugly cases

Before you loop over anything, run your function on four inputs by hand.

A normal set of notes. A set with no actions in it at all. A three-line fragment. And an empty string.

python
print(extract(""))

An empty input is not a hypothetical — in a folder of 400 files, some are empty, and finding out what your function does with one now is much better than finding out on file 213.

The prompt is code, so keep it with the code

One habit, worth adopting immediately: when you change a prompt, note what you changed and why. A comment above SYSTEM is enough.

Prompts drift. Six months from now you will find a rule and have no idea which failure it was defending against, and you will remove it, and the failure will come back. This is the code equivalent of the failure log, and it costs one line.

Do this today: write your SYSTEM string and your extract function, then run it on an empty string and on a fragment. Whatever it does with those two is your real behaviour.

← Previous