您的位置:首页 > 手游攻略 > Agent 并行工具执行 —— 让多个工具同时干活,而非排队等

Agent 并行工具执行 —— 让多个工具同时干活,而非排队等

作者:互联网  时间: 2026-07-31 13:34:02  

处理Agent 并行工具执行 —— 让多个工具同时干活,而非排队等这类问题时,先确认目标场景,再按步骤核对配置或玩法细节。

一、问题:工具在排队,Agent 在空转

前几篇文章构建的 Agent 有一个隐含的性能瓶颈——多个工具是串行执行的。当 LLM 一次性要求调用多个独立工具时:

Agent 并行工具执行 —— 让多个工具同时干活,而非排队等

LLM → 要查三个城市的天气:北京、上海、广州串行执行(之前)search_web("北京") → 等 0.5s → 结果search_web("上海") → 等 0.5s → 结果search_web("广州") → 等 0.5s → 结果总耗时: 1.5s并行执行(本篇)search_web("北京") ─┐search_web("上海") ─┼─ 同时跑 → 0.5s 全部完成search_web("广州") ─┘总耗时: 0.5s

这不是理论优化——当 LLM 决定同时调用 5 个独立的搜索、计算或文件读取工具时,串行意味着用户要多等 4 倍的时间。更糟糕的是,一个慢工具会阻塞后面所有快工具。

二、核心思路:线程池 + 批量提交 + 按完成顺序收集

flowchart LRsubgraph OLD[串行模式]O1[search_web 北京 0.5s] --> O2[search_web 上海 0.5s]O2 --> O3[search_web 广州 0.5s]O3 --> O4[总耗时 1.5s]endsubgraph NEW[并行模式]N1[search_web 北京 0.5s]N2[search_web 上海 0.5s]N3[search_web 广州 0.5s]N1 --> N4[总耗时 0.5s]N2 --> N4N3 --> N4end

三个关键决策:

  1. 线程池而非 asyncio —— 工具函数是同步的,线程池最自然,且与已有 call_with_timeout 完美兼容
  2. 按完成顺序收集 —— as_completed() 让快的工具先返回,不等的工具也不阻塞
  3. final_output 特殊处理 —— 先到但不返回,等其他工具跑完

三、实现

with concurrent.futures.ThreadPoolExecutor(max_workers=len(tool_calls)) as executor:# Step 1: 提交所有工具到线程池future_map = {}for tc in tool_calls:name = tc["function"]["name"]args = json.loads(tc["function"]["arguments"])future = executor.submit(call_with_timeout,# ← 复用已有的超时包装active_tool_map[name],kwargs=args, timeout=30,)future_map[future] = {"name": name, "args": args, "tc": tc}# Step 2: 按完成顺序收集结果tool_result_spans = []final_output_found = Nonefor future in concurrent.futures.as_completed(future_map):meta = future_map[future]name, args, tc = meta["name"], meta["args"], meta["tc"]try:result = future.result()except Exception as e:result = f"工具执行错误: {e}"# final_output:记录但不立即返回if name in OUTPUT_TOOL_NAMES:final_output_found = {"result": result, "tc": tc}tracer.log_tool_call(name, args, result, ...)continuetracer.log_tool_call(name, args, result, ...)tool_result_spans.append((tc["id"], name, result))# Step 3: final_output 到达 → 返回if final_output_found:messages.append({"role": "assistant", "content": ...})return final_output_found["result"]# Step 4: 追加工具结果到 messagesfor tc_id, name, result in tool_result_spans:messages.append({"role": "tool", "tool_call_id": tc_id, "content": result})

四、final_output 的特殊处理

在并行模式下,final_output 可能与其他工具同时被调用。如果先于其他工具完成就立即返回,会导致并发工具的消息未被记录,下一次对话丢失上下文。

sequenceDiagramparticipant LLM as LLMparticipant EX as ThreadPoolExecutorparticipant SW as search_webparticipant FO as final_outputLLM->>EX: 提交 3 个工具EX->>SW: search_web("北京")EX->>SW: search_web("上海")EX->>FO: final_output({...})SW-->>EX: "北京结果" (0.3s)FO-->>EX: "结构化答案" (0.4s)Note over EX: final_output 到了但不返回SW-->>EX: "上海结果" (0.8s)Note over EX: 所有工具完成,final_output 返回EX-->>LLM: 结构化答案

五、与串行模式的对比

维度串行并行
执行方式for tc in tool_calls: result = ...executor.submitas_completed
总耗时N × 单次耗时max(单次耗时)
慢工具影响阻塞后续所有工具不阻塞其他工具
结果顺序按 LLM 输出顺序按完成先后顺序
代码复杂度简单需 future_map + as_completed
final_output立刻返回等其他工具跑完才返回

六、设计精要

6.1 最大并行度 = 工具数量

max_workers=len(tool_calls) —— LLM 一次调几个工具就开几个线程,不预设上限也不浪费资源。

6.2 复用 call_with_timeout

两层线程池各司其职:外层管理工具间并行,内层管理单个工具超时。并行化没有重新实现超时逻辑。

6.3 结果顺序不影响 LLM 推理

每个 tool 消息都带有 tool_call_id,LLM 通过 id 关联而非位置。

6.4 零侵入前序代码

只影响 run_agent_with_trace 中一段代码。SkillManager、AgentTracer、ContextManager、PersistenceManager、chat_loop 完全无感。

七、完整演进路径

Phase 1:基础Agent(~50行)Phase 2:可观测+压缩+持久化(+~200行)Phase 3:Skill渐进加载(+~150行)Phase 4:多轮对话循环(+~120行)Phase 5:流式输出(+~80行)Phase 6:重试+超时(+~128行)Phase 7:结构化输出(+~140行)Phase 8:并行工具执行(+~50行)本文

不改架构、不加新文件,只是把串行 for 升级为线程池并行。

推荐学习资源

  1. 从零开始打造一个AI Agent CLI — 手把手构建完整 AI Agent 命令行工具。
  2. AI Agents 开发实践 — Agent 架构设计、记忆系统、多 Agent 协作。
  3. AI 全栈编程生存指南 — AI 时代全栈开发者生存法则。

最新游戏

更多

Copyright©2010-2019. All rights reserved | 波波三国游戏官网|[email protected]

备案编号:湘ICP备2022015115号-4