Instructions to use patdev/k3-a40-bootstrap with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use patdev/k3-a40-bootstrap with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf patdev/k3-a40-bootstrap:BF16 # Run inference directly in the terminal: llama cli -hf patdev/k3-a40-bootstrap:BF16
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf patdev/k3-a40-bootstrap:BF16 # Run inference directly in the terminal: llama cli -hf patdev/k3-a40-bootstrap:BF16
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf patdev/k3-a40-bootstrap:BF16 # Run inference directly in the terminal: ./llama-cli -hf patdev/k3-a40-bootstrap:BF16
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf patdev/k3-a40-bootstrap:BF16 # Run inference directly in the terminal: ./build/bin/llama-cli -hf patdev/k3-a40-bootstrap:BF16
Use Docker
docker model run hf.co/patdev/k3-a40-bootstrap:BF16
- LM Studio
- Jan
- Ollama
How to use patdev/k3-a40-bootstrap with Ollama:
ollama run hf.co/patdev/k3-a40-bootstrap:BF16
- Unsloth Desktop
- Docker Model Runner
How to use patdev/k3-a40-bootstrap with Docker Model Runner:
docker model run hf.co/patdev/k3-a40-bootstrap:BF16
- Lemonade
How to use patdev/k3-a40-bootstrap with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull patdev/k3-a40-bootstrap:BF16
Run and chat with the model
lemonade run user.k3-a40-bootstrap-BF16
List all available models
lemonade list
- Atomic Chat
Upload distill/generate.py with huggingface_hub
Browse files- distill/generate.py +280 -0
distill/generate.py
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Étape 1 — collecte des réponses de Kimi-K3 pour distiller vers Kimi-Linear.
|
| 2 |
+
|
| 3 |
+
L'API officielle ne rend pas les logits : la distillation est donc au niveau
|
| 4 |
+
séquence (le socle apprend à imiter les sorties de K3), pas au niveau
|
| 5 |
+
distribution. C'est moins efficace en tokens qu'une KD sur logits, mais c'est
|
| 6 |
+
la seule voie disponible sans poids K3 locaux -- et c'est la recette déjà
|
| 7 |
+
validée dans Kimi-K3-L4-Distill-9B-LoRA.
|
| 8 |
+
|
| 9 |
+
Le budget est un plafond dur, vérifié avant chaque appel : l'endpoint facture
|
| 10 |
+
~15 $/1M de tokens de sortie, et une boucle non bornée y passerait des crédits
|
| 11 |
+
sans prévenir.
|
| 12 |
+
|
| 13 |
+
python generate.py --budget 2.0 --out data/k3.jsonl
|
| 14 |
+
"""
|
| 15 |
+
|
| 16 |
+
from __future__ import annotations
|
| 17 |
+
|
| 18 |
+
import argparse
|
| 19 |
+
import json
|
| 20 |
+
import os
|
| 21 |
+
import pathlib
|
| 22 |
+
import random
|
| 23 |
+
import sys
|
| 24 |
+
import time
|
| 25 |
+
import urllib.error
|
| 26 |
+
import urllib.request
|
| 27 |
+
|
| 28 |
+
ENDPOINT = "https://api.runpod.ai/v2/moonshot-kimi/runsync"
|
| 29 |
+
PRICE_OUT = 15.0 / 1_000_000 # $/token de sortie, tarif affiche
|
| 30 |
+
PRICE_IN = 3.0 / 1_000_000
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def api_key() -> str:
|
| 34 |
+
"""Le jeton n'est jamais journalise ni affiche."""
|
| 35 |
+
k = os.environ.get("RUNPOD_API_KEY")
|
| 36 |
+
if k:
|
| 37 |
+
return k.strip()
|
| 38 |
+
for p in (r"G:\AI\runpod\.env", ".env"):
|
| 39 |
+
f = pathlib.Path(p)
|
| 40 |
+
if f.exists():
|
| 41 |
+
for line in f.read_text(encoding="utf-8", errors="ignore").splitlines():
|
| 42 |
+
if line.startswith("RUNPOD_API_KEY="):
|
| 43 |
+
v = line.split("=", 1)[1].strip().strip('"').strip("'")
|
| 44 |
+
if v:
|
| 45 |
+
return v
|
| 46 |
+
sys.exit("RUNPOD_API_KEY introuvable (env ou G:\\AI\\runpod\\.env)")
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
# ---------------------------------------------------------------------- prompts
|
| 50 |
+
# Cible les écarts mesurés entre Kimi-Linear et K3, pas des tâches génériques :
|
| 51 |
+
# le français imprécis ("gate" traduit en "gâteau"), l'usage d'outils, et
|
| 52 |
+
# l'édition de code, qui est le régime réel d'un agent.
|
| 53 |
+
|
| 54 |
+
CODE = [
|
| 55 |
+
"Écris une fonction Python qui parse un fichier .env en dictionnaire, en gérant les commentaires, les guillemets et les lignes vides. Code seulement.",
|
| 56 |
+
"Refactorise ce code pour éliminer la duplication :\n\n```python\ndef get_user(id):\n r = requests.get(f'/users/{id}')\n if r.status_code != 200: raise Exception('fail')\n return r.json()\n\ndef get_post(id):\n r = requests.get(f'/posts/{id}')\n if r.status_code != 200: raise Exception('fail')\n return r.json()\n```",
|
| 57 |
+
"Explique pourquoi ce code a une condition de course et corrige-le :\n\n```python\ncounter = 0\ndef worker():\n global counter\n for _ in range(100000):\n counter += 1\n```",
|
| 58 |
+
"Écris un décorateur Python qui réessaie une fonction avec un backoff exponentiel et un jitter. Type hints complets.",
|
| 59 |
+
"Convertis cette boucle en compréhension et explique si c'est vraiment plus lisible :\n\n```python\nout = []\nfor x in items:\n if x.active:\n out.append(x.name.upper())\n```",
|
| 60 |
+
"Trouve le bug :\n\n```python\ndef binary_search(a, t):\n lo, hi = 0, len(a)\n while lo < hi:\n mid = (lo + hi) // 2\n if a[mid] < t: lo = mid\n elif a[mid] > t: hi = mid\n else: return mid\n return -1\n```",
|
| 61 |
+
"Écris un contexte manager asynchrone Python qui limite la concurrence à N tâches.",
|
| 62 |
+
"Implémente un LRU cache en Python sans utiliser functools, avec O(1) en lecture et écriture.",
|
| 63 |
+
]
|
| 64 |
+
|
| 65 |
+
FRENCH = [
|
| 66 |
+
"Explique en trois phrases précises ce qu'est le mécanisme de gating dans un modèle mixture-of-experts. Emploie la terminologie française correcte.",
|
| 67 |
+
"Quelle est la différence entre la mémoïsation et la programmation dynamique ? Réponds en français technique rigoureux.",
|
| 68 |
+
"Explique ce qu'est une condition de concurrence et donne un exemple concret en français.",
|
| 69 |
+
"Décris le fonctionnement d'un cache de préfixe dans un moteur d'inférence, en français, sans anglicismes inutiles.",
|
| 70 |
+
"Explique la différence entre latence et débit pour un serveur d'inférence, avec un exemple chiffré.",
|
| 71 |
+
"Qu'est-ce que la quantification d'un modèle de langage ? Explique les compromis en français précis.",
|
| 72 |
+
]
|
| 73 |
+
|
| 74 |
+
# Les outils sont passes dans le champ `tools` de la requete, pas decrits en
|
| 75 |
+
# prose : sollicite ainsi, K3 repond a juste titre "aucun outil ne m'est
|
| 76 |
+
# reellement fourni", et l'exemple collecte est inutilisable pour apprendre
|
| 77 |
+
# l'usage d'outils.
|
| 78 |
+
TOOL_SCHEMA = [
|
| 79 |
+
{"type": "function", "function": {"name": "read_file", "description": "Lit un fichier",
|
| 80 |
+
"parameters": {"type": "object", "properties": {"path": {"type": "string"}}, "required": ["path"]}}},
|
| 81 |
+
{"type": "function", "function": {"name": "write_file", "description": "Ecrit un fichier",
|
| 82 |
+
"parameters": {"type": "object", "properties": {"path": {"type": "string"}, "content": {"type": "string"}}, "required": ["path", "content"]}}},
|
| 83 |
+
{"type": "function", "function": {"name": "grep", "description": "Cherche un motif",
|
| 84 |
+
"parameters": {"type": "object", "properties": {"pattern": {"type": "string"}, "path": {"type": "string"}}, "required": ["pattern"]}}},
|
| 85 |
+
{"type": "function", "function": {"name": "list_dir", "description": "Liste un dossier",
|
| 86 |
+
"parameters": {"type": "object", "properties": {"path": {"type": "string"}}, "required": ["path"]}}},
|
| 87 |
+
{"type": "function", "function": {"name": "run_command", "description": "Execute une commande shell",
|
| 88 |
+
"parameters": {"type": "object", "properties": {"cmd": {"type": "string"}}, "required": ["cmd"]}}},
|
| 89 |
+
]
|
| 90 |
+
|
| 91 |
+
TOOLS = [
|
| 92 |
+
"Lis /etc/config.yaml, remplace le port 8080 par 9090, et reecris le fichier.",
|
| 93 |
+
"Trouve tous les fichiers Python de plus de 500 lignes dans ce depot.",
|
| 94 |
+
"Trouve ou la variable MAX_RETRIES est definie, puis montre son contexte.",
|
| 95 |
+
"Determine quel framework de test utilise ce projet.",
|
| 96 |
+
]
|
| 97 |
+
|
| 98 |
+
REASONING = [
|
| 99 |
+
"Un serveur traite 1200 requêtes/s avec 8 workers. On passe à 12 workers et le débit monte à 1500 req/s. Que peut-on en déduire sur le goulot d'étranglement ?",
|
| 100 |
+
"Un modèle lit 4,7 Go de poids par token et la carte offre 696 Go/s. Quel est le plafond théorique en tokens/s ? Comment le décodage spéculatif le dépasse-t-il ?",
|
| 101 |
+
"Pourquoi un cache KV quantifié en 8 bits peut-il être refusé par un moteur alors que les poids en 4 bits sont acceptés ?",
|
| 102 |
+
]
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
def build_prompts(n: int, seed: int = 0) -> list[str]:
|
| 106 |
+
"""Mélange déterministe : deux exécutions avec la même graine donnent le
|
| 107 |
+
même jeu, ce qui rend une reprise après interruption reproductible."""
|
| 108 |
+
pool = CODE * 3 + FRENCH * 3 + TOOLS * 2 + REASONING * 2
|
| 109 |
+
rng = random.Random(seed)
|
| 110 |
+
rng.shuffle(pool)
|
| 111 |
+
return (pool * (n // len(pool) + 1))[:n]
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def _req(url: str, key: str, body: bytes | None = None, timeout: int = 300):
|
| 115 |
+
req = urllib.request.Request(
|
| 116 |
+
url, data=body,
|
| 117 |
+
headers={"Authorization": f"Bearer {key}",
|
| 118 |
+
"Content-Type": "application/json",
|
| 119 |
+
# Cloudflare, devant l'API Runpod, rejette la signature par
|
| 120 |
+
# defaut d'urllib avec un 403 "error code: 1010".
|
| 121 |
+
"User-Agent": "Mozilla/5.0 (distill)"})
|
| 122 |
+
with urllib.request.urlopen(req, timeout=timeout) as r:
|
| 123 |
+
return json.loads(r.read())
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
def call_k3(prompt: str, key: str, max_tokens: int, timeout: int = 300,
|
| 127 |
+
tools: list | None = None) -> dict | None:
|
| 128 |
+
"""Soumet puis, si necessaire, suit la tache jusqu'a son terme.
|
| 129 |
+
|
| 130 |
+
`runsync` ne rend le resultat que si la generation tient dans son attente
|
| 131 |
+
interne ; au-dela il renvoie un identifiant et un statut IN_QUEUE ou
|
| 132 |
+
IN_PROGRESS. Ne pas le suivre donnait une reponse sans `output`, donc vide
|
| 133 |
+
et sans cout -- un symptome qui ressemblait a tort a un probleme de modele.
|
| 134 |
+
"""
|
| 135 |
+
body = json.dumps({"input": {
|
| 136 |
+
"model": "kimi-k3",
|
| 137 |
+
"messages": [{"role": "user", "content": prompt}],
|
| 138 |
+
"max_tokens": max_tokens,
|
| 139 |
+
# K3 refuse toute temperature autre que 1 :
|
| 140 |
+
# "invalid temperature: only 1 is allowed for this model"
|
| 141 |
+
# L'erreur n'apparaissait pas tant que la tache n'etait pas suivie.
|
| 142 |
+
"temperature": 1,
|
| 143 |
+
**({"tools": tools, "tool_choice": "auto"} if tools else {}),
|
| 144 |
+
}}).encode()
|
| 145 |
+
try:
|
| 146 |
+
r = _req("https://api.runpod.ai/v2/moonshot-kimi/runsync", key, body, timeout)
|
| 147 |
+
except urllib.error.HTTPError as e:
|
| 148 |
+
print(f" HTTP {e.code}: {e.read()[:200].decode('utf-8', 'ignore')}", flush=True)
|
| 149 |
+
return None
|
| 150 |
+
except Exception as e:
|
| 151 |
+
print(f" {type(e).__name__}: {e}", flush=True)
|
| 152 |
+
return None
|
| 153 |
+
|
| 154 |
+
if r.get("output") is not None:
|
| 155 |
+
return r
|
| 156 |
+
|
| 157 |
+
job = r.get("id")
|
| 158 |
+
status = r.get("status")
|
| 159 |
+
if not job:
|
| 160 |
+
print(f" reponse sans output ni id : {str(r)[:160]}", flush=True)
|
| 161 |
+
return None
|
| 162 |
+
|
| 163 |
+
deadline = time.time() + timeout
|
| 164 |
+
while time.time() < deadline:
|
| 165 |
+
time.sleep(3)
|
| 166 |
+
try:
|
| 167 |
+
r = _req(f"https://api.runpod.ai/v2/moonshot-kimi/status/{job}", key)
|
| 168 |
+
except Exception as e:
|
| 169 |
+
print(f" suivi : {type(e).__name__}", flush=True)
|
| 170 |
+
continue
|
| 171 |
+
status = r.get("status")
|
| 172 |
+
if status == "COMPLETED":
|
| 173 |
+
return r
|
| 174 |
+
if status in ("FAILED", "CANCELLED", "TIMED_OUT"):
|
| 175 |
+
print(f" tache {status}: {str(r.get('error'))[:160]}", flush=True)
|
| 176 |
+
return None
|
| 177 |
+
print(f" tache toujours {status} apres {timeout} s", flush=True)
|
| 178 |
+
return None
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
def extract(resp: dict) -> tuple[str, str, dict, float, list]:
|
| 182 |
+
"""Renvoie (contenu, trace de raisonnement, usage, coût réel).
|
| 183 |
+
|
| 184 |
+
K3 expose son raisonnement dans `reasoning_content`. On le conserve à part :
|
| 185 |
+
l'entraîner ou non est une décision à prendre en aval, pas ici.
|
| 186 |
+
"""
|
| 187 |
+
out = resp.get("output")
|
| 188 |
+
if isinstance(out, list) and out:
|
| 189 |
+
out = out[0]
|
| 190 |
+
res = (out or {}).get("result") or {}
|
| 191 |
+
ch = (res.get("choices") or [{}])[0]
|
| 192 |
+
msg = ch.get("message") or {}
|
| 193 |
+
usage = res.get("usage") or {}
|
| 194 |
+
cost = (out or {}).get("cost")
|
| 195 |
+
if cost is None:
|
| 196 |
+
cost = (usage.get("completion_tokens", 0) * PRICE_OUT
|
| 197 |
+
+ usage.get("prompt_tokens", 0) * PRICE_IN)
|
| 198 |
+
return (msg.get("content") or "", msg.get("reasoning_content") or "",
|
| 199 |
+
usage, float(cost), msg.get("tool_calls") or [])
|
| 200 |
+
|
| 201 |
+
|
| 202 |
+
def main() -> None:
|
| 203 |
+
ap = argparse.ArgumentParser()
|
| 204 |
+
ap.add_argument("--budget", type=float, default=1.0, help="plafond dur en dollars")
|
| 205 |
+
ap.add_argument("--out", default="data/k3.jsonl")
|
| 206 |
+
# K3 raisonne avant de repondre : un budget trop court ne produit que de la
|
| 207 |
+
# reflexion. 2000 laisse la place a la trace ET a la reponse.
|
| 208 |
+
ap.add_argument("--max-tokens", type=int, default=2000)
|
| 209 |
+
ap.add_argument("--n", type=int, default=400)
|
| 210 |
+
ap.add_argument("--seed", type=int, default=0)
|
| 211 |
+
a = ap.parse_args()
|
| 212 |
+
|
| 213 |
+
key = api_key()
|
| 214 |
+
path = pathlib.Path(a.out)
|
| 215 |
+
path.parent.mkdir(parents=True, exist_ok=True)
|
| 216 |
+
|
| 217 |
+
# Reprise : on saute ce qui est déjà collecté plutôt que de le repayer.
|
| 218 |
+
done = set()
|
| 219 |
+
if path.exists():
|
| 220 |
+
for line in path.open(encoding="utf-8"):
|
| 221 |
+
try:
|
| 222 |
+
done.add(json.loads(line)["prompt"])
|
| 223 |
+
except Exception:
|
| 224 |
+
pass
|
| 225 |
+
print(f"reprise : {len(done)} exemples deja collectes")
|
| 226 |
+
|
| 227 |
+
prompts = [p for p in build_prompts(a.n, a.seed) if p not in done]
|
| 228 |
+
spent = 0.0
|
| 229 |
+
kept = 0
|
| 230 |
+
t0 = time.time()
|
| 231 |
+
|
| 232 |
+
with path.open("a", encoding="utf-8") as f:
|
| 233 |
+
for i, p in enumerate(prompts, 1):
|
| 234 |
+
# Verification AVANT l'appel : depasser le plafond puis s'en
|
| 235 |
+
# apercevoir ne sert a rien, l'argent est deja parti.
|
| 236 |
+
if spent >= a.budget:
|
| 237 |
+
print(f"plafond de {a.budget} $ atteint, arret propre")
|
| 238 |
+
break
|
| 239 |
+
r = call_k3(p, key, a.max_tokens,
|
| 240 |
+
tools=TOOL_SCHEMA if p in TOOLS else None)
|
| 241 |
+
if not r:
|
| 242 |
+
continue
|
| 243 |
+
content, reasoning, usage, cost, tool_calls = extract(r)
|
| 244 |
+
spent += cost
|
| 245 |
+
# Un tour qui n'emet que des appels d'outils est un exemple
|
| 246 |
+
# valide : c'est meme le comportement qu'on cherche a distiller.
|
| 247 |
+
if not content.strip() and not tool_calls:
|
| 248 |
+
# K3 est un modele a raisonnement : il remplit d'abord
|
| 249 |
+
# reasoning_content. Avec un max_tokens trop bas il consomme
|
| 250 |
+
# tout son budget en reflexion et n'emet jamais la reponse.
|
| 251 |
+
# Le distinguer d'une vraie reponse vide evite de chercher
|
| 252 |
+
# ailleurs.
|
| 253 |
+
why = (f"raisonnement seul ({len(reasoning)} car., "
|
| 254 |
+
f"{usage.get('completion_tokens',0)} tokens) "
|
| 255 |
+
f"-- augmentez --max-tokens"
|
| 256 |
+
if reasoning.strip() else "reponse totalement vide")
|
| 257 |
+
print(f" {i}: {why}")
|
| 258 |
+
continue
|
| 259 |
+
f.write(json.dumps({
|
| 260 |
+
"prompt": p,
|
| 261 |
+
"completion": content,
|
| 262 |
+
"reasoning": reasoning,
|
| 263 |
+
"tool_calls": tool_calls,
|
| 264 |
+
"usage": usage,
|
| 265 |
+
"cost": cost,
|
| 266 |
+
}, ensure_ascii=False) + "\n")
|
| 267 |
+
f.flush()
|
| 268 |
+
kept += 1
|
| 269 |
+
if kept % 10 == 0 or i == 1:
|
| 270 |
+
print(f" {kept} gardes | {spent:.3f} $ / {a.budget} $ | "
|
| 271 |
+
f"{time.time()-t0:.0f} s", flush=True)
|
| 272 |
+
|
| 273 |
+
print(f"\n{kept} exemples ecrits dans {path}")
|
| 274 |
+
print(f"cout reel : {spent:.3f} $")
|
| 275 |
+
if kept:
|
| 276 |
+
print(f"soit {spent/kept*1000:.2f} $ pour 1000 exemples")
|
| 277 |
+
|
| 278 |
+
|
| 279 |
+
if __name__ == "__main__":
|
| 280 |
+
main()
|