5.2Function Calling / Tool Use
本课只解决一个主问题:本单元只解决一个主问题:LLM 本身只会生成文本,为什么它能查数据库、发邮件、执行代码或操作外部系统?
学习目标
学完本单元后,学习者应该能够:
- 解释 Function Calling / Tool Use 的基本机制。
- 理解工具 schema、参数校验、工具返回和模型后续生成的关系。
- 设计一个基础工具调用流程。
- 识别工具调用中的权限、幂等性和错误处理问题。
- 判断什么时候应该让模型调用工具,什么时候不应该。
先给直觉
模型本身不会真的“打开日历”或“查询数据库”。
它能做的是:
- 理解用户想做什么。
- 选择一个可用工具。
- 生成符合工具要求的参数。
- 由外部程序真正执行工具。
- 工具把结果返回给模型。
- 模型根据结果继续回答或决定下一步。
所以工具调用不是模型突然长出了手,而是系统给它配了受控的接口。
基本流程
一个简化工具调用流程:
用户请求
↓
模型判断需要调用工具
↓
模型生成工具名和参数
↓
系统校验参数和权限
↓
外部工具执行
↓
工具返回结果
↓
模型根据结果生成回答
关键点:真正执行动作的是系统,不是模型自己。
什么是工具
工具是模型可以请求调用的外部能力。
常见工具:
- 搜索网页
- 查询数据库
- 读取文件
- 写入文件
- 执行代码
- 发送邮件
- 创建日历事件
- 调用支付接口
- 查询订单状态
- 生成图片
工具可以很简单,也可以很危险。查询天气和转账付款显然不是一个风险等级。
工具 schema
工具 schema 是告诉模型:
- 有哪些工具。
- 每个工具做什么。
- 需要哪些参数。
- 参数类型是什么。
- 哪些参数必填。
- 参数有什么约束。
例子:
{
"name": "search_course",
"description": "在课程资料中搜索相关内容",
"parameters": {
"query": {
"type": "string",
"description": "用户要搜索的问题"
},
"module": {
"type": "string",
"description": "可选,限定课程模块"
}
},
"required": ["query"]
}
好的 schema 能减少模型误用工具。
差 schema 的问题:
- 工具描述太模糊。
- 参数名不清楚。
- 没有说明必填项。
- 没有限制输入范围。
- 把高风险能力暴露得太随意。
参数校验
模型生成的参数不能直接信任。
系统必须校验:
- 类型是否正确。
- 必填项是否存在。
- 值是否在允许范围内。
- 用户是否有权限。
- 是否包含危险内容。
- 是否会造成重复或破坏性操作。
例子:
模型想调用:
{
"tool": "send_email",
"to": "all@company.com",
"subject": "紧急通知",
"body": "..."
}
系统不应该直接发送。它至少要检查权限,并要求用户确认。
工具返回结果
工具返回给模型的内容也要设计。
好的返回结果应该:
- 结构清晰。
- 包含必要字段。
- 明确成功或失败。
- 错误信息可理解。
- 避免泄露无关敏感数据。
例子:
{
"status": "success",
"results": [
{
"title": "4.1 为什么需要 RAG",
"path": "04_rag_knowledge/01_why_rag/lesson.md",
"snippet": "RAG 的思路是先查资料,再让模型带着资料回答。"
}
]
}
模型看到这个结果后,才能继续生成有依据的回答。
幂等性
幂等性是工程里非常重要的概念。
简单说:同一个操作执行多次,结果不会造成额外副作用。
查询天气通常是幂等的。
发送邮件不是幂等的。调用两次就可能发两封。
付款、删除文件、发布文章,也通常不是幂等的。
对非幂等工具,必须特别小心:
- 加确认节点。
- 加去重 ID。
- 加日志。
- 加回滚或补救方案。
- 限制重试。
Agent 系统最怕的是工具失败后模型“再试一次”,结果把邮件发了五遍。收件人也许会记住你,但方式不太理想。
权限边界
工具调用必须有权限设计。
至少考虑:
- 哪些用户能调用工具。
- 工具能访问哪些数据。
- 工具能执行哪些动作。
- 是否需要二次确认。
- 是否有日志审计。
- 是否能撤销。
权限不能靠 Prompt 约束。
不要只写:
请不要访问敏感数据。
系统层必须真的不让它访问。
错误处理
工具调用一定会失败。
常见失败:
- 参数错误。
- 权限不足。
- 网络超时。
- 外部 API 失败。
- 返回数据为空。
- 结果格式变化。
- 工具执行了一半失败。
系统要告诉模型失败原因,并让模型采取合理下一步。
例子:
{
"status": "error",
"code": "PERMISSION_DENIED",
"message": "当前用户无权访问该文档"
}
模型应该回复:
我无法访问该文档。你可以提供有权限的资料,或联系管理员调整权限。
而不是编一个答案。
工具选择
不是所有问题都需要工具。
适合调用工具:
- 需要实时信息。
- 需要私有数据。
- 需要执行动作。
- 需要精确计算。
- 需要验证事实。
不一定需要工具:
- 通用概念解释。
- 轻量改写。
- 头脑风暴。
- 风格润色。
工具调用会增加成本、延迟和失败点。能不用工具稳定解决,就不要为了显得高级硬加工具。
人类确认
高风险工具调用前必须确认。
建议确认的动作:
- 发邮件。
- 发消息。
- 删除文件。
- 覆盖文档。
- 付款。
- 下单。
- 发布内容。
- 修改生产数据。
- 调用外部客户系统。
确认界面应该显示:
- 工具名称。
- 即将执行的动作。
- 参数。
- 影响范围。
- 是否可撤销。
不要只给一个“确定吗?”按钮。用户需要知道自己在确认什么。
案例:课程资料搜索工具
目标:让模型搜索 LLMCourse 内容。
工具:
{
"name": "search_course",
"description": "搜索课程讲义和模块说明",
"parameters": {
"query": {
"type": "string",
"description": "搜索问题或关键词"
},
"module": {
"type": "string",
"description": "可选,限定模块,如 RAG、Agent、Prompt"
},
"top_k": {
"type": "integer",
"description": "返回结果数量,范围 1 到 10"
}
},
"required": ["query"]
}
系统校验:
query不能为空。top_k默认 5,最大 10。module必须来自允许列表。- 只搜索已发布课程内容。
工具返回:
- 文件路径。
- 小标题。
- 片段。
- 相似度或排序分数。
模型生成回答:
- 根据返回片段回答。
- 引用课程路径。
- 如果没有结果,说明未找到资料。
常见误区
误区 1:模型调用工具就是模型自己执行动作
不是。模型生成调用请求,系统执行工具。
误区 2:Prompt 可以替代权限控制
不能。权限必须在系统层实现。
误区 3:工具越多,Agent 越强
工具越多,选择和安全问题越复杂。工具要按任务需要设计。
误区 4:工具失败时让模型自己圆回来就行
不行。工具失败要明确暴露,不能让模型编造结果。
误区 5:所有工具都可以自动重试
非幂等工具不能随意重试,否则可能造成重复副作用。
动手练习
设计一个工具,让 AI 帮你管理课程任务。
填写:
| 项目 | 你的设计 |
|---|---|
| 工具名称 | |
| 工具用途 | |
| 输入参数 | |
| 必填参数 | |
| 参数校验规则 | |
| 返回结果格式 | |
| 权限限制 | |
| 是否需要确认 | |
| 失败时怎么办 |
检查题(自测)
- 工具调用的基本流程是什么?
- 为什么模型生成的工具参数必须校验?
- 什么是幂等性?为什么它对工具调用重要?
参考答案
- 基本流程:模型输出结构化的工具调用请求 → 系统解析并校验参数 → 执行工具 → 把结果返回给模型 → 模型基于结果继续生成。
- 模型生成的参数可能格式错误、取值非法或越权,不校验可能导致错误执行、数据损坏或权限滥用;校验是工具调用的安全底线。
- 幂等性指同一操作执行多次结果一致。它对工具调用重要,因为重试不可避免:如果每次重试都重复扣款、重复发送,后果会很严重。
Takeaway
Tool Use 让 LLM 能连接外部世界,但真正可靠的工具调用依赖 schema、参数校验、权限、错误处理、幂等性和人类确认。模型负责提出动作,系统负责安全执行。