↓ Skip to main content
  1. Blog/

Når modellen tager fejl

·1402 ord·7 minutter
De kiilske principper for AI - Denne artikel er en del af en serie.
Del 3: Denne artikel

Det andet af de kiilske principper for AI er også et spørgsmål.

Hvad sker der, når modellen tager fejl?

Ikke hvis. Når. Enhver model tager fejl. Det eneste spørgsmål er, om nogen opdager det.

I det forrige indlæg flyttede jeg reglerne ud af prompten og ind i kode. Det tager sig af de ting, der har et rigtigt svar. Dette indlæg handler om alt det andet.

De stille fejl er de farlige
#

En larmende fejl er ikke noget stort problem. Programmet crasher, I ser en rød fejl, I retter den.

De farlige fejl er stille. De ligner præcis et normalt resultat.

En model, der ikke kender svaret, svarer alligevel. Den siger ikke »det ved jeg ikke«. Den siger noget plausibelt.

En ødelagt integration rapporterer »ingen nye data«. Og ingen nye data ligner præcis en stille dag. Jeg havde engang en datakilde, der returnerede nul resultater i fire dage, før jeg opdagede det. Intet crashede. Intet var rødt. Det var bare tomt.

Så opgaven er at gøre stille fejl larmende. Jeg bruger tre tricks.

Trick 1: Nul er mistænkeligt
#

Hvis en kilde returnerer ingenting, stop. Returner ikke en tom liste og fortsæt, for en tom liste er et helt fint svar. Alt nedstrøms vil gladeligt behandle den.

Nogle gange er nul faktisk det rigtige svar. Men jeg vil hellere have besked og tjekke det end at opdage det fire dage senere.

Trick 2: Valider, før I bruger
#

Når jeg beder en model om JSON, får jeg som regel JSON. Som regel. Nogle gange får jeg en venlig sætning først. Nogle gange mangler et felt. Nogle gange kommer true tilbage som "yes".

Så hvert svar tjekkes, før der gøres noget med det. Hvis det ikke har præcis den form, jeg bad om, stopper kørslen.

Trick 3: Spørg to gange
#

Det her er det trick, jeg bedst kan lide. Stil det samme spørgsmål to gange: én gang med regler og én gang med modellen.

Hvor de er enige, kører sagen videre af sig selv. Hvor de er uenige, tager et menneske et kig.

Reglerne er dumme, men forudsigelige. Modellen er klog, men uforudsigelig. Når de er enige, kan I være nogenlunde sikre. Når de er uenige, er en af dem forkert, og det er netop dér, I vil have et menneske.

Et eksempel: screening af jobopslag
#

Lad os se på alle tre tricks i Nushell. Eksemplet screener jobopslag. Jeg bruger igen aichat til modelkaldet.

# Rule: an empty source is a failure, not a quiet day
export def assert-not-empty [source: string]: list<any> -> list<any> {
  let items = $in
  if ($items | is-empty) {
    error make {
      msg: $"($source) returned nothing"
      help: "A broken source and a quiet day look the same. Check it before you trust a zero."
    }
  }
  $items
}

# Rule: the model's answer must have the shape we asked for before anything is used
export def parse-verdict []: string -> record<relevant: bool, reason: string> {
  let raw = $in
  let verdict = try { $raw | from json } catch {
    error make {msg: "The model did not answer with JSON", help: $raw}
  }
  let valid = (
    ($verdict | describe | str starts-with "record")
    and (($verdict.relevant? | describe) == "bool")
    and (($verdict.reason? | describe) == "string")
  )
  if not $valid {
    error make {msg: "The model answered with the wrong shape", help: $raw}
  }
  $verdict | select relevant reason
}

# Rules: a plain keyword match that gives the same answer every time
export def rule-verdict [keywords: list<string>]: record -> bool {
  let text = $"($in.title) ($in.description)" | str lowercase
  $keywords | any {|k| $text | str contains ($k | str lowercase) }
}

# Judgement: ask the model whether the ad fits my profile
export def model-verdict [profile: string]: record -> record<relevant: bool, reason: string> {
  let ad = $in
  let prompt = [
    "Is this job ad relevant for the profile below?"
    'Answer only with JSON: {"relevant": true or false, "reason": "one short sentence"}'
    ""
    $"Profile: ($profile)"
    $"Title: ($ad.title)"
    $"Ad: ($ad.description)"
  ] | str join (char newline)

  ^aichat $prompt | parse-verdict
}

