patdev/k3-a40-bootstrap
01.3k
1"""Valide le contexte long : l'aiguille est-elle retrouvee AU-DELA du natif ?2 3Le modele est natif 262 144 jetons. Le million annonce vient d'un YaRN facteur44,0, qui reechelonne TOUTES les positions. Retrouver une information placee5au-dela de 262 144 est donc la seule preuve que le chiffre annonce est reel.6 7Trois defauts des tentatives precedentes, tous corriges ici :8 91. NON-STREAMING. Un preremplissage de plusieurs centaines de milliers de jetons10 depasse deux minutes ; sans flux, aucun octet ne circule et le proxy Runpod11 coupe vers 125 s (524). On diffuse.122. TAILLE DEVINEE. J'estimais 18 jetons par ligne ; la valeur reelle est ~28.13 Une cible de 850 k demandait 1 322 k jetons, au-dela de la limite, et vLLM14 refusait a juste titre. On CALIBRE avec /v1/messages/count_tokens.153. GPU OCCUPE. Le test tournait pendant que douze requetes fantomes tenaient le16 moteur a 0,5 jeton/s. On verifie que la machine est libre avant.17 18L'aiguille est placee au MILIEU : les extremites restent bien retrouvees meme19par un modele dont le contexte long est degrade, donc les y placer ne prouverait20rien.21 22 python valide_1m.py --base https://<pod>-8080.proxy.runpod.net --cible 40000023"""24 25from __future__ import annotations26 27import argparse28import json29import time30import urllib.error31import urllib.request32 33LIGNE = ("Le registre {} consigne les operations de maintenance courante du "34 "parc, sans incident notable ni intervention requise.\n")35SECRET = "MARMOTTE-7391"36 37 38def _req(url: str, body: dict, stream: bool) -> urllib.request.Request:39 h = {"Content-Type": "application/json", "anthropic-version": "2023-06-01",40 "User-Agent": "Mozilla/5.0 (valide-1m)"}41 if stream:42 h["Accept"] = "text/event-stream"43 return urllib.request.Request(url, data=json.dumps(body).encode(), headers=h)44 45 46def compte(base: str, model: str, texte: str) -> int | None:47 """Nombre de jetons vu par le serveur, ou None si la route est absente."""48 try:49 r = urllib.request.urlopen(_req(50 base + "/v1/messages/count_tokens",51 {"model": model, "messages": [{"role": "user", "content": texte}]},52 False), timeout=300)53 return json.load(r).get("input_tokens")54 except Exception: # noqa: BLE00155 return None56 57 58def botte(n_lignes: int) -> str:59 moitie = n_lignes // 260 parts = [LIGNE.format(i) for i in range(moitie)]61 parts.append(f"Note importante : le code de verrouillage est {SECRET}.\n")62 parts += [LIGNE.format(i) for i in range(moitie, n_lignes)]63 return "".join(parts)64 65 66def cherche(base: str, model: str, foin: str, budget: float) -> tuple[bool, str, float, int]:67 q = (foin + "\n\nQuestion : quel est le code de verrouillage mentionne dans "68 "le texte ci-dessus ? Reponds uniquement par le code, rien d'autre.")69 body = {"model": model, "max_tokens": 100, "temperature": 0, "stream": True,70 "thinking": {"type": "disabled"},71 "messages": [{"role": "user", "content": q}]}72 t0 = time.time()73 txt, entree, premier = "", 0, None74 try:75 with urllib.request.urlopen(_req(base + "/v1/messages", body, True),76 timeout=budget) as r:77 for raw in r:78 line = raw.decode("utf-8", "ignore").strip()79 if not line.startswith("data:"):80 continue81 try:82 ev = json.loads(line[5:].strip())83 except json.JSONDecodeError:84 continue85 t = ev.get("type")86 # Le vrai decompte arrive dans `message_delta` : le protocole87 # Anthropic met des zeros dans `message_start`, l'usage n'etant88 # pas connu au moment ou l'entete part.89 if t in ("message_start", "message_delta"):90 u = (ev.get("usage")91 or (ev.get("message") or {}).get("usage") or {})92 entree = u.get("input_tokens") or entree93 elif t == "content_block_delta":94 if premier is None:95 premier = time.time() - t096 txt += ev.get("delta", {}).get("text") or ""97 elif t == "error":98 return False, f"[amont] {ev.get('error', {}).get('message', '')[:150]}", \99 time.time() - t0, 0100 except urllib.error.HTTPError as e:101 return False, f"[HTTP {e.code}]", time.time() - t0, 0102 except Exception as e: # noqa: BLE001103 return False, f"[{type(e).__name__}] {e}", time.time() - t0, 0104 return (SECRET in txt), txt.strip()[:60], time.time() - t0, entree105 106 107def main() -> None:108 ap = argparse.ArgumentParser()109 ap.add_argument("--base", required=True)110 ap.add_argument("--model", default="claude-ornith")111 ap.add_argument("--cible", type=int, default=400000)112 ap.add_argument("--budget", type=float, default=280.0,113 help="secondes maximum, coupure comprise")114 a = ap.parse_args()115 base = a.base.rstrip("/")116 117 # Calibration : on mesure une botte temoin, puis on met a l'echelle.118 temoin_n = 2000119 n_tok = compte(base, a.model, botte(temoin_n))120 if n_tok:121 par_ligne = n_tok / temoin_n122 source = "mesure par le serveur"123 else:124 par_ligne = len(LIGNE.format(0)) / 3.5125 source = "estimee (route count_tokens absente)"126 n_lignes = max(40, int(a.cible / par_ligne))127 print(f" calibration : {par_ligne:.1f} jetons/ligne ({source})")128 print(f" cible {a.cible:,} jetons -> {n_lignes:,} lignes")129 130 foin = botte(n_lignes)131 ok, rep, dt, entree = cherche(base, a.model, foin, a.budget)132 natif = 262144133 print(f" contexte reel : {entree:,} jetons "134 f"({'AU-DELA' if entree > natif else 'SOUS'} le natif de {natif:,})")135 print(f" duree : {dt:.1f}s")136 print(f" reponse : {rep!r}")137 print()138 if ok and entree > natif:139 print(f" VALIDE : aiguille retrouvee a {entree:,} jetons, "140 f"soit {entree / natif:.1f}x le contexte natif.")141 elif ok:142 print(f" Trouvee, mais a {entree:,} jetons : SOUS le natif. "143 "Ne prouve rien sur le YaRN.")144 else:145 print(" ECHEC : aiguille non retrouvee.")146 147 148if __name__ == "__main__":149 main()150 