Comprueba las dependencias de tareas de IA antes de programarlas con Python
En esta página
Un asistente de IA convierte tus notas de una reunión en un plan de publicación de cinco tareas. Los pasos parecen razonables, pero «review» espera a «publish», mientras «publish» espera a «review». Ninguna de esas dos tareas puede empezar. Otra respuesta menciona un requisito previo que no existe.
Comprueba la estructura de dependencias antes de conectar el plan a un programador de tareas. Este tutorial crea una vista previa de solo lectura con Python: rechaza ambos errores y devuelve un orden completo para un plan válido. Complementa los conceptos de planificación de los patrones de diseño de IA agéntica; no requiere llamadas a modelos, cuentas ni paquetes externos.
1. Define qué significa el plan
Usa un diccionario que asocie cada identificador de tarea con sus requisitos previos. Por ejemplo, {"review": ["draft"]} significa que la redacción debe terminar antes de la revisión, no al revés. Una lista vacía indica que la tarea no tiene requisitos previos.
Establece un contrato pequeño y explícito:
- Acepta entre 1 y 100 tareas, cada una con un identificador ASCII en minúsculas de hasta 40 caracteres, que empiece con una letra; después puede contener dígitos y guiones bajos.
- Exige una lista de identificadores de requisitos previos sin repeticiones para cada tarea.
- Rechaza requisitos no declarados y dependencias circulares, incluida una tarea que dependa de sí misma.
La función siguiente acepta un diccionario ya decodificado, no texto del modelo sin procesar. Si recibes JSON, limita el tamaño de entrada antes de decodificarlo y rechaza por separado las claves de objeto duplicadas. La documentación de JSON de Python advierte del consumo excesivo de recursos con entradas no confiables. El límite de 100 tareas es una política del tutorial, no una afirmación sobre la capacidad del programador.
2. Crea un validador que solo genere una vista previa
La documentación de graphlib de Python explica los diccionarios de requisitos previos y la detección de ciclos. También señala que los requisitos no declarados se añaden automáticamente como nodos. Los rechazamos expresamente para que una tarea inventada no entre en el plan sin avisar.
Convierte el resultado de static_order() en una tupla antes de devolver nada. Nunca ejecutes tareas mientras consumes ese iterador: la validación debe terminar primero. Guarda este código como check_plan.py y usa Python 3.11 o posterior:
import re
from graphlib import CycleError, TopologicalSorter
TASK_ID = re.compile(r"[a-z][a-z0-9_]{0,39}")
def checked_order(plan):
if not isinstance(plan, dict) or not 1 <= len(plan) <= 100:
raise ValueError("expected 1 to 100 tasks")
if any(not isinstance(t, str) or not TASK_ID.fullmatch(t) for t in plan):
raise ValueError("invalid task ID")
for dependencies in plan.values():
if not isinstance(dependencies, list) or any(
not isinstance(d, str) for d in dependencies
):
raise ValueError("dependencies must be lists of task IDs")
if len(dependencies) != len(set(dependencies)):
raise ValueError("repeated dependency")
unknown = sorted({d for deps in plan.values() for d in deps} - set(plan))
if unknown:
raise ValueError("unknown dependencies: " + ", ".join(unknown))
try:
return tuple(TopologicalSorter(plan).static_order())
except CycleError as error:
raise ValueError("cycle detected") from error
def main():
plan = {
"collect": [],
"draft": ["collect"],
"artwork": ["collect"],
"review": ["draft", "artwork"],
"publish": ["review"],
}
order = checked_order(plan)
positions = {task: i for i, task in enumerate(order)}
assert set(order) == set(plan) and len(order) == len(plan)
assert all(positions[d] < positions[t] for t in plan for d in plan[t])
print("valid: 5 tasks, all prerequisites precede dependents")
cases = [
("unknown", {"draft": ["missing"]}, "unknown dependencies: missing"),
("cycle", {"draft": ["review"], "review": ["draft"]}, "cycle detected"),
("self_cycle", {"review": ["review"]}, "cycle detected"),
("bad_shape", {"draft": "collect"}, "dependencies must be lists of task IDs"),
("repeated", {"a": [], "b": ["a", "a"]}, "repeated dependency"),
("empty", {}, "expected 1 to 100 tasks"),
]
for label, candidate, expected in cases:
try:
checked_order(candidate)
except ValueError as error:
assert str(error) == expected
print(f"{label}: rejected ({error})")
else:
raise AssertionError(f"{label} was accepted")
if __name__ == "__main__":
main()
La función solo devuelve identificadores. Nombres como publish son etiquetas inertes del caso de prueba, no comandos, aprobaciones ni permisos para publicar. Mantén los manejadores ejecutables en código controlado por la aplicación, fuera de la respuesta del modelo.
3. Valida los casos positivos y negativos
Ejecuta sin la opción -O de Python para mantener activas las aserciones del caso de prueba:
python3 check_plan.py
Salida estándar esperada:
valid: 5 tasks, all prerequisites precede dependents
unknown: rejected (unknown dependencies: missing)
cycle: rejected (cycle detected)
self_cycle: rejected (cycle detected)
bad_shape: rejected (dependencies must be lists of task IDs)
repeated: rejected (repeated dependency)
empty: rejected (expected 1 to 100 tasks)
El comando se probó localmente con Python 3.11.4: código de salida 0 y salida de error vacía. La prueba acepta un plan de cinco tareas y rechaza seis planes inválidos. Los rechazos son resultados esperados, por lo que el comando completo termina correctamente; un caso aceptado por error provoca una aserción.
El caso positivo comprueba que cada tarea aparezca una sola vez y que cada requisito previo preceda a la tarea que depende de él. No exige un único orden exacto entre tareas independientes. Conserva estos casos al cambiar los prompts, siguiendo el enfoque de pruebas fijas de la comparación de regresiones entre prompts de IA.
4. Resuelve problemas antes de añadir ejecución
- Dependencia desconocida: busca un error de escritura o una tarea omitida. Solicita una propuesta corregida; no crees silenciosamente una tarea vacía para completar la referencia.
- Ciclo detectado: revisa las listas de requisitos previos con la persona responsable. Elimina una relación solo si cambia el requisito real, no simplemente para superar la validación.
- Formato incorrecto o dependencia repetida: vuelve a pedir el mismo contrato de diccionario. No adivines si una cadena representa un identificador, varios o una explicación.
- Grafo válido, flujo incorrecto: las comprobaciones estructurales no detectan una aprobación ausente ni una tarea inventada pero declarada. Contrasta los identificadores y los requisitos obligatorios con un registro y una política controlados por la aplicación. El tutorial de campos JSON permitidos para cambios de IA muestra el principio relacionado de restringir propuestas antes de escribir.
- Fallos durante la ejecución: un orden no es un registro de tareas completadas. Un ejecutor real debe esperar a que los requisitos previos terminen correctamente, gestionar fallos y reintentos y comprobar permisos antes de causar efectos. Esta vista previa no implementa ninguno de esos comportamientos.
Conclusión práctica
Trata el plan generado por IA como una propuesta. Exige referencias conocidas, rechaza ciclos y valida el grafo completo antes de presentar un orden para su aprobación. Un plan que se puede ordenar está listo para revisar el flujo de trabajo, no para ejecutarse automáticamente.
Artículos relacionados
Compara versiones de prompts de IA con una prueba de regresión en Python
Comprueba las cifras de resúmenes de IA con una tabla de referencia
Revisa planes de renombrado de IA sin cambiar archivos
Comprueba citas textuales de IA con fuentes locales y Python
Comprueba las horas de calendario de IA antes de crear eventos
Evalúa probabilidades de IA con la puntuación de Brier en Python
Detecta texto repetido entre entrenamiento y prueba antes de evaluar una IA
Evalúa la clasificación de incidencias con una matriz de confusión
Rechaza JSON ambiguo de IA antes de automatizar con Python
Comprueba los marcadores de traducciones de IA con Python
Prueba expresiones regulares de IA con casos pequeños en Python
Elige umbrales de revisión de IA con cobertura y tasas de error
Últimos artículos
Evalúa campos extraídos por IA con precisión y recall de coincidencia exacta
Comprueba las rutas propuestas por IA antes de escribir con Python
Evita actualizaciones de IA obsoletas con un control de versión en SQLite
Revisa los cambios JSON de la IA con una lista de campos permitidos
Combina resultados RAG con fusión de rangos recíprocos
Comprueba las horas de calendario de IA antes de crear eventos
Comprueba citas textuales de IA con fuentes locales y Python
Comprueba las cifras de resúmenes de IA con una tabla de referencia
Elige umbrales de revisión de IA con cobertura y tasas de error
Comprueba los marcadores de traducciones de IA con Python
Compara versiones de prompts de IA con una prueba de regresión en Python