Skip to main content
ANVISoftware Solutions
Lesson 3 of 22Beginner12 min

Generative AI

By the end of this lesson

Describe what generative models produce and how that differs from classification.

A spam filter decides. A model that writes produces. That sentence is the distinction, and the engineering consequences of it run through everything else in this course.

A classifier picks from a set of options you defined. Four categories in, one of four categories out. A generative model produces new content one piece at a time, and the set of things it could produce is effectively unlimited. You cannot enumerate the possible outputs, which means you cannot test them all, and you cannot assume the shape of what comes back.

The same expense claim, handled two ways:

 ClassificationGeneration
Question it answersWhich of these four categories is this?Write the employee an explanation of why it was rejected
Output spaceClosed — one of a fixed listOpen — any text
Checking it in codeCompare against the expected labelNo single correct answer to compare against
Typical failureThe wrong label, and you can count how oftenFluent text that is subtly wrong, and counting is harder
Cost per callUsually tiny, often running on your own hardwarePaid per piece of text in and out
Two function shapes: closed output and open output
Python
CATEGORIES = ["travel", "meals", "software", "equipment"]

def categorise(description: str) -> str:
    """Closed output. The return value is always one of four strings."""
    return classifier.predict([description])[0]

def draft_rejection_note(claim: dict, reason: str) -> str:
    """Open output. The return value is text that did not exist before."""
    response = client.chat.completions.create(
        model="gpt-4.1-mini",
        messages=[
            {
                "role": "system",
                "content": (
                    "You write short, plain, courteous notes to employees about "
                    "expense claims. Two sentences. State the reason given. "
                    "Do not invent policy."
                ),
            },
            {"role": "user", "content": f"Claim: {claim['description']}. Reason: {reason}"},
        ],
    )
    return response.choices[0].message.content
  • categorise has a return type you can reason about. Four values are possible, so a test can cover the behaviour and a bug is visible as the wrong label.
  • draft_rejection_note returns a string, and that is all its type tells you. It might be two sentences as asked. It might be five. It might contain a policy detail nobody supplied.
  • The system message is where you constrain a generative call — length, tone, and an explicit instruction not to invent policy. Constraints in words are guidance, not enforcement, which is why later lessons validate the result in code.
  • The full mechanics of this call — the client, the key, timeouts, retries — come in "Your First Model Integration". For now, notice only the shape: instructions plus data in, free text out.

Where generation earns its cost in the internal knowledge assistant:

  • Answering a policy question in a sentence, using document extracts you supply
  • Summarising a long handbook section down to what the person asked about
  • Rewriting a dense paragraph of finance wording into plain English
  • Turning a messy claim description into structured fields
  • Drafting a reply that a human reads before it is sent

Summary

  • Classification chooses from a fixed set of options; generation produces new content piece by piece
  • A generative model's output space is open, so you cannot enumerate, test or assume the shape of what comes back
  • Prefer a classifier for closed decisions — cheaper, faster, and closed by construction
  • When you do generate, constrain the request in words and validate the result in code

Practice

Attempt each one before opening the solution. Getting it wrong first is how the idea sticks.

Think about it

Classify, generate, or neither

Decide which approach fits each of these, and say why: routing an incoming email to the right team; writing the first draft of a reply to that email; extracting the invoice number from the email body; deciding whether the email is urgent.

Show solution

Routing to a team is classification. The set of teams is fixed and you have years of routed email as examples.

Drafting a reply is generation. There is no correct answer to compare against, so a human should read it before it goes out.

Extracting an invoice number is neither, if the format is reliable — a pattern match is exact, free and instant. If invoice numbers arrive in a dozen inconsistent shapes across suppliers, generation with validation becomes reasonable, because you can check the extracted value against your records.

Urgency is classification, but pause on who defines it. Unless someone has labelled what urgent means in your organisation, you do not have a target to learn. This is the common case where the data problem is the real problem.

Saved in this browser only.