Skip to content
academia.sh

Lesson 02 / 22

System Instruction

Measuring how a persistent behavior definition is sent again in every request and how its cost is multiplied by the number of requests: a 62-token instruction holds 0.8378 of a single prompt and 7440 tokens across 120 requests. Four lengths are set side by side. The prompt without an instruction gives a label hit rate of 0.4583 and 2985 tokens, the short instruction 0.7167 and 4751, the medium instruction 0.7500 and 5856, the long instruction 0.7417 and 9343. Cutting the long instruction to the medium one saves 3487 tokens and gives up nothing in hit rate; cutting the medium one to the short one saves 1105 tokens but raises the unlabeled response share from 0.0250 to 0.2167.

Published Updated

In this lesson

  • Computes the total token cost of a persistent system instruction together with the number of requests and derives the share of the instruction in input tokens.
  • Measures four instruction lengths on the same task and determines the length at which the hit rate saturates.
  • Writes the tokens gained by shortening the instruction next to the hit rate it gives up and singles out the lossless shortening.
Contents

The previous lesson split the prompt into three components and measured that the instruction and the context held 0.7059 of the total input. That measurement was made inside a single request. When the code sent the same two texts one hundred twenty times, the cost stayed hidden in a single line, because the repetition was inside the loop and was not counted anywhere.

This lesson counts that repetition. A system instruction is the persistent behavior definition written so that the model behaves the same way in every request: what the task is, which options exist, in which form the response is given, what to do under ambiguity. Its name is persistent but the place where it is stored is the prompt itself; the model remembers nothing between two calls. The instruction is therefore written once and paid for in every request. That is what will be measured: the total of the repetition, the share of the repetition, and how much of the hit rate shortening the instruction gives back.

  • PD9. The code calls a simulator; no real model endpoint is called. The support tickets are fictional and are the same 120 records as in the previous lesson.
  • PD10. The system instruction and the input are inside the same prompt. The simulator has no separate instruction field, because what is measured is the token cost and the name of the field does not change the cost.
  • PD11. Four instruction lengths are built incrementally: none, short (the label set only), medium (the label set plus the task and the response form), long (that, with ambiguity rules added).
  • PD12. The cost of the instruction is length times number of requests. In the table the repeat column is this product and it is included in the total input tokens.
  • PD13. The criterion is the label hit rate; the unlabeled response share is also printed. Tokens per correct label is found by dividing total tokens by the hit rate and the record count.
  • PD14. Every row is run with two seeds (20260218 and 20260219). A hit rate difference that stays smaller than the two-run difference counts as unmeasured in this course.
  • PD15. The rate limit fires on every thirty-seventh call and returns an empty response. In one hundred twenty calls three records are left unlabeled because of it; this share belongs not to the prompt but to the surface.
  • PD16. Token cost and budget were measured in the closing lesson of the previous course; here only the token unit is used.

The Instruction Does Not Stay in the Model

The first block sets up the simulator and the fiction, defines the four instruction lengths incrementally and writes the total cost of each over one hundred twenty requests. At the end a single fictional ticket is called with the short and the medium instruction, with two separate seeds.

# 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


E1 = "Etiketler: fatura , ariza , sayac , tarife , kesinti ."
E2 = " Talebi bu etiketlerden birine ata . Yanit olarak tek etiket yaz ."
E3 = (" Birden cok etiket uyuyorsa talebin ana konusunu sec ."
      " Hicbiri uymuyorsa en yakin etiketi sec . Aciklama ekleme .")
INSTRUCTIONS = (("none", ""), ("short", E1), ("medium", E1 + E2), ("long", E1 + E2 + E3))


def build_prompt(s, x):                     # persistent instruction + input that changes per request
    return (s + " " if s else "") + "Talep: " + x["text"]


print(f"{'instruction':<11} {'tokens':>9} {'in 120 requests':>15}")
for name, s in INSTRUCTIONS:
    b = len(tokenize(s))
    print(f"{name:<11} {b:>9d} {b * len(TICKETS):>15d}")
x0 = TICKETS[1]
gb = len(tokenize("Talep: " + x0["text"]))
ub = len(tokenize(INSTRUCTIONS[3][1]))
print(f"long prompt: instruction {ub} + input {gb} tokens, instruction share "
      f"{ub / (ub + gb):.4f}")
