AI Agent工具调用(Function Calling)深度实战:从原理到生产级架构
工具调用是AI Agent的核心能力——让大语言模型不仅能"说",还能"做"。本文从协议原理到生产级实现,手把手带你掌握Function Calling的每一个细节。
前言
2024年以来,AI Agent的概念火遍整个技术圈。但你有没有想过,一个Agent到底是怎么"动手"操作外部世界的?答案就是工具调用(Tool Use / Function Calling)。
我在实际项目中踩过无数坑:参数解析失败、工具名幻觉、循环调用死循环、并发工具调用竞态……这些问题官方文档很少提及,但每一个都可能让你的Agent在生产环境中翻车。
这篇文章会从协议层面讲清楚工具调用的原理,然后用真实的Python代码带你从零实现一个生产级的工具调用框架。
一、Function Calling 协议原理
1.1 核心概念
Function Calling的本质是:让LLM输出结构化的工具调用请求,由外部系统执行后将结果返回给LLM。
整个流程是这样的:
用户输入 → LLM推理 → 输出工具调用请求(JSON) → 外部系统执行工具 → 将结果返回LLM → LLM整合结果生成最终回复关键点在于:LLM本身不执行任何工具,它只是决定"要调用什么工具、传什么参数"。真正的执行发生在你的应用层代码中。
1.2 三大厂商协议对比
不同厂商的Function Calling协议有细微但重要的差异:
OpenAI 协议
# OpenAI 的工具定义格式tools=[{"type":"function","function":{"name":"get_weather","description":"获取指定城市的天气信息","parameters":{"type":"object","properties":{"city":{"type":"string","description":"城市名称,如'北京'"},"unit":{"type":"string","enum":["celsius","fahrenheit"],"description":"温度单位"}},"required":["city"]}}}]response=client.chat.completions.create(model="gpt-4o",messages=[{"role":"user","content":"北京今天天气怎么样?"}],tools=tools,tool_choice="auto"# auto | none | required | {"type":"function","function":{"name":"xxx"}})OpenAI返回的工具调用在message.tool_calls中:
# 返回结构message=response.choices[0].messageifmessage.tool_calls:fortcinmessage.tool_calls:print(tc.function.name)# "get_weather"print(tc.function.arguments)# '{"city":"北京","unit":"celsius"}'print(tc.id)# "call_abc123",用于后续提交结果Anthropic (Claude) 协议
# Claude 的工具定义格式 - 注意差异!tools=[{"name":"get_weather","description":"获取指定城市的天气信息","input_schema":{# 注意:Claude用 input_schema,不是 parameters"type":"object","properties":{"city":{"type":"string","description":"城市名称"}},"required":["city"]}}]response=client.messages.create(model="claude-sonnet-4-20250514",max_tokens=1024,messages=[{"role":"user","content":"北京今天天气怎么样?"}],tools=tools)Claude的返回结构也不同:
# Claude 返回在 content 数组中,类型为 tool_useforblockinresponse.content:ifblock.type=="tool_use":print(block.name)# "get_weather"print(block.input)# {"city": "北京"} - 注意是 dict,不是字符串!print(block.id)# "toolu_abc123"Google Gemini 协议
# Gemini 的工具定义importgoogle.generativeaiasgenaidefget_weather(city:str,unit:str="celsius")->dict:"""获取指定城市的天气信息"""pass# Gemini 支持直接传入 Python 函数!model=genai.GenerativeModel('gemini-2.0-flash',tools=[get_weather]# 自动从函数签名生成Schema)# 也可以用 FunctionDeclaration 手动定义fromgoogle.generativeai.typesimportFunctionDeclaration,Tool weather_func=FunctionDeclaration(name="get_weather",description="获取指定城市的天气信息",parameters={"type":"object","properties":{"city":{"type":"string","description":"城市名称"}},"required":["city"]})model=genai.GenerativeModel('gemini-2.0-flash',tools=[Tool(function_declarations=[weather_func])])1.3 关键差异总结
| 特性 | OpenAI | Claude | Gemini |
|---|---|---|---|
| Schema字段名 | parameters | input_schema | parameters |
| 返回格式 | 字符串JSON | 原生dict | 原生dict |
| 工具ID | 自动生成 | 自动生成 | 无(靠name匹配) |
| 并行调用 | 支持(多个tool_calls) | 支持(多个tool_use块) | 支持(多个function_call) |
| 强制调用 | tool_choice="required" | 无直接支持 | 无直接支持 |
| 原生函数支持 | 不支持 | 不支持 | 支持(Python函数直接传入) |
二、工具定义的 JSON Schema 最佳实践
2.1 常见错误:模糊的描述
# ❌ 错误:描述太模糊,LLM不知道怎么调用{"name":"search","description":"搜索","parameters":{"type":"object","properties":{"q":{"type":"string"}}}}# ✅ 正确:描述清晰,包含使用场景和约束{"name":"search_products","description":"在商品库中搜索产品。支持关键词模糊匹配。返回最多20条结果,按相关性排序。当用户询问商品信息、价格比较、购买建议时使用此工具。","parameters":{"type":"object","properties":{"query":{"type":"string","description":"搜索关键词,如'无线蓝牙耳机'、'iPhone手机壳'"},"category":{"type":"string","enum":["electronics","clothing","food","books"],"description":"商品分类筛选,可选。不指定则搜索全部分类"},"max_price":{"type":"number","description":"最高价格限制(元),可选"},"sort_by":{"type":"string","enum":["relevance","price_asc","price_desc","sales"],"description":"排序方式,默认按相关性排序"}},"required":["query"]}}2.2 嵌套对象与数组
当工具需要复杂参数时,Schema的定义变得关键:
# 复杂参数的正确定义{"name":"create_order","description":"创建订单。当用户确认购买意向后调用。","parameters":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"product_id":{"type":"string","description":"商品ID,格式为'PROD-XXXX'"},"quantity":{"type":"integer","minimum":1,"maximum":99,"description":"购买数量"}},"required":["product_id","quantity"]},"description":"订单商品列表"},"shipping_address":{"type":"object","properties":{"province":{"type":"string"},"city":{"type":"