Phase 5: re-quantize merged checkpoint to NVFP4 with MTP/vision tensor reinjection and production-config verification #4

Merged
aleleba merged 16 commits from agente-fase5-quantize-nvfp4 into master 2026-07-30 06:41:14 -06:00
Showing only changes of commit 77e6804a4f - Show all commits
+21 -3
View File
@@ -33,6 +33,11 @@ EVAL_URL = os.environ.get("VLLM_EVAL_URL", "http://localhost:8001")
EVAL_MODEL = os.environ.get("VLLM_EVAL_MODEL", "qwen3.6-35b-a3b-mcp-bf16") EVAL_MODEL = os.environ.get("VLLM_EVAL_MODEL", "qwen3.6-35b-a3b-mcp-bf16")
PROD_URL = os.environ.get("VLLM_PROD_URL", "http://localhost:8000") PROD_URL = os.environ.get("VLLM_PROD_URL", "http://localhost:8000")
PROD_MODEL = os.environ.get("VLLM_PROD_MODEL", "qwen3.6-35b-a3b") PROD_MODEL = os.environ.get("VLLM_PROD_MODEL", "qwen3.6-35b-a3b")
# 512 dejaba cortar la respuesta a mitad de razonamiento en los prompts mas
# abiertos (modelo de razonamiento con --reasoning-parser activo) antes de
# emitir el contenido final -- un FAIL por presupuesto de tokens agotado, no
# por adherencia real. Ver hallazgo de Fase 5.
GATE3_MAX_TOKENS = int(os.environ.get("GATE3_MAX_TOKENS", "2048"))
# Checklists por skill: (skill, tipo, prompt, [substrings esperados en la respuesta, any-of]) # Checklists por skill: (skill, tipo, prompt, [substrings esperados en la respuesta, any-of])
CHECKLISTS = [ CHECKLISTS = [
@@ -103,10 +108,10 @@ def call_model(base_url, model_name, prompt):
payload = { payload = {
"model": model_name, "model": model_name,
"messages": [{"role": "user", "content": prompt}], "messages": [{"role": "user", "content": prompt}],
"max_tokens": 512, "max_tokens": GATE3_MAX_TOKENS,
"temperature": 0.0, "temperature": 0.0,
} }
resp = requests.post(f"{base_url}/v1/chat/completions", json=payload, timeout=120) resp = requests.post(f"{base_url}/v1/chat/completions", json=payload, timeout=240)
resp.raise_for_status() resp.raise_for_status()
data = resp.json() data = resp.json()
message = data["choices"][0]["message"] message = data["choices"][0]["message"]
@@ -147,9 +152,20 @@ def run_checklist(base_url, model_name, label):
print(f" [ERROR] {skill}/{kind}: {e}") print(f" [ERROR] {skill}/{kind}: {e}")
continue continue
# Se guarda siempre el texto completo (content + reasoning) para poder auditar
# con criterio humano los casos que fallan -- antes solo se guardaba passed/hits,
# lo que hacia imposible revisar despues que dijo realmente el modelo.
if kind == "adherencia": if kind == "adherencia":
passed, hits = check_adherencia(response, expected) passed, hits = check_adherencia(response, expected)
rows.append({"skill": skill, "kind": kind, "prompt": prompt, "passed": passed, "hits": hits}) rows.append({
"skill": skill,
"kind": kind,
"prompt": prompt,
"passed": passed,
"hits": hits,
"content": response["content"],
"reasoning": response["reasoning"],
})
print(f" {'OK ' if passed else 'FAIL'} {skill:20s} adherencia hits={hits}") print(f" {'OK ' if passed else 'FAIL'} {skill:20s} adherencia hits={hits}")
else: else:
passed = check_no_activacion(response) passed = check_no_activacion(response)
@@ -159,6 +175,8 @@ def run_checklist(base_url, model_name, label):
"prompt": prompt, "prompt": prompt,
"passed": passed, "passed": passed,
"tool_calls": [tc["function"]["name"] for tc in response["tool_calls"]], "tool_calls": [tc["function"]["name"] for tc in response["tool_calls"]],
"content": response["content"],
"reasoning": response["reasoning"],
}) })
print(f" {'OK ' if passed else 'FAIL'} {skill:20s} {kind:20s} tool_calls={len(response['tool_calls'])}") print(f" {'OK ' if passed else 'FAIL'} {skill:20s} {kind:20s} tool_calls={len(response['tool_calls'])}")
return rows return rows