print(f"FICTIONAL ticket {x0['id']} ({x0['topic']}): {x0['text']}")
for name, s in INSTRUCTIONS[1:3]:
    CALL_COUNT[0] = 0
    for sd in (SEED, SEED + 1):
        print(f"{name} / seed {sd}: {call(build_prompt(s, x0), seed=sd)['response']}")
instruction    tokens in 120 requests
none                0               0
short              15            1800
medium             33            3960
long               62            7440
long prompt: instruction 62 + input 12 tokens, instruction share 0.8378
FICTIONAL ticket 4002 (fatura): fatura ayrintisini nereden gorebilirim
short / seed 20260218: talebiniz fatura konusuyla ilgili gorunuyor
short / seed 20260219: bu kayit fatura basligina girer , ilgili ekibe yonlendirildi
medium / seed 20260218: fatura
medium / seed 20260219: fatura

The last four lines show what the medium instruction does. With the short instruction the two runs give two different sentences, and the second one contains no label at all; with the medium instruction both runs give a single word, and the label is correct in both. What changes is not the hit rate but the readability of the response, and its cost is eighteen tokens.

The lines above are the actual proportion to be measured. The long instruction is 62 tokens; the ticket to be classified is 12 tokens. In a single prompt the instruction holds a share of 0.8378. Across one hundred twenty requests the same 62 tokens are sent one hundred twenty times and the total rises to 7440 tokens. Dropping one token from the instruction saves one hundred twenty tokens over one hundred twenty requests; this means that every decision taken while writing the instruction is multiplied by the number of requests.

The Total of the Repetition

The second block runs the four instructions on the same 120 records, then repeats the long instruction with three different request counts, and finally sets the tokens that each shortening gains next to the hit rate it drops.

def measure(s, seed=SEED, n=None):
    CALL_COUNT[0] = 0
    dataset = TICKETS if n is None else TICKETS[:n]
    ti = to = d = unl = 0
    for x in dataset:
        c = call(build_prompt(s, x), seed=seed)
        ti, to = ti + c["tokens_in"], to + c["tokens_out"]
        e = read_label(c["response"])
        unl += e is None
        d += e == x["topic"]
    m = len(dataset)
    return {"hit_rate": d / m, "unlabeled": unl / m, "tokens_in": ti, "tokens_out": to,
            "instruction": len(tokenize(s)) * m, "total": ti + to}


R = {name: measure(s) for name, s in INSTRUCTIONS}
print(f"{'instruction':<11} {'repeat':>7} {'in':>6} {'share':>7} {'out':>6} {'hit rate':>8} "
      f"{'run 2':>8} {'unlabeled':>10} {'per correct':>13}")
for name, s in INSTRUCTIONS:
    v, k2 = R[name], measure(s, seed=SEED + 1)["hit_rate"]
    print(f"{name:<11} {v['instruction']:>7d} {v['tokens_in']:>6d} "
          f"{v['instruction'] / v['tokens_in']:>7.4f} "
          f"{v['tokens_out']:>6d} {v['hit_rate']:>8.4f} {k2:>8.4f} {v['unlabeled']:>10.4f} "
          f"{v['total'] / v['hit_rate'] / len(TICKETS):>13.1f}")
print()
print(f"{'requests':>8} {'instruction tokens':>18} {'total input':>13} {'share':>7}")
for n in (30, 60, 120):
    v = measure(INSTRUCTIONS[3][1], n=n)
    print(f"{n:>8d} {v['instruction']:>18d} {v['tokens_in']:>13d} "
          f"{v['instruction'] / v['tokens_in']:>7.4f}")
print()
print(f"{'shortening':<16} {'tokens gained':>19} {'hit rate diff':>13} "
      f"{'per 0.01 hit rate':>19}")
for (a1, _), (a2, _) in zip(INSTRUCTIONS[1:], INSTRUCTIONS[:-1]):
    kb = R[a1]["total"] - R[a2]["total"]
    fi = R[a2]["hit_rate"] - R[a1]["hit_rate"]
    o = f"{kb * 0.01 / abs(fi):.0f} tokens" if fi < 0 else "lossless"
    print(f"{a1 + ' -> ' + a2:<16} {kb:>19d} {fi:>+13.4f} {o:>19}")
instruction  repeat     in   share    out hit rate    run 2  unlabeled   per correct
none              0   1700  0.0000   1285   0.4583   0.6333     0.2917          54.3
short          1800   3500  0.5143   1251   0.7167   0.4583     0.2167          55.2
medium         3960   5660  0.6996    196   0.7500   0.7500     0.0250          65.1
long           7440   9140  0.8140    203   0.7417   0.7583     0.0250         105.0

