agent / backend /backend_app /helloAgents /tools /async_executor.py
Toadied's picture
2312
8b383ad verified
Raw
History Blame Contribute Delete
6.37 kB
"""异步工具执行器 - HelloAgents异步工具执行支持"""
import asyncio
import concurrent.futures
from typing import Dict, Any, List
from .registry import ToolRegistry
import time
class AsyncToolExecutor:
"""异步工具执行器"""
def __init__(self, registry: ToolRegistry, max_workers: int = 4):
self.registry = registry
self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=max_workers)
async def execute_tool_async(self, tool_name: str, input_data: dict) -> str:
"""异步执行单个工具"""
loop = asyncio.get_event_loop()
def _execute():
return self.registry.execute_tool(tool_name, input_data)
try:
result = await loop.run_in_executor(self.executor, _execute)
return result
except Exception as e:
return f"❌ 工具 '{tool_name}' 异步执行失败: {e}"
async def execute_tools_parallel(self, tasks: List[Dict]) -> List[Dict[str, Any]]:
"""
真正并行执行 + 时间戳打印(判断是否并发)
"""
print(f"\n🚀 开始并行执行 {len(tasks)} 个任务,当前时间:{time.strftime('%H:%M:%S')}")
async_tasks = []
task_list = []
for i, task in enumerate(tasks):
tool_name = task.get("tool_name")
input_data = task.get("input_data", {})
if not tool_name:
continue
# 包装任务,加入【开始执行】打印
async def wrapped_task(idx, t_name, data):
# print(f"➡️ 任务 {idx+1} 开始执行 | 工具:{t_name} | 时间:{time.strftime('%H:%M:%S')}")
res = await self.execute_tool_async(t_name, data)
# print(f"✅ 任务 {idx+1} 执行完成 | 工具:{t_name} | 时间:{time.strftime('%H:%M:%S')}")
return res
async_tasks.append(wrapped_task(i, tool_name, input_data))
task_list.append(task)
# ======================
# 🔥 真正并行:全部同时运行
# ======================
results_raw = await asyncio.gather(*async_tasks, return_exceptions=True)
# print(f"\n🎉 全部并行执行完成 | 结束时间:{time.strftime('%H:%M:%S')}")
# 组装结果
results = []
for idx, (task, result) in enumerate(zip(task_list, results_raw)):
if isinstance(result, Exception):
results.append({
"task_id": idx,
"tool_name": task["tool_name"],
"status": "error",
"result": str(result)
})
else:
results.append({
"task_id": idx,
"tool_name": task["tool_name"],
"status": "success",
"result": result
})
return results
async def execute_tools_batch(self, tool_name: str, input_list: List[str]) -> List[Dict[str, Any]]:
"""
批量执行同一个工具
Args:
tool_name: 工具名称
input_list: 输入数据列表
Returns:
执行结果列表
"""
tasks = [
{"tool_name": tool_name, "input_data": input_data}
for input_data in input_list
]
return await self.execute_tools_parallel(tasks)
def close(self):
"""关闭执行器"""
self.executor.shutdown(wait=True)
print("🔒 异步工具执行器已关闭")
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.close()
# 便捷函数
async def run_parallel_tools(registry: ToolRegistry, tasks: List[Dict[str, str]], max_workers: int = 4) -> List[Dict[str, Any]]:
"""
便捷函数:并行执行多个工具
Args:
registry: 工具注册表
tasks: 任务列表
max_workers: 最大工作线程数
Returns:
执行结果列表
"""
executor = AsyncToolExecutor(registry, max_workers)
# 下面完全不变
results = await executor.execute_tools_parallel(tasks)
return results
async def run_batch_tool(registry: ToolRegistry, tool_name: str, input_list: List[str], max_workers: int = 4) -> List[Dict[str, Any]]:
"""
便捷函数:批量执行同一个工具
Args:
registry: 工具注册表
tool_name: 工具名称
input_list: 输入数据列表
max_workers: 最大工作线程数
Returns:
执行结果列表
"""
async with AsyncToolExecutor(registry, max_workers) as executor:
return await executor.execute_tools_batch(tool_name, input_list)
# 同步包装函数(为了兼容性)
def run_parallel_tools_sync(registry: ToolRegistry, tasks: List[Dict[str, str]], max_workers: int = 4) -> List[Dict[str, Any]]:
"""同步版本的并行工具执行"""
return asyncio.run(run_parallel_tools(registry, tasks, max_workers))
def run_batch_tool_sync(registry: ToolRegistry, tool_name: str, input_list: List[str], max_workers: int = 4) -> List[Dict[str, Any]]:
"""同步版本的批量工具执行"""
return asyncio.run(run_batch_tool(registry, tool_name, input_list, max_workers))
# 示例函数
async def demo_parallel_execution():
"""演示并行执行的示例"""
from .registry import ToolRegistry
# 创建注册表(这里假设已经注册了工具)
registry = ToolRegistry()
# 定义并行任务
tasks = [
{"tool_name": "my_calculator", "input_data": "2 + 2"},
{"tool_name": "my_calculator", "input_data": "3 * 4"},
{"tool_name": "my_calculator", "input_data": "sqrt(16)"},
{"tool_name": "my_calculator", "input_data": "10 / 2"},
]
# 并行执行
results = await run_parallel_tools(registry, tasks)
# 显示结果
print("\n📊 并行执行结果:")
for result in results:
status_icon = "✅" if result["status"] == "success" else "❌"
print(f"{status_icon} {result['tool_name']}({result['input_data']}) = {result['result']}")
return results
if __name__ == "__main__":
# 运行演示
asyncio.run(demo_parallel_execution())