Agent 工具调度设计,简单来说,就是给 AI 智能体配一套“组合拳”,让它能根据用户的需求,自己决定调用哪些工具(函数或 API)、怎么调用、调用完了怎么处理结果,最终把事儿办成。它是实现“大模型思考 + 工具执行”这套闭环方案的核心技术。

一、为什么需要工具调度设计?
首先,大模型的本职工作是理解语言和生成文本——这活儿它干得确实漂亮。但要说实时计算、接入数据库、操作软件甚至控制硬件,那可就超出它的能力范围了。其次,很多任务本身就没那么“简单”。比如“搜索最新科技新闻,翻译成中文然后发给我”,这需要搜索、翻译、发送三个步骤协同完成。最关键的一点是,Agent 需要能根据中间结果动态决定下一步该做什么,而不是走一条写死的流程。
二、核心设计要素
我们先来看一下,一套完整的工具调度系统,需要哪些基础组件。本质上,它是一张“功能地图”。
| 要素 | 说明 | 示例 |
|---|---|---|
| 工具描述 | 给 LLM 提供每个工具的“操作手册”——名称、参数、功能说明 | search(query: str) -> list |
| 意图解析 | LLM 理解用户到底想干嘛,再决定该调哪个工具,以及传什么参数 | 用户说“今天北京天气”→ 决定调用 get_weather(city=“北京”) |
| 参数提取 | 从对话中精准抓取符合工具要求的参数 | 从“明天下午3点开会”提取 time=“2025-05-14 15:00” |
| 执行与反馈 | 真正去调用工具,然后把结果送回给 LLM 处理 | 调用天气 API 返回 JSON,LLM 把它变乘人能看懂的自然语言 |
| 错误处理 | 工具调用失败、超时、参数缺了怎么办?得有应急方案 | 参数缺失时,主动反问用户 |
| 多步编排 | 支持顺序执行、并行执行、条件分支、循环等复杂模式 | 先搜索,再对搜索结果做摘要,最后发送 |
| 状态管理 | 记住整个任务执行过程中的上下文:已经调了什么工具、中间结果是什么 | 记住上一轮搜索用的关键词 |
三、常见调度模式
不同的任务复杂度,对应不同的调度模式。从最简单的到最复杂的,我们来捋一遍。
1. 单步调用
最基础的用法:Agent 一次响应只调一个工具,结果直接作为最终答案返回。
用户: 告诉我 2+2 等于几Agent: 调用 calculator(expression="2+2") → 4 → 回答“等于4”
2. 多步顺序调用
更常见的场景:Agent 调用一个工具后,把得到的结果作为上下文,接着决定下一步调什么。
用户: 搜索最新的 AI 新闻,然后翻译成中文Agent: 第一步: search("AI news 2025") → 返回5条英文新闻第二步: translate(text=上一步结果, target="zh") → 输出中文新闻最终回答: 中文新闻列表
3. 并行调用
有些子任务之间互不依赖,那就可以同时开动多个工具,提升效率。
用户: 比较北京和上海的天气Agent: 同时调用 get_weather("北京") 和 get_weather("上海") → 合并结果 → 回答
4. 条件分支
根据中间的返回结果,决定下一步是继续调用另一个工具,还是提前收工。
用户: 检查用户 ID 123 的积分是否大于100,如果是则发送优惠券Agent: 第一步: query_points(user_id=123) → 80第二步: 80 < 100 → 不调用 send_coupon,回答“积分不足”
5. 循环迭代
这类场景最考验 Agent 的“聪明”程度:它需要在“思考-行动-观察”的循环里反复调用工具,直到收集到足够信息再给出答案。这就是经典的 ReAct 模式。
用户: 帮我找到一家离我最近且评分高于4.5的咖啡店Agent:思考: 需要先获取用户位置,再搜索附近的咖啡店行动: get_user_location() → {lat: 40.7128, lng: -74.0060}观察: 位置在纽约时代广场思考: 现在搜索附近咖啡店行动: search_nearby(lat, lng, query="咖啡店", radius=1000)观察: 返回12家咖啡店思考: 需要筛选评分>4.5的行动: filter_by_rating(shops, min=4.5) → 3家店思考: 信息够了,可以回答回答: “以下是距离您最近且评分高于4.5的三家咖啡店...”
6. 错误恢复与重试
工具调用难免翻车,Agent 得有自主应对的能力。
调用天气 API 超时 → Agent 尝试备用天气 API → 还是失败 → 回答“暂时无法获取天气,请稍后再试”
四、典型技术实现:函数调用
好消息是,现在的主流大模型(GPT-4、Claude、DeepSeek 等)普遍原生支持函数调用,这极大降低了工具调度的实现门槛。
核心流程
- 用 JSON 格式定义好工具的 Schema
- 把用户的消息和工具描述一起发给 LLM
- LLM 返回类似
{ name: "get_weather", arguments: { city: "Beijing" } }的结果 - 执行对应的函数,拿到结果
- 把结果再送回给 LLM,让它生成最终回复
举个实际例子(Python + OpenAI)
import openaitools = [{ "type": "function", "function": { "name": "get_weather", "description": "获取指定城市当前天气", "parameters": { "type": "object", "properties": { "city": {"type": "string", "description": "城市名称"} }, "required": ["city"] } }}] 用户消息messages = [{"role": "user", "content": "北京今天天气怎么样?"}] 第一次调用 LLMresponse = openai.ChatCompletion.create( model="gpt-4", messages=messages, tools=tools, tool_choice="auto") 检查是否需要调用工具if response.choices[0].message.tool_calls: tool_call = response.choices[0].message.tool_calls[0] if tool_call.function.name == "get_weather": args = json.loads(tool_call.function.arguments) weather = get_weather(args["city"]) # 真正调用函数 将工具结果添加到对话 messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": weather }) 第二次调用 LLM 生成最终回答 final = openai.ChatCompletion.create(model="gpt-4", messages=messages) print(final.choices[0].message.content)
五、高级调度设计模式
当任务场景变得更复杂,就需要引入更高级的设计模式。
| 模式 | 描述 | 适用场景 |
|---|---|---|
| 计划-执行 | 先由 LLM 生成完整的步骤计划(比如 JSON 列表),然后依次执行 | 步骤固定、可预测的任务 |
| 反思 (Reflexion) | 执行结果不理想时,LLM 根据错误反馈修改计划并重试 | 编程、数学推理等需要反复试错的场景 |
| 多智能体协作 | 多个 Agent 各有各的工具集,通过调度器进行通信和协作 | 复杂工作流,比如客服+技术+财务的协同作业 |
| 人机回环 | 遇到不确定或高风险操作时,Agent 主动请求用户确认 | 发邮件、转账、删除数据等涉及安全或财务的操作 |
| 资源感知调度 | 根据工具调用的成本、延迟、配额等因素动态选择最合适的工具 | 需要低成本优先或者快速响应的场景 |
六、设计时的关键考量
工具粒度的把握是个技术活儿:工具太小(比如一个 add_one 函数)会导致调用次数激增,太大(比如一个 do_everything 函数)又会丧失灵活性。理想状态是保持单一职责。
当多个工具都能满足同一个需求时,LLM 该如何选择?可以在描述中标注优先级,或者增加额外的约束条件。
安全方面的设计同样不能马虎。对于高危操作(如发送邮件、写入数据库),一定要加上确认机制或权限校验。
上下文长度是另一个现实问题。工具返回的结果可能很长,需要做截断或摘要之后再送入 LLM,否则很容易超出模型的处理上限。
最后,要把可观测性纳入设计。记录每一次工具调用的输入、输出和耗时,这对调试和持续优化至关重要。
七、总结
Agent 工具调度设计的本质,就是一套“决策 + 执行 + 反馈”的闭环系统。它让大模型从一个纯粹的“聊天机器人”进化成一个能操控外部世界的“行动机器人”。在设计时,需要根据任务复杂度、实时性、稳定性和成本等因素综合考虑,选择合适的调度模式,并借助函数调用等机制来快速落地。