requests instruction tokens   total input   share
      30               1860          2295  0.8105
      60               3720          4547  0.8181
     120               7440          9140  0.8140

shortening             tokens gained hit rate diff   per 0.01 hit rate
short -> none                   1766       -0.2583           68 tokens
medium -> short                 1105       -0.0333          332 tokens
long -> medium                  3487       +0.0083            lossless

The second table shows how the repetition behaves. At thirty requests the long instruction comes to 1860, at sixty requests to 3720, at one hundred twenty requests to 7440 tokens: the cost grows linearly with the number of requests. The share of the instruction in total input stays steady between 0.8105 and 0.8181. There is no such thing as the share of the repetition thinning out as scale grows; whatever the number of requests, more than three quarters of the input is the instruction. However well an instruction is written, its cost is not its own length but its length multiplied by traffic.

The Cost of Shortening

The first table says where the hit rate saturates. The prompt without an instruction gives 0.4583. The short instruction raises it to 0.7167. The medium instruction raises it to 0.7500. The long instruction gives 0.7417, that is, below the medium one. The twenty-nine-token addition — ambiguity rules, main topic selection, the ban on explanation — added a total of 3487 tokens and took 0.0083 away from the hit rate. The cost per correct label went from 65.1 to 105.0 tokens. In this course such a row is written by name: the cost of the added text is certain, its gain is uncertain.

The third table reads the shortening from the opposite direction. Going from the long instruction to the medium one saves 3487 tokens and takes nothing from the hit rate; this is a lossless shortening. Going from medium to short saves 1105 tokens and takes 0.0333 of hit rate, that is, 332 tokens for every 0.01 of hit rate. Going from short to none saves 1766 tokens and takes 0.2583 of hit rate, that is, 68 tokens for every 0.01 of hit rate. The return on shortening is not constant: the shorter the instruction gets, the more expensive each remaining token becomes.

The unlabeled column of the table shows the real loss of shortening. With no instruction, no label can be read from 0.2917 of the responses, and with the short instruction none can be read from 0.2167 of them. With the medium instruction this share falls to 0.0250 and stays there. The remaining three records belong not to the prompt but to the surface: the rate limit returns three of the one hundred twenty calls empty. So the medium instruction has closed the gap that can be closed with a prompt. Since the long instruction has nothing left to add, it adds only tokens.

Finally the run 2 column is read. The prompt without an instruction gave 0.4583 and 0.6333 in two runs, the short instruction 0.7167 and 0.4583: in the second run the prompt without an instruction beat the prompt with the short instruction. The gain of the short instruction shows in one run and does not carry over to two. The medium instruction gave 0.7500 in both runs. The long instruction gave 0.7417 and 0.7583; its own two runs differ by 0.0167. The 0.0083 difference between the long and the medium instruction stays below that and counts as unmeasured in this course. The rule is applied by name in the next lesson.

Summary

  • The system instruction is a persistent behavior definition, but its persistence is in the prompt, not in the model: it is sent again in every request and paid for again in every request.
  • The 62-token long instruction holds 0.8378 of a single prompt and 7440 tokens across 120 requests. The share is steady between 0.8105 and 0.8181 at thirty, sixty and one hundred twenty requests; the total grows linearly.
  • The hit rate saturates at the medium instruction: none 0.4583, short 0.7167, medium 0.7500, long 0.7417. The long instruction added 3487 tokens, took 0.0083 from the hit rate and raised the cost per correct label from 65.1 to 105.0.
  • The return on shortening is not constant: going from long to medium is lossless, going from medium to short gains 332 tokens per 0.01 of hit rate, going from short to none gains 68 tokens.
  • The real gap the instruction closes is the unlabeled response share: it falls from 0.2917 to 0.0250 and stays there. The remaining share comes from the rate limit, so it cannot be closed with a prompt.

Next Step

The difference between the medium and the long instruction stayed below the own run difference of the long one: the twenty-nine added tokens produced nothing measurable. This does not close the question of what to add to an instruction. A frequent answer is to tell the model who it is: an expertise, a job title, a style. That this addition raises the hit rate is a common belief, and just like the ambiguity rules it is paid for in every request. The next lesson measures this: what difference specifying a role adds, how many tokens it costs, and whether that difference is larger than the difference between two runs of the same prompt.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ ↵ Esc navigate · open · close