# Where rules and model agree, the ad moves on. Where they disagree, a human looks.
export def route []: record<rule: bool, model: bool> -> string {
  if $in.rule != $in.model {
    "human"
  } else if $in.rule {
    "apply"
  } else {
    "skip"
  }
}

export def screen-ads [profile: string, keywords: list<string>]: list<record> -> table {
  assert-not-empty "The job feed"
  | each {|ad|
    let verdict = $ad | model-verdict $profile
    $ad
    | insert rule ($ad | rule-verdict $keywords)
    | insert model $verdict.relevant
    | insert reason $verdict.reason
    | insert route { route }
  }
}

Gem den som screen.nu. Her er den med tre opdigtede opslag:

use screen.nu screen-ads

[[title description];
  ["Nushell developer" "Automate data pipelines"]
  ["Sommelier" "Pair wine with food"]
  ["Prompt trainer" "Teach staff to use LLMs"]
]
| screen-ads "AI and automation" [nushell automation]
| select title rule model route

Og så får vi det her:

╭───┬───────────────────┬───────┬───────┬───────╮
│ # │       title       │ rule  │ model │ route │
├───┼───────────────────┼───────┼───────┼───────┤
│ 0 │ Nushell developer │ true  │ true  │ apply │
│ 1 │ Sommelier         │ false │ false │ skip  │
│ 2 │ Prompt trainer    │ false │ true  │ human │
╰───┴───────────────────┴───────┴───────┴───────╯

De første to er lette. Regler og model er enige, så ingen behøver at kigge.

Prompt trainer-opslaget er det interessante. Mine søgeord fangede det ikke, men modellen mener, det er relevant. Måske har modellen ret, og mine søgeord er for snævre. Måske er modellen for gavmild. Det ved jeg ikke, og det ved systemet heller ikke. Så det ryger til mig.

Læg mærke til, at mennesket kun ser det ene opslag ud af tre, hvor der faktisk er noget at beslutte. Det er pointen. Hvis et menneske skal kigge på alt, kigger et menneske snart på ingenting.

Og hvis feedet er tomt, bliver der slet ikke screenet noget:

Error: nu::shell::error

  x The job feed returned nothing
  help: A broken source and a quiet day look the same. Check it before you
        trust a zero.

Et tjek, I kun har set bestå
#

Her er den del, folk springer over.

Et tjek, I kun har set bestå, er et tjek, I ikke ved, om virker. Måske fanger det problemet. Måske har det en fejl og slipper alt igennem. Udefra ser de to ens ud: grønt, hver dag.

Så I er nødt til at se det fejle mindst én gang. Med vilje.

Fordi tjekkene er almindelige funktioner, er det nemt. Jeg giver dem dårligt input og sørger for, at de stopper:

use std/assert
use screen.nu [assert-not-empty parse-verdict route]

# An empty feed stops the run
assert error { [] | assert-not-empty "The job feed" }

# Prose instead of JSON stops the run
assert error { "Sure! This one looks relevant." | parse-verdict }

# JSON with a missing field stops the run
assert error { '{"relevant": true}' | parse-verdict }

# So does the right field with the wrong type
assert error { '{"relevant": "yes", "reason": "Fits well"}' | parse-verdict }

# A well-formed answer passes
assert equal ('{"relevant": true, "reason": "Fits well"}' | parse-verdict) {relevant: true, reason: "Fits well"}

# Agreement moves on, disagreement goes to a human
assert equal ({rule: true, model: true} | route) "apply"
assert equal ({rule: false, model: false} | route) "skip"
assert equal ({rule: true, model: false} | route) "human"
assert equal ({rule: false, model: true} | route) "human"

De fleste af disse tests handler om at fejle. Det er ikke et tilfælde. Den lykkelige vej passer sig selv. Det er fejlene, jeg skal være sikker på.

For at opsummere
#

Når I bygger noget med en model i, så gå ud fra, at den vil tage fejl. Sørg derefter for, at I hører om det:

  • Nul er mistænkeligt. Stop i stedet for at returnere et tomt svar, der ligner et rigtigt.
  • Valider, før I bruger. Hvis svaret ikke har den form, I bad om, så stop.
  • Spørg to gange. Lad regler og model besvare det samme spørgsmål, og send uenighederne til et menneske.
  • Se det fejle. Et tjek, I kun har set bestå, er et tjek, I ikke ved, om virker.

Næste indlæg handler om det tredje princip: Kan I bagefter vise mig, hvorfor systemet traf en bestemt beslutning?

Hvis I vil have hjælp til at finde de stille fejl i jeres egne systemer, så skriv eller ring.

De kiilske principper for AI - Denne artikel er en del af en serie.
Del 3: Denne artikel