patdev/k3-a40-bootstrap
01.3k
1"""Patch du serveur Anthropic natif de vLLM 0.27.1 : niveau de raisonnement.2 3Ce que vLLM fait nativement (verifie dans les sources, 22/08) :4 - `output_config.effort` -> `reasoning_effort`, que seul Harmony/GPT-OSS lit ;5 sur Qwen/Ornith ca ne change RIEN (mesure : effort max = effort low).6 - `thinking: {type, budget_tokens}` n'existe pas dans AnthropicMessagesRequest :7 pydantic le jette. Ni `disabled` ni le budget n'agissent.8 9Ce patch, applique a l'installation dans le venv (idempotent, avant `vllm serve`) :10 1. ajoute le champ `thinking` a AnthropicMessagesRequest ;11 2. dans `_handle_output_config` : effort -> `thinking_token_budget`12 (low 1024, medium 4096, high 16384, xhigh 32768, max/illimite = None) ;13 `thinking.budget_tokens` explicite gagne ; `thinking.type == "disabled"`14 -> chat_template_kwargs.enable_thinking = False.15`thinking_token_budget` est applique par vLLM cote echantillonnage (le bloc de16raisonnement est ferme au plafond) : c'est le meme mecanisme que le pont.17 18 /opt/venv/bin/python vllm_anthropic_effort_patch.py # applique19 /opt/venv/bin/python vllm_anthropic_effort_patch.py --check # verifie seulement20"""21from __future__ import annotations22 23import ast24import importlib.util25import os26import sys27 28MARK = "# [patch effort->thinking_token_budget]"29 30 31def _chemin(mod: str) -> str:32 spec = importlib.util.find_spec(mod)33 if not spec or not spec.origin:34 raise SystemExit(f"module introuvable : {mod}")35 return spec.origin36 37 38def patch_protocol(p: str) -> bool:39 s = open(p, encoding="utf-8").read()40 if MARK in s:41 return False42 anchor = " output_config: AnthropicOutputConfig | None = None\n"43 if anchor not in s:44 raise SystemExit("protocol.py : ancre output_config introuvable (version differente ?)")45 s = s.replace(anchor, anchor + f" thinking: dict[str, Any] | None = None {MARK}\n", 1)46 ast.parse(s)47 open(p, "w", encoding="utf-8").write(s)48 return True49 50 51def patch_serving(p: str) -> bool:52 s = open(p, encoding="utf-8").read()53 if MARK in s:54 return False55 anchor = (" if output_config and output_config.effort is not None:\n"56 " req.reasoning_effort = output_config.effort\n")57 if anchor not in s:58 raise SystemExit("serving.py : ancre effort introuvable (version differente ?)")59 new = anchor + f''' {MARK}60 # Niveau de raisonnement -> plafond de jetons de raisonnement, seul61 # mecanisme que les modeles Qwen/Ornith honorent. Le budget explicite62 # d'Anthropic (thinking.budget_tokens) gagne sur l'effort.63 _BUDGET = {{"low": 1024, "medium": 4096, "high": 16384, "xhigh": 32768, "max": None}}64 _eff = output_config.effort if output_config else None65 if _eff in _BUDGET:66 req.thinking_token_budget = _BUDGET[_eff]67 _th = getattr(anthropic_request, "thinking", None)68 if isinstance(_th, dict):69 if _th.get("type") == "disabled":70 _kw = dict(req.chat_template_kwargs or {{}})71 _kw.setdefault("enable_thinking", False)72 req.chat_template_kwargs = _kw73 elif _th.get("budget_tokens"):74 try:75 req.thinking_token_budget = max(1, int(_th["budget_tokens"]))76 except (TypeError, ValueError):77 pass78'''79 s = s.replace(anchor, new, 1)80 ast.parse(s)81 open(p, "w", encoding="utf-8").write(s)82 return True83 84 85def main() -> None:86 check = "--check" in sys.argv87 pp = _chemin("vllm.entrypoints.anthropic.protocol")88 sp = _chemin("vllm.entrypoints.anthropic.serving")89 if check:90 ok = MARK in open(pp, encoding="utf-8").read() and MARK in open(sp, encoding="utf-8").read()91 print("patch effort :", "present" if ok else "ABSENT")92 sys.exit(0 if ok else 1)93 a = patch_protocol(pp)94 b = patch_serving(sp)95 print(f"protocol.py {'patche' if a else 'deja patche'} ; serving.py {'patche' if b else 'deja patche'}")96 # purge des .pyc pour que la version patchee soit bien celle chargee97 for p in (pp, sp):98 d = os.path.join(os.path.dirname(p), "__pycache__")99 if os.path.isdir(d):100 for f in os.listdir(d):101 if f.startswith(os.path.basename(p)[:-3]):102 try:103 os.remove(os.path.join(d, f))104 except OSError:105 pass106 107 108if __name__ == "__main__":109 main()110 