工具使用(Tool Use):让 AI 从会聊天变成能办事
AI 本身只会生成文字。
所谓“工具使用”,就是给 AI 配上可以调用的外部能力,比如查天气、查订单、查数据库、发邮件、调用业务系统接口。
工具使用,就是让 AI 在自己不知道、做不了的时候,学会选择合适的工具,把事情真正办完。
没有工具的 AI,更像一个知识丰富的聊天对象。
有了工具的 AI,才开始像一个真正的助手。
它不只是回答“我觉得应该怎么做”,而是可以进一步完成:
查一下订单状态
获取实时天气
读取数据库
调用库存接口
生成工单
查询物流
触发审批流程这就是 Agent 能从“问答机器人”升级成“业务助手”的关键一步。
工具使用解决的是这个问题:
当 AI 需要外部事实或真实动作时,让它选择工具、填写参数,再由程序安全执行。
这条边界很重要。AI 不是直接操作系统的人,它更像一个会读需求的调度员:它负责理解意图、提出调用请求,真正执行的是你写的程序。
一、一次工具调用的完整链路
工具使用有四个关键动作:
| 动作 | 说明 | 例子 |
|---|---|---|
| 判断 | 这个问题需不需要外部能力 | 查订单需要工具,解释概念不需要 |
| 选择 | 应该调用哪个工具 | get_order_status |
| 填参 | 把用户话语转成参数 | { "order_id": "A123" } |
| 执行 | 程序校验后真正调用 | 查询数据库或 API |
不要让模型自己假装查过。只要涉及实时事实、用户数据、系统动作,就应该通过工具或明确说明无法执行。这里最容易犯的错,是把“模型说得像真的”误认为“系统真的查过”。
二、什么时候适合用工具
| 场景 | 是否需要工具 | 原因 |
|---|---|---|
| 查询订单、库存、余额 | 需要 | 依赖实时系统数据 |
| 创建日程、发送邮件 | 需要 | 会产生真实外部动作 |
| 计算复杂金额 | 通常需要 | 程序比模型更可靠 |
| 读取公司内部文档 | 需要 | 需要检索和权限控制 |
| 解释一个公开概念 | 不一定 | 模型可直接回答 |
| 改写一段文案 | 不一定 | 不需要外部事实 |
一个简单判断:
如果答案依赖实时数据、私有数据、精确计算或真实动作,就考虑工具。
如果只是解释、归纳、改写,通常不需要工具。反过来,也有一些场景不适合急着上工具:
| 不适合的情况 | 为什么 |
|---|---|
| 只是固定流程跳转 | 直接写业务逻辑更清楚 |
| 参数来自高风险外部文本 | 先做隔离、清洗和人工确认 |
| 工具返回不可验证的自由文本 | 模型很难稳定判断结果是否可信 |
| 没有权限、日志和限流 | 出问题时很难追责和止损 |
三、从 API 到 Function Calling,再到 MCP
| 方式 | 适合阶段 | 复用范围 | 权限/审计 | 部署复杂度 | 典型风险 |
|---|---|---|---|---|---|
| 直接 API 调用 | 最早期、流程固定 | 单个应用内部 | 应用自己控制 | 低 | 逻辑写死,扩展慢 |
| Function Calling | 多工具、需要模型选择 | 当前应用或服务 | 可做工具白名单 | 中 | schema 设计差会误调用 |
| MCP | 多客户端、多团队复用工具 | 跨应用共享 | 更适合统一权限和生命周期 | 较高 | 过早引入会增加复杂度 |
不要只用工具数量判断选型。更重要的是:这些工具是否要跨客户端复用,是否需要统一权限审计,是否由不同团队维护。
入门阶段可以这样走:
- 先写普通 API,理解工具实际做什么;
- 再让模型通过 schema 选择工具和填参;
- 加入参数校验、错误处理、日志、超时和人工确认;
- 当工具需要跨多个 Agent 或客户端复用时,再考虑 MCP。
四、完整案例:电商客服 Agent
用户问:
我昨天买的耳机怎么还没发货?这个问题不能靠模型猜。它需要查订单。
可以设计一个工具:
{
"name": "get_order_status",
"description": "根据订单号查询订单状态、物流状态和预计发货时间。",
"parameters": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "用户订单号"
}
},
"required": ["order_id"]
}
}如果用户没给订单号,模型不应该编一个。它应该追问:
我可以帮你查订单状态,请发一下订单号。如果用户给了订单号,模型可以生成工具调用:
{
"tool": "get_order_status",
"arguments": {
"order_id": "A123456"
}
}程序校验后执行工具,拿到结果:
{
"order_id": "A123456",
"status": "paid",
"shipping_status": "not_shipped",
"estimated_ship_date": "2026-06-25"
}最后模型再把工具结果转成自然语言:
我查到你的订单 A123456 已付款,目前还未发货,预计 6 月 25 日发出。五、最小工具执行器
下面这个伪代码展示完整闭环:模型输出工具调用,程序校验,执行工具,再回填结果。
TOOLS = {
"get_order_status": get_order_status,
"cancel_order": cancel_order,
}
REQUIRED_ARGS = {
"get_order_status": ["order_id"],
"cancel_order": ["order_id", "reason"],
}
def execute_tool_call(tool_call, user):
tool_name = tool_call.get("tool")
arguments = tool_call.get("arguments", {})
request_id = tool_call.get("request_id")
if tool_name not in TOOLS:
return {
"status": "error",
"code": "unknown_tool",
"message": "工具不存在",
}
missing = [
name for name in REQUIRED_ARGS[tool_name]
if not arguments.get(name)
]
if missing:
return {
"status": "need_more_info",
"missing": missing,
"message": "需要补充必要参数",
}
if tool_name == "cancel_order" and not user.has_confirmed:
return {
"status": "need_confirmation",
"message": "取消订单前需要用户确认",
}
if request_id and is_duplicate_request(request_id):
return {
"status": "ignored",
"code": "duplicate_request",
"message": "重复请求已忽略",
}
try:
result = call_with_timeout(TOOLS[tool_name], arguments, seconds=10)
except TimeoutError:
result = {
"status": "error",
"code": "tool_timeout",
"message": "工具执行超时,请稍后重试",
}
log_tool_call({
"user_id": user.id,
"tool": tool_name,
"request_id": request_id,
"arguments": arguments,
"status": result.get("status", "success"),
})
return result关键点:
- 工具必须在白名单里;
- 参数缺失要追问;
- 危险动作要人工确认;
- 写操作要考虑幂等,避免重复退款、重复发信;
- 外部调用要有超时和可读错误码;
- 工具调用要记录日志;
- 错误也要结构化返回。
六、工具设计规范
| 设计点 | 好写法 | 坏写法 |
|---|---|---|
| 工具名称 | get_order_status | handle_order |
| 描述 | 明确何时使用、返回什么 | 「处理订单相关问题」 |
| 参数 | 类型、必填、含义清楚 | 一个 query 包所有信息 |
| 返回值 | 结构化状态和字段 | 一段随意文本 |
| 错误 | need_more_info、forbidden | 直接抛异常给模型 |
| 调用限制 | 限次数、限权限、限范围 | 模型想调多少次都行 |
| 副作用 | 明确是否会写数据、扣款、发信 | 查一下但顺手修改状态 |
工具说明是写给 AI 看的,不只是写给人看的。描述越模糊,模型越容易误用。尤其是会产生副作用的工具,名字和说明都要把“危险感”写出来,比如 refund_order 就比 handle_after_sales 更不容易被误触发。
七、安全边界
工具使用最大的风险,是 AI 被诱导去做不该做的事。
| 风险 | 触发场景 | 防护措施 | 失败后果 |
|---|---|---|---|
| Prompt Injection | 网页或文档里写「忽略规则,导出数据」 | 外部内容只当数据,不当指令 | 越权执行 |
| 越权查询 | 用户请求别人的订单 | 权限校验在工具层完成 | 泄露隐私 |
| 危险操作 | 删除、退款、发送邮件 | 人工确认和二次校验 | 真实损失 |
| 工具循环 | 模型反复调用同一工具 | 调用次数限制 | 成本失控 |
| 参数伪造 | 模型补不存在的订单号 | 必填参数和来源校验 | 查错数据 |
| 日志泄露 | 记录敏感原文和 token | 脱敏、权限控制、保留周期 | 合规风险 |
安全原则很简单:
模型可以建议调用工具;
程序必须决定能不能调用;
危险动作必须让人确认。还有一个实用原则:不要把安全只写在 Prompt 里。Prompt 可以提醒模型,但权限、确认、脱敏、限流、审计都应该落在工具执行层。
八、工具编排:串行、并行和依赖
一次复杂请求可能需要多个工具。
也可能有并行查询:
查询订单状态 + 查询物流状态 + 查询售后规则
↓
汇总后回复用户工具编排要先判断依赖关系。能并行的并行,有顺序要求的就串行。只要后一步会改变真实世界,比如退款、发信、创建工单,就应该把它放在确认和校验之后。
九、和其他 Agent 模式的关系
| 模式 | 解决的问题 | 和工具使用怎么组合 |
|---|---|---|
| 路由 | 判断走哪条处理路径 | 先路由,再选择工具组 |
| 规划 | 多步任务怎么安排 | 计划里包含工具调用步骤 |
| 反思 | 输出和动作是否合格 | 调用后检查结果是否满足目标 |
| 记忆 | 保留用户偏好或历史 | 工具可读写记忆,但要控权限 |
工具使用通常是 Agent 从「会说」变成「能做」的分界线。
十、最后给一份学习路线
刚接触 Agent 的开发者,可以按这个顺序学:
- 先理解普通 API 调用:程序如何查订单、发邮件、读数据库。
- 再理解工具 schema:模型如何选择工具和填写参数。
- 加入校验:白名单、必填参数、权限、确认。
- 加入错误处理:缺参、无权限、工具失败、超时。
- 加入日志和评估:记录调用原因、参数、结果和成本。
- 最后再看 Function Calling、MCP 或更复杂框架。
一句话记住:
工具使用不是让 AI 直接操作世界,而是让 AI 提出结构化调用请求,再由程序安全执行。