Resposta A: Anthropic Claude Fable 5
Agendador de tarefas baseado em dependências.
Produz um plano de execução como uma lista de lotes (listas de IDs de tarefas),
onde cada tarefa em um lote pode ser executada simultaneamente, e os lotes devem ser executados sequencialmente.
Usa o algoritmo de Kahn (ordenação topológica nível a nível).
Levanta ValueError em caso de:
- IDs de tarefas duplicados,
- dependências que referenciam IDs de tarefas desconhecidos,
- dependências circulares (com as tarefas problemáticas listadas).
from collections import deque
from typing import Dict, List
class TaskScheduler:
"""Agenda tarefas em lote...
Mostrar resposta completa ▼
Agendador de tarefas baseado em dependências.
Produz um plano de execução como uma lista de lotes (listas de IDs de tarefas),
onde cada tarefa em um lote pode ser executada simultaneamente, e os lotes devem ser executados sequencialmente.
Usa o algoritmo de Kahn (ordenação topológica nível a nível).
Levanta ValueError em caso de:
- IDs de tarefas duplicados,
- dependências que referenciam IDs de tarefas desconhecidos,
- dependências circulares (com as tarefas problemáticas listadas).
from collections import deque
from typing import Dict, List
class TaskScheduler:
"""Agenda tarefas em lotes paralelizados com base em dependências."""
def __init__(self, tasks: List[dict]):
self.tasks = tasks
self._validate_and_build_graph()
def _validate_and_build_graph(self) -> None:
# Coleta todos os IDs de tarefas e verifica duplicatas.
self.task_ids = set()
for task in self.tasks:
if 'id' not in task:
raise ValueError(f"Tarefa está sem a chave 'id' obrigatória: {task!r}")
task_id = task['id']
if task_id in self.task_ids:
raise ValueError(f"ID de tarefa duplicado encontrado: '{task_id}'")
self.task_ids.add(task_id)
# Constrói a lista de adjacências (dependência -> dependentes) e o mapa de grau de entrada.
self.dependents: Dict[str, List[str]] = {tid: [] for tid in self.task_ids}
self.in_degree: Dict[str, int] = {tid: 0 for tid in self.task_ids}
for task in self.tasks:
task_id = task['id']
for dep in task.get('dependencies') or []:
if dep not in self.task_ids:
raise ValueError(
f"Tarefa '{task_id}' depende do ID de tarefa desconhecido '{dep}'"
)
if dep == task_id:
raise ValueError(
f"Tarefa '{task_id}' depende de si mesma (dependência circular)"
)
self.dependents[dep].append(task_id)
self.in_degree[task_id] += 1
def schedule(self) -> List[List[str]]:
"""
Retorna o plano de execução como uma lista de lotes.
Cada lote é uma lista de IDs de tarefas que podem ser executados simultaneamente.
Os lotes devem ser executados na ordem retornada.
"""
in_degree = dict(self.in_degree) # trabalha em uma cópia
current_batch = deque(
tid for tid in in_degree if in_degree[tid] == 0
)
plan: List[List[str]] = []
scheduled_count = 0
while current_batch:
batch = sorted(current_batch) # saída determinística (ordem é arbitrária)
plan.append(batch)
scheduled_count += len(batch)
next_batch = deque()
for task_id in batch:
for dependent in self.dependents[task_id]:
in_degree[dependent] -= 1
if in_degree[dependent] == 0:
next_batch.append(dependent)
current_batch = next_batch
if scheduled_count != len(self.task_ids):
unresolved = sorted(
tid for tid in in_degree if in_degree[tid] > 0
)
raise ValueError(
"Dependência circular detectada envolvendo as tarefas: "
+ ", ".join(f"'{t}'" for t in unresolved)
)
return plan
def schedule_tasks(tasks: List[dict]) -> List[List[str]]:
"""
Função de conveniência: agenda uma lista de dicionários de tarefas.
Args:
tasks: Lista de dicionários, cada um com as chaves 'id' (str), opcionalmente 'name'
(str), e 'dependencies' (lista de strings de ID de tarefa).
Returns:
Uma lista de listas de IDs de tarefas. Cada lista interna é um lote de tarefas
que podem ser executadas em paralelo; os lotes são executados sequencialmente em ordem.
Raises:
ValueError: Se uma dependência se refere a um ID de tarefa inexistente, se uma
dependência circular existir, ou se os IDs de tarefa forem duplicados.
"""
return TaskScheduler(tasks).schedule()
if __name__ == '__main__':
# Exemplo 1
tasks = [
{'id': 'A', 'name': 'Data Ingestion', 'dependencies': []},
{'id': 'B', 'name': 'Data Cleaning', 'dependencies': ['A']},
{'id': 'C', 'name': 'Feature Engineering', 'dependencies': ['A']},
{'id': 'D', 'name': 'Model Training', 'dependencies': ['B', 'C']},
{'id': 'E', 'name': 'Setup Logging', 'dependencies': []},
{'id': 'F', 'name': 'Model Deployment', 'dependencies': ['D']},
]
print(schedule_tasks(tasks))
# -> [['A', 'E'], ['B', 'C'], ['D'], ['F']]
# Exemplo 2
pipeline = [
{'id': 'checkout', 'dependencies': []},
{'id': 'build', 'dependencies': ['checkout']},
{'id': 'unit_test', 'dependencies': ['build']},
{'id': 'integration_test', 'dependencies': ['build']},
{'id': 'deploy', 'dependencies': ['unit_test', 'integration_test']},
]
print(schedule_tasks(pipeline))
# -> [['checkout'], ['build'], ['integration_test', 'unit_test'], ['deploy']]
# Exemplo 3: dependência circular levanta ValueError
cyclic = [
{'id': 'X', 'dependencies': ['Y']},
{'id': 'Y', 'dependencies': ['X']},
]
try:
schedule_tasks(cyclic)
except ValueError as e:
print(f"ValueError: {e}")
# Exemplo 4: dependência desconhecida levanta ValueError
broken = [
{'id': 'A', 'dependencies': ['missing_task']},
]
try:
schedule_tasks(broken)
except ValueError as e:
print(f"ValueError: {e}")
Resultado
Votos de vitoria
2 / 3
Pontuacao media
Pontuacao total
Comentario geral
A Resposta A está funcionalmente correta, utilizando o algoritmo de Kahn com uma ordenação topológica limpa nível a nível (em lotes). Valida IDs duplicados, dependências desconhecidas e auto-loops, e detecta ciclos através da verificação de contagem agendada, levantando ValueErrors descritivas que até listam as tarefas problemáticas. Pontos fortes notáveis: constrói o grafo no momento da construção (portanto, erros de dependência desconhecida surgem prontamente), produz saída determinística através da ordenação, inclui docstrings completas, dicas de tipo e um conjunto abrangente de exemplos executáveis cobrindo casos válidos e inválidos (ciclo e dependência desconhecida). Também oferece uma API de classe e uma função de conveniência, correspondendo à flexibilidade do prompt. Pontos fracos menores: ordenar cada lote é uma pequena sobrecarga (e não solicitada), e a verificação explícita de auto-dependência é ligeiramente redundante dado o detector de ciclos, mas nenhum deles é prejudicial.
Ver detalhes da avaliacao ▼
Correcao
Peso 35%Implementa corretamente o algoritmo de Kahn nível a nível; horários válidos correspondem às saídas esperadas, ciclos e dependências desconhecidas levantam ValueError, e a verificação de ciclo via scheduled_count é sólida. Lotes ordenados garantem resultados corretos e determinísticos.
Completude
Peso 20%Lida com duplicados, dependências desconhecidas, auto-loops e ciclos; fornece APIs de classe e função; e inclui quatro exemplos executáveis cobrindo horários válidos mais ambos os tipos de erro, demonstrando cobertura completa.
Qualidade do codigo
Peso 20%Estrutura de classe limpa com clara separação de validação e agendamento, boas docstrings, dicas de tipo e mensagens de erro informativas. Pequena redundância na verificação explícita de auto-dependência.
Valor pratico
Peso 15%Saída determinística e validação antecipada na construção tornam-na confiável e fácil de integrar; exemplos executáveis para todos os caminhos auxiliam na adoção prática.
Seguimento de instrucoes
Peso 10%Corresponde ao formato de saída exigido, levanta ValueError para ambos os casos de erro exigidos com mensagens descritivas e fornece uma função conforme solicitado; alinha-se totalmente com o prompt.
Pontuacao total
Comentario geral
A Resposta A é uma implementação forte e, em sua maioria, correta usando o algoritmo de Kahn nível a nível, e retorna lotes paralelizáveis de forma limpa. Ela lida com dependências desconhecidas, IDs duplicados e ciclos com erros claros, e o código é legível e bem estruturado. Sua principal fraqueza é que realiza menos validação de entrada do que a Resposta B e é ligeiramente menos robusta para entradas malformadas além dos requisitos centrais do prompt.
Ver detalhes da avaliacao ▼
Correcao
Peso 35%Implementa a ordenação topológica em lote corretamente e detecta dependências desconhecidas e ciclos. Também detecta explicitamente a auto-dependência. Uma limitação menor é que os tipos de campo de dependência malformados não são validados e podem levar a um comportamento não intencional em vez de um erro claro que preserve o contrato.
Completude
Peso 20%Cobre todos os comportamentos exigidos e ainda adiciona tratamento de ID duplicado e exemplos. No entanto, é menos completo em relação à validação de entrada malformada, como dependências não-lista ou IDs não-string além da falta de 'id'.
Qualidade do codigo
Peso 20%Bem organizado com um design de classe claro, método auxiliar, dicas de tipo, docstrings e lotes ordenados determinísticos. A estrutura é fácil de seguir e manter.
Valor pratico
Peso 15%Útil na prática, especialmente com ordenação de lotes determinística e erros descritivos. É um pouco menos defensivo contra entradas malformadas, o que diminui a robustez em contextos de produção.
Seguimento de instrucoes
Peso 10%Segue o prompt de perto: aceita dicionários de tarefas, retorna lotes de lista-de-listas e levanta ValueError para ciclos e dependências ausentes. A implementação e os exemplos se alinham bem com o tipo de resposta exigido.
Pontuacao total
Comentario geral
A Resposta A fornece uma solução excelente e de qualidade profissional. Utiliza um design baseado em classes bem estruturado que separa claramente a construção e validação do grafo da lógica de agendamento. A implementação do algoritmo de Kahn está correta e é eficiente. O tratamento de erros é robusto, cobrindo todos os casos especificados mais outros adicionais, como IDs de tarefas duplicadas. O código é limpo, bem documentado com dicas de tipo e inclui um bloco `if __name__ == '__main__'` abrangente que serve como um conjunto de mini-testes, demonstrando tanto a execução bem-sucedida quanto o tratamento de erros.
Ver detalhes da avaliacao ▼
Correcao
Peso 35%A implementação do algoritmo de Kahn é impecável. Identifica corretamente lotes de tarefas paralelizadas e respeita todas as dependências, produzindo a saída correta para os exemplos fornecidos.
Completude
Peso 20%A solução lida corretamente com todos os requisitos especificados, incluindo a detecção de dependências circulares e inexistentes. Também adiciona verificações úteis para IDs de tarefas duplicadas e auto-dependências.
Qualidade do codigo
Peso 20%A qualidade do código é excelente. O design baseado em classes oferece ótima estrutura e separação de responsabilidades. O código é limpo, legível, bem documentado e utiliza dicas de tipo de forma eficaz. O bloco `if __name__ == '__main__'` é abrangente e demonstra a funcionalidade completa do código.
Valor pratico
Peso 15%A solução é altamente prática. O design baseado em classes torna-a fácil de reutilizar e estender. Uma instância do agendador poderia ser criada e seu grafo inspecionado ou reutilizado, o que é um requisito comum em aplicações do mundo real.
Seguimento de instrucoes
Peso 10%A resposta segue perfeitamente todas as instruções, incluindo o formato de entrada/saída, a escolha de uma função ou classe e os requisitos específicos de tratamento de erros.