#let accent = rgb("#22617f") #let ember = rgb("#a85430") #let paper = rgb("#faf8f3") #let _row(label, frac, pct, color) = grid( columns: (86pt, 1fr, 36pt), column-gutter: 5pt, align(right + horizon, text(size: 10pt)[#label]), place(left + horizon, place(left + horizon, rect(width: 100%, height: 7pt, fill: luma(242), radius: 1.5pt)) + place(left + horizon, rect(width: frac * 100%, height: 7pt, fill: color, radius: 1.5pt))), align(right + horizon, text(size: 9.5pt, fill: luma(110))[#pct]), ) #let next-token-chart() = block(width: 100%, { box(width: 100%, stroke: 0.8pt + accent.lighten(30%), fill: accent.lighten(94%), radius: 3pt, inset: (x: 8pt, y: 4pt), align(left, text(size: 11.5pt)[„Der Himmel über der Stadt ist …“])) v(5pt) _row("blau", 0.58, "58 %", accent) v(2.5pt) _row("bedeckt", 0.17, "17 %", accent.lighten(35%)) v(2.5pt) _row("dunkel", 0.09, "9 %", accent.lighten(52%)) v(2.5pt) _row("grau", 0.07, "7 %", accent.lighten(62%)) v(2.5pt) _row("…", 0.09, "9 %", luma(224)) }) #let _pipebox(title, ..lines, highlight: false, dashed: false) = block( width: 100%, stroke: ( paint: if highlight { accent } else { luma(205) }, thickness: if highlight { 1.1pt } else { 0.6pt }, dash: if dashed { "dashed" }, ), fill: if highlight { accent.lighten(94%) } else { paper }, radius: 3pt, inset: (x: 5pt, y: 6pt), align(center)[ #text(size: 10pt, weight: "bold")[#title] #v(2pt) #for l in lines.pos() [ #text(size: 8.5pt, fill: luma(110))[#l] #v(1pt) ] ], ) #let training-pipeline() = grid( columns: (1fr, 11pt, 1fr, 11pt, 1fr, 11pt, 1fr, 11pt, 1fr), align(horizon, _pipebox("Rohdaten", "")), align(horizon, text(fill: accent)[→]), _pipebox("Pretraining", "Nächstes Token", "Tausende GPUs", "Wochen–Monate", highlight: true), align(horizon, text(fill: accent)[→]), align(horizon, _pipebox("Basismodell", "reiner Text-", "vervollständiger", dashed: true)), align(horizon, text(fill: accent)[→]), align(horizon, _pipebox("Fine-Tuning", "SFT: Dialoge", "RLHF: Präferenzen")), align(horizon, text(fill: accent)[→]), align(horizon, _pipebox("Assistent", "Chat · API · Agents")), ) #let _edot(x, y, c) = place(top + left, dx: x - 2.4pt, dy: y - 2.4pt, circle(radius: 2.4pt, fill: c)) #let _head(x, y, ang, color) = { let c = calc.cos(ang) let s = calc.sin(ang) let bx = x - 6.5pt * c let by = y - 6.5pt * s place(top + left, dx: 0pt, dy: 0pt, polygon( (x, y), (bx - 2.6pt * s, by + 2.6pt * c), (bx + 2.6pt * s, by - 2.6pt * c), fill: color, )) } #let _elabel-c(x, y, body) = place(top, dx: x - 35pt, dy: y, box(width: 70pt, align(center, text(size: 10.5pt, fill: luma(70))[#body]))) #let embedding-plot() = align(center, block(width: 330pt, height: 122pt, { place(top + left, dx: 56pt, dy: 16pt, line(angle: 90deg, length: 76pt, stroke: 0.7pt + luma(175))) place(top + left, dx: 56pt, dy: 92pt, line(angle: 0deg, length: 250pt, stroke: 0.7pt + luma(175))) _head(56pt, 16pt, -90deg, luma(175)) _head(306pt, 92pt, 0deg, luma(175)) place(top + left, dx: -6pt, dy: 46pt, rotate(-90deg, text(size: 9pt, fill: luma(140))[einfach → königlich])) place(top, dx: 56pt, dy: 101pt, box(width: 250pt, align(center, text(size: 9pt, fill: luma(140))[männlich → weiblich]))) place(top, dx: 46pt, dy: -3pt, box(width: 270pt, align(center, text(size: 12pt, weight: "bold")[König − Mann + Frau ≈ Königin]))) place(top + left, dx: 106pt, dy: 78pt, line(angle: 0deg, length: 94pt, stroke: (paint: luma(160), thickness: 0.8pt, dash: "dashed"))) place(top + left, dx: 106pt, dy: 78pt, line(angle: -81.3deg, length: 47pt, stroke: 1.1pt + accent)) place(top + left, dx: 206pt, dy: 78pt, line(angle: -81.3deg, length: 47pt, stroke: 1.1pt + accent)) _head(200pt, 78pt, 0deg, luma(160)) _head(113.2pt, 31.6pt, -81.3deg, accent) _head(213.2pt, 31.6pt, -81.3deg, accent) place(top, dx: 46pt, dy: 47pt, box(width: 58pt, align(right, text(size: 9pt, fill: accent)[König − Mann]))) place(top, dx: 111pt, dy: 60pt, box(width: 90pt, align(center, text(size: 9pt, fill: luma(130))[Frau − Mann]))) place(top, dx: 223pt, dy: 47pt, box(width: 82pt, align(left, text(size: 9pt, fill: accent)[≈ gleicher Vektor]))) _edot(106pt, 78pt, luma(85)) _edot(206pt, 78pt, luma(85)) _edot(114pt, 26pt, accent) _edot(214pt, 26pt, accent) _elabel-c(106pt, 84pt, [Mann]) _elabel-c(206pt, 84pt, [Frau]) place(top, dx: 48pt, dy: 20pt, box(width: 60pt, align(right, text(size: 10.5pt, fill: luma(70))[König]))) place(top, dx: 222pt, dy: 20pt, box(width: 66pt, align(left, text(size: 10.5pt, fill: luma(70))[Königin]))) })) #let _tl-fx(y) = 22pt + (y - 2023.0) / 2.72 * 378pt #let _tl-ev(yr, above, lvl, label, w: 95pt) = ( x: _tl-fx(yr), dy: if above { 17pt - lvl * 17pt } else { 55pt + lvl * 17pt }, label: label, w: w, ) #let _tl-lane(events, color, title) = block(width: 100%, height: 98pt, { for yr in (2023, 2024, 2025) { place(top + left, dx: _tl-fx(yr), dy: 2pt, line(angle: 90deg, length: 94pt, stroke: 0.4pt + luma(235))) } place(horizon + left, line(length: 100%, stroke: 0.8pt + luma(205))) place(top + left, dx: 2pt, dy: 0pt, text(size: 10pt, weight: "bold", fill: color)[#title]) for e in events { place(top + left, dx: e.x - e.w / 2, dy: e.dy, box(width: e.w, align(center, text(size: 9.5pt, fill: luma(70))[#e.label]))) } for e in events { place(top + left, dx: e.x - 2.2pt, dy: 46.8pt, circle(radius: 2.2pt, fill: color)) } }) #let _tl-years() = block(width: 100%, height: 14pt, { for (yr, name) in ((2023, [2023]), (2024, [2024]), (2025, [2025])) { place(top, dx: _tl-fx(yr) - 25pt, box(width: 50pt, align(center, text(size: 8.5pt, fill: luma(140), font: "DejaVu Sans Mono")[#name]))) } }) #let two-llm-timeline() = block(width: 100%, { _tl-lane(( _tl-ev(2023.21, true, 0, []), _tl-ev(2023.87, false, 0, []), _tl-ev(2024.21, true, 1, []), _tl-ev(2025.08, false, 1, []), _tl-ev(2025.24, true, 0, []), _tl-ev(2025.52, false, 0, [], w: 120pt), ), ember, []) _tl-lane(( _tl-ev(2023.28, true, 0, []), _tl-ev(2023.71, false, 0, [], w: 120pt), _tl-ev(2024.54, true, 0, []), _tl-ev(2025.10, false, 0, []), _tl-ev(2025.71, true, 1, [], w: 66pt), ), accent, []) _tl-years() }) #let hbar(label, value, max, fillc: accent, valstr: "") = grid( columns: (92pt, 1fr, 42pt), column-gutter: 5pt, align(right + horizon, text(size: 10pt)[#label]), place(left + horizon, place(left + horizon, rect(width: 100%, height: 7pt, fill: luma(242), radius: 1.5pt)) + place(left + horizon, rect(width: value / max * 100%, height: 7pt, fill: fillc, radius: 1.5pt))), align(right + horizon, text(size: 9.5pt, fill: luma(110))[#valstr]), )