Proyecto independiente No afiliado, patrocinado ni avalado por la Watch Tower Bible and Tract Society o Jehovah's Witnesses.
jw-agent-toolkit
EN

Release F77-F79 · alineamiento al canon publicado

Principios YAML · RLAIF · DPO / ORPO sobre Qwen3.5

Tres fases que aplican Constitutional AI, RLAIF y DPO/ORPO al problema concreto del toolkit: que el fine-tune local no se aleje del canon publicado por la organización. La fuente de verdad sigue siendo el material vigente; estas técnicas son ingeniería de alineamiento, no doctrina nueva. Cero anotadores humanos en el camino crítico — el judge con sus principios actúa como anotador IA. Modelo base de ejemplo: Qwen3.5-0.8B (Apache-2.0).

Fases

3

Tests nuevos

+41

Principios builtin

5

Suite total

1326

passing · 0 ciclos

▌ Decisiones de diseño que ataron las 3 fases

  • El canon publicado vigente es la fuente de verdad. El toolkit refleja, no legisla.
  • Principios codificados en YAML versionado e inspeccionable, no en heurísticas dispersas.
  • Severidades explícitas: hard bloquea, soft solo anota.
  • Lazy imports cross-paquete — cero ciclos de dependencia (jw-agents ↛ jw-eval).
  • Single source of truth: score_pair reusa score, no duplica lógica.
  • Modelo base con licencia permisiva (Apache-2.0) para que cualquiera pueda usarlo.
  • CLI sigue funcionando sin Unsloth — solo los trainers requieren GPU extras.
  • Sin regresiones: 1.326 tests pasan, ningún ciclo nuevo, ruff verde.

Fase 77

fidelity-principles

Criterios de fidelidad al canon publicado, versionados en YAML

✅ Entregada 🧪 21 tests T1 Alineamiento
Guía técnica →

Codifica como YAML los principios doctrinales que antes vivían dispersos por código (regla del cánon, no-suplantación, humildad epistémica, citas obligatorias, respeto a la conciencia). Cada principio tiene id, severidad (hard/soft), applies_to por agente, source con cita a publicación oficial, y un tier regex opcional para detección barata. El judge de jw-finetune y el decorator fidelity_wrap de jw-agents lo consultan en runtime. Lazy import desde jw-agents para evitar el ciclo (jw-eval ya depende de jw-agents).

Qué se entregó

  • 5 principios builtin: PF001-canon-only, PF002-cite-before-paraphrase, PF003-citation-required, PF010-no-impersonation, PF012-respect-conscience.
  • Loader Pydantic con override por id: un YAML del usuario reemplaza al builtin con el mismo id.
  • violations_for(text, principles) ejecuta forbidden_phrases + forbidden_regex en una pasada (case-insensitive).
  • Judge.score_qa_pair() acepta principles=; un hard hit añade RejectionCode.principle_hard_violation.
  • fidelity_wrap(principles=…) filtra por agent_name, sella metadata principle_hard/soft, respeta on_fail warn/reject/annotate.
  • Lazy import de jw_eval.principles desde jw_agents para evitar ciclo de dependencias.
  • Severidad hard = bloqueo; soft = anotación; sin políticas escondidas.

Fase 78

rlaif-pipeline

El judge promovido a anotador de preferencias + SL-CAI

✅ Entregada 🧪 8 tests T1 Alineamiento
Guía técnica →

Convierte el Judge de jw-finetune en un preference model determinístico: dado (question, answer_a, answer_b) decide ganador con un protocolo claro — hard fails primero (sin-cita, NLI contradicts, hard principle), luego overall con ε de tolerancia, y NLI como tiebreak. El builder de dataset genera N candidatos por prompt con sweep de temperaturas, los puntúa por pares y exporta JSONL en formato trl. El módulo critique.py implementa la mitad supervisada de Constitutional AI: para cada par Q&A, el LLM revisa contra principios y reescribe si encuentra violación hard.

