跳到主要内容

工具调用机制

问题

LLM 的 Function Calling / Tool Use 是如何工作的?如何设计好的工具定义?

答案

工具调用(Function Calling / Tool Use)是 Agent 与外部世界交互的核心机制。LLM 不直接执行工具,而是生成结构化的调用请求,由应用层执行后返回结果。

一、工作流程

关键理解

LLM 不执行工具——它只是决定调用什么工具、传什么参数。实际执行由应用层完成。

二、工具定义

OpenAI 格式

tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的天气信息。当用户问天气相关问题时调用。",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,如'北京'、'上海'"
},
"date": {
"type": "string",
"description": "日期,格式 YYYY-MM-DD,默认今天"
}
},
"required": ["city"]
}
}
}
]

Anthropic 格式

tools = [
{
"name": "get_weather",
"description": "获取指定城市的天气信息",
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名称"},
},
"required": ["city"]
}
}
]

三、工具设计最佳实践

原则正确做法错误做法
描述清晰"获取指定城市的实时天气""天气工具"
参数明确标注类型、格式、枚举值只写参数名
单一职责一个工具做一件事一个工具做很多事
何时调用描述中说明触发条件不说明使用时机
错误返回返回结构化错误信息抛异常或空返回
# ✅ 好的工具描述
{
"name": "search_products",
"description": "在商品库中搜索商品。当用户询问商品信息、价格、库存时调用。返回匹配的商品列表。",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "搜索关键词"},
"category": {
"type": "string",
"enum": ["electronics", "clothing", "food"],
"description": "商品类别(可选)"
},
"max_results": {
"type": "integer",
"description": "最大返回数量,默认5",
"default": 5
}
},
"required": ["query"]
}
}

四、并行工具调用

LLM 可以在一次响应中发起多个并行的工具调用:

# LLM 一次返回多个 tool_calls
response.choices[0].message.tool_calls = [
ToolCall(id="call_1", function=Function(name="get_weather", arguments='{"city":"北京"}')),
ToolCall(id="call_2", function=Function(name="get_weather", arguments='{"city":"上海"}')),
]

# 并行执行,分别返回结果
for tool_call in message.tool_calls:
result = execute_tool(tool_call)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})

五、工具调用安全

风险说明防御
越权调用Agent 调用了不该调用的工具白名单限制可用工具
参数注入恶意输入导致危险参数参数校验、沙箱执行
数据泄露工具返回敏感信息输出过滤、权限控制
无限循环Agent 反复调用同一工具次数限制
# 工具执行层必须有安全防护
def safe_execute_tool(name: str, arguments: dict, user_permissions: list):
# 1. 检查权限
if name not in user_permissions:
return {"error": "无权限调用此工具"}

# 2. 参数校验
validated_args = validate_arguments(name, arguments)

# 3. 沙箱执行
result = sandbox_execute(name, validated_args)

# 4. 输出过滤(脱敏)
return sanitize_output(result)

常见面试问题

Q1: Function Calling 的参数是 LLM 生成的,如何保证准确性?

答案

  1. 清晰的参数描述:description 中给出格式和示例
  2. enum 约束:可枚举的参数用 enum 限定范围
  3. Structured Output:OpenAI 的 Structured Output 可以保证 JSON Schema 合规
  4. 应用层兜底:对参数做类型校验和范围检查

Q2: 工具太多(>20个)时 LLM 会不会选错?

答案

  • 工具数量多确实会降低选择准确率
  • 优化方式:
    1. 分组:根据意图先分类,再暴露该类工具
    2. 动态工具:用 Embedding 检索最相关的 5-10 个工具
    3. 描述优化:清晰的 description 比工具数量更重要

相关链接