David Gomez
Software Development Engineer
David Gómez · Plain Concepts
Cuando usamos un LLM en un proceso de desarrollo, la conversación suele girar en torno al modelo: cuál es mejor, cuánto razona, cómo escribirle el prompt, etc. Pero cuando ese proceso tiene que funcionar todos los días, la pregunta importante es otra, y tiene que ver con el determinismo: ¿qué partes del sistema pueden comportarse de forma distinta cada vez que se ejecutan, y cuáles no deberían hacerlo nunca?
En software tradicional damos por hecho que la misma entrada produce la misma salida. Si un test falla, falla igual la segunda vez. Un LLM no cumple esa propiedad.
Con temperatura 0, el modelo elige en cada paso el token más probable. En teoría, eso hace la generación determinista. En la práctica, no.
Horace He y Thinking Machines Lab lo midieron en Defeating Nondeterminism in LLM Inference (10 de septiembre de 2025): 1000 respuestas al mismo prompt con temperatura 0 sobre Qwen3-235B dieron 80 respuestas distintas. La más frecuente apareció 78 veces y las divergencias empezaban en el token 103. La causa es aritmética: la suma en coma flotante no es asociativa, y los kernels de inferencia cambian el orden de las operaciones según el tamaño del lote, que depende de la carga del servidor. Quien llama obtiene un resultado que depende de algo que no controla. Con kernels invariantes al lote, los autores consiguieron 1000 respuestas idénticas, a cambio de una inferencia más lenta.
Los proveedores lo reconocen. OpenAI ofrece seed y system_fingerprint para mejorar la reproducibilidad, pero no la garantiza (OpenAI Cookbook). Azure OpenAI dice lo mismo y añade que la variabilidad crece con respuestas más largas (Microsoft Learn). Y en un servicio gestionado no controlamos ni los kernels ni el lote.
Un agente encadena muchas llamadas, y cada una depende de las anteriores. Si en el primer paso lee otro fichero, todo lo demás parte de otro contexto, y una divergencia pequeña acaba en una trayectoria distinta. En una cadena de agentes, el efecto se multiplica en cada frontera.
Empeora mucho si el propio modelo decide qué paso es el siguiente. Si un LLM hace de orquestador («ahora llama al revisor», «esto ya está»), la variabilidad pasa del contenido a la estructura: qué se ejecuta, cuántas veces y cuándo se para. Ya no tenemos un proceso con partes variables. Tenemos un proceso variable.
La conclusión no es que los LLM no sirvan. Es que su variabilidad no se elimina: se acota, y para eso hace falta algo predecible a su alrededor.
Cualquier proceso que automaticemos con agentes, como implementar un ticket, mezcla tres tipos de trabajo:
| Trabajo | Ejemplos | Naturaleza adecuada |
|---|---|---|
| Resolver ambigüedad | Interpretar un requisito, diseñar una solución, escribir código, redactar una revisión | Probabilista (LLM) |
| Preservar, validar, transformar y mutar estado | Copiar campos, generar identificadores, validar un esquema, ejecutar tests, cambiar el estado de un ticket, decidir el siguiente paso, parar | Determinista (código) |
| Asumir responsabilidad | Aceptar una entrega, aprobar una excepción | Humana |
La regla que más me ha costado aprender: modelos para resolver ambigüedad, código para preservar, validar, transformar y mutar estado. Cada vez que un LLM hace algo de la segunda fila, añade variabilidad, reinterpretación, pérdida de información y tokens donde no aportan nada. El problema rara vez es que el agente razone mal. Es que le hemos pedido razonar donde no debía.
Hay piezas que no deberían depender nunca de un modelo:
Que el grafo llegue al final sin excepciones no dice si el artefacto existe, si es válido o si alguien lo aceptó. Cada camino debería terminar en un resultado explícito: aceptado, rechazado, bloqueado, no materializable. El final genérico del motor es un detalle de implementación. El negocio necesita saber cómo acabó.
En los componentes deterministas esperamos el mismo resultado ante la misma entrada, y lo comprobamos con tests convencionales. En los probabilistas verificamos la envolvente (que la salida respeta el contrato, que el flujo no se sale del grafo, que los límites se cumplen) y medimos propiedades con evals, frente a un umbral declarado de antemano. No buscamos un sistema perfecto, sino uno observable, falsable y contrastable con contratos explícitos.
Que el flujo sea determinista no significa que el orquestador decida qué es «listo para desarrollo» o si una transición de estado es legal. Esas reglas son del dominio. El reparto que me funciona:
Disclaimer
Los detalles sobre Conductor y el ejemplo corresponden a la versión 0.1.42 (octubre de 2026). El proyecto evoluciona rápido, así que conviene contrastarlos con la documentación actual.
Nota sobre el uso de IA: redactado con ayuda de herramientas de inteligencia artificial, a partir de la experiencia, las ideas y el criterio del autor, que ha dirigido, revisado y validado todo el contenido. Las opiniones, el análisis y las reflexiones son del autor.
docs/workflow-syntax.md, src/conductor/engine/router.py, src/conductor/engine/limits.py, src/conductor/engine/workflow.py, src/conductor/gates/human.py, src/conductor/config/schema.py, src/conductor/engine/context.py, release v0.1.42, 6 de octubre de 2026).David Gomez
Software Development Engineer