Lesson 04 / 22
Clear and Measurable Requests
Measuring that an ambiguous request produces not a single wrong response but a distribution: the same ambiguous prompt gives a mean of 4.81 distinct responses per record in ten runs, the most frequent response is repeated in only 0.3944 of the runs, and no label can be read from 0.4333 of the responses. Four request forms are set side by side. Clarifying the verb adds two tokens and lowers the distribution to 4.53; closing the option set adds 15 tokens and lowers the distribution to 3.89 and the unlabeled share to 0.2889; adding an ambiguity rule adds 10 more tokens and raises the unlabeled share back to 0.3722. The band of the hit rate read in a single run is between 0.2778 and 0.3333 and cannot tell the four requests apart.
Published Updated
In this lesson
- Counts the response distribution that a request produces by summing ten runs of the same prompt.
- Compares four different ways of clarifying the request by distribution width, unlabeled response share and token cost.
- Shows with the run band why the hit rate read in a single run cannot measure ambiguity.
Contents
The previous lesson added an identity and a procedure to the prompt and found that the difference of none of the four prefixes is measurable. Throughout that measurement one thing never changed: what was asked. The request was the same sentence in every prompt, and that sentence itself was never questioned. Yet the task definition is not the most expensive part of the prompt but its most decisive part.
The cost of an ambiguous request is not that it gives an ambiguous response. An ambiguous request does not produce a single wrong answer; it produces a distribution. The same prompt, the same record, the same model, and in ten separate runs a few separate responses that do not replace one another. This distribution is not visible in any measure that looks at a single run; what shows in a single run is one sample drawn from that distribution. This lesson measures the distribution and counts how far making the request measurable narrows it.
- PD26. The code calls a simulator; no real model endpoint is called. The support tickets are fictional and are the first 36 records of the dataset in the previous lessons. The dataset was made smaller because every record is called ten times.
- PD27. Every record is measured with ten runs: seeds 20260218 to 20260227. The distribution measures are the total of these ten responses, not of a single run.
- PD28. The number of distinct responses is the number of response texts that come out different from one another in ten runs, averaged per record. Its smallest value is 1 and its largest is 10.
- PD29. The top share is the share of the most repeated response in ten runs. It approaches 1 in a narrow distribution and 0.1 in a wide one.
- PD30. The rate limit fires on every thirty-seventh call and returns an empty response. So that it does not disturb the distribution count, the call counter is reset before the ten runs of every record; this is a measurement decision and it is in the code.
- PD31. The four request forms are built incrementally: a vague verb, a clear verb, a clear verb with a closed option set, and that with an ambiguity rule added.
- PD32. In this lesson the form of the response is not requested in any prompt. What is measured is the clarity of the request; the form of the output is the subject of the next lesson.
- PD33. The hit rate is computed separately in each of the ten runs; the table prints its mean and its band (the difference between the largest and the smallest run).
- PD34. The cost is in tokens and is written per request as input and output; the cost of ten runs is ten times that.
The Distribution an Ambiguous Request Produces
The first block sets up the simulator and the fiction, defines the four request forms, calls a single fictional record ten times with the most ambiguous form and counts the responses that come out.
# SIMULATOR. This code does not call a real model endpoint; it is a language model # simulator written with the standard library. The support tickets are FICTIONAL too. import math SEED, M32 = 20260218, 0xFFFFFFFF WINDOW, MAX_OUT = 240, 24 # context window and maximum output, in tokens def rng(t): x = ((t ^ (t >> 16)) * 2246822507) & M32 x = ((x ^ (x >> 13)) * 3266489909) & M32 s = [(x ^ (x >> 16)) & M32] def next_value(): s[0] = (s[0] * 1664525 + 1013904223) & M32 return s[0] / 4294967296 return next_value def pick(u, w): t = 0.0 for i, x in enumerate(w): t += x if u < t: return i return len(w) - 1 def tokenize(m): # FICTIONAL tokenizer: pieces of at most five characters b = [] for s in m.lower().replace(",", " , ").split(): while len(s) > 5: b.append(s[:5]) s = s[5:] b.append(s) return b def prompt_trace(m): # trace that depends on the prompt content, independent of the run h = 2166136261 for c in m: h = ((h ^ ord(c)) * 16777619) & M32 return h TOPICS = ["fatura", "ariza", "sayac", "tarife", "kesinti"] TEMPLATES = { "fatura": ["bu ayki fatura tutari gecen aya gore cok yuksek geldi", "faturami odedim ama sistemde borc gorunuyor", "fatura ayrintisini nereden gorebilirim"], "ariza": ["evde su akmiyor bir ariza var galiba", "baglanti bozuk oldu ve hic calismiyor", "ariza kaydi actim ama ekip gelmedi"], "sayac": ["sayac okumasi yanlis girilmis endeks tutmuyor", "sayac degisimi icin randevu istiyorum", "sayac uzerindeki endeks ile fatura ayni degil"], "tarife": ["hangi tarife basamagindayim ogrenmek istiyorum", "tarife degisikligi icin ne yapmam gerekiyor", "birim ucret abone tipine gore degisiyor mu"], "kesinti": ["mahallede kesinti var ne zaman gelecek", "planli kesinti duyurusu nereden takip edilir", "aksamdan beri kesinti yasiyoruz"], } EXTRAS = ["ayrica gecen ay da ayni sorun olmustu", "bu konuda memnun degilim", "acil bilgi almam gerekiyor", "kayit numaram elimde yok"] TICKETS = [] for i in range(120): r = rng(SEED + i) k = TOPICS[pick(r(), [0.24, 0.22, 0.18, 0.20, 0.16])] m = TEMPLATES[k][int(r() * 3)] if r() < 0.34: m += " " + EXTRAS[int(r() * 4)] TICKETS.append({"id": 4001 + i, "text": m, "topic": k}) CONCEPTS = TOPICS + ["odeme", "sikayet", "bilgi", "genel"] CUES = {"fatur": "fatura", "tutar": "fatura", "ayrin": "fatura", "ariza": "ariza", "bozuk": "ariza", "calis": "ariza", "akmiy": "ariza", "sayac": "sayac", "endek": "sayac", "okuma": "sayac", "tarif": "tarife", "birim": "tarife", "abone": "tarife", "basam": "tarife", "kesin": "kesinti", "duyur": "kesinti", "mahal": "kesinti", "borc": "odeme", "odedi": "odeme", "ucret": "odeme", "memnu": "sikayet", "sorun": "sikayet", "acil": "sikayet", "bilgi": "bilgi", "ogren": "bilgi", "nered": "bilgi"} TRAPS = {"degis": "tarife", "kayit": "ariza", "yukse": "tarife", "gorun": "fatura", "ekip": "kesinti", "takip": "tarife", "giril": "fatura"} # misleading cues FREE_FORM = ["talebiniz {k} konusuyla ilgili gorunuyor", "bu kayit {k} basligina girer , ilgili ekibe yonlendirildi", "kaydiniz alindi , konuyu inceleyip donus yapacagiz"] CALL_COUNT = [0] def call(prompt, seed=SEED, temperature=0.6, max_out=MAX_OUT): CALL_COUNT[0] += 1 tok = tokenize(prompt) if len(tok) > WINDOW: return {"status": "context_overflow", "tokens_in": len(tok), "tokens_out": 0, "response": ""} if CALL_COUNT[0] % 37 == 0: return {"status": "rate_limit", "tokens_in": len(tok), "tokens_out": 0, "response": ""} r = rng(seed ^ prompt_trace(prompt)) if len(tok) > 90 and r() < 0.04: return {"status": "timeout", "tokens_in": len(tok), "tokens_out": 0, "response": ""} cand = [k for k in CONCEPTS if k[:5] in tok] # concepts named in the prompt if len(cand) < 3: cand = CONCEPTS p = {k: 0.15 for k in cand} for t in tok: for table, w in ((CUES, 1.0), (TRAPS, 1.3)): if table.get(t) in p: p[table[t]] += w if temperature <= 0.0: k = max(sorted(p), key=lambda a: p[a]) # most likely choice else: e = [math.exp(p[a] / temperature) for a in sorted(p)] k = sorted(p)[pick(r(), [v / sum(e) for v in e])] y = k if "tek" in tok else FREE_FORM[pick(r(), [0.42, 0.26, 0.32])].format(k=k) ot = tokenize(y) if len(ot) > max_out: # stop condition ot = ot[:max_out] y = " ".join(ot) return {"status": "ok", "tokens_in": len(tok), "tokens_out": len(ot), "response": y} def read_label(y): # extract a label from the response for s in y.lower().split(): if s in TOPICS: return s return None VERB = "Su destek talebini konusuna gore etiketle ." SET_TEXT = " Etiketler: fatura , ariza , sayac , tarife , kesinti ." REQUEST_FORMS = (("vague verb", "Su destek talebini degerlendir ."), ("clear verb", VERB), ("closed set", VERB + SET_TEXT), ("ambiguity rule", VERB + SET_TEXT + " Birden cok konu varsa ana konuyu sec .")) DATASET = TICKETS[:36] SEEDS = [SEED + i for i in range(10)] def runs(head, x): CALL_COUNT[0] = 0 # reset for every ticket so the rate limit does not disturb the distribution count return [call(head + " Talep: " + x["text"], seed=t) for t in SEEDS] def breakdown(name, head, x): s = [c["response"] for c in runs(head, x)] print(f"{name}, ten runs -> {len(set(s))} distinct responses") for v in sorted(set(s)): print(f" {s.count(v)}/10 {v}") print(f"{'request':<19} {'tokens':>9}") for name, h in REQUEST_FORMS: print(f"{name:<19} {len(tokenize(h)):>9d}") x0 = DATASET[3] print(f"FICTIONAL ticket {x0['id']} (true topic {x0['topic']}): {x0['text']}") breakdown(REQUEST_FORMS[0][0], REQUEST_FORMS[0][1], x0)
request tokens vague verb 9 clear verb 11 closed set 26 ambiguity rule 36 FICTIONAL ticket 4004 (true topic ariza): ariza kaydi actim ama ekip gelmedi vague verb, ten runs -> 7 distinct responses 1/10 bu kayit ariza basligina girer , ilgili ekibe yonlendirildi 1/10 bu kayit odeme basligina girer , ilgili ekibe yonlendirildi 1/10 bu kayit sayac basligina girer , ilgili ekibe yonlendirildi 2/10 kaydiniz alindi , konuyu inceleyip donus yapacagiz 1/10 talebiniz fatura konusuyla ilgili gorunuyor 2/10 talebiniz kesinti konusuyla ilgili gorunuyor 2/10 talebiniz sikayet konusuyla ilgili gorunuyor
A single record gave seven distinct responses in ten runs. The most frequent response was
repeated in only two runs. One of the responses carries no label at all; two others use the labels
odeme (payment) and sikayet (complaint), that is, names that have no counterpart in the fictional
document vocabulary of the field team. The prompt said “evaluate”, and that verb never said which set
a result was wanted from or in what form. The model filled this gap in a different way across the runs.
The real meaning of this table lies not in one record but in the distribution across records. An
observer who looks at only one of the seven distinct responses reaches the conclusion that the prompt
worked or did not work with equal ease.
Four Requests Side by Side
The second block measures the four request forms on thirty-six records and with ten runs. In every row stand the mean number of distinct responses per record, the share of the most frequent response, the unlabeled response share, the mean hit rate of the ten runs, the band of the hit rate and the token cost.
def measure(head): dr = tp = unl = ti = to = 0 hits = [0] * len(SEEDS) for x in DATASET: c = runs(head, x) s = [v["response"] for v in c] e = [read_label(v) for v in s] dr += len(set(s)) tp += max(s.count(v) for v in s) / len(s) unl += sum(v is None for v in e) / len(e) for j, v in enumerate(e): hits[j] += v == x["topic"] ti += sum(v["tokens_in"] for v in c) / len(c) to += sum(v["tokens_out"] for v in c) / len(c) n = len(DATASET) hr = [v / n for v in hits] return (dr / n, tp / n, unl / n, sum(hr) / len(hr), max(hr) - min(hr), ti / n, to / n) print(f"{'request':<19} {'tok':>4} {'distinct':>11} {'top share':>9} {'unlabeled':>10} " f"{'hit rate':>8} {'band':>7} {'in':>6} {'out':>6}") for name, h in REQUEST_FORMS: dr, tp, unl, hr, band, ti, to = measure(h) print(f"{name:<19} {len(tokenize(h)):>4d} {dr:>11.2f} {tp:>9.4f} {unl:>10.4f} " f"{hr:>8.4f} {band:>7.4f} {ti:>6.1f} {to:>6.1f}") print() breakdown(REQUEST_FORMS[2][0], REQUEST_FORMS[2][1], x0)
request tok distinct top share unlabeled hit rate band in out vague verb 9 4.81 0.3944 0.4333 0.4611 0.3333 23.1 11.4 clear verb 11 4.53 0.4333 0.4500 0.4417 0.3333 25.1 11.3 closed set 26 3.89 0.4083 0.2889 0.5306 0.2778 40.1 11.5 ambiguity rule 36 3.78 0.4611 0.3722 0.4722 0.3333 50.1 11.6 closed set, ten runs -> 4 distinct responses 2/10 bu kayit kesinti basligina girer , ilgili ekibe yonlendirildi 3/10 kaydiniz alindi , konuyu inceleyip donus yapacagiz 2/10 talebiniz ariza konusuyla ilgili gorunuyor 3/10 talebiniz kesinti konusuyla ilgili gorunuyor
Clarifying the Verb Is Not Measurability
The second row is the result of this lesson that is the easiest to misunderstand. The verb “evaluate” was replaced with “label by its topic”; the request is clear as grammar and explicit as an action. The number of distinct responses fell from 4.81 to 4.53, the hit rate fell from 0.4611 to 0.4417, and the unlabeled response share rose from 0.4333 to 0.4500. The two-token addition did not narrow the distribution in any measurable way.
The reason is structural. A clear verb says what to do; it does not say which set to choose from. A prompt that says “label” leaves it to the model where the label will come from, and in every run the model produces a name from its own vocabulary. For a request to be measurable, the verb does not need to be sharp; the set from which the answer can be taken needs to be closed.
The third row shows this. When the names of the five labels are written into the prompt, the number of distinct responses falls to 3.89, the unlabeled share drops from 0.4333 to 0.2889 and the hit rate rises to 0.5306. The cost is plainly countable: the input per request rises from 25.1 to 40.1 tokens, that is, 15 tokens. Over thirty-six records that is 540 and over ten runs 5400 tokens. The ten runs of the same record with the closed set are at the end of the block output: seven distinct responses have fallen to four and the names outside the set have disappeared. On this record the concentration happened on the wrong label; narrowing of the distribution is not a guarantee of hit rate, and the two numbers must stand in separate columns. The fourth row pays off the second claim of the course. The sentence “if many topics, pick the main one” adds ten tokens and lowers the number of distinct responses from 3.89 to 3.78. The same sentence raises the unlabeled share from 0.2889 to 0.3722 and drops the hit rate from 0.5306 to 0.4722. A sentence written to reduce ambiguity may, when measured, have increased it.
The Distribution Is Not Visible in a Single Run
The band column of the table is the methodological result of this lesson. The hit rate bands of the
four requests across ten runs are 0.3333, 0.3333, 0.2778 and 0.3333 respectively. The effect of the
closed set on the hit rate is +0.0695; exactly a quarter of its own band. Read by the criterion of the
previous lesson, this difference counts as unmeasured. That is, which of the four requests is
better cannot be told apart in any way with the hit rate read in a single run.
The numbers that can tell them apart are different, and all of them are totals over ten runs: the
number of distinct responses falls from 4.81 to 3.89 and the unlabeled share from 0.4333 to 0.2889.
These two measures cannot be computed from a single run, because in a single run every record has one
response and it is not visible which of how many possibilities that response is. The cost of an
ambiguous request is a cost that cannot be measured in a single run; this is why most prompt trials
never see it and close with a single successful sample.
Summary
- An ambiguous request produces not a single wrong response but a distribution. A single record gave seven distinct responses in ten runs; across the dataset the result was a mean of 4.81 distinct responses per record and a top share of only 0.3944.
- Clarifying the verb is not measurability: the two-token addition lowered the distinct responses to 4.53, dropped the hit rate to 0.4417 and raised the unlabeled share to 0.4500.
- The decision that makes the request measurable is closing the option set: 3.89 distinct responses, an unlabeled share of 0.2889, a hit rate of 0.5306. Its cost is 15 tokens per request, 5400 tokens over ten runs.
- Adding an ambiguity rule added ten tokens and took the unlabeled share to 0.3722 and the hit rate to 0.4722: the sentence written to reduce ambiguity increased it when measured.
- The band of the hit rate across ten runs is between 0.2778 and 0.3333; the +0.0695 effect of the closed set is inside the band. The distribution measures cannot be computed from a single run.
Next Step
In four lessons the components of the prompt were separated, the repetition cost of the persistent instruction was counted, the difference of the role prefixes was found unmeasurable and the request was tied to a closed set. Even so, the prompt with the closed set still produces a mean of 3.89 distinct responses per record, and no label can be read from 0.2889 of the responses. The source of the remaining distribution is no longer what is asked but how it is said: the same label is given in three separate sentence patterns, and sometimes with no label name at all. The request was clarified, but the form of the response is still left to the model. The next lesson takes this up: when the output form is requested, how many responses can be parsed by a machine, and how much of the hit rate the length limit takes back.
To keep your progress and take notes, Log in
My notes
Log in to take notes.