Function Calling 与工具使用开发指南
AI 导读
Function Calling 与工具使用开发指南 Maurice | 灵阙学院 2026-02-27 什么是 Function Calling Function Calling 让大模型不再只是输出文本,而是能够结构化地调用外部工具。模型根据用户请求决定调用哪个函数、传入什么参数,开发者执行函数后将结果返回模型,模型再基于结果生成最终回答。...
Function Calling 与工具使用开发指南
Maurice | 灵阙学院 2026-02-27
什么是 Function Calling
Function Calling 让大模型不再只是输出文本,而是能够结构化地调用外部工具。模型根据用户请求决定调用哪个函数、传入什么参数,开发者执行函数后将结果返回模型,模型再基于结果生成最终回答。
┌────────────────────────────────────────────────────────────┐
│ Function Calling 流程 │
├────────────────────────────────────────────────────────────┤
│ │
│ User: "北京今天天气怎么样?" │
│ │ │
│ v │
│ LLM: 判断需要调用 get_weather(city="北京") │
│ │ │
│ v │
│ App: 执行 get_weather("北京") --> {"temp": 5, ...} │
│ │ │
│ v │
│ LLM: "北京今天气温 5 度C,多云,建议穿厚外套。" │
│ │
└────────────────────────────────────────────────────────────┘
三大平台 API 对比
| 特性 | OpenAI | Anthropic (Claude) | Google (Gemini) |
|---|---|---|---|
| 参数名 | tools |
tools |
tools |
| 格式 | JSON Schema | JSON Schema | JSON Schema (兼容) |
| 并行调用 | 支持 | 支持 | 支持 |
| 强制调用 | tool_choice: {function:{name:...}} |
tool_choice: {type:tool,name:...} |
tool_config |
| 最大工具数 | 128 | 64 | 128 |
| Strict Mode | strict: true |
默认较严格 | -- |
工具 Schema 设计原则
- 函数名:动词+名词,清晰表达意图(
get_weather而非weather) - 描述:告诉模型"什么时候应该调用这个工具",这比参数定义更重要
- 参数:用 enum 约束可选值,required 标记必填项,default 减少调用歧义
- 粒度:一个工具做一件事;宁可多几个单一工具,也不要一个万能工具
Schema 示例(核心工具)
tools = [
{
"type": "function",
"function": {
"name": "query_tax_policy",
"description": "查询中国税收政策法规。当用户询问税率、免税条件、申报规则时调用。",
"strict": True,
"parameters": {
"type": "object",
"properties": {
"tax_type": {
"type": "string",
"enum": ["增值税", "企业所得税", "个人所得税", "印花税", "消费税"],
},
"query": {"type": "string", "description": "具体查询内容"},
"year": {"type": "integer", "default": 2026},
},
"required": ["tax_type", "query"],
"additionalProperties": False,
},
},
},
{
"type": "function",
"function": {
"name": "calculate_tax",
"description": "计算应缴税额。当用户提供金额并要求计算税费时调用。",
"strict": True,
"parameters": {
"type": "object",
"properties": {
"tax_type": {"type": "string", "enum": ["增值税", "企业所得税", "个人所得税"]},
"amount": {"type": "number", "description": "金额(元)"},
"rate": {"type": "number", "description": "税率(小数形式,如0.13)"},
"deductions": {"type": "number", "default": 0},
},
"required": ["tax_type", "amount", "rate"],
"additionalProperties": False,
},
},
},
]
完整调用流程(OpenAI)
from openai import OpenAI
import json
client = OpenAI()
TOOL_MAP = {
"query_tax_policy": lambda **kw: {"policy": f"{kw.get('year',2026)}年{kw['tax_type']}相关政策..."},
"calculate_tax": lambda **kw: {"tax_due": round((kw["amount"] - kw.get("deductions", 0)) * kw["rate"], 2)},
}
def run_agent(user_message: str) -> str:
messages = [
{"role": "system", "content": "你是税务合规助手。使用工具回答用户问题。"},
{"role": "user", "content": user_message},
]
response = client.chat.completions.create(
model="gpt-4o", messages=messages, tools=tools, tool_choice="auto",
)
assistant_msg = response.choices[0].message
messages.append(assistant_msg)
if not assistant_msg.tool_calls:
return assistant_msg.content
# 执行所有工具调用(支持并行)
for tool_call in assistant_msg.tool_calls:
fn_name = tool_call.function.name
fn_args = json.loads(tool_call.function.arguments)
result = TOOL_MAP[fn_name](**fn_args)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result, ensure_ascii=False),
})
# 第二轮:模型基于工具结果生成最终回答
final = client.chat.completions.create(model="gpt-4o", messages=messages, tools=tools)
return final.choices[0].message.content
answer = run_agent("帮我算一下100万元收入按13%增值税要交多少税")
print(answer)
Claude 工具调用示例
import anthropic, json
client = anthropic.Anthropic()
claude_tools = [{
"name": "calculate_tax",
"description": "计算应缴税额",
"input_schema": {
"type": "object",
"properties": {
"tax_type": {"type": "string", "enum": ["增值税", "企业所得税", "个人所得税"]},
"amount": {"type": "number"}, "rate": {"type": "number"},
},
"required": ["tax_type", "amount", "rate"],
},
}]
response = client.messages.create(
model="claude-sonnet-4-20250514", max_tokens=1024,
tools=claude_tools,
messages=[{"role": "user", "content": "100万按13%增值税算多少"}],
)
for block in response.content:
if block.type == "tool_use":
result = {"tax_due": block.input["amount"] * block.input["rate"]}
follow_up = client.messages.create(
model="claude-sonnet-4-20250514", max_tokens=1024, tools=claude_tools,
messages=[
{"role": "user", "content": "100万按13%增值税算多少"},
{"role": "assistant", "content": response.content},
{"role": "user", "content": [
{"type": "tool_result", "tool_use_id": block.id,
"content": json.dumps(result, ensure_ascii=False)}
]},
],
)
print(follow_up.content[0].text)
多工具编排模式
┌──────────────────────────────────────────────────┐
│ Multi-Tool Orchestration │
├──────────────────────────────────────────────────┤
│ │
│ Sequential: Tool A --> Tool B --> Tool C │
│ (上一步输出是下一步输入) │
│ │
│ Parallel: Tool A ─┐ │
│ Tool B ─┼──> Merge --> Answer │
│ Tool C ─┘ │
│ │
│ Conditional: IF condition THEN Tool A │
│ ELSE Tool B │
│ │
│ Loop: WHILE not satisfied DO Tool A │
│ (Self-RAG / Agentic pattern) │
│ │
└──────────────────────────────────────────────────┘
错误处理最佳实践
| 错误类型 | 处理方式 | 返回给模型的信息 |
|---|---|---|
| 参数校验失败 | 拒绝执行,返回错误 | {"error": "amount must be positive"} |
| 外部 API 超时 | 重试 1-2 次后降级 | {"error": "service temporarily unavailable"} |
| 权限不足 | 拒绝执行 | {"error": "permission denied"} |
| 函数不存在 | 记录日志,安全拒绝 | {"error": "unknown function"} |
| 结果过大 | 截断或摘要 | 前 N 条 + "truncated": true |
安全考量
- 输入验证:永远不要直接将模型生成的参数传入危险操作(SQL、shell 命令)
- 权限控制:工具分级(只读/读写/危险),危险工具需要人工确认
- 速率限制:防止模型陷入循环调用耗尽 API 配额
- 审计日志:记录每次工具调用的输入输出,用于事后追溯
- 沙盒执行:代码执行类工具必须在隔离环境中运行
- 输出过滤:工具返回的数据可能包含敏感信息,需脱敏后再传给模型
def safe_tool_call(fn_name: str, fn_args: dict, user_permissions: list) -> dict:
if fn_name not in TOOL_MAP:
return {"error": f"Unknown function: {fn_name}"}
if TOOL_PERMISSIONS.get(fn_name, "admin") not in user_permissions:
return {"error": f"Permission denied for {fn_name}"}
sanitized_args = sanitize_inputs(fn_args)
try:
result = execute_with_timeout(TOOL_MAP[fn_name], sanitized_args, timeout=30)
except TimeoutError:
return {"error": "Function execution timed out"}
return redact_sensitive_fields(result)
Maurice | [email protected]
深度加工(NotebookLM 生成)
基于本文内容生成的 PPT 大纲、博客摘要、短视频脚本与 Deep Dive 播客,用于多场景复用
PPT 大纲(5-8 张幻灯片) 点击展开
Function Calling 与工具使用开发指南 — ppt
幻灯片 1:什么是 Function Calling?
- 核心价值:Function Calling 让大模型不再局限于输出文本,而是能够结构化地调用外部工具 [1]。
- 基本工作流程:用户发起请求后,模型判断并决定调用哪个函数以及传入什么参数 [1]。
- 应用执行与闭环:开发者在本地执行工具函数并将结果返回给模型,模型再基于此结果生成最终的自然语言回答 [1]。
幻灯片 2:三大主流平台 API 特性对比
- 通用标准:OpenAI、Claude 和 Google Gemini 均支持兼容 JSON Schema 的格式来定义工具(tools) [1]。
- 并行能力:这三大平台目前均全面支持并行调用(Parallel Calling)多个工具 [1]。
- 工具数量限制:OpenAI 和 Gemini 最多支持 128 个工具,而 Claude 最多支持 64 个 [1]。
- 严格模式:OpenAI 默认提供较严格的 Strict Mode,可以通过设置
strict: true规范模型的输出格式 [1]。
幻灯片 3:工具 Schema 的设计原则
- 函数命名:应采用“动词+名词”形式清晰表达意图,例如使用
get_weather而非weather[1]。 - 描述定义:工具的 description 字段比参数本身更重要,必须明确告诉模型“什么时候应该调用这个工具” [1]。
- 参数约束:建议用 enum 约束可选值,使用 required 标记必填项,并通过 default 值减少调用的歧义 [1]。
- 功能粒度:坚持一个工具只做一件事的原则,宁可多设计几个单一功能的工具,也不要设计“万能工具” [1, 2]。
幻灯片 4:多工具编排模式
- 串行模式 (Sequential):按照顺序依次执行,上一步工具的输出作为下一步工具的输入 [3]。
- 并行模式 (Parallel):同时执行多个互不依赖的工具,然后合并它们的结果以生成答案 [3]。
- 条件模式 (Conditional):根据特定的条件判断,决定调用工具 A 还是工具 B [3]。
- 循环模式 (Loop):不断调用工具直到满足特定条件,常见于 Self-RAG 或 Agent 等复杂模式 [3]。
幻灯片 5:错误处理最佳实践
- 参数校验失败:应拒绝执行,并向模型返回明确的错误原因(如“金额必须为正数”)以便模型修正 [3]。
- 服务超时异常:外部 API 超时建议重试 1-2 次,之后进行降级处理并提示服务暂不可用 [3]。
- 权限及路由错误:遇到权限不足或调用了不存在的函数时,必须记录日志并安全地拒绝执行 [3]。
- 返回结果过大:当工具返回的数据过多时,应截取前 N 条数据或进行摘要处理 [3]。
幻灯片 6:工具调用的安全考量
- 输入验证:永远不要直接将模型生成的参数传入高风险操作(如 SQL 查询、Shell 命令) [3]。
- 权限控制:对工具进行分级(如只读、读写、危险),高危工具执行前需要人工确认 [3]。
- 沙盒与过滤:代码执行类工具必须在隔离的沙盒环境中运行,工具返回的数据如果包含敏感信息需要脱敏后再传给模型 [3]。
- 配额与审计:设置速率限制以防模型陷入循环调用耗尽 API 配额,并记录每次调用的输入输出以便事后追溯 [3]。
博客摘要 + 核心看点 点击展开
Function Calling 与工具使用开发指南 — summary
SEO 友好博客摘要
本文是一份硬核的“Function Calling 与工具使用开发指南”,深入解析了如何让大模型通过结构化调用外部工具来打破文本输出的局限[1]。文章不仅横向对比了 OpenAI、Claude 和 Gemini 三大主流平台的 API 核心特性[1],还详细剖析了工具 Schema 的设计原则与实战级代码示例[1-3]。此外,指南系统总结了多工具编排模式(如串行、并行和条件调用),并针对开发者关注的错误处理、权限控制、沙盒执行等核心安全考量提供了生产级最佳实践[3]。无论您是 AI 智能体开发者还是架构师,本文都能助您高效构建安全的大模型应用。
核心看点
- 三大平台横向对比:深度解析 Function Calling 核心流程,对比 OpenAI、Claude 与 Gemini 的 API 规范与差异[1]。
- Schema 设计与实战:强调工具描述重于参数设定,并提供了基于 OpenAI 和 Claude 的完整 Python 接入流程[1, 3]。
- 多工具编排与安全防护:总结四大编排模式,提供权限控制、沙盒执行及错误兜底等生产环境最佳实践[3]。
60 秒短视频脚本 点击展开
Function Calling 与工具使用开发指南 — video
钩子开场:
大模型只会聊天?教它用工具![1]
核心解说:
- 函数调用让模型不再只输出文本,而是能结构化调用外部工具办事。[1]
- 设计工具时,描述比参数更重要,切记一个工具最好只做一件事。[1, 2]
- 安全考量是底线,严禁直连危险操作,代码执行必须在隔离沙盒里。[3]
一句收束:
掌握多工具编排,让你的AI应用真正长出“手脚”![3]
课后巩固
与本文内容匹配的闪卡与测验,帮助巩固所学知识
延伸阅读
根据本文主题,为你推荐相关的学习资料