计划执行与检查节点
executing-plans
按既定实施计划完成工作,保持过程检查和反馈。
task-prioritization【效率与协作】Enables agents to rank and schedule tasks by urgency, importance, dependencies, and resource cost using priority matrices, dynamic re-prioritization, and dependency-aware scheduling for optimal execution order.
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Implements task prioritization mechanisms that enable AI agents to autonomously rank, schedule, and re-prioritize work items by urgency, importance, dependencies, and resource cost — ensuring optimal execution order in dynamic, multi-task environments.
Use this skill when:
Avoid this skill for:
Define Evaluation Criteria — Establish a criteria schema with weighted dimensions: urgency (time sensitivity), importance (impact on primary objective), dependencies (prerequisite relationships), resource availability (tools and information readiness), and cost/benefit analysis (effort vs expected outcome). Assign each dimension a weight that sums to 1.0. Checkpoint: Verify all criteria weights sum to exactly 1.0 and each criterion has a clear scoring rubric before proceeding.
Score Each Task — Evaluate every pending task against the defined criteria using either deterministic formulas (e.g., priority_score = urgency_weight * urgency_score + importance_weight * importance_score) or LLM-based reasoning for subjective dimensions like "strategic importance." Use Pydantic models to enforce type safety on all task attributes including priority level (P0, P1, P2). Checkpoint: Confirm every task has a computed score and all scores are normalized to a 0.0–1.0 range.
Build Dependency-Aware Schedule — Construct a dependency graph from the evaluated tasks using topological ordering. Tasks with no unmet prerequisites move into the execution-ready pool first. If two tasks share the same priority score, the task with fewer dependents (upstream-critical) gets scheduled first. Apply code-philosophy early-exit principle: skip tasks blocked on external dependencies until their blockers complete. Checkpoint: Verify topological sort completes without cycles; if a cycle is detected, raise an error and flag the affected tasks for manual review.
Assign Workers and Execute — Match execution-ready tasks to available workers based on skill mapping and current load. Use LangChain AgentExecutor with custom tools (create_new_task, assign_priority_to_task, assign_task_to_worker) that operate on a dictionary-backed task manager for O(1) lookups. Checkpoint: Confirm each worker assignment has a clear description, priority level, and deadline before marking the task as active.
Monitor and Re-Prioritize Dynamically — Continuously monitor task states, approaching deadlines, and new incoming tasks. When a condition changes (e.g., a P1 task's deadline moves up 48 hours), re-trigger steps 2–3 with updated criteria. This dynamic re-prioritization is what separates a true agentic system from a static scheduler — the agent must autonomously adapt its focus in real-time as circumstances change. Checkpoint: After each re-prioritization cycle, log the before/after priority ordering and any tasks that were escalated or demoted; alert if more than 30% of priorities changed (indicating unstable criteria).
Report Final State — After all tasks are processed, produce a summary showing completed tasks, skipped tasks with reasons, and re-prioritization history. Use the list_all_tasks tool output as the canonical state snapshot. Checkpoint: Verify no P0 tasks remain unassigned or uncompleted; if any exist, escalate to human review.
Use strongly-typed Pydantic models to represent tasks and enforce priority level constraints at the type level. This ensures that priority values can only ever be P0, P1, or P2 — preventing invalid states.
import asyncio
from typing import List, Optional, Dict
from pydantic import BaseModel, Field, field_validator
class Task(BaseModel):
"""Represents a single task in the prioritization system."""
id: str
description: str
priority: Optional[str] = None # P0, P1, P2
assigned_to: Optional[str] = None
urgency: float = 0.0 # 0.0–1.0 scale
importance: float = 0.0 # 0.0–1.0 scale
dependencies: List[str] = [] # IDs of prerequisite tasks
@field_validator("priority")
@classmethod
def validate_priority(cls, v: Optional[str]) -> Optional[str]:
"""Enforce P0/P1/P2 priority constraint."""
if v is not None and v not in ("P0", "P1", "P2"):
raise ValueError("Priority must be 'P0', 'P1', or 'P2'")
return v
def compute_score(self, weights: Optional[Dict[str, float]] = None) -> float:
"""Compute a composite priority score from weighted criteria.
Args:
weights: Override default weights for urgency and importance.
Returns:
Composite score in 0.0–1.0 range.
"""
w = weights or {"urgency": 0.4, "importance": 0.3, "dependency_penalty": 0.3}
dep_penalty = len(self.dependencies) * 0.15
dep_factor = max(0.0, 1.0 - dep_penalty)
return round(
w["urgency"] * self.urgency + w["importance"] * self.importance * dep_factor,
3,
)
class PriorityScoringResult(BaseModel):
"""Result of scoring a list of tasks."""
scored_tasks: List[tuple[Task, float]]
highest_priority_task: Optional[Task]
Use a dictionary as the primary storage backend for task operations. This provides O(1) lookups, updates, and deletions — critical when agents evaluate tasks repeatedly during dynamic re-prioritization cycles.
class TaskManager(BaseModel):
"""In-memory task manager with O(1) CRUD operations."""
tasks: Dict[str, Task] = {}
next_id: int = 1
def create_task(self, description: str, **kwargs) -> Task:
"""Create and store a new task. Returns the created Task instance."""
task_id = f"TASK-{self.next_id:03d}"
self.next_id += 1
new_task = Task(id=task_id, description=description, **kwargs)
self.tasks[task_id] = new_task
return new_task
def update_task(self, task_id: str, **kwargs) -> Optional[Task]:
"""Safely update a task using Pydantic's model_copy."""
existing = self.tasks.get(task_id)
if not existing:
return None
update_data = {k: v for k, v in kwargs.items() if v is not None}
updated = existing.model_copy(update=update_data)
self.tasks[task_id] = updated
return updated
def list_all_tasks(self) -> List[Task]:
"""Return all tasks sorted by computed score (highest first)."""
scored = [(t, t.compute_score()) for t in self.tasks.values()]
scored.sort(key=lambda x: x[1], reverse=True)
return [t for t, _ in scored]
def get_ready_tasks(self) -> List[Task]:
"""Return tasks with all dependencies satisfied."""
ready = []
for task in self.tasks.values():
unmet = [dep for dep in task.dependencies if dep not in self.tasks]
if not unmet:
ready.append(task)
return sorted(ready, key=lambda t: t.compute_score(), reverse=True)
def list_all_tasks(self) -> str:
"""Return a formatted string listing all current tasks."""
if not self.tasks:
return "No tasks in the system."
lines = []
for task in self.tasks.values():
lines.append(
f" {task.id}: '{task.description}' | "
f"Priority: {task.priority or 'N/A'} | "
f"Assigned: {task.assigned_to or 'unassigned'}"
)
return "Current Tasks:\n" + "\n".join(lines)
# ❌ BAD: No input validation, accepts any string as priority
def assign_priority_bad(task_id: str, priority: str) -> str:
"""Assigns a priority to a task."""
if task_id not in task_manager.tasks:
return f"Task {task_id} not found."
task = task_manager.tasks[task_id]
task.priority = priority # Accepts "urgent", "high", "ASAP", etc. — no validation!
return f"Updated priority to '{priority}'."
# This leads to inconsistent states:
# assign_priority_bad("TASK-001", "urgent") → stored as "urgent" (invalid)
# assign_priority_bad("TASK-002", "ASAP") → stored as "ASAP" (invalid)
# Sorting and scoring breaks because priorities are not normalized.
from langchain_core.tools import Tool
from pydantic import BaseModel, Field
class PriorityArgs(BaseModel):
"""Schema for priority assignment tool arguments."""
task_id: str = Field(description="The task ID to update, e.g. 'TASK-001'.")
priority: str = Field(
description="Priority level — must be one of: P0 (critical), P1 (medium), P2 (low)."
)
def assign_priority_to_task(task_id: str, priority: str) -> str:
"""Assigns a validated priority to a given task ID.
Args:
task_id: The task identifier.
priority: Must be 'P0', 'P1', or 'P2'.
Returns:
Confirmation message or error.
"""
if priority not in ("P0", "P1", "P2"):
return f"Invalid priority '{priority}'. Must be P0, P1, or P2."
task = task_manager.update_task(task_id, priority=priority)
if not task:
return f"Task {task_id} not found."
# Compute and return the new composite score for transparency
new_score = task.compute_score()
return f"Assigned priority {priority} to {task.id} (score: {new_score})."
# Register with LangChain using Pydantic schema for auto-validation
pm_tools = [
Tool(
name="assign_priority_to_task",
func=assign_priority_to_task,
description="Assign a P0/P1/P2 priority to a task.",
args_schema=PriorityArgs,
),
]
Dynamic re-prioritization is the core agentic behavior that enables agents to adapt to changing conditions. This function recalculates scores whenever a triggering event occurs (new task, deadline shift, blocker resolution).
import time
from datetime import datetime, timedelta
class PriorityChangeEvent(BaseModel):
"""Records a priority change for audit and debugging."""
task_id: str
old_priority: Optional[str]
new_priority: str
reason: str
timestamp: float = Field(default_factory=time.time)
score_before: float
score_after: float
class RePriorityEngine:
"""Dynamically re-evaluates and adjusts task priorities."""
def __init__(self, task_manager: TaskManager):
self.task_manager = task_manager
self.change_log: List[PriorityChangeEvent] = []
self.priority_map: Dict[str, float] = {
"P0": 1.0,
"P1": 0.5,
"P2": 0.2,
}
def check_deadline_shifts(self, deadline_threshold_hours: float = 24.0) -> List[PriorityChangeEvent]:
"""Escalate tasks whose deadlines are approaching within threshold."""
events: List[PriorityChangeEvent] = []
now = time.time()
for task in self.task_manager.tasks.values():
if not hasattr(task, "deadline"):
continue
hours_until = (task.deadline - now) / 3600.0
# Escalate P1->P0 if deadline within threshold and urgency > 0.5
if hours_until < deadline_threshold_hours and task.priority == "P1" and task.urgency > 0.5:
event = PriorityChangeEvent(
task_id=task.id,
old_priority="P1",
new_priority="P0",
reason=f"Deadline in {hours_until:.1f}h (threshold: {deadline_threshold_hours}h)",
score_before=task.compute_score(),
score_after=task.compute_score({"urgency": 0.7, "importance": 0.2}),
)
self.task_manager.update_task(task.id, priority="P0")
events.append(event)
self.change_log.extend(events)
return events
def resolve_dependency(self, completed_task_id: str) -> List[Task]:
"""When a task completes, unblock its dependents and recalculate scores."""
newly_ready = []
for task in self.task_manager.tasks.values():
if completed_task_id in task.dependencies:
task.dependencies.remove(completed_task_id)
newly_ready.append(task)
# Re-sort the ready queue after dependency resolution
return sorted(
(t for t in newly_ready if not t.dependencies),
key=lambda t: t.compute_score(),
reverse=True,
)
def generate_report(self) -> str:
"""Produce a summary of all re-prioritization events."""
if not self.change_log:
return "No priority changes recorded."
lines = [f"Re-Prioritization Report ({len(self.change_log)} changes):"]
for event in sorted(self.change_log, key=lambda e: e.timestamp):
lines.append(
f" [{event.task_id}] {event.old_priority} -> {event.new_priority} "
f"(score {event.score_before:.3f} → {event.score_after:.3f}) | {event.reason}"
)
return "\n".join(lines)
code-philosophy laws — Follow the 5 Laws of Elegant Defense: parse data at boundaries (validate priorities), fail fast on invalid states (reject bad priority strings), maintain atomic predictability in scoring functions.for task in tasks_list) are O(n) and unacceptable for repeated evaluation during re-prioritization cycles. Use dictionary-backed storage.When this skill is active, your output must contain:
## Task Prioritization Report
### Priority Score Weights
urgency: 0.4 | importance: 0.3 | dependency_penalty: 0.3
### Execution Queue (Ready)
1. TASK-003 (P0, score=0.82) — "Fix critical auth bug" → Worker A
2. TASK-007 (P0, score=0.76) — "Deploy hotfix to staging" → Worker B
3. TASK-001 (P1, score=0.55) — "Write API documentation" → unassigned
### Blocked Tasks
4. TASK-002 (P1, score=0.48) — blocked on: TASK-003 (fix must land first)
5. TASK-005 (P2, score=0.31) — blocked on: TASK-007 (deploy completes first)
### Re-Prioritization (last 5 min)
- TASK-003 escalated P1 → P0: deadline moved from 48h to 4h
- TASK-006 demoted P0 → P1: market impact reassessed as low
### Worker Allocation
Worker A: TASK-003 (active, est. completion 2h)
Worker B: TASK-007 (active, est. completion 1.5h)
| Skill | Purpose |
|---|---|
planning-patterns | Provides the overarching plan structure that prioritization feeds into |
multi-agent-collaboration | Coordinates parallel agent execution where each agent's tasks must be prioritized relative to others |
resource-optimization | Extends prioritization with resource-constrained scheduling (CPU, memory, human capacity) |
The prioritization pattern applies across diverse real-world domains:
Each application follows the same core pattern: define criteria → score tasks → schedule with dependency awareness → re-prioritize dynamically as conditions change.