LINEAMIENTOS TÉCNICOS
BetSmart: Evolución Fararoni G-Master — Control Determinista de Dos Capas para Sistemas Agénticos Locales
Eber Cruz — Software Engineer | Proyecto C-FARARONI
2026 · Notas Técnicas
Fase: Hardened Signal Filtering · Versión 1.0
1. Propósito de este Documento
Este documento codifica la transición del control preventivo al control determinista de dos capas para sistemas agénticos locales, basado en la evolución empírica del Kernel Fararoni durante la Fase 91.
Todo lo aquí documentado fue descubierto, implementado y validado con trazas reales sobre Qwen 3.5:35b ejecutando localmente vía Ollama. No es teoría — es ingeniería de combate.
2. La Ley de Alucinación Proyectiva de Herramientas
2.1 Definición
Los modelos LLM con fine-tuning de tool calling generan nombres de herramientas desde su vocabulario de entrenamiento, NO desde la lista de tools proporcionada en el request API.
El campo tools del API actúa como sugerencia probabilística, no como restricción dura. El modelo puede generar cualquier herramienta que "recuerde" de su entrenamiento, independientemente de lo que se le ofrezca.
2.2 Evidencia Empírica
PRUEBA: Enviar tools=[fs_patch, fs_write] (solo 2 herramientas)
RESULTADO: Modelo genera tool_call con name="ShellCommand"
Traza real (Sesión 14, depth=2):
allowedTools=[fs_write, fs_patch] filteredCount=2
→ isToolCall=true tool=ShellCommand ← NO ESTABA EN LA LISTA2.3 Vocabularios Nativos Conocidos
┌──────────────────────┬─────────────────────────────────────────────┐
│ Modelo │ Vocabulario Nativo de Tools │
├──────────────────────┼─────────────────────────────────────────────┤
│ Qwen 2.5-coder │ ShellCommand, ReadFile, WriteFile, │
│ │ ListFiles, FileSearch, GitAction │
├──────────────────────┼─────────────────────────────────────────────┤
│ Qwen 3.5 │ Bash, Read, Write, Edit, Glob, Grep │
│ │ (vocabulario Claude Code) │
├──────────────────────┼─────────────────────────────────────────────┤
│ DeepSeek-R1 │ Varía — usa formatos XML/JSON mixtos │
└──────────────────────┴─────────────────────────────────────────────┘2.4 Mandato
NO intentes filtrar herramientas pre-generación. El modelo las ignorará. En su lugar: 1. Envía TODAS las herramientas disponibles 2. Intercepta la respuesta post-generación 3. Normaliza nombres (ReadFile→fs_read, Bash→ShellCommand) 4. Valida contra la máquina de estados 5. Rechaza con feedback si es ilegal
3. Arquitectura de Gobernanza de Dos Capas (Fix-G)
3.1 Visión General
3.2 Capa 1: Imán de Certeza — Inyección de PROTOCOL-MANDATE
Principio
El último mensaje role:system en la ventana de contexto tiene el mayor peso en la decisión del modelo. Al inyectar una directiva precisa justo antes de la llamada, creamos un "campo gravitacional" que atrae al modelo hacia la herramienta correcta.
Directivas por Estado
POST_SHELL (después de compilación fallida):
PROTOCOL-MANDATE: Build failed. Read the error messages above carefully.
Use fs_read to open the file mentioned in the errors, then fix it with fs_patch.
Do NOT re-run the build without fixing something first.
POST_READ (después de leer un archivo):
PROTOCOL-MANDATE: File analysis is complete.
You MUST now apply the fix using the 'fs_patch' tool.
Group ALL corrections (imports, methods, types) into a SINGLE fs_patch call.
Do NOT re-read the file. Do NOT compile yet. Apply the fix NOW.
POST_PATCH (después de parchear):
PROTOCOL-MANDATE: Your patch has been applied to disk successfully.
If there are MORE errors to fix in this or another file, use fs_patch again.
If you have fixed ALL errors, verify by running 'mvn compile' via ShellCommand.
Do NOT re-read a file you already patched.
Implementación
private void injectCertaintyDirective(ArrayNode messages, String lastToolUsed) {
String normalized = normalizeToolName(lastToolUsed);
String directive = switch (normalized) {
case "fs_read" -> "PROTOCOL-MANDATE: File analysis is complete...";
case "fs_patch", "fs_write" -> "PROTOCOL-MANDATE: Your patch has been applied...";
default -> "PROTOCOL-MANDATE: Build failed...";
};
ObjectNode sysDirective = JSON_MAPPER.createObjectNode();
sysDirective.put("role", "system");
sysDirective.put("content", directive);
messages.add(sysDirective);
}
3.3 Capa 2: Muro de Intercepción — Interceptor Agnóstico
Principio
Si pese a la Capa 1 el modelo genera una herramienta ilegal, el Interceptor:
- Normaliza el nombre (mapeo agnóstico multi-versión Qwen)
- Valida contra la máquina de estados
- Rechaza con
role:toolERROR explicativo - Reintenta (budget de 2 rechazos por depth)
- Fallback si el budget se agota
Normalización de Nombres
private String normalizeToolName(String rawName) {
return switch (rawName.toLowerCase()) {
case "fs_read", "readfile", "read" -> "fs_read";
case "fs_write", "writefile", "write" -> "fs_write";
case "fs_patch", "edit" -> "fs_patch";
case "shellcommand", "bash", "shell_execute" -> "ShellCommand";
default -> rawName;
};
}
4. La Máquina de Estados Relajada (One-Shot Flow)
4.1 Evolución de la Máquina de Estados
VERSIÓN ESTRICTA (Fix F — FRACASÓ):
POST_PATCH → [ShellCommand] ← Forzaba compilación tras CADA patch
RESULTADO: 6+ rechazos, 10+ min desperdiciados, multi-patch bloqueado
VERSIÓN RELAJADA (Fix G — VALIDADA):
POST_PATCH → [ShellCommand, fs_patch, fs_write, fs_read]
RESULTADO: 0 rechazos, multi-patch fluido, ciclos completos4.2 Tabla de Transiciones
┌───────────────────┬──────────────────────────────────┬────────────────────────┐
│ Estado │ Tools Válidas │ Razón │
├───────────────────┼──────────────────────────────────┼────────────────────────┤
│ POST_READ │ fs_patch, fs_write │ DEBE parchear. │
│ (después de leer) │ │ Prohibido re-leer. │
│ │ │ Prohibido compilar. │
├───────────────────┼──────────────────────────────────┼────────────────────────┤
│ POST_PATCH │ ShellCommand, fs_patch, │ Puede parchear MÁS │
│ (después de │ fs_write, fs_read │ errores (multi-patch) │
│ parchear) │ │ O verificar compilación│
│ │ │ La Capa 1 guía la │
│ │ │ decisión correcta. │
├───────────────────┼──────────────────────────────────┼────────────────────────┤
│ POST_COMPILE │ fs_read, fs_patch, │ Si falló → reiniciar │
│ (después de │ fs_write, ShellCommand │ ciclo con datos │
│ compilar) │ │ destilados. │
│ │ │ Si éxito → FIN. │
└───────────────────┴──────────────────────────────────┴────────────────────────┘4.3 POST_READ: Prohibición de Bucles de Lectura Infinita
Problema descubierto en Sesión 10: Con tool_choice="required", el modelo eligió fs_read 9 de 10 veces (1 hora 20 minutos). La lectura es la "acción segura" que no modifica nada.
Solución: POST_READ solo permite fs_patch y fs_write. El modelo DEBE hacer algo productivo después de leer. No puede re-leer como escape.
4.4 POST_PATCH: Multi-Patch Legítimo
Problema descubierto en Sesión 14: Un archivo con 5 errores necesita 5 patches (o N patches consolidados). Forzar compilación después de CADA patch desperdicia iteraciones:
Ciclo estricto (Fix F): read → patch → compile → read → patch → compile (6 depths)
Ciclo relajado (Fix G): read → patch → patch → patch → compile (5 depths)Solución: POST_PATCH permite fs_patch (más patches) O ShellCommand (compilar cuando esté listo). La Capa 1 (Inyección de Certeza) guía al modelo: _"Si hay más errores, usa fs_patch. Si ya corregiste todo, verifica con mvn compile."_
4.5 POST_COMPILE: Ciclo con Datos Destilados
Componente crítico: BuildOutputDistiller reduce ~1MB de output de build a ~2000 chars de errores accionables. Sin esto, el contexto acumulado causa "saturación cognitiva" y el modelo responde con texto explicativo en vez de tool calls.
// BuildOutputDistiller — Extrae solo la inteligencia crítica
// 1. Filtra líneas con [ERROR], BUILD FAILURE, COMPILATION ERROR
// 2. Captura las últimas 20 líneas (resumen del build)
// 3. Combina errores + resumen, sin duplicados
// 4. Trunca a máximo 3000 chars manteniendo el final
// 5. Envuelve con metadata: "[DISTILLED BUILD OUTPUT] Original: 850K → Distilled: 2K"4.6 Flujo Completo One-Shot
5. Topología de Grafos y Algoritmos de Control
5.1 El Grafo de Estados Dirigido (FSM-Graph)
5.2 Algoritmos de Gobernanza (Evolución G)
Los tres algoritmos que operan sobre el grafo forman un sistema coordinado: cada uno actúa en una fase diferente del ciclo de vida de una transición (pre-generación, post-generación, y reducción de entropía).
Algoritmo 1: Normalización de Grafos — normalizeToolName()
Complejidad algorítmica: O(1) — un switch expression sobre el nombre en lowercase. El costo es despreciable (~0 tokens, ~0ms de latencia).
Algoritmo 2: Inyección TFI — injectCertaintyDirective()
Impacto medido: 0 rechazos en 8 depths (100% One-Shot Success). Sin la inyección (Fix F), había 6+ rechazos en 5 depths (~30% success rate).
Algoritmo 3: Destilación Heurística — BuildOutputDistiller.distill()
Función: Reduce la entropía del nodo POST_COMPILE. Cuando un build falla, genera ~1MB de logs. Enviar esto al LLM causa "saturación cognitiva" — el modelo no puede encontrar la señal entre el ruido y responde con texto genérico.
5.3 Garantía de Convergencia
6. Métricas de Éxito de Grado Militar
6.1 Reducción de Rechazos por Insubordinación
6.2 Eliminación de Penalización de Latencia
6 rechazos eliminados (promedio por test) = ~12 minutos + ~18,000 tokens
En 100 compilaciones/día: ~20 horas + ~1.8M tokens ahorrados
7. Arqueología de la Evolución (Fixes A-G)
7.1 Timeline de Descubrimientos
SESIÓN │ FIX │ ESTRATEGIA │ RESULTADO
───────┼───────┼──────────────────────────────────┼──────────────────────────
7-8 │ - │ Tracing quirúrgico │ Identificó: saturación cognitiva
9 │ A+B+C │ Extractor + Distiller + Hints │ Parcial: depth 4 aún falla
10 │ D │ tool_choice=required global │ ❌ Loop infinito de fs_read
10 │ E │ Filtro pre-generación │ ❌ Modelo ignora lista de tools
11 │ - │ Descubrimiento FASE33.2 │ Qwen tiene vocabulario hardcoded
12 │ - │ Documentación hallazgos │ "Alucinación Proyectiva de Tools"
13 │ F │ Interceptor post-generación │ ⚠️ Funciona pero CARO (120s/rechazo)
14 │ - │ Test real Fix F │ 6+ rechazos, estado demasiado estricto
15 │ G │ Inyección de Certeza + Relajar │ ✅ 0 rechazos, 100% One-Shot Success
│ │ estado + Interceptor safety net │7.2 Las Tres Estrategias de Control (y por qué solo una funciona)
8. Reglas de Implementación para Sistemas Futuros
8.1 Regla 1: Nunca Filtrar Tools
PROHIBIDO:
tools = filterByState(allTools, lastAction); // El modelo lo ignora
CORRECTO:
tools = allTools; // Enviar todas
response = llm.generate(messages, tools);
validate(response.toolCall(), stateMachine); // Validar DESPUÉS8.2 Regla 2: Siempre Inyectar Antes de Generar
PROHIBIDO:
response = llm.generate(messages, tools); // Sin guía
CORRECTO:
injectDirective(messages, currentState); // Guía determinista
response = llm.generate(messages, tools); // El modelo "sabe" qué hacer8.3 Regla 3: Normalizar Siempre
PROHIBIDO:
if (toolName.equals("fs_read")) { ... } // Solo un nombre
CORRECTO:
String normalized = normalizeToolName(toolName); // ReadFile, Read, fs_read → "fs_read"
if ("fs_read".equals(normalized)) { ... }8.4 Regla 4: Estados Relajados > Estados Estrictos
PROHIBIDO:
POST_PATCH → [ShellCommand] // Demasiado estricto, bloquea multi-patch
CORRECTO:
POST_PATCH → [ShellCommand, fs_patch, fs_write, fs_read] // Relajado
// La Capa 1 guía al modelo a la decisión correcta8.5 Regla 5: El Interceptor es un Seguro, No el Motor
El Interceptor (Capa 2) debe existir pero NUNCA debería activarse.
Si se activa frecuentemente, la Capa 1 (Inyección de Certeza) necesita
mejores directivas. El Interceptor es el Anillo 3 — última línea de
defensa, no la primera.9. Glosario
| Término | Definición |
|---|---|
| Alucinación Proyectiva | LLM genera herramientas de su vocabulario de training, ignora lista API |
| Inyección de Certeza | Mensaje role:system inyectado antes de cada LLM call con directiva exacta |
| One-Shot Success | El modelo acierta la herramienta correcta en su primer intento |
| Multi-Patch | Múltiples patches consecutivos antes de compilar (legítimo para multi-error) |
| BuildOutputDistiller | Reduce 1MB de build logs a ~2K chars de errores accionables |
| Interceptor | Safety net post-generación que rechaza herramientas ilegales con feedback |
| PROTOCOL-MANDATE | Prefijo de las directivas de certeza inyectadas |
| Retry Budget | Máximo 2 rechazos del Interceptor por depth antes de fallback |
| Normalizer | Mapeo de nombres nativos del modelo a nombres canónicos de Fararoni |
| Estado Relajado | POST_PATCH permite más patches O compilación (vs solo compilación) |
_Documento generado como lineamiento técnico BetSmart para la Evolución G-Master del Kernel Fararoni. Basado en evidencia empírica de 8 sesiones de debug, 7 fixes iterativos, y trazas de producción sobre Qwen 3.5:35b local._
Acerca del Autor
Eber Cruz es un ingeniero de software con una década de experiencia en el diseño de infraestructuras backend y sistemas distribuidos. Este documento refleja el trabajo de diseño detrás de C-FARARONI, un ecosistema experimental orientado a la soberanía tecnológica y la ejecución segura de modelos de IA locales.
Repositorio: github.com/ebercruzf/fararoni-ecosystem
Notas y contacto: ebercruz.com