為什麼需要任務編排?
想象一下這個場景:使用者要求 Agent 完成一篇市場調查報告。這個任務需要:
- 收集市場資料
- 分析競爭對手
- 生成圖表
- 撰寫報告
這就是一個典型的需要任務編排的場景。
核心架構設計
1. 任務分解策略
使用 LLM 進行智慧任務分解:
from typing import List, Dict
import asyncio
class TaskDecomposer:
def __init__(self, llm_service):
self.llm = llm_service
async def decompose_task(self, task_description: str) -> Dict:
"""智慧任務分解"""
prompt = f"""
任務描述:{task_description}
請將該任務分解為子任務,輸出格式:
{{
"subtasks": [
{{
"id": "task_1",
"name": "子任務名稱",
"description": "詳細描述",
"dependencies": [],
"estimated_time": "預計耗時(分鐘)"
}}
]
}}
要求:
1. 子任務粒度適中
2. 明確任務依賴關係
3. 便於並行處理
"""
response = await self.llm.generate(prompt)
return self._validate_and_process(response)
def _validate_and_process(self, decomposition_result: dict) -> dict:
"""驗證和處理分解結果"""
# 驗證任務依賴關係是否合法
self._check_circular_dependencies(decomposition_result["subtasks"])
# 構建任務執行圖
return self._build_execution_graph(decomposition_result["subtasks"])
2. 並行處理架構
使用非同步任務池管理並行執行:
class TaskExecutor:
def __init__(self, max_workers: int = 5):
self.max_workers = max_workers
self.task_queue = asyncio.Queue()
self.results = {}
self.semaphore = asyncio.Semaphore(max_workers)
async def execute_tasks(self, task_graph: Dict):
"""執行任務圖"""
# 建立工作者池
workers = [
self._worker(f"worker_{i}")
for i in range(self.max_workers)
]
# 新增可執行的任務到佇列
ready_tasks = self._get_ready_tasks(task_graph)
for task in ready_tasks:
await self.task_queue.put(task)
# 等待所有任務完成
await asyncio.gather(*workers)
async def _worker(self, worker_id: str):
"""工作者協程"""
while True:
try:
async with self.semaphore:
task = await self.task_queue.get()
if task is None:
break
# 執行任務
result = await self._execute_single_task(task)
self.results[task["id"]] = result
# 檢查並新增新的可執行任務
new_ready_tasks = self._get_ready_tasks(task_graph)
for new_task in new_ready_tasks:
await self.task_queue.put(new_task)
except Exception as e:
logger.error(f"Worker {worker_id} error: {str(e)}")
3. 中間結果管理
使用 Redis 儲存中間結果:
class ResultManager:
def __init__(self):
self.redis_client = redis.Redis()
async def save_result(self, task_id: str, result: Any):
"""儲存任務結果"""
key = f"task_result:{task_id}"
try:
# 序列化結果
serialized_result = self._serialize_result(result)
# 儲存到Redis,設定24小時過期
await self.redis_client.set(
key,
serialized_result,
ex=86400
)
except Exception as e:
logger.error(f"Failed to save result for task {task_id}: {e}")
raise
async def get_result(self, task_id: str) -> Any:
"""獲取任務結果"""
key = f"task_result:{task_id}"
result = await self.redis_client.get(key)
if result is None:
raise KeyError(f"No result found for task {task_id}")
return self._deserialize_result(result)
def _serialize_result(self, result: Any) -> bytes:
"""序列化結果"""
if isinstance(result, (dict, list)):
return json.dumps(result).encode()
elif isinstance(result, bytes):
return result
else:
return pickle.dumps(result)
4. 任務編排模式
實現不同的任務編排模式:
class TaskOrchestrator:
def __init__(self):
self.decomposer = TaskDecomposer()
self.executor = TaskExecutor()
self.result_manager = ResultManager()
async def execute_pipeline(self, tasks: List[Dict]):
"""流水線模式執行"""
for task in tasks:
result = await self.executor.execute_single_task(task)
await self.result_manager.save_result(task["id"], result)
async def execute_parallel(self, tasks: List[Dict]):
"""並行模式執行"""
results = await asyncio.gather(*[
self.executor.execute_single_task(task)
for task in tasks
])
for task, result in zip(tasks, results):
await self.result_manager.save_result(task["id"], result)
async def execute_dag(self, task_graph: Dict):
"""DAG模式執行"""
return await self.executor.execute_tasks(task_graph)
5. 效能最佳化技巧
class PerformanceOptimizer:
def __init__(self):
self.cache = LRUCache(maxsize=1000)
async def optimize_task(self, task: Dict) -> Dict:
"""任務最佳化"""
# 1. 資源評估
required_resources = self._estimate_resources(task)
# 2. 快取檢查
if cached_result := self.cache.get(task["id"]):
return cached_result
# 3. 批處理最佳化
if self._can_batch(task):
task = self._batch_similar_tasks(task)
# 4. 資源分配
task["resources"] = self._allocate_resources(required_resources)
return task
def _estimate_resources(self, task: Dict) -> Dict:
"""估算任務資源需求"""
return {
"cpu": self._estimate_cpu_usage(task),
"memory": self._estimate_memory_usage(task),
"io": self._estimate_io_usage(task)
}
def _can_batch(self, task: Dict) -> bool:
"""判斷任務是否可以批處理"""
return (
task["type"] in ["data_processing", "llm_inference"] and
task["size"] < self.batch_size_threshold
)
實戰案例:市場調查報告生成系統
class MarketResearchSystem:
def __init__(self):
self.orchestrator = TaskOrchestrator()
self.optimizer = PerformanceOptimizer()
async def generate_report(self, topic: str):
# 1. 任務分解
tasks = await self.orchestrator.decomposer.decompose_task(
f"生成關於 {topic} 的市場調查報告"
)
# 2. 任務最佳化
optimized_tasks = await asyncio.gather(*[
self.optimizer.optimize_task(task)
for task in tasks["subtasks"]
])
# 3. 執行任務圖
results = await self.orchestrator.execute_dag({
"tasks": optimized_tasks
})
# 4. 生成最終報告
return await self._compile_report(results)
async def _compile_report(self, results: Dict) -> str:
"""編譯最終報告"""
sections = []
for task_id, result in results.items():
if task_id.startswith("data_collection"):
sections.append(self._format_data_section(result))
elif task_id.startswith("competitor_analysis"):
sections.append(self._format_analysis_section(result))
elif task_id.startswith("chart_generation"):
sections.append(self._format_chart_section(result))
return self._combine_sections(sections)
最佳實踐
-
任務分解原則
- 保持任務粒度適中
- 明確定義依賴關係
- 考慮並行執行可能性
-
資源管理策略
- 動態調整並行度
- 實現任務優先順序
- 合理分配計算資源
-
錯誤處理機制
- 實現任務重試
- 提供回滾機制
- 儲存執行狀態
-
監控和日誌
- 記錄詳細執行日誌
- 監控系統資源
- 追蹤任務狀態
常見問題和解決方案
-
任務依賴死鎖
- 問題:迴圈依賴導致任務無法執行
- 解決:實現依賴檢測和超時機制
-
資源競爭
- 問題:並行任務爭搶資源
- 解決:實現資源池和排程演算法
-
狀態一致性
- 問題:分散式環境下狀態不一致
- 解決:使用分散式鎖和事務
總結
一個好的任務編排系統應該具備:
- 靈活的任務分解能力
- 高效的並行處理架構
- 可靠的中間結果管理
- 多樣的任務編排模式
- 優秀的效能最佳化能力