Qué se entregó

  • PreferenceVerdict (winner/margin/reasons/score_a/score_b) + compare_scores con tie_epsilon.
  • Hard-fail asymmetry: el lado con nli_contradicts, no_jw_citation o principle_hard_violation pierde frente al otro.
  • Judge.score_pair(question, answer_a, answer_b, language) reusa score() — single source of truth.
  • build_preference_dataset() con n_candidates, min_margin, temperature sweep determinista [0.1, 0.5, 0.8, 1.0].
  • PreferenceStats con counters items/candidates/kept/tied/low_margin/provider_errors/by_winner.
  • Output JSONL formato {prompt, chosen, rejected, metadata} listo para trl.DPOTrainer/ORPOTrainer.
  • self_critique(pair, principles, llm) — SL-CAI loop con preserve_original opt-in para auditoría.
  • batch_critique(pairs) → (revised_pairs, num_changed) para integración con orchestrator existente.

Fase 79

dpo-orpo-trainers

DPO y ORPO con Unsloth sobre Qwen3.5-0.8B (Apache-2.0)

✅ Entregada 🧪 12 tests T2 Entrenamiento
Guía técnica →

Cierra el ciclo de alineamiento: dataset de preferencias → trainer → checkpoint → export GGUF/MLX. Dos trainers nuevos: DPO (con beta=0.1 por defecto, ref_model auto-derivado del base con LoRA) y ORPO (una sola fase, sin modelo de referencia, ideal para MLX/ROCm). Tres recetas builtin sobre Qwen3.5-0.8B Apache-2.0 con chat_template=qwen-3. CLI extendida: jw-finetune train despacha automáticamente por recipe.task; nuevo subcomando prepare-preference que enlaza el judge con principios cargados.

Qué se entregó

  • train_dpo() con trl.DPOTrainer + Unsloth FastLanguageModel + get_chat_template (alineación correcta del template).
  • train_orpo() con trl.ORPOTrainer — una sola fase, sin reference model, ideal para datasets pequeños.
  • Recipe.task admite 'dpo' y 'orpo' además de cpt/sft/grpo; validación se extiende coherentemente.
  • 3 recetas: doctrinal-qa-es-sft-qwen35 (base SFT), doctrinal-qa-es-dpo-qwen35 (lr 5e-6, 1 epoch), doctrinal-qa-es-orpo-qwen35 (lr 8e-6).
  • CLI dispatch en train: rec.task=='dpo' → train_dpo; rec.task=='orpo' → train_orpo; dataset por convención preference_pairs.jsonl.
  • Nuevo comando jw-finetune prepare-preference --judge-mode strict --principles para generar el JSONL listo.
  • Compatible con todos los exporters existentes: GGUF (llama.cpp/Ollama), MLX (Apple), SafeTensors merged/adapter.
  • Lazy import de Unsloth — el CLI sigue funcionando sin GPU para los comandos no-training.

▌ Flujo completo de end-to-end

Las 3 fases componen un pipeline coherente sobre las recetas Qwen3.5-0.8B Apache-2.0:

# 1. Generar receta SFT desde preset (Qwen3.5-0.8B, chat_template qwen-3)
uv run jw-finetune init -p doctrinal-qa-es-sft-qwen35 -o ws/recipe.yaml

# 2. Preparar dataset SFT (extract → dedupe → chunk → synth Q&A)
uv run jw-finetune prepare --recipe-file ws/recipe.yaml --source ./pubs/

# 3. SFT base
uv run jw-finetune train --workspace ws/run-YYYYMMDD-HHMMSS

# 4. Cambiar la receta a DPO (mismo base_model)
uv run jw-finetune init -p doctrinal-qa-es-dpo-qwen35 -o ws-dpo/recipe.yaml

# 5. Generar dataset de preferencias con SL-CAI + RLAIF
#    El judge consulta los 5 principios builtin automáticamente.
uv run jw-finetune prepare-preference \
    --workspace ws-dpo \
    --prompts prompts.jsonl \
    --judge-mode strict \
    --principles

# 6. DPO (despacha automáticamente por recipe.task)
uv run jw-finetune train --workspace ws-dpo

# 7. Exportar a GGUF o MLX
uv run jw-finetune export -c ws-dpo/checkpoints/final -f gguf -q Q4_